import "server-only"; import { upsertSystemSetting } from "@/lib/db/queries"; import { AGENT_PSD_TEMPLATES_KEY, type AgentPsdTemplate, } from "@/lib/agents/psd-template-config"; import { readAgentPsdTemplates } from "@/lib/agents/psd-template-settings"; export const AGENT_PSD_TEMPLATE_QUICK_PARSE_TIMEOUT_MS = 8 * 60 * 1000; export const AGENT_PSD_TEMPLATE_ASSET_BACKFILL_TIMEOUT_MS = 20 * 60 * 1000; function getTemplateUpdatedAtTime(template: AgentPsdTemplate) { const updatedAt = new Date(template.updatedAt).getTime(); if (Number.isFinite(updatedAt)) { return updatedAt; } const createdAt = new Date(template.createdAt).getTime(); return Number.isFinite(createdAt) ? createdAt : null; } function hasPassedFastParsePhase(template: AgentPsdTemplate) { return ( Number(template.parseProgress || 0) >= 48 || template.layers.length > 0 || (Number(template.width || 0) > 1 && Number(template.height || 0) > 1) ); } export function getAgentPsdTemplateParseTimeoutMs(template: AgentPsdTemplate) { return hasPassedFastParsePhase(template) ? AGENT_PSD_TEMPLATE_ASSET_BACKFILL_TIMEOUT_MS : AGENT_PSD_TEMPLATE_QUICK_PARSE_TIMEOUT_MS; } export function getAgentPsdTemplateParseAgeMs( template: AgentPsdTemplate, now = Date.now() ) { const updatedAt = getTemplateUpdatedAtTime(template); if (!updatedAt) { return Number.POSITIVE_INFINITY; } return Math.max(0, now - updatedAt); } export function isAgentPsdTemplateParseTimedOut( template: AgentPsdTemplate, now = Date.now() ) { if (template.parseStatus !== "processing") { return false; } return ( getAgentPsdTemplateParseAgeMs(template, now) > getAgentPsdTemplateParseTimeoutMs(template) ); } function buildTimeoutMessage(template: AgentPsdTemplate) { const timeoutMinutes = Math.round( getAgentPsdTemplateParseTimeoutMs(template) / 60_000 ); const phase = hasPassedFastParsePhase(template) ? "后台图层资产补全" : "PSD 快速解析"; const stage = template.parseStage ? `,最后阶段:${template.parseStage}` : ""; return `${phase}超过 ${timeoutMinutes} 分钟未更新进度,系统已自动结束本次任务${stage}。可检查 PSD 文件后重新解析。`; } export function failTimedOutAgentPsdTemplatesInMemory(params: { templates: AgentPsdTemplate[]; now?: Date; }) { const now = params.now || new Date(); let changed = false; const timedOutTemplates: AgentPsdTemplate[] = []; const templates = params.templates.map((template) => { if (!isAgentPsdTemplateParseTimedOut(template, now.getTime())) { return template; } changed = true; const nextTemplate: AgentPsdTemplate = { ...template, parseStatus: "failed", parseProgress: Math.min( 95, Math.max(0, Math.round(Number(template.parseProgress || 0))) ), parseStage: hasPassedFastParsePhase(template) ? "后台图层资产补全超时" : "PSD 快速解析超时", parseError: buildTimeoutMessage(template), updatedAt: now.toISOString(), }; timedOutTemplates.push(nextTemplate); return nextTemplate; }); return { changed, templates, timedOutTemplates, }; } export async function failTimedOutAgentPsdTemplates(params: { updatedBy: string; now?: Date; }) { const currentTemplates = await readAgentPsdTemplates(); const result = failTimedOutAgentPsdTemplatesInMemory({ templates: currentTemplates, now: params.now, }); if (result.changed) { await upsertSystemSetting({ key: AGENT_PSD_TEMPLATES_KEY, value: result.templates, updatedBy: params.updatedBy, }); } return result; }