fix: 复用现有 Qwen VL 模型调用方式
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-02-02 12:06:57 +08:00
parent 3558eed251
commit f7debfb55f

View File

@ -1,6 +1,7 @@
import { NextResponse } from "next/server";
import { db } from "@/lib/db";
import { aiProvider } from "@/lib/db/schema";
import { generateText } from "ai";
import { getEnabledAiModelsWithProvider } from "@/lib/db/queries";
import { getLanguageModelById } from "@/lib/ai/dynamic-provider";
export const runtime = "nodejs";
export const maxDuration = 30;
@ -13,7 +14,7 @@ const POSITION_OPTIONS = [
] as const;
interface PickObjectRequest {
imageUrl: string; // 图片 URL(不再使用 Base64)
imageUrl: string; // 图片 URL
clickX: number; // 点击位置 X (0-1)
clickY: number; // 点击位置 Y (0-1)
}
@ -52,17 +53,28 @@ export async function POST(request: Request) {
}, { status: 400 });
}
// 获取 Qwen-VL 配置 - 使用原生 SQL 查询
const providers = await db.select().from(aiProvider);
const qwenProvider = providers.find(p => p.providerId === 'qwen');
// 获取 Qwen VL 模型(复用现有逻辑)
const allModels = await getEnabledAiModelsWithProvider();
const qwenModel = allModels.find(
(m) => m.provider.type === "alibaba" && m.model.supportsVision
);
console.log('[PickObject] 找到 providers:', providers.length, '个');
console.log('[PickObject] Qwen provider:', qwenProvider ? '已找到' : '未找到');
if (!qwenProvider || !qwenProvider.isEnabled || !qwenProvider.apiKey) {
if (!qwenModel) {
console.log("[PickObject] No Qwen VL model found");
return NextResponse.json({
success: false,
error: 'Qwen 服务未配置或未启用',
error: 'Qwen VL 模型未配置',
}, { status: 500 });
}
console.log('[PickObject] 使用模型:', qwenModel.model.modelId, qwenModel.model.displayName);
const model = await getLanguageModelById(qwenModel.model.id);
if (!model) {
console.log("[PickObject] Failed to get language model");
return NextResponse.json({
success: false,
error: '无法加载模型',
}, { status: 500 });
}
@ -89,56 +101,33 @@ ${POSITION_OPTIONS.join('、')}
【boundingBox】相对坐标 0-1,精确到小数点后2位
`.trim();
const apiUrl = `${qwenProvider.apiBaseUrl || 'https://dashscope.aliyuncs.com/compatible-mode/v1'}/chat/completions`;
console.log('[PickObject] 调用 Qwen API:', apiUrl);
console.log('[PickObject] 调用 Qwen VL 模型...');
// 调用 Qwen-VL API(使用图片 URL)
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${qwenProvider.apiKey}`,
},
body: JSON.stringify({
model: 'qwen-vl-max',
messages: [
{
role: 'user',
content: [
{
type: 'image_url',
image_url: {
url: imageUrl, // 直接使用图片 URL
},
},
{
type: 'text',
text: prompt,
},
],
},
],
max_tokens: 200,
}),
});
// 调用 Qwen VL 模型(复用现有的 generateText)
const { text: responseText } = await generateText({
model,
messages: [
{
role: 'user',
content: [
{
type: 'image',
image: imageUrl, // 直接使用图片 URL
},
{
type: 'text',
text: prompt,
},
],
},
],
temperature: 0.1,
maxTokens: 300,
} as any);
console.log('[PickObject] Qwen API 响应状态:', response.status);
console.log('[PickObject] Qwen 返回内容:', responseText?.substring(0, 200));
if (!response.ok) {
const errorText = await response.text();
console.error('[PickObject] Qwen API error:', errorText);
return NextResponse.json({
success: false,
error: `AI 识别服务错误: ${response.status}`,
}, { status: 500 });
}
const data = await response.json();
const content = data.choices?.[0]?.message?.content;
console.log('[PickObject] Qwen 返回内容:', content?.substring(0, 200));
if (!content) {
if (!responseText) {
return NextResponse.json({
success: false,
error: 'AI 未返回结果',
@ -149,7 +138,7 @@ ${POSITION_OPTIONS.join('、')}
let result: PickObjectResult;
try {
// 尝试从返回内容中提取 JSON
const jsonMatch = content.match(/\{[\s\S]*\}/);
const jsonMatch = responseText.match(/\{[\s\S]*\}/);
if (!jsonMatch) {
throw new Error('未找到 JSON');
}
@ -190,7 +179,7 @@ ${POSITION_OPTIONS.join('、')}
}
} catch (parseError) {
console.error('[PickObject] JSON parse error:', parseError, 'Content:', content);
console.error('[PickObject] JSON parse error:', parseError, 'Content:', responseText);
// 返回默认结果
const posX = clickX < 0.33 ? '左' : clickX > 0.66 ? '右' : '中央';