62 lines
3.5 KiB
TypeScript
62 lines
3.5 KiB
TypeScript
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<string>();
|
|
|
|
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);
|
|
}
|
|
}
|