import { generateText } from "ai"; import { createLogger } from "@/lib/observability/logger"; const logger = createLogger("canvas-prompt-tools"); import { NextResponse } from "next/server"; import { auth } from "@/app/(auth)/auth"; import { getLanguageModelById } from "@/lib/ai/dynamic-provider"; import { getEnabledAiModelsWithProvider, getSystemSetting } from "@/lib/db/queries"; import { VIDEO_CANVAS_FUNCTION_CONFIG_KEY, normalizeVideoCanvasFunctionConfig } from "@/lib/video-canvas/config"; import { promptToolErrorMessage, promptToolFunctionKey, promptToolSchema, selectPromptToolModel } from "@/lib/video-canvas/prompt-tools"; export const runtime = "nodejs"; export const maxDuration = 120; const running = new Set(); export async function POST(request: Request) { const session = await auth(); if (!session?.user?.id) return NextResponse.json({ success: false, error: "未登录" }, { status: 401 }); const parsed = promptToolSchema.safeParse(await request.json().catch(() => null)); if (!parsed.success) return NextResponse.json({ success: false, error: parsed.error.issues[0]?.message || "参数无效" }, { status: 400 }); if (running.has(session.user.id)) return NextResponse.json({ success: false, error: "提示词处理中,请稍候" }, { status: 429 }); running.add(session.user.id); try { const [setting, available] = await Promise.all([ getSystemSetting({ key: VIDEO_CANVAS_FUNCTION_CONFIG_KEY }), getEnabledAiModelsWithProvider(false), ]); const config = normalizeVideoCanvasFunctionConfig(setting?.value); const definition = config.functions[promptToolFunctionKey(parsed.data.mode)]; if (!config.enabled || !definition?.enabled) return NextResponse.json({ success: false, error: "此提示词功能已停用" }, { status: 403 }); const requested = parsed.data.model && parsed.data.model !== "auto" ? parsed.data.model : definition.model && definition.model !== "auto" ? definition.model : config.defaultMultimodalModel; let selected; try { selected = selectPromptToolModel(available .filter(item => item.provider.isEnabled && item.model.isEnabled && !item.model.isSubModel) .map(item => ({ ...item.model, providerType: item.provider.type })), requested); } catch (error) { return NextResponse.json({ success: false, error: (error as Error).message }, { status: 400 }); } const model = await getLanguageModelById(selected.id); if (!model) return NextResponse.json({ success: false, error: "提示词模型初始化失败" }, { status: 502 }); const { text } = await generateText({ model, system: definition.prompt, prompt: parsed.data.prompt, temperature: parsed.data.mode === "translate" ? 0.1 : 0.4, maxOutputTokens: 4000, maxRetries: 0, abortSignal: AbortSignal.any([request.signal, AbortSignal.timeout(90_000)]), }); if (!text.trim()) throw new Error("empty model output"); return NextResponse.json({ success: true, data: { text: text.trim(), model: selected.id, modelName: selected.displayName || selected.modelId } }); } catch (error) { const detail = error as { name?: string; statusCode?: number; cause?: { code?: string }; data?: { error?: { code?: string } } }; logger.warn("Prompt tool request failed", { name: detail?.name, statusCode: detail?.statusCode, code: detail?.data?.error?.code || detail?.cause?.code }); return NextResponse.json({ success: false, error: promptToolErrorMessage(error) }, { status: 502 }); } finally { running.delete(session.user.id); } }