Add runtime restore and temp asset cleanup

This commit is contained in:
2026-06-05 20:28:26 +08:00
parent 644a6f9d17
commit d41d9482c7
22 changed files with 1837 additions and 50 deletions
+100 -21
View File
@@ -9,11 +9,13 @@ export function RealtimeLoadPanel(props: {
modelRateLimitsUpdatedAt: number | null;
platforms: IntegrationPlatform[];
onSavePlatformDynamicPriority: (platformId: string, input: PlatformDynamicPriorityUpdateRequest) => Promise<void>;
onRestoreRuntimeModel: (platformModelId: string) => Promise<void>;
}) {
const [now, setNow] = useState(() => Date.now());
const [priorityDialog, setPriorityDialog] = useState<PriorityDialogState | null>(null);
const [priorityError, setPriorityError] = useState('');
const [prioritySaving, setPrioritySaving] = useState(false);
const [restoreSavingId, setRestoreSavingId] = useState<string | null>(null);
const platformMap = useMemo(() => new Map(props.platforms.map((item) => [item.id, item])), [props.platforms]);
useEffect(() => {
@@ -65,6 +67,17 @@ export function RealtimeLoadPanel(props: {
}
}
async function restoreRuntimeModel(platformModelId: string) {
setRestoreSavingId(platformModelId);
try {
await props.onRestoreRuntimeModel(platformModelId);
} catch {
// App-level state owns the error message.
} finally {
setRestoreSavingId(null);
}
}
return (
<section className="pageStack">
<Card>
@@ -81,6 +94,8 @@ export function RealtimeLoadPanel(props: {
statuses={props.modelRateLimits}
updatedAt={props.modelRateLimitsUpdatedAt}
onAdjustPriority={openPriorityDialog}
onRestoreRuntimeModel={restoreRuntimeModel}
restoreSavingId={restoreSavingId}
/>
</CardContent>
</Card>
@@ -109,6 +124,8 @@ function RateLimitStatusTable(props: {
now: number;
updatedAt: number | null;
onAdjustPriority: (status: ModelRateLimitStatus, platform: IntegrationPlatform | undefined) => void;
onRestoreRuntimeModel: (platformModelId: string) => Promise<void>;
restoreSavingId: string | null;
}) {
if (!props.statuses.length) {
return <EmptyState title="暂无实时负载" description="模型产生请求后会在这里显示实时 RPM、TPM 和并发窗口。" />;
@@ -150,7 +167,15 @@ function RateLimitStatusTable(props: {
<small>{status.provider}</small>
</span>
</TableCell>
<TableCell className="platformLimitStatusCell">{modelRuntimeStatusCell(status, platform, props.now)}</TableCell>
<TableCell className="platformLimitStatusCell">
{modelRuntimeStatusCell(
status,
platform,
props.now,
props.onRestoreRuntimeModel,
props.restoreSavingId === status.platformModelId,
)}
</TableCell>
<TableCell className="platformLimitNumberCell">{platformPriorityCell(status, platform, props.onAdjustPriority)}</TableCell>
<TableCell className="platformLimitNumberCell">
<span className="rateLoadCell" data-overloaded={status.loadRatio > 0.8 ? 'true' : undefined}>
@@ -447,50 +472,104 @@ function shortId(value: string | undefined) {
return value.length > 8 ? value.slice(0, 8) : value;
}
function modelRuntimeStatusCell(status: ModelRateLimitStatus, platform: IntegrationPlatform | undefined, now: number) {
function modelRuntimeStatusCell(
status: ModelRateLimitStatus,
platform: IntegrationPlatform | undefined,
now: number,
onRestore: (platformModelId: string) => Promise<void>,
restoring: boolean,
) {
const modelCooldownMs = cooldownRemainingMs(status.modelCooldownUntil, now);
const platformCooldownMs = cooldownRemainingMs(status.platformCooldownUntil, now);
const platformStatus = platform?.status || status.platformStatus || 'enabled';
const restoreButton = runtimeRestoreButton(status, platformStatus, modelCooldownMs, platformCooldownMs, onRestore, restoring);
if (modelCooldownMs > 0) {
return (
<span className="platformTableName">
<strong><Badge variant="warning"></Badge></strong>
<small> {formatCooldownRemaining(modelCooldownMs)}</small>
<span className="platformRuntimeStatusCell">
<span className="platformTableName">
<strong><Badge variant="warning"></Badge></strong>
<small> {formatCooldownRemaining(modelCooldownMs)}</small>
</span>
{restoreButton}
</span>
);
}
if (platformStatus !== 'enabled') {
const badge = <Badge variant="warning"></Badge>;
return (
<AntPopover
align={{ offset: [0, 8] }}
content={<PlatformDisabledReasonPopover record={status.platformDisabledReason} />}
overlayClassName="priorityDemotionAntPopover"
placement="bottomLeft"
trigger={['hover', 'focus']}
>
<span className="platformTableName" tabIndex={0}>
<strong>{badge}</strong>
<span className="platformRuntimeStatusCell">
<AntPopover
align={{ offset: [0, 8] }}
content={<PlatformDisabledReasonPopover record={status.platformDisabledReason} />}
overlayClassName="priorityDemotionAntPopover"
placement="bottomLeft"
trigger={['hover', 'focus']}
>
<span className="platformTableName" tabIndex={0}>
<strong>{badge}</strong>
</span>
</AntPopover>
{restoreButton}
</span>
);
}
if (!status.enabled) {
return (
<span className="platformRuntimeStatusCell">
<span className="platformTableName">
<strong><Badge variant="secondary"></Badge></strong>
<small></small>
</span>
</AntPopover>
{restoreButton}
</span>
);
}
if (platformCooldownMs > 0) {
return (
<span className="platformTableName">
<strong><Badge variant="warning"></Badge></strong>
<small> {formatCooldownRemaining(platformCooldownMs)}</small>
<span className="platformRuntimeStatusCell">
<span className="platformTableName">
<strong><Badge variant="warning"></Badge></strong>
<small> {formatCooldownRemaining(platformCooldownMs)}</small>
</span>
{restoreButton}
</span>
);
}
return (
<span className="platformTableName">
<strong><Badge variant={status.enabled ? 'success' : 'secondary'}>{status.enabled ? '可用' : '已停用'}</Badge></strong>
<small>{status.enabled ? '参与路由' : '不参与路由'}</small>
<span className="platformRuntimeStatusCell">
<span className="platformTableName">
<strong><Badge variant="success"></Badge></strong>
<small></small>
</span>
</span>
);
}
function runtimeRestoreButton(
status: ModelRateLimitStatus,
platformStatus: string,
modelCooldownMs: number,
platformCooldownMs: number,
onRestore: (platformModelId: string) => Promise<void>,
restoring: boolean,
) {
const canRestore = modelCooldownMs > 0 || platformCooldownMs > 0 || platformStatus !== 'enabled' || !status.enabled;
if (!canRestore) return null;
return (
<Button
className="platformRestoreButton"
type="button"
variant="outline"
size="xs"
disabled={restoring}
onClick={() => void onRestore(status.platformModelId)}
>
<RotateCcw size={13} />
{restoring ? '恢复中' : '恢复'}
</Button>
);
}
function cooldownRemainingMs(cooldownUntil: string | undefined, now: number) {
if (!cooldownUntil) return 0;
const until = Date.parse(cooldownUntil);