export type CreativeAnalysisModel = { id: string; label: string; modelId: string; providerType: string; supportsVision: boolean; }; type CreativeAnalysisRequest = { mode: "agent-plan" | "story-script" | "character-scene-extraction"; prompt: string; nodeTitle: string; models: CreativeAnalysisModel[]; preferredModelRef?: string; imageUrls?: string[]; videoUrls?: string[]; }; function modelPriority(model: CreativeAnalysisModel) { if (model.providerType === "alibaba" && model.modelId === "qwen3.8-max") return 0; if (model.providerType === "alibaba" && model.modelId === "qwen3.8-omni-flash") return 1; return 2; } export async function requestCreativeAnalysis(input: CreativeAnalysisRequest): Promise> { const hasVisualInput = Boolean(input.imageUrls?.length || input.videoUrls?.length); const compatible = input.models.filter(model => !hasVisualInput || model.supportsVision); const selected = input.preferredModelRef ? compatible.find(model => model.id === input.preferredModelRef || model.modelId === input.preferredModelRef) : undefined; if (input.preferredModelRef && !selected) throw new Error("所选模型不支持当前素材,请重新选择模型"); const candidates = selected ? [selected] : [...compatible].sort((left, right) => modelPriority(left) - modelPriority(right)); const attempts: (CreativeAnalysisModel | undefined)[] = candidates.length ? candidates : [undefined]; let lastError = "分析失败,请稍后重试"; for (const [index, model] of attempts.entries()) { const response = await fetch("/api/canvas/workflow/analyze", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ mode: input.mode, prompt: input.prompt, nodeTitle: input.nodeTitle, preferredModelRef: model?.id, imageUrls: input.imageUrls?.slice(0, 4) || [], videoUrls: input.videoUrls?.slice(0, 2) || [], }), }); const result = await response.json().catch(() => ({})); if (response.ok && result.success) return result.data as Record; lastError = String(result.error || "分析失败,请稍后重试"); const authenticationFailure = /invalid authentication|invalid token|invalid api.?key|authentication failed|鉴权失败|认证失败/i.test(lastError); if (selected || !authenticationFailure || index === attempts.length - 1) break; } throw new Error(lastError); }