diff --git a/app/api/pick-object/route.ts b/app/api/pick-object/route.ts index f2eed4ae1..b1afb81cd 100644 --- a/app/api/pick-object/route.ts +++ b/app/api/pick-object/route.ts @@ -1,12 +1,15 @@ import { NextResponse } from "next/server"; import { auth } from "@/app/(auth)/auth"; -import { uploadFile } from "@/lib/storage/service"; import { callQwen3Vl } from "@/lib/ai/qwen3-vl"; +import { createLogger } from "@/lib/observability/logger"; +import { uploadFile } from "@/lib/storage/service"; import sharp from "sharp"; export const runtime = "nodejs"; export const maxDuration = 30; +const logger = createLogger("pick-object"); + // 位置词库 const POSITION_OPTIONS = [ '左上区域', '中央顶部', '右上区域', @@ -106,11 +109,12 @@ async function uploadVisionAnalysisImage(buffer: Buffer, filenamePrefix: string) const { buffer: processedBuffer, ext, width, height } = await downscaleImageForVision(buffer); const filename = `${filenamePrefix}-${Date.now()}.${ext}`; const uploaded = await uploadFile(filename, processedBuffer as any); - console.log("[PickObject] 视觉分析图片已缩放:", { + logger.info("vision image prepared", { originalWidth: width, originalHeight: height, maxSide: MAX_VISION_SIDE, outputExt: ext, + outputBytes: processedBuffer.length, }); return uploaded.url; } @@ -172,7 +176,11 @@ export async function POST(request: Request) { const body: PickObjectRequest = await request.json(); const { imageData, clickX, clickY } = body; - console.log('[PickObject] 收到请求:', { imageDataLength: imageData?.length, clickX, clickY }); + logger.info("request received", { + imageDataLength: imageData?.length, + clickX, + clickY, + }); // 验证参数 if (!imageData) { @@ -198,7 +206,7 @@ export async function POST(request: Request) { const normalizedImage = await normalizeImageInput(imageData); - console.log("[PickObject] 使用硬编码模型: qwen3-vl"); + logger.info("vision model selected", { model: "qwen3-vl" }); // 构建 prompt - AI 通过红色标记来识别用户选择的物品 const prompt = ` @@ -225,7 +233,7 @@ export async function POST(request: Request) { ${POSITION_OPTIONS.join('、')} `.trim(); - console.log('[PickObject] 调用视觉模型...'); + logger.info("vision model call started"); // 调用视觉模型,发送带红色标记的图片 const { text: responseText, model } = await callQwen3Vl({ @@ -235,7 +243,10 @@ ${POSITION_OPTIONS.join('、')} maxTokens: 300, }); - console.log('[PickObject] 模型返回内容:', model, responseText?.substring(0, 200)); + logger.info("vision model call completed", { + model, + responseLength: responseText?.length || 0, + }); if (!responseText) { return NextResponse.json({ @@ -287,7 +298,10 @@ ${POSITION_OPTIONS.join('、')} }; } catch (parseError) { - console.error('[PickObject] JSON parse error:', parseError, 'Content:', responseText); + logger.warn("model response parse failed", { + error: parseError, + responseLength: responseText.length, + }); // 返回默认结果 const posX = clickX < 0.33 ? '左' : clickX > 0.66 ? '右' : '中央'; @@ -304,7 +318,11 @@ ${POSITION_OPTIONS.join('、')} }; } - console.log('[PickObject] 识别结果:', result); + logger.info("object picked", { + nameLength: result.name.length, + position: result.position, + confidence: result.confidence, + }); return NextResponse.json({ success: true, @@ -317,7 +335,7 @@ ${POSITION_OPTIONS.join('、')} }); } catch (error) { - console.error('[PickObject] Error:', error); + logger.error("pick object failed", error); return NextResponse.json({ success: false, error: `识别失败: ${error instanceof Error ? error.message : '未知错误'}`, diff --git a/scripts/check-log-hygiene.mjs b/scripts/check-log-hygiene.mjs index 4873d4ff9..706ab8f90 100644 --- a/scripts/check-log-hygiene.mjs +++ b/scripts/check-log-hygiene.mjs @@ -31,6 +31,7 @@ const files = [ "app/api/canvas/text-detect/route.ts", "app/api/canvas/detail-plan/route.ts", "app/api/scene-fusion/route.ts", + "app/api/pick-object/route.ts", ]; const consolePattern = /\bconsole\.(log|warn|error|info|debug)\b/g;