Your Name 94640002d0 fix: 多图支持和画布自动命名模型ID映射
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-01 16:58:27 +08:00

99 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { NextRequest, NextResponse } from "next/server";
import { auth } from "@/app/(auth)/auth";
import { generateText } from "ai";
import { getEnabledAiModelsWithProvider, getAiProviderById } from "@/lib/db/queries";
import { createOpenAI } from "@ai-sdk/openai";
export async function POST(request: NextRequest) {
console.log("[Auto-title] API called");
try {
const session = await auth();
if (!session?.user?.id) {
console.log("[Auto-title] Unauthorized");
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const { imageUrl } = await request.json();
console.log("[Auto-title] Image URL:", imageUrl);
if (!imageUrl) {
return NextResponse.json({ error: "Image URL is required" }, { status: 400 });
}
// 从数据库获取支持视觉的模型(查找包含 qwen-vl 或 vision 的模型)
const modelsData = await getEnabledAiModelsWithProvider();
console.log("[Auto-title] Available models count:", modelsData.length);
console.log("[Auto-title] All model IDs:", modelsData.map(m => m.model.modelId));
// 查找千问VL模型(支持多种命名格式)
const visionModelData = modelsData.find(m => {
const id = m.model.modelId?.toLowerCase() || '';
const name = m.model.displayName?.toLowerCase() || '';
return id.includes('qwen-vl') ||
id.includes('qwen3-vl') ||
id.includes('qwen2.5-vl') ||
id.includes('vision') ||
name.includes('vl') ||
name.includes('视觉');
});
console.log("[Auto-title] Found vision model:", visionModelData?.model.modelId, visionModelData?.model.displayName);
if (!visionModelData) {
console.log("[Auto-title] No vision model found, using default title");
return NextResponse.json({ title: "未命名画布" });
}
// 直接使用返回的 provider 信息
const provider = visionModelData.provider;
const visionModel = visionModelData.model;
if (!provider || !provider.apiKey || !provider.baseUrl) {
console.log("[Auto-title] Provider not configured");
return NextResponse.json({ title: "未命名画布" });
}
console.log("[Auto-title] Using provider:", provider.name, "baseUrl:", provider.baseUrl);
// 构造 Prompt
const prompt = "请用2-4个字概括这张图片的主体内容,作为文件标题。直接返回标题,不要包含任何标点符号或其他文字。";
// 使用数据库配置的 provider
const openai = createOpenAI({
apiKey: provider.apiKey,
baseURL: provider.baseUrl,
});
// 🆕 模型 ID 映射(处理数据库中的别名到实际 API 模型 ID)
const modelIdMapping: Record<string, string> = {
'qwen3-vl-plus': 'qwen-vl-plus', // 映射到阿里云实际模型
'qwen3-vl-max': 'qwen-vl-max',
'qwen2.5-vl-plus': 'qwen-vl-plus',
};
const actualModelId = modelIdMapping[visionModel.modelId] || visionModel.modelId;
console.log("[Auto-title] Model ID mapping:", visionModel.modelId, "->", actualModelId);
const { text } = await generateText({
model: openai(actualModelId),
messages: [
{
role: 'user',
content: [
{ type: 'text', text: prompt },
{ type: 'image', image: imageUrl },
],
},
],
});
console.log("[Auto-title] Generated title:", text.trim());
return NextResponse.json({ title: text.trim() });
} catch (error) {
console.error("[Auto-title] Error:", error);
// 失败时返回默认标题,不报错中断流程
return NextResponse.json({ title: "新画布" });
}
}