From cc52f414af7a6eb5ca9743727a8756ba5c352167 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 27 May 2026 09:43:43 +0800 Subject: [PATCH] chore: govern chat api logging --- app/(chat)/api/chat/_lib/billing.ts | 20 +- .../api/chat/_lib/detail-replacement.ts | 22 +- app/(chat)/api/chat/_lib/errors.ts | 6 +- app/(chat)/api/chat/_lib/image-failover.ts | 12 +- app/(chat)/api/chat/_lib/image-media.ts | 30 +- .../api/chat/_lib/message-preparation.ts | 12 +- app/(chat)/api/chat/_lib/stream.ts | 6 +- app/(chat)/api/chat/_lib/video-models.ts | 8 +- app/(chat)/api/chat/route.ts | 826 +++++++----------- scripts/check-log-hygiene.mjs | 13 + 10 files changed, 375 insertions(+), 580 deletions(-) diff --git a/app/(chat)/api/chat/_lib/billing.ts b/app/(chat)/api/chat/_lib/billing.ts index a6c0ede9d..59251e201 100644 --- a/app/(chat)/api/chat/_lib/billing.ts +++ b/app/(chat)/api/chat/_lib/billing.ts @@ -1,3 +1,4 @@ +import { createLogger } from "@/lib/observability/logger"; import { getModelGenerationCreditCost } from "@/lib/ai/image-model-pricing"; import { consumeUserPoints, @@ -7,6 +8,9 @@ import { getUserById, } from "@/lib/db/queries"; +const chatApiLogger = createLogger("chat.billing"); + + const MODEL_UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; @@ -50,7 +54,7 @@ export async function consumeGeneratedVideoPoints(params: { const userData = await getUserById({ id: params.userId }).catch(() => undefined); if (userData?.isHighVip) { - console.log(`[Points] Skip video points for VIP user=${params.userId}`); + chatApiLogger.info(`[Points] Skip video points for VIP user=${params.userId}`); return; } @@ -89,19 +93,13 @@ export async function consumeGeneratedVideoPoints(params: { }); if (!consumeResult.ok) { - console.warn( - `[Points] Failed to consume video points. user=${params.userId} model=${billingModel.id} cost=${unitCost}`, - ); + chatApiLogger.warn(`[Points] Failed to consume video points. user=${params.userId} model=${billingModel.id} cost=${unitCost}`); } else if (consumeResult.skipped) { - console.log( - `[Points] Skipped ${unitCost} video points for VIP user=${params.userId} model=${billingModel.id}`, - ); + chatApiLogger.info(`[Points] Skipped ${unitCost} video points for VIP user=${params.userId} model=${billingModel.id}`); } else { - console.log( - `[Points] Consumed ${unitCost} points for video. balance=${consumeResult.balance}`, - ); + chatApiLogger.info(`[Points] Consumed ${unitCost} points for video. balance=${consumeResult.balance}`); } } catch (error) { - console.error("[Points] Failed to consume points after video generation:", error); + chatApiLogger.error("[Points] Failed to consume points after video generation:", error); } } diff --git a/app/(chat)/api/chat/_lib/detail-replacement.ts b/app/(chat)/api/chat/_lib/detail-replacement.ts index bd8b76ffa..88936ad9b 100644 --- a/app/(chat)/api/chat/_lib/detail-replacement.ts +++ b/app/(chat)/api/chat/_lib/detail-replacement.ts @@ -1,3 +1,4 @@ +import { createLogger } from "@/lib/observability/logger"; import { generateText } from "ai"; import { fetchImageBufferFromUrl } from "@/lib/ai/rmbg/service"; import { getLanguageModelById } from "@/lib/ai/dynamic-provider"; @@ -10,6 +11,9 @@ import { isVideoProviderType } from "./video-models"; import type { AgentPresetMessageImagePart } from "./agent-scene-workflow"; import type { PostRequestBody } from "../schema"; +const chatApiLogger = createLogger("chat.detailReplacement"); + + export async function createAgentImageThumbnailBuffer(buffer: Buffer): Promise { const sharp = (await import("sharp")).default; return sharp(buffer, { failOn: "none" }) @@ -91,7 +95,7 @@ export async function resolveReplacementReferenceGeometry( aspectRatio: inferClosestReplacementAspectRatio(width, height), }; } catch (error) { - console.warn("[Chat API] Failed to resolve replacement reference geometry:", { + chatApiLogger.warn("[Chat API] Failed to resolve replacement reference geometry:", { referenceImageUrl, error: error instanceof Error ? error.message : "unknown", }); @@ -318,7 +322,7 @@ export function parseReplacementScenePlan( return scenePlan; } catch (error) { - console.warn("[Chat API] Failed to parse replacement scene plan JSON:", error); + chatApiLogger.warn("[Chat API] Failed to parse replacement scene plan JSON:", error); return null; } } @@ -583,7 +587,7 @@ export function parseReplacementReferenceDecision( }; } } catch (error) { - console.warn("[Chat API] Failed to parse replacement reference decision JSON:", error); + chatApiLogger.warn("[Chat API] Failed to parse replacement reference decision JSON:", error); } } @@ -694,7 +698,7 @@ export async function analyzeReplacementReferenceImage(params: { } } } catch (error) { - console.warn("[Chat API] Configured Qwen-VL reference analysis failed:", error); + chatApiLogger.warn("[Chat API] Configured Qwen-VL reference analysis failed:", error); } } @@ -717,7 +721,7 @@ export async function analyzeReplacementReferenceImage(params: { }; } } catch (error) { - console.warn("[Chat API] Fallback Qwen3-VL reference analysis failed:", error); + chatApiLogger.warn("[Chat API] Fallback Qwen3-VL reference analysis failed:", error); } return { @@ -747,7 +751,7 @@ export async function resolveReplacementScenePlanningRuntime(params: { }; } } catch (error) { - console.warn("[Chat API] Failed to resolve local Moonshot scene planning model:", error); + chatApiLogger.warn("[Chat API] Failed to resolve local Moonshot scene planning model:", error); } const configuredModels = params.models || (await getEnabledAiModelsWithProvider()); @@ -777,7 +781,7 @@ export async function resolveReplacementScenePlanningRuntime(params: { configuredVisionModel.model.modelId, }; } catch (error) { - console.warn("[Chat API] Failed to resolve configured replacement scene planning model:", { + chatApiLogger.warn("[Chat API] Failed to resolve configured replacement scene planning model:", { modelId: configuredVisionModel.model.id, error, }); @@ -811,7 +815,7 @@ export async function analyzeReplacementExecutionPlan(params: { retries: 2, loggerPrefix: "[Chat API] Replacement scene plan", }).catch((error) => { - console.warn("[Chat API] Failed to inline replacement scene planning images:", error); + chatApiLogger.warn("[Chat API] Failed to inline replacement scene planning images:", error); return { inlineDataUrls: [], skipped: [] }; }); const effectiveVisionImages = @@ -926,7 +930,7 @@ export async function analyzeReplacementExecutionPlan(params: { }; } } catch (error) { - console.warn("[Chat API] Replacement scene planning analysis failed:", { + chatApiLogger.warn("[Chat API] Replacement scene planning analysis failed:", { referenceLabel: params.referenceLabel, referenceImageUrl: params.referenceImageUrl, error, diff --git a/app/(chat)/api/chat/_lib/errors.ts b/app/(chat)/api/chat/_lib/errors.ts index 02d935472..9c0c42592 100644 --- a/app/(chat)/api/chat/_lib/errors.ts +++ b/app/(chat)/api/chat/_lib/errors.ts @@ -1,7 +1,11 @@ +import { createLogger } from "@/lib/observability/logger"; import { NextResponse } from "next/server"; import { getRequestErrorMessage } from "@/lib/request-error"; import { generateUUID } from "@/lib/utils"; +const chatApiLogger = createLogger("chat.errors"); + + const DEFAULT_CHAT_PRE_RESPONSE_SOFT_TIMEOUT_MS = 55_000; export class OperationTimeoutError extends Error { @@ -124,7 +128,7 @@ export function createChatApiFailureResponse( const failure = resolveChatApiFailure(error); const traceId = generateUUID(); - console.error("[Chat API] Unhandled request failure:", { + chatApiLogger.error("[Chat API] Unhandled request failure:", { traceId, vercelId, category: failure.category, diff --git a/app/(chat)/api/chat/_lib/image-failover.ts b/app/(chat)/api/chat/_lib/image-failover.ts index 4b2d54663..d52054805 100644 --- a/app/(chat)/api/chat/_lib/image-failover.ts +++ b/app/(chat)/api/chat/_lib/image-failover.ts @@ -1,8 +1,12 @@ +import { createLogger } from "@/lib/observability/logger"; import { isFalGptImage2EditModelId } from "@/lib/ai/providers/fal-image"; import { getLanguageModelById } from "@/lib/ai/dynamic-provider"; import type { ChatMessage } from "@/lib/types"; import { convertMessagesWithImages } from "./image-media"; +const chatApiLogger = createLogger("chat.imageFailover"); + + export const IMAGE_FAILOVER_PROVIDER_ALLOWLIST = new Set([ "alibaba-image", "bfl-image", @@ -130,9 +134,7 @@ export function buildImageFallbackCandidates( } if (isImageFallbackModelCoolingDown(item.model.id)) { const cooldown = imageFailoverModelCooldown.get(item.model.id); - console.log( - `[Chat API] ⏭ Skip configured image fallback on cooldown: ${item.model.displayName} (${providerType}) - ${cooldown?.reason || "cooldown"}` - ); + chatApiLogger.info(`[Chat API] ⏭ Skip configured image fallback on cooldown: ${item.model.displayName} (${providerType}) - ${cooldown?.reason || "cooldown"}`); return false; } return true; @@ -243,9 +245,7 @@ export function getImageCrossProviderCandidates( if (options.currentProviderId && m.provider.id === options.currentProviderId) return false; if (isImageFallbackModelCoolingDown(m.model.id)) { const cooldown = imageFailoverModelCooldown.get(m.model.id); - console.log( - `[Chat API] ⏭ Skip image failover model on cooldown: ${m.model.displayName} (${m.provider.type}) - ${cooldown?.reason || "cooldown"}` - ); + chatApiLogger.info(`[Chat API] ⏭ Skip image failover model on cooldown: ${m.model.displayName} (${m.provider.type}) - ${cooldown?.reason || "cooldown"}`); return false; } return true; diff --git a/app/(chat)/api/chat/_lib/image-media.ts b/app/(chat)/api/chat/_lib/image-media.ts index 4b42d5ade..7ca6da5c3 100644 --- a/app/(chat)/api/chat/_lib/image-media.ts +++ b/app/(chat)/api/chat/_lib/image-media.ts @@ -1,3 +1,4 @@ +import { createLogger } from "@/lib/observability/logger"; import { convertToModelMessages } from "ai"; import { inlineVisionImages } from "@/lib/ai/vision-inline"; import { extractImageUrlsFromText } from "@/lib/image-url"; @@ -6,6 +7,9 @@ import { uploadFile } from "@/lib/storage/service"; import type { ChatMessage } from "@/lib/types"; import { ANNOTATION_SYSTEM_PROMPT, hasAnnotatedImage } from "./message-preparation"; +const chatApiLogger = createLogger("chat.imageMedia"); + + export function guessImageMediaType(url: string): string { const cleanUrl = url.split("?")[0]?.toLowerCase() || ""; if (cleanUrl.endsWith(".jpg") || cleanUrl.endsWith(".jpeg")) return "image/jpeg"; @@ -458,7 +462,7 @@ export async function convertMessagesWithImages( retries: 2, loggerPrefix: target.loggerPrefix, }).catch((error) => { - console.warn(`${target.loggerPrefix} failed to inline message images:`, error); + chatApiLogger.warn(`${target.loggerPrefix} failed to inline message images:`, error); return { inlineDataUrls: [], skipped: [] }; }); @@ -479,7 +483,7 @@ export async function convertMessagesWithImages( return sourceMessages; } - console.log(`${target.loggerPrefix} inlined chat message images:`, { + chatApiLogger.info(`${target.loggerPrefix} inlined chat message images:`, { total: uniqueUrls.length, inlined: inlineMap.size, providerType: target.providerType, @@ -575,7 +579,7 @@ export async function convertMessagesWithImages( // 🆕 检测是否有标注图片 const hasAnnotation = hasAnnotatedImage(messages); if (hasAnnotation) { - console.log("[Message Convert] 🎨 检测到标注图片,将自动添加系统提示"); + chatApiLogger.info("[Message Convert] 🎨 检测到标注图片,将自动添加系统提示"); } // 对于 Gemini,需要特殊处理图片 @@ -596,7 +600,7 @@ export async function convertMessagesWithImages( if (hasAnnotation && message.role === "user" && !hasAddedAnnotationPrompt) { textContent = ANNOTATION_SYSTEM_PROMPT + "\n\n用户请求:" + textContent; hasAddedAnnotationPrompt = true; - console.log("[Message Convert] 🎨 已注入标注提示词"); + chatApiLogger.info("[Message Convert] 🎨 已注入标注提示词"); } content.push({ @@ -612,7 +616,7 @@ export async function convertMessagesWithImages( url: part.url, }, }); - console.log("[Message Convert] Image kept as URL format:", part.url.substring(0, 80) + "..."); + chatApiLogger.info("[Message Convert] Image kept as URL format:", part.url.substring(0, 80) + "..."); } } @@ -622,7 +626,7 @@ export async function convertMessagesWithImages( type: "text", text: ANNOTATION_SYSTEM_PROMPT, }); - console.log("[Message Convert] 🎨 已在消息开头注入标注提示词"); + chatApiLogger.info("[Message Convert] 🎨 已在消息开头注入标注提示词"); } convertedMessages.push({ @@ -862,7 +866,7 @@ export async function normalizeAssistantImageMarkdown( uploadedUrls.push(uploadedUrl); rebuilt += `![thumb|||${uploadedUrl}|||${imageSize}](${uploadedUrl})`; } catch (error) { - console.error("[Chat API] Failed to upload inline data URL image:", error); + chatApiLogger.error("[Chat API] Failed to upload inline data URL image:", error); rebuilt += matchText; } @@ -883,7 +887,7 @@ export async function normalizeAssistantImageMarkdown( uploadedUrls.push(uploadedUrl); normalizedText = normalizedText.replace(rawDataUrl, uploadedUrl); } catch (error) { - console.error("[Chat API] Failed to normalize raw data URL image:", error); + chatApiLogger.error("[Chat API] Failed to normalize raw data URL image:", error); } } } @@ -917,14 +921,14 @@ export async function normalizeAssistantImageMarkdown( try { hostedThumbnailUrl = await ensureHostedImageUrl(thumbnailUrl); } catch (error) { - console.error("[Chat API] Failed to normalize remote thumbnail URL:", error); + chatApiLogger.error("[Chat API] Failed to normalize remote thumbnail URL:", error); } if (originalUrl && originalUrl !== thumbnailUrl) { try { hostedOriginalUrl = await ensureHostedImageUrl(originalUrl); } catch (error) { - console.error("[Chat API] Failed to normalize remote original URL:", error); + chatApiLogger.error("[Chat API] Failed to normalize remote original URL:", error); hostedOriginalUrl = hostedThumbnailUrl || originalUrl; } } else { @@ -938,7 +942,7 @@ export async function normalizeAssistantImageMarkdown( uploadedUrls.push(finalOriginalUrl); rebuilt += `![thumb|||${finalOriginalUrl}|||${parsedImageSize || imageSize}](${finalThumbnailUrl})`; } catch (error) { - console.error("[Chat API] Failed to parse remote image markdown metadata:", error); + chatApiLogger.error("[Chat API] Failed to parse remote image markdown metadata:", error); rebuilt += matchText; } @@ -952,9 +956,7 @@ export async function normalizeAssistantImageMarkdown( const hasMarkdownImage = /!\[[^\]]*\]\((https?:\/\/[^)]+)\)/i.test(normalizedText); if (!hasMarkdownImage && uploadedUrls.length > 0) { const uniqueUrls = [...new Set(uploadedUrls)]; - console.log( - `[Chat API] Converted ${uniqueUrls.length} image link(s) to hosted link(s)` - ); + chatApiLogger.info(`[Chat API] Converted ${uniqueUrls.length} image link(s) to hosted link(s)`); return uniqueUrls .map((url) => `![thumb|||${url}|||${imageSize}](${url})`) .join("\n"); diff --git a/app/(chat)/api/chat/_lib/message-preparation.ts b/app/(chat)/api/chat/_lib/message-preparation.ts index 1fb03d059..cc55f36f5 100644 --- a/app/(chat)/api/chat/_lib/message-preparation.ts +++ b/app/(chat)/api/chat/_lib/message-preparation.ts @@ -1,16 +1,20 @@ +import { createLogger } from "@/lib/observability/logger"; import { analyzeOptimizedPromptMerge, buildOptimizedPromptPreview, } from "@/lib/ai/runtime/optimized-prompt"; import type { ChatMessage } from "@/lib/types"; +const chatApiLogger = createLogger("chat.messagePreparation"); + + /** * 将图片 URL 转换为 base64 格式 * 用于将 S3 URL 的图片转换为 base64 发送给 Gemini API */ export async function convertImageUrlToBase64(url: string): Promise { try { - console.log("[Image Convert] Fetching image from:", url); + chatApiLogger.info("[Image Convert] Fetching image from:", url); const response = await fetch(url); if (!response.ok) { throw new Error(`Failed to fetch image: ${response.statusText}`); @@ -24,10 +28,10 @@ export async function convertImageUrlToBase64(url: string): Promise { const contentType = response.headers.get("content-type") || "image/jpeg"; const dataUrl = `data:${contentType};base64,${base64}`; - console.log("[Image Convert] Converted to base64, size:", base64.length); + chatApiLogger.info("[Image Convert] Converted to base64, size:", base64.length); return dataUrl; } catch (error) { - console.error("[Image Convert] Failed:", error); + chatApiLogger.error("[Image Convert] Failed:", error); throw error; } } @@ -113,7 +117,7 @@ export function applyOptimizedPromptToLatestUserMessage( .join("\n\n") .trim() : `${hiddenPromptPrefix}${prompt}`.trim(); - console.log("[Prompt Merge] Final image prompt prepared:", { + chatApiLogger.info("[Prompt Merge] Final image prompt prepared:", { original: normalizedOriginal.substring(0, 120), optimized: prompt.substring(0, 120), merged: finalPrompt.substring(0, 180), diff --git a/app/(chat)/api/chat/_lib/stream.ts b/app/(chat)/api/chat/_lib/stream.ts index 02fe5c313..d7edcb496 100644 --- a/app/(chat)/api/chat/_lib/stream.ts +++ b/app/(chat)/api/chat/_lib/stream.ts @@ -1,3 +1,4 @@ +import { createLogger } from "@/lib/observability/logger"; import { JsonToSseTransformStream } from "ai"; import { extractImageUrlsFromText } from "@/lib/image-url"; import type { @@ -7,6 +8,9 @@ import type { } from "@/lib/ai/context-memory/types"; import { generateUUID } from "@/lib/utils"; +const chatApiLogger = createLogger("chat.stream"); + + export type StreamWriter = { write: (chunk: any) => void; }; @@ -20,7 +24,7 @@ export function safeWriteStreamChunk( writer.write(chunk); return true; } catch (error) { - console.warn(`[Chat API] Stream write skipped (${label})`, error); + chatApiLogger.warn(`[Chat API] Stream write skipped (${label})`, error); return false; } } diff --git a/app/(chat)/api/chat/_lib/video-models.ts b/app/(chat)/api/chat/_lib/video-models.ts index dce8055e3..85e9ed531 100644 --- a/app/(chat)/api/chat/_lib/video-models.ts +++ b/app/(chat)/api/chat/_lib/video-models.ts @@ -1,3 +1,4 @@ +import { createLogger } from "@/lib/observability/logger"; import { after } from "next/server"; import { getAiModelById, @@ -10,6 +11,9 @@ import { } from "@/lib/ai/model-classification"; import type { StoryboardModelCandidate } from "@/lib/video-agent/types"; +const chatApiLogger = createLogger("chat.videoModels"); + + export type VideoModeType = | "text-to-video" | "first-frame" @@ -260,12 +264,12 @@ export function scheduleVideoArchive(params: { videoMetadata: nextMetadata as any, }); - console.log("[Chat API] 🕒 已登记延迟归档视频:", { + chatApiLogger.info("[Chat API] 🕒 已登记延迟归档视频:", { messageId, archiveAfterAt: new Date(archiveAfterAtMs).toISOString(), }); } catch (error) { - console.error("[Chat API] ❌ 登记视频延迟归档失败(保留临时地址):", { + chatApiLogger.error("[Chat API] ❌ 登记视频延迟归档失败(保留临时地址):", { messageId, temporaryVideoUrl, error, diff --git a/app/(chat)/api/chat/route.ts b/app/(chat)/api/chat/route.ts index 4a2f88667..09866011c 100644 --- a/app/(chat)/api/chat/route.ts +++ b/app/(chat)/api/chat/route.ts @@ -1,3 +1,4 @@ +import { createLogger } from "@/lib/observability/logger"; import { geolocation } from "@vercel/functions"; import { convertToModelMessages, @@ -333,6 +334,9 @@ import { type VideoModeType, } from "./_lib/video-models"; +const chatApiLogger = createLogger("chat.route"); + + const AGENT_REPLACEMENT_PARALLEL_WORKER_COUNT = Math.max( 1, Math.min(8, Number(process.env.AGENT_REPLACEMENT_PARALLEL_WORKER_COUNT || 6) || 6), @@ -387,7 +391,7 @@ async function replayAssistantMessagesForDuplicateRequest({ } } } catch (error) { - console.warn(`[Chat API] Failed duplicate replay fetch (${source})`, error); + chatApiLogger.warn(`[Chat API] Failed duplicate replay fetch (${source})`, error); } safeWriteStreamChunk( @@ -592,10 +596,7 @@ const getTokenlensCatalog = cache( try { return await fetchModels(); } catch (err) { - console.warn( - "TokenLens: catalog fetch failed, using default catalog", - err - ); + chatApiLogger.warn("TokenLens: catalog fetch failed, using default catalog", err); return; // tokenlens helpers will fall back to defaultCatalog } }, @@ -611,11 +612,9 @@ export function getStreamContext() { }); } catch (error: any) { if (error.message.includes("REDIS_URL")) { - console.log( - " > Resumable streams are disabled due to missing REDIS_URL" - ); + chatApiLogger.info(" > Resumable streams are disabled due to missing REDIS_URL"); } else { - console.error(error); + chatApiLogger.error("console_error", error); } } } @@ -630,10 +629,10 @@ export async function POST(request: Request) { try { const json = await request.json(); - console.log("[Chat API] Received request body:", JSON.stringify(json, null, 2)); + chatApiLogger.info("[Chat API] Received request body:", JSON.stringify(json, null, 2)); requestBody = postRequestBodySchema.parse(json); } catch (error) { - console.error("[Chat API] Schema validation failed:", error); + chatApiLogger.error("[Chat API] Schema validation failed:", error); return new ChatSDKError("bad_request:api").toResponse(); } @@ -691,9 +690,7 @@ export async function POST(request: Request) { requestDedupKey = `${id}:${message.id}`; if (inFlightChatRequests.has(requestDedupKey)) { - console.warn( - `[Chat API] Duplicate in-flight request ignored (chatId=${id}, messageId=${message.id})` - ); + chatApiLogger.warn(`[Chat API] Duplicate in-flight request ignored (chatId=${id}, messageId=${message.id})`); const duplicateStream = createUIMessageStream({ execute: async ({ writer }) => { await replayAssistantMessagesForDuplicateRequest({ @@ -750,9 +747,7 @@ export async function POST(request: Request) { let shouldKeepSelectedModel = false; if (shouldRespectDirectComposerMode && shouldRunAgentConversation) { shouldRunAgentConversation = false; - console.log( - `[Smart Auto Mode] ⛳ Direct composer mode (${composerMode}) disables initial auto-agent routing`, - ); + chatApiLogger.info(`[Smart Auto Mode] ⛳ Direct composer mode (${composerMode}) disables initial auto-agent routing`); } const pendingProtocolDebugEvents: Array<{ phase: string; payload: Record }> = []; const requestedModelId = selectedChatModel; @@ -808,30 +803,22 @@ export async function POST(request: Request) { if (deepThinkingOn) { if (isAiModelAgentAuto(selectedModelConfig)) { if (shouldRespectDirectComposerMode) { - console.log( - `[Smart Auto Mode] ⛳ Respect direct composer mode (${composerMode}), skip forcing agent-only routing for: ${selectedModelConfig.displayName}`, - ); + chatApiLogger.info(`[Smart Auto Mode] ⛳ Respect direct composer mode (${composerMode}), skip forcing agent-only routing for: ${selectedModelConfig.displayName}`); } else { shouldRunAgentConversation = true; shouldKeepSelectedModel = false; preferredAgentModelId = selectedModelConfig.id; configuredAgentConversationModelId = selectedModelConfig.id; - console.log( - `[Smart Auto Mode] 🧠 Agent-only model detected, force auto routing: ${selectedModelConfig.displayName}` - ); + chatApiLogger.info(`[Smart Auto Mode] 🧠 Agent-only model detected, force auto routing: ${selectedModelConfig.displayName}`); } } else if (isFixedVisualModel || isConversationMultimodalModel) { if (shouldRespectDirectComposerMode) { - console.log( - `[Smart Auto Mode] ⛳ Respect direct composer mode (${composerMode}), keep direct execution model: ${selectedModelConfig.displayName}`, - ); + chatApiLogger.info(`[Smart Auto Mode] ⛳ Respect direct composer mode (${composerMode}), keep direct execution model: ${selectedModelConfig.displayName}`); } else { shouldRunAgentConversation = true; shouldKeepSelectedModel = true; preferredAgentModelId = selectedModelConfig.id; - console.log( - `[Smart Auto Mode] 🎯 Agent conversation enabled for selected model: ${selectedModelConfig.displayName} (${selectedModelProviderType || "unknown"}), preferredAgentModelId=${preferredAgentModelId}` - ); + chatApiLogger.info(`[Smart Auto Mode] 🎯 Agent conversation enabled for selected model: ${selectedModelConfig.displayName} (${selectedModelProviderType || "unknown"}), preferredAgentModelId=${preferredAgentModelId}`); } } } else if ( @@ -839,16 +826,14 @@ export async function POST(request: Request) { isConversationMultimodalModel || isAiModelAgentAuto(selectedModelConfig) ) { - console.log( - `[Smart Auto Mode] ⏭️ Deep thinking disabled, skip agent analysis for: ${selectedModelConfig.displayName}` - ); + chatApiLogger.info(`[Smart Auto Mode] ⏭️ Deep thinking disabled, skip agent analysis for: ${selectedModelConfig.displayName}`); } } } if (shouldRunAgentConversation && !preferredAgentModelId) { const configuredAgentModel = await getAgentAiModelWithProvider().catch((agentModelError) => { - console.warn("[Chat API] Failed to load configured agent model:", agentModelError); + chatApiLogger.warn("[Chat API] Failed to load configured agent model:", agentModelError); return null; }); @@ -873,9 +858,7 @@ export async function POST(request: Request) { source: "configured_agent_default", reason: "agent_default_model", }); - console.log( - `[Smart Auto Mode] 🧠 Loaded configured agent conversation model: ${configuredAgentModel.model.displayName}`, - ); + chatApiLogger.info(`[Smart Auto Mode] 🧠 Loaded configured agent conversation model: ${configuredAgentModel.model.displayName}`); } } @@ -968,10 +951,7 @@ export async function POST(request: Request) { : await getLatestActiveVideoStoryboardTaskByChatId({ chatId: id, }).catch((storyboardLookupError) => { - console.warn( - "[Chat API] Failed to preload active storyboard task before smart auto mode:", - storyboardLookupError - ); + chatApiLogger.warn("[Chat API] Failed to preload active storyboard task before smart auto mode:", storyboardLookupError); return null; }); @@ -980,10 +960,7 @@ export async function POST(request: Request) { : await getConversationWorkingStateByChatId({ chatId: id, }).catch((workingStatePreloadError) => { - console.warn( - "[Chat API] Failed to preload conversation working state before smart auto mode:", - workingStatePreloadError - ); + chatApiLogger.warn("[Chat API] Failed to preload conversation working state before smart auto mode:", workingStatePreloadError); return null; }); const hasImageInputForConversationAction = message.parts.some((part: any) => @@ -996,7 +973,7 @@ export async function POST(request: Request) { hasImageInputForPromptCarryForward: hasImageInputForConversationAction, hasCanvasSelection: Boolean(contextPayload?.selectedNodeIds?.length), }); - console.log("[ConversationStateProtocol] Bootstrap:", { + chatApiLogger.info("[ConversationStateProtocol] Bootstrap:", { action: conversationStateBootstrap.actionResolution.kind, taskType: conversationStateBootstrap.taskBoundaryDecision.taskType, taskMode: conversationStateBootstrap.taskBoundaryDecision.taskMode, @@ -1049,52 +1026,38 @@ export async function POST(request: Request) { if (taskBoundaryRequiresAgentConversation && !shouldRunAgentConversation) { if (shouldRespectDirectComposerMode) { - console.log( - `[Smart Auto Mode] ⛳ Respect direct composer mode (${composerMode}), skip task-boundary agent force: ${taskBoundaryDecision.taskType}/${taskBoundaryDecision.taskMode}`, - ); + chatApiLogger.info(`[Smart Auto Mode] ⛳ Respect direct composer mode (${composerMode}), skip task-boundary agent force: ${taskBoundaryDecision.taskType}/${taskBoundaryDecision.taskMode}`); } else { shouldRunAgentConversation = true; shouldKeepSelectedModel = false; - console.log( - `[Smart Auto Mode] 🧭 Force agent conversation due to task boundary: ${taskBoundaryDecision.taskType}/${taskBoundaryDecision.taskMode}`, - ); + chatApiLogger.info(`[Smart Auto Mode] 🧭 Force agent conversation due to task boundary: ${taskBoundaryDecision.taskType}/${taskBoundaryDecision.taskMode}`); } } if (taskBoundaryOverridesLegacyWorkflow && shouldKeepSelectedModel) { shouldKeepSelectedModel = false; - console.log( - `[Smart Auto Mode] 🧼 Release selected-model lock due to task boundary override: ${taskBoundaryDecision.taskType}`, - ); + chatApiLogger.info(`[Smart Auto Mode] 🧼 Release selected-model lock due to task boundary override: ${taskBoundaryDecision.taskType}`); } if (resolvedConversationAction.forceAgentConversation && !shouldRunAgentConversation) { if (shouldRespectDirectComposerMode) { - console.log( - `[Smart Auto Mode] ⛳ Respect direct composer mode (${composerMode}), skip legacy workflow force: ${resolvedConversationAction.kind}`, - ); + chatApiLogger.info(`[Smart Auto Mode] ⛳ Respect direct composer mode (${composerMode}), skip legacy workflow force: ${resolvedConversationAction.kind}`); } else if (taskBoundaryOverridesLegacyWorkflow) { - console.log( - `[Smart Auto Mode] 🪫 Ignore legacy workflow follow-up due to task boundary override: ${resolvedConversationAction.kind} -> ${taskBoundaryDecision.taskType}`, - ); + chatApiLogger.info(`[Smart Auto Mode] 🪫 Ignore legacy workflow follow-up due to task boundary override: ${resolvedConversationAction.kind} -> ${taskBoundaryDecision.taskType}`); } else { shouldRunAgentConversation = true; shouldKeepSelectedModel = resolvedConversationAction.shouldKeepSelectedModel; if (resolvedConversationAction.kind === "grid_confirmation_followup" && pendingGridConfirmation) { - console.log( - `[Smart Auto Mode] 🧩 Force agent conversation due to pending grid confirmation: ${pendingGridConfirmation.label}` - ); + chatApiLogger.info(`[Smart Auto Mode] 🧩 Force agent conversation due to pending grid confirmation: ${pendingGridConfirmation.label}`); } else if ( resolvedConversationAction.kind === "active_storyboard_followup" && activeStoryboardTaskForChat?.task?.id ) { - console.log( - `[Smart Auto Mode] 🔐 Force agent conversation due to active storyboard task: ${activeStoryboardTaskForChat.task.id}` - ); + chatApiLogger.info(`[Smart Auto Mode] 🔐 Force agent conversation due to active storyboard task: ${activeStoryboardTaskForChat.task.id}`); } else if (resolvedConversationAction.kind === "image_generation_followup") { - console.log("[Smart Auto Mode] 🪄 Force agent conversation due to image generation follow-up workflow"); + chatApiLogger.info("[Smart Auto Mode] 🪄 Force agent conversation due to image generation follow-up workflow"); } else if (resolvedConversationAction.kind === "image_edit_followup") { - console.log("[Smart Auto Mode] 🖼️ Force agent conversation due to image edit follow-up workflow"); + chatApiLogger.info("[Smart Auto Mode] 🖼️ Force agent conversation due to image edit follow-up workflow"); } } } @@ -1125,12 +1088,12 @@ export async function POST(request: Request) { smartAutoNeedsClarification = false; smartAutoFriendlyMessage = "收到,我先分析这张图并整理可直接使用的提示词,不会直接生图。"; - console.log("[Smart Auto Mode] ✍️ Fast-path prompt-only request, skip heavy auto-agent workflow"); + chatApiLogger.info("[Smart Auto Mode] ✍️ Fast-path prompt-only request, skip heavy auto-agent workflow"); } // ========== Smart Auto Mode Logic ========== if (shouldRunAgentConversation && !shouldFastTrackPromptOnly) { - console.log("[Smart Auto Mode] 🚀 Starting intelligent analysis..."); + chatApiLogger.info("[Smart Auto Mode] 🚀 Starting intelligent analysis..."); let autoTextForFallback = ""; let autoFromHistoryForFallback = false; let autoCurrentImageUrlsForFallback: string[] = []; @@ -1155,8 +1118,8 @@ export async function POST(request: Request) { purpose: "media", hasCurrentImageInput: hasImageInputForConversationAction, }); - console.log("[Smart Auto Mode] Loaded", loadedHistoryMessages.length, "messages from DB"); - console.log("[Smart Auto Mode] Pruned history:", { + chatApiLogger.info("[Smart Auto Mode] Loaded", loadedHistoryMessages.length, "messages from DB"); + chatApiLogger.info("[Smart Auto Mode] Pruned history:", { modelMessages: smartAutoHistoryMessagesFromDb.length, mediaMessages: smartAutoMediaHistoryMessagesFromDb.length, taskType: taskBoundaryDecision.taskType, @@ -1224,10 +1187,10 @@ export async function POST(request: Request) { autoFromHistoryForFallback = false; autoTextForFallback = confirmedPromptForGeneration || requestTextContent; smartAutoOptimizedPrompt = confirmedPromptForGeneration; - console.log("[Smart Auto Mode] 🎯 Using confirmed prompt-only result for image generation"); + chatApiLogger.info("[Smart Auto Mode] 🎯 Using confirmed prompt-only result for image generation"); } - console.log("[Smart Auto Mode] Input:", { + chatApiLogger.info("[Smart Auto Mode] Input:", { textContent: requestTextContent.substring(0, 100), hasImage, imageCount: imageUrls.length, @@ -1252,7 +1215,7 @@ export async function POST(request: Request) { } } } - console.log("[Smart Auto Mode] History context:", historyMessages.length, "messages"); + chatApiLogger.info("[Smart Auto Mode] History context:", historyMessages.length, "messages"); // 2. 使用 LangGraph 驱动的自动模式工作流 const { runAutoAgentGraph } = await import("@/lib/ai/auto-agent-graph"); @@ -1273,7 +1236,7 @@ export async function POST(request: Request) { resolvedMediaInput: requestResolvedMediaInput, targetResolution: requestTargetResolution, }); - console.log("[ConversationStateProtocol] Composed:", { + chatApiLogger.info("[ConversationStateProtocol] Composed:", { workflowType: composedConversationState.threadState.workflowState?.type || null, workflowStatus: composedConversationState.threadState.workflowState?.status || null, memoryHintsCount: composedConversationState.threadState.memoryHints.length, @@ -1342,7 +1305,7 @@ export async function POST(request: Request) { if (autoGraphResult.workflowDecision) { smartAutoWorkflowDecision = autoGraphResult.workflowDecision; - console.log("[Smart Auto Mode] Workflow decision:", { + chatApiLogger.info("[Smart Auto Mode] Workflow decision:", { action: autoGraphResult.workflowDecision.action, intent: autoGraphResult.workflowDecision.confirmationIntent, workflowId: autoGraphResult.workflowDecision.workflowId, @@ -1385,10 +1348,7 @@ export async function POST(request: Request) { break; } } catch (workflowPersistError) { - console.warn( - "[Smart Auto Mode] Failed to persist storyboard workflow decision:", - workflowPersistError - ); + chatApiLogger.warn("[Smart Auto Mode] Failed to persist storyboard workflow decision:", workflowPersistError); } } } @@ -1419,7 +1379,7 @@ export async function POST(request: Request) { } if (smartAutoPlan) { - console.log("[Smart Auto Mode] Plan result:", { + chatApiLogger.info("[Smart Auto Mode] Plan result:", { goal: smartAutoPlan.goal, nextAction: smartAutoPlan.nextAction, intent: smartAutoPlan.intent, @@ -1431,7 +1391,7 @@ export async function POST(request: Request) { } if (autoGraphResult.analysis) { - console.log("[Smart Auto Mode] Analysis result:", { + chatApiLogger.info("[Smart Auto Mode] Analysis result:", { intent: autoGraphResult.analysis.intent, subIntent: autoGraphResult.analysis.subIntent, confidence: autoGraphResult.analysis.confidence, @@ -1449,7 +1409,7 @@ export async function POST(request: Request) { targetSource: requestTargetResolution.resolutionMode, }); if (arbitratedIntent.overridden) { - console.log("[IntentArbiter] Override auto-agent intent:", { + chatApiLogger.info("[IntentArbiter] Override auto-agent intent:", { fromIntent: autoGraphResult.analysis.intent, fromMode: autoGraphResult.execution?.mode, toIntent: arbitratedIntent.analysis.intent, @@ -1488,9 +1448,7 @@ export async function POST(request: Request) { smartAutoClarificationQuestion = undefined; smartAutoOptimizedPrompt = targetExecutionOverride.nextOptimizedPrompt; smartAutoFriendlyMessage = targetExecutionOverride.nextFriendlyMessage; - console.log( - "[Smart Auto Mode] ✅ Skip clarification due to explicit target/selection context" - ); + chatApiLogger.info("[Smart Auto Mode] ✅ Skip clarification due to explicit target/selection context"); } } @@ -1512,7 +1470,7 @@ export async function POST(request: Request) { smartAutoClarificationQuestion = gridConfirmationResolution.clarificationMessage; smartAutoFriendlyMessage = gridConfirmationResolution.clarificationMessage; pendingGridConfirmation = gridConfirmationResolution.pendingGridConfirmation; - console.log("[Smart Auto Mode] 🧱 Require grid confirmation before generation:", { + chatApiLogger.info("[Smart Auto Mode] 🧱 Require grid confirmation before generation:", { gridType: gridConfirmationResolution.pendingGridConfirmation?.gridType, shotCount: gridConfirmationResolution.pendingGridConfirmation?.shotCount, }); @@ -1520,7 +1478,7 @@ export async function POST(request: Request) { if (autoGraphResult.friendlyMessage && !shouldPreferArbitratedFriendlyMessage) { smartAutoFriendlyMessage = autoGraphResult.friendlyMessage; - console.log("[Smart Auto Mode] 💬 Conversational reply:", smartAutoFriendlyMessage); + chatApiLogger.info("[Smart Auto Mode] 💬 Conversational reply:", smartAutoFriendlyMessage); } if (shouldAskGridConfirmation && smartAutoClarificationQuestion) { @@ -1537,7 +1495,7 @@ export async function POST(request: Request) { /哪一张|哪个|请先确认/.test(smartAutoFriendlyMessage)) ) { smartAutoFriendlyMessage = "收到,我将按你指定的目标图直接执行。"; - console.log("[Smart Auto Mode] ✅ Replace clarification-like friendly reply"); + chatApiLogger.info("[Smart Auto Mode] ✅ Replace clarification-like friendly reply"); } const autoIntent = smartAutoDetectedIntent || autoGraphResult.analysis?.intent; @@ -1572,12 +1530,12 @@ export async function POST(request: Request) { }) : "收到,我先理解你的当前目标,再继续处理。"; } - console.log("[Smart Auto Mode] 🧩 Filled missing conversational reply"); + chatApiLogger.info("[Smart Auto Mode] 🧩 Filled missing conversational reply"); } if (autoGraphResult.optimizedPrompt) { smartAutoOptimizedPrompt = autoGraphResult.optimizedPrompt; - console.log("[Smart Auto Mode] ✨ Prompt optimized (LLM):", { + chatApiLogger.info("[Smart Auto Mode] ✨ Prompt optimized (LLM):", { original: requestTextContent.substring(0, 50), optimized: autoGraphResult.optimizedPrompt.substring(0, 100), }); @@ -1589,7 +1547,7 @@ export async function POST(request: Request) { smartAutoOptimizedPrompt = autoGraphResult.videoPlan.finalPrompt.trim(); smartAutoPromptFromVideoPlan = true; } - console.log("[Smart Auto Mode] 🎬 Agent video plan ready:", { + chatApiLogger.info("[Smart Auto Mode] 🎬 Agent video plan ready:", { hasScript: Boolean(autoGraphResult.videoPlan.script), storyboardCount: autoGraphResult.videoPlan.storyboard?.length || 0, hasFinalPrompt: Boolean(autoGraphResult.videoPlan.finalPrompt), @@ -1598,7 +1556,7 @@ export async function POST(request: Request) { } if (autoGraphResult.recommendedImageParams) { smartAutoRecommendedImageParams = autoGraphResult.recommendedImageParams; - console.log("[Smart Auto Mode] 🎛️ Agent recommended image params:", smartAutoRecommendedImageParams); + chatApiLogger.info("[Smart Auto Mode] 🎛️ Agent recommended image params:", smartAutoRecommendedImageParams); } const shouldForceConversationalRouteForVisualModel = @@ -1636,9 +1594,7 @@ export async function POST(request: Request) { smartAutoFriendlyMessage && !/视频/.test(smartAutoFriendlyMessage) ? smartAutoFriendlyMessage : "当前 Agent 默认按图片任务执行;如需生成视频,请先手动切换到“视频”模式。"; - console.log( - `[Smart Auto Mode] 🚫 Blocked auto video route (${autoGraphResult.route.displayName}), fallback to ${fallbackIntent}`, - ); + chatApiLogger.info(`[Smart Auto Mode] 🚫 Blocked auto video route (${autoGraphResult.route.displayName}), fallback to ${fallbackIntent}`); try { const { routeToModel } = await import("@/lib/ai/model-router"); const fallbackRoute = await routeToModel({ @@ -1648,38 +1604,30 @@ export async function POST(request: Request) { }); if (!isVideoProviderType(fallbackRoute.providerType, { modelId: fallbackRoute.modelId })) { finalModelId = fallbackRoute.id; - console.log( - `[Smart Auto Mode] ✅ Fallback routed to: ${fallbackRoute.displayName} (${fallbackRoute.reason})`, - ); + chatApiLogger.info(`[Smart Auto Mode] ✅ Fallback routed to: ${fallbackRoute.displayName} (${fallbackRoute.reason})`); } else { - console.warn( - `[Smart Auto Mode] ⚠️ Fallback route still video (${fallbackRoute.displayName}), keep previous model`, - ); + chatApiLogger.warn(`[Smart Auto Mode] ⚠️ Fallback route still video (${fallbackRoute.displayName}), keep previous model`); } } catch (fallbackRouteError) { - console.error("[Smart Auto Mode] Failed to resolve non-video fallback route:", fallbackRouteError); + chatApiLogger.error("[Smart Auto Mode] Failed to resolve non-video fallback route:", fallbackRouteError); } } else { finalModelId = autoGraphResult.route.id; - console.log( - shouldForceConversationalRouteForVisualModel + chatApiLogger.info("console_log", shouldForceConversationalRouteForVisualModel ? `[Smart Auto Mode] ✅ Switched visual model to conversational route: ${autoGraphResult.route.displayName} (${autoGraphResult.route.reason})` - : `[Smart Auto Mode] ✅ Routed to: ${autoGraphResult.route.displayName} (${autoGraphResult.route.reason})`, - ); + : `[Smart Auto Mode] ✅ Routed to: ${autoGraphResult.route.displayName} (${autoGraphResult.route.reason})`); } } else if (autoGraphResult.route && shouldKeepSelectedModel) { finalModelId = requestedModelId; - console.log("[Smart Auto Mode] 🔒 Keep user-selected model, skip routing override"); + chatApiLogger.info("[Smart Auto Mode] 🔒 Keep user-selected model, skip routing override"); } } catch (autoError) { // 智能分析失败时,回退到简单逻辑 - console.error("[Smart Auto Mode] ❌ Error, falling back:", autoError); + chatApiLogger.error("[Smart Auto Mode] ❌ Error, falling back:", autoError); const isAutoTimeout = autoError instanceof OperationTimeoutError; if (isAutoTimeout) { - console.warn( - `[Smart Auto Mode] ⏱️ Auto-agent timed out or exceeded pre-response budget (${CHAT_PRE_RESPONSE_SOFT_TIMEOUT_MS}ms), using local fallback`, - ); + chatApiLogger.warn(`[Smart Auto Mode] ⏱️ Auto-agent timed out or exceeded pre-response budget (${CHAT_PRE_RESPONSE_SOFT_TIMEOUT_MS}ms), using local fallback`); } try { const { analyzeIntent } = await import("@/lib/ai/smart-analyzer"); @@ -1730,7 +1678,7 @@ export async function POST(request: Request) { targetSource: requestTargetResolution?.resolutionMode || "none", }); if (arbitratedIntent.overridden) { - console.log("[IntentArbiter] Override rescue intent:", { + chatApiLogger.info("[IntentArbiter] Override rescue intent:", { fromIntent: rescueAnalysis.intent, toIntent: arbitratedIntent.analysis.intent, toMode: arbitratedIntent.execution.mode, @@ -1749,10 +1697,10 @@ export async function POST(request: Request) { ).trim(); } } else { - console.warn("[Smart Auto Mode] Skip rescue analysis due to pre-response budget"); + chatApiLogger.warn("[Smart Auto Mode] Skip rescue analysis due to pre-response budget"); } } catch (rescueError) { - console.error("[Smart Auto Mode] Rescue analysis failed:", rescueError); + chatApiLogger.error("[Smart Auto Mode] Rescue analysis failed:", rescueError); try { const { fallbackKeywordAnalysis } = await import("@/lib/ai/smart-analyzer"); const keywordFallback = fallbackKeywordAnalysis( @@ -1771,7 +1719,7 @@ export async function POST(request: Request) { targetSource: requestTargetResolution?.resolutionMode || "none", }); if (arbitratedIntent.overridden) { - console.log("[IntentArbiter] Override keyword-fallback intent:", { + chatApiLogger.info("[IntentArbiter] Override keyword-fallback intent:", { fromIntent: keywordFallback.intent, toIntent: arbitratedIntent.analysis.intent, toMode: arbitratedIntent.execution.mode, @@ -1788,13 +1736,10 @@ export async function POST(request: Request) { keywordFallback.conversationalReply || "" ).trim(); - console.warn("[Smart Auto Mode] Applied keyword fallback after rescue failure"); + chatApiLogger.warn("[Smart Auto Mode] Applied keyword fallback after rescue failure"); } } catch (keywordFallbackError) { - console.warn( - "[Smart Auto Mode] Keyword fallback after rescue failure also failed:", - keywordFallbackError, - ); + chatApiLogger.warn("[Smart Auto Mode] Keyword fallback after rescue failure also failed:", keywordFallbackError); } } @@ -1812,7 +1757,7 @@ export async function POST(request: Request) { }); if (optimizedFallback.optimizedPrompt?.trim()) { smartAutoOptimizedPrompt = optimizedFallback.optimizedPrompt.trim(); - console.log("[Smart Auto Mode] ✨ Prompt optimized (fallback heuristic):", { + chatApiLogger.info("[Smart Auto Mode] ✨ Prompt optimized (fallback heuristic):", { original: autoTextForFallback.substring(0, 80), optimized: smartAutoOptimizedPrompt.substring(0, 140), intent: smartAutoDetectedIntent, @@ -1823,7 +1768,7 @@ export async function POST(request: Request) { smartAutoRecommendedImageParams = optimizedFallback.recommendedImageParams; } } catch (fallbackOptimizeError) { - console.warn("[Smart Auto Mode] Fallback prompt optimization failed:", fallbackOptimizeError); + chatApiLogger.warn("[Smart Auto Mode] Fallback prompt optimization failed:", fallbackOptimizeError); } } @@ -1871,11 +1816,11 @@ export async function POST(request: Request) { fallbackVisualSummary = summary.trim(); } } else { - console.warn("[Smart Auto Mode] Skip fallback visual summary due to pre-response budget"); + chatApiLogger.warn("[Smart Auto Mode] Skip fallback visual summary due to pre-response budget"); } } } catch (summaryError) { - console.warn("[Smart Auto Mode] Fallback visual summary failed:", summaryError); + chatApiLogger.warn("[Smart Auto Mode] Fallback visual summary failed:", summaryError); } } @@ -1894,12 +1839,10 @@ export async function POST(request: Request) { (item) => item.model.id === fallbackRoute.id || item.model.modelId === fallbackRoute.modelId, ) || null; if (bestModel) { - console.log( - `[Smart Auto Mode] Fallback routed by intent: ${fallbackRoute.displayName} (${fallbackRoute.reason})`, - ); + chatApiLogger.info(`[Smart Auto Mode] Fallback routed by intent: ${fallbackRoute.displayName} (${fallbackRoute.reason})`); } } catch (fallbackRouteError) { - console.warn("[Smart Auto Mode] Fallback routeByIntent failed, use local heuristic:", fallbackRouteError); + chatApiLogger.warn("[Smart Auto Mode] Fallback routeByIntent failed, use local heuristic:", fallbackRouteError); } if (!bestModel && hasImage) { @@ -1949,10 +1892,10 @@ export async function POST(request: Request) { if (shouldKeepSelectedModel) { finalModelId = requestedModelId; - console.log("[Smart Auto Mode] 🔒 Keep user-selected model in fallback mode"); + chatApiLogger.info("[Smart Auto Mode] 🔒 Keep user-selected model in fallback mode"); } else if (bestModel) { finalModelId = bestModel.model.id; - console.log(`[Smart Auto Mode] Fallback selected: ${bestModel.model.displayName}`); + chatApiLogger.info(`[Smart Auto Mode] Fallback selected: ${bestModel.model.displayName}`); } else { return new ChatSDKError("bad_request:api", "No available models for auto mode").toResponse(); } @@ -2010,9 +1953,7 @@ export async function POST(request: Request) { finalModelId = fallbackModel.model.id; smartAutoVideoPlan = undefined; smartAutoRecommendedVideoParams = undefined; - console.log( - `[Smart Auto Mode] 🚫 Safety override: replace video model (${finalProviderType}) with ${fallbackModel.model.displayName}`, - ); + chatApiLogger.info(`[Smart Auto Mode] 🚫 Safety override: replace video model (${finalProviderType}) with ${fallbackModel.model.displayName}`); } } } @@ -2038,7 +1979,7 @@ export async function POST(request: Request) { fromHistory: !hasCurrentImageInput && hasHistoryImageInput, }) : "收到,我先理解你的当前目标,再继续处理。"; - console.log("[Smart Auto Mode] 🧩 Backfilled conversational reply with fallback"); + chatApiLogger.info("[Smart Auto Mode] 🧩 Backfilled conversational reply with fallback"); } if ( @@ -2095,7 +2036,7 @@ export async function POST(request: Request) { } as const; if (shouldApplyAgentImageParams) { - console.log("[Smart Auto Mode] 🎯 Effective image params:", { + chatApiLogger.info("[Smart Auto Mode] 🎯 Effective image params:", { incoming: requestBody.imageParams, recommended: smartAutoRecommendedImageParams, merged: effectiveImageParams, @@ -2103,7 +2044,7 @@ export async function POST(request: Request) { }); } if (shouldApplyAgentVideoParams) { - console.log("[Smart Auto Mode] 🎯 Effective video params:", { + chatApiLogger.info("[Smart Auto Mode] 🎯 Effective video params:", { incoming: requestBody.videoParams, recommended: smartAutoRecommendedVideoParams, merged: effectiveVideoParams, @@ -2169,7 +2110,7 @@ export async function POST(request: Request) { summaryTimeoutMs, ); } else { - console.warn("[Smart Auto Mode] Skip image summary enrichment due to pre-response budget"); + chatApiLogger.warn("[Smart Auto Mode] Skip image summary enrichment due to pre-response budget"); } if (summary?.trim() && smartAutoExecution?.shouldUseStructuredReply) { @@ -2189,10 +2130,7 @@ export async function POST(request: Request) { }), summary.trim(), ); - console.log( - "[Smart Auto Mode] ✅ Image analysis summary ready:", - summary.trim().slice(0, 160), - ); + chatApiLogger.info("[Smart Auto Mode] ✅ Image analysis summary ready:", summary.trim().slice(0, 160)); } else if ( summary?.trim() && !smartAutoExecution?.shouldUseStructuredReply && @@ -2200,10 +2138,10 @@ export async function POST(request: Request) { ) { smartAutoFriendlyMessage = "收到,我会结合这张图的内容直接回答你。"; } else if (smartAutoFriendlyMessage && shouldEnrichImageAnalysisText(smartAutoFriendlyMessage)) { - console.warn("[Smart Auto Mode] ⚠️ Image summary unavailable, keep original analysis text"); + chatApiLogger.warn("[Smart Auto Mode] ⚠️ Image summary unavailable, keep original analysis text"); } } catch (enrichError) { - console.warn("[Smart Auto Mode] Skip image analysis enrichment:", enrichError); + chatApiLogger.warn("[Smart Auto Mode] Skip image analysis enrichment:", enrichError); } } } @@ -2224,9 +2162,7 @@ export async function POST(request: Request) { ) { if (finalModelId !== preferredAgentModelId) { finalModelId = preferredAgentModelId; - console.log( - `[Smart Auto Mode] 🧠 Conversational reply follows agent default model: ${configuredAgentConversationModelId || preferredAgentModelId}`, - ); + chatApiLogger.info(`[Smart Auto Mode] 🧠 Conversational reply follows agent default model: ${configuredAgentConversationModelId || preferredAgentModelId}`); } } @@ -2282,10 +2218,7 @@ export async function POST(request: Request) { fallbackReplyModelId = replyFallbackRoute.id; } } catch (replyRouteError) { - console.warn( - "[Smart Auto Mode] Failed to resolve reply fallback route after provider degradation:", - replyRouteError, - ); + chatApiLogger.warn("[Smart Auto Mode] Failed to resolve reply fallback route after provider degradation:", replyRouteError); } } @@ -2302,9 +2235,7 @@ export async function POST(request: Request) { locked: false, }); } - console.warn( - `[Smart Auto Mode] ♻️ Switched reply model due provider health: ${candidateReplyDescriptor.displayName || candidateReplyDescriptor.modelId} -> ${fallbackDescriptor?.displayName || fallbackReplyModelId}`, - ); + chatApiLogger.warn(`[Smart Auto Mode] ♻️ Switched reply model due provider health: ${candidateReplyDescriptor.displayName || candidateReplyDescriptor.modelId} -> ${fallbackDescriptor?.displayName || fallbackReplyModelId}`); } } } @@ -2342,7 +2273,7 @@ export async function POST(request: Request) { const isWithinUsageTime = currentTime >= startTime && currentTime <= endTime; if (!isWithinUsageTime) { - console.log(`[Chat API] ⛔ 访问被拒绝:当前时间 ${currentTime} 不在允许范围 ${startTime}-${endTime}`); + chatApiLogger.info(`[Chat API] ⛔ 访问被拒绝:当前时间 ${currentTime} 不在允许范围 ${startTime}-${endTime}`); return NextResponse.json( { error: "usage_time_restricted", @@ -2354,10 +2285,10 @@ export async function POST(request: Request) { ); } - console.log(`[Chat API] ✅ 时间验证通过:${currentTime} 在允许范围 ${startTime}-${endTime}`); + chatApiLogger.info(`[Chat API] ✅ 时间验证通过:${currentTime} 在允许范围 ${startTime}-${endTime}`); } } catch (timeCheckError) { - console.error("[Chat API] ⚠️ 时间验证失败(继续执行):", timeCheckError); + chatApiLogger.error("[Chat API] ⚠️ 时间验证失败(继续执行):", timeCheckError); // 如果时间检查失败,继续执行(避免因检查逻辑错误导致系统不可用) } @@ -2393,7 +2324,7 @@ export async function POST(request: Request) { return new ChatSDKError("forbidden:chat").toResponse(); } - console.warn("[Chat API] saveChat conflicted, reused existing chat:", { + chatApiLogger.warn("[Chat API] saveChat conflicted, reused existing chat:", { chatId: id, userId: session.user.id, }); @@ -2472,7 +2403,7 @@ export async function POST(request: Request) { .split("\n") .map((line) => line.trim()) .filter(Boolean); - console.info("[Chat API] Hidden workflow prompt summary:", { + chatApiLogger.info("[Chat API] Hidden workflow prompt summary:", { lineCount: hiddenPromptLines.length, preview: hiddenPromptLines.slice(0, 12), }); @@ -2508,9 +2439,7 @@ export async function POST(request: Request) { .returning({ id: messageTable.id }); if (insertedUserMessage.length === 0) { - console.warn( - `[Chat API] Duplicate user message ignored (chatId=${id}, messageId=${message.id})` - ); + chatApiLogger.warn(`[Chat API] Duplicate user message ignored (chatId=${id}, messageId=${message.id})`); const duplicateStream = createUIMessageStream({ execute: async ({ writer }) => { await replayAssistantMessagesForDuplicateRequest({ @@ -2588,7 +2517,7 @@ export async function POST(request: Request) { confidence: requestTargetResolution.confidence, }); } catch (memoryError) { - console.warn("[Chat API] Failed to persist context-memory state:", memoryError); + chatApiLogger.warn("[Chat API] Failed to persist context-memory state:", memoryError); } } @@ -2667,7 +2596,7 @@ export async function POST(request: Request) { } } } catch (promptOnlySummaryError) { - console.warn("[Chat API] Prompt-only image summary failed:", promptOnlySummaryError); + chatApiLogger.warn("[Chat API] Prompt-only image summary failed:", promptOnlySummaryError); } let promptOnlyOptimizedPrompt = smartAutoOptimizedPrompt?.trim() || ""; @@ -2706,7 +2635,7 @@ export async function POST(request: Request) { ); promptOnlyOptimizedPrompt = String(optimizedResult?.optimizedPrompt || "").trim(); } catch (promptOnlyOptimizeError) { - console.warn("[Chat API] Prompt-only optimization failed:", promptOnlyOptimizeError); + chatApiLogger.warn("[Chat API] Prompt-only optimization failed:", promptOnlyOptimizeError); } } @@ -2771,7 +2700,7 @@ export async function POST(request: Request) { sourceImageUrls: promptOnlySourceImageUrls, }); } catch (promptOnlyMemoryError) { - console.warn("[Chat API] Failed to persist prompt-only response state:", promptOnlyMemoryError); + chatApiLogger.warn("[Chat API] Failed to persist prompt-only response state:", promptOnlyMemoryError); } writeAgentProgressChunk( @@ -2813,7 +2742,7 @@ export async function POST(request: Request) { smartAutoNeedsClarification = false; smartAutoClarificationQuestion = undefined; smartAutoFriendlyMessage = clarificationBypass.nextFriendlyMessage; - console.log("[Smart Auto Mode] ✅ Force direct execution (skip clarification)"); + chatApiLogger.info("[Smart Auto Mode] ✅ Force direct execution (skip clarification)"); } } @@ -2835,7 +2764,7 @@ export async function POST(request: Request) { canvasClarificationGate.clarificationMessage || smartAutoClarificationQuestion; smartAutoFriendlyMessage = canvasClarificationGate.clarificationMessage || smartAutoFriendlyMessage; - console.log("[Smart Auto Mode] 🧭 Canvas clarification gate triggered:", { + chatApiLogger.info("[Smart Auto Mode] 🧭 Canvas clarification gate triggered:", { reason: canvasClarificationGate.reason, executionMode: smartAutoExecution?.mode, resolutionMode: requestTargetResolution?.resolutionMode, @@ -2912,10 +2841,7 @@ export async function POST(request: Request) { : null, }); } catch (clarificationPersistError) { - console.warn( - "[Chat API] Failed to persist clarification state:", - clarificationPersistError - ); + chatApiLogger.warn("[Chat API] Failed to persist clarification state:", clarificationPersistError); } }, }); @@ -3005,10 +2931,7 @@ export async function POST(request: Request) { }); } } catch (workflowPersistError) { - console.warn( - "[Chat API] Failed to persist storyboard workflow interruption state:", - workflowPersistError - ); + chatApiLogger.warn("[Chat API] Failed to persist storyboard workflow interruption state:", workflowPersistError); } }, }); @@ -3068,10 +2991,7 @@ export async function POST(request: Request) { status: "confirmed", }); } catch (storyboardConfirmMemoryError) { - console.warn( - "[Chat API] Failed to persist storyboard confirmation memory:", - storyboardConfirmMemoryError - ); + chatApiLogger.warn("[Chat API] Failed to persist storyboard confirmation memory:", storyboardConfirmMemoryError); } try { @@ -3085,10 +3005,7 @@ export async function POST(request: Request) { status: "running", }); } catch (storyboardExecutionStartError) { - console.warn( - "[Chat API] Failed to persist storyboard execution start state:", - storyboardExecutionStartError - ); + chatApiLogger.warn("[Chat API] Failed to persist storyboard execution start state:", storyboardExecutionStartError); } const { executionResult, firstVideoUrl, finalVideoMetadata } = @@ -3139,10 +3056,7 @@ export async function POST(request: Request) { taskId: executionResult.taskId, messageId: finalMessageId, }).catch((taskAttachError) => { - console.warn( - "[Chat API] Failed to attach confirmed storyboard task with message:", - taskAttachError - ); + chatApiLogger.warn("[Chat API] Failed to attach confirmed storyboard task with message:", taskAttachError); }); try { @@ -3159,10 +3073,7 @@ export async function POST(request: Request) { firstVideoUrl: firstVideoUrl || undefined, }); } catch (storyboardExecutionCompletedError) { - console.warn( - "[Chat API] Failed to persist storyboard execution completion state:", - storyboardExecutionCompletedError - ); + chatApiLogger.warn("[Chat API] Failed to persist storyboard execution completion state:", storyboardExecutionCompletedError); } if (firstVideoUrl) { @@ -3266,7 +3177,7 @@ export async function POST(request: Request) { } const directReplacementModels = await getEnabledAiModelsWithProvider().catch((error) => { - console.warn("[Chat API] Failed to load models for direct detail replacement:", error); + chatApiLogger.warn("[Chat API] Failed to load models for direct detail replacement:", error); return undefined; }); const resolvedModelRef = await resolveDirectReplacementModelRef({ @@ -3338,10 +3249,7 @@ export async function POST(request: Request) { const replacementVisionModels = directReplacementModels || (await getEnabledAiModelsWithProvider().catch((error) => { - console.warn( - "[Chat API] Failed to load configured vision models for direct detail replacement:", - error, - ); + chatApiLogger.warn("[Chat API] Failed to load configured vision models for direct detail replacement:", error); return undefined; })); const replacementScenePlanningRuntime = @@ -3614,9 +3522,7 @@ export async function POST(request: Request) { }; finalImageSizeLabel = normalizedImage.imageSize; } catch (normalizeError) { - console.warn( - "[Chat API] Failed to normalize direct detail replacement output:", - { + chatApiLogger.warn("[Chat API] Failed to normalize direct detail replacement output:", { referenceLabel: reference.label, referenceImageUrl: reference.imageUrl, resultImageUrl: firstImage.originalUrl, @@ -3624,8 +3530,7 @@ export async function POST(request: Request) { normalizeError instanceof Error ? normalizeError.message : "unknown", - }, - ); + }); } await emitReplacementResultMessage({ @@ -3645,7 +3550,7 @@ export async function POST(request: Request) { }); successCount += 1; } catch (replacementItemError) { - console.error("[Chat API] Direct detail replacement item failed:", { + chatApiLogger.error("[Chat API] Direct detail replacement item failed:", { referenceIndex, referenceLabel: reference.label, error: replacementItemError, @@ -3880,7 +3785,7 @@ export async function POST(request: Request) { }) .where(eq(agentPresetTable.id, selectedAgentPreset.id)); } catch (agentUsageError) { - console.warn("[Chat API] Failed to update agent preset usage stats:", agentUsageError); + chatApiLogger.warn("[Chat API] Failed to update agent preset usage stats:", agentUsageError); } const agentSequenceStream = createUIMessageStream({ @@ -3998,19 +3903,13 @@ export async function POST(request: Request) { configuredReplacementAspectRatio && configuredReplacementAspectRatio !== "auto" ) { - console.info( - "[Chat API] Replacement mode forced aspect ratio to auto to preserve reference canvas:", - { + chatApiLogger.info("[Chat API] Replacement mode forced aspect ratio to auto to preserve reference canvas:", { configuredAspectRatio: configuredReplacementAspectRatio, - }, - ); + }); } const replacementVisionModels = await getEnabledAiModelsWithProvider().catch( (error) => { - console.warn( - "[Chat API] Failed to load configured vision models for replacement analysis:", - error, - ); + chatApiLogger.warn("[Chat API] Failed to load configured vision models for replacement analysis:", error); return undefined; }, ); @@ -4022,7 +3921,7 @@ export async function POST(request: Request) { replacementScenePlanningRuntime?.kind === "local_moonshot" ? 90_000 : 45_000; - console.info("[Chat API] Replacement scene planning runtime:", { + chatApiLogger.info("[Chat API] Replacement scene planning runtime:", { kind: replacementScenePlanningRuntime?.kind || "none", modelName: replacementScenePlanningRuntime?.modelName || null, timeoutMs: replacementScenePlanningTimeoutMs, @@ -4205,7 +4104,7 @@ export async function POST(request: Request) { const replacementSourceType = isDetailReplacementPreset ? "detail_replacement" : "sku_replacement"; - console.info("[Chat API] Replacement reference decision:", { + chatApiLogger.info("[Chat API] Replacement reference decision:", { mode: replacementSourceType, referenceIndex: referenceIndex + 1, totalReferences: replacementReferences.length, @@ -4222,7 +4121,7 @@ export async function POST(request: Request) { replacementExecutionPlan.scenePlan.selectedProductImageIndexes, useModelImage: replacementExecutionPlan.scenePlan.useModelImage, }); - console.info("[Chat API] Replacement scene plan summary:", { + chatApiLogger.info("[Chat API] Replacement scene plan summary:", { mode: replacementSourceType, referenceIndex: referenceIndex + 1, referenceLabel: reference.label, @@ -4244,7 +4143,7 @@ export async function POST(request: Request) { ); if (!replacementExecutionPlan.shouldReplace) { - console.info("[Chat API] Replacement reference skipped and reused:", { + chatApiLogger.info("[Chat API] Replacement reference skipped and reused:", { mode: replacementSourceType, referenceIndex: referenceIndex + 1, totalReferences: replacementReferences.length, @@ -4325,7 +4224,7 @@ export async function POST(request: Request) { scenePlan: replacementExecutionPlan.scenePlan, referenceGeometry, }); - console.info("[Chat API] Replacement image generation started:", { + chatApiLogger.info("[Chat API] Replacement image generation started:", { mode: replacementSourceType, referenceIndex: referenceIndex + 1, totalReferences: replacementReferences.length, @@ -4413,9 +4312,7 @@ export async function POST(request: Request) { }; finalImageSizeLabel = normalizedImage.imageSize; } catch (normalizeError) { - console.warn( - "[Chat API] Failed to normalize replacement output to reference size, using original model output:", - { + chatApiLogger.warn("[Chat API] Failed to normalize replacement output to reference size, using original model output:", { referenceLabel: reference.label, referenceImageUrl: reference.imageUrl, resultImageUrl: firstImage.originalUrl, @@ -4423,10 +4320,9 @@ export async function POST(request: Request) { normalizeError instanceof Error ? normalizeError.message : "unknown", - }, - ); + }); } - console.info("[Chat API] Replacement image generation completed:", { + chatApiLogger.info("[Chat API] Replacement image generation completed:", { mode: replacementSourceType, referenceIndex: referenceIndex + 1, totalReferences: replacementReferences.length, @@ -4454,7 +4350,7 @@ export async function POST(request: Request) { }); successCount += 1; } catch (replacementItemError) { - console.error("[Chat API] Agent replacement item execution failed:", { + chatApiLogger.error("[Chat API] Agent replacement item execution failed:", { referenceIndex, referenceLabel: reference.label, error: replacementItemError, @@ -4538,7 +4434,7 @@ export async function POST(request: Request) { primaryImageUrl: sceneOptimizationImageUrls.primaryImageUrl, modelImageUrl: sceneOptimizationImageUrls.modelImageUrl, }).catch((error) => { - console.warn("[Chat API] Agent scene workflow prompt optimization failed:", error); + chatApiLogger.warn("[Chat API] Agent scene workflow prompt optimization failed:", error); return null; }) : null; @@ -4549,7 +4445,7 @@ export async function POST(request: Request) { }) : ""; if (optimizedSceneWorkflowResult) { - console.info("[Chat API] Agent scene workflow prompt optimized:", { + chatApiLogger.info("[Chat API] Agent scene workflow prompt optimized:", { chatId: id, agentPresetId: selectedAgentPreset.id, optimizationModelName: optimizedSceneWorkflowResult.optimizationModelName || null, @@ -4562,7 +4458,7 @@ export async function POST(request: Request) { conflicts: optimizedSceneWorkflowResult.conflicts, }); } else if (hiddenPromptText && workflowPromptOptimizationEnabled === false) { - console.info("[Chat API] Agent scene workflow prompt optimization skipped:", { + chatApiLogger.info("[Chat API] Agent scene workflow prompt optimization skipped:", { chatId: id, agentPresetId: selectedAgentPreset.id, reason: "workflow_prompt_optimization_disabled", @@ -4583,7 +4479,7 @@ export async function POST(request: Request) { modeType: "scene_generation", }); const sceneGenerationStartedAt = Date.now(); - console.info("[Chat API] Agent scene prompt guardrails:", { + chatApiLogger.info("[Chat API] Agent scene prompt guardrails:", { chatId: id, agentPresetId: selectedAgentPreset.id, agentPresetName: selectedAgentPreset.name, @@ -4625,7 +4521,7 @@ export async function POST(request: Request) { ? String(selectedChatModel || "").trim() : presetModelId; const resolvedImageCount = Math.max(1, effectiveImageParams?.imageCount || 1); - console.info("[Chat API] Agent scene generation started:", { + chatApiLogger.info("[Chat API] Agent scene generation started:", { chatId: id, agentPresetId: selectedAgentPreset.id, agentPresetName: selectedAgentPreset.name, @@ -4702,7 +4598,7 @@ export async function POST(request: Request) { } : undefined, }); - console.info("[Chat API] Agent scene generation model completed:", { + chatApiLogger.info("[Chat API] Agent scene generation model completed:", { chatId: id, agentPresetId: selectedAgentPreset.id, agentPresetName: selectedAgentPreset.name, @@ -4765,7 +4661,7 @@ export async function POST(request: Request) { requestedImageCount: resolvedImageCount, }, ); - console.info("[Chat API] Agent scene generation persisted:", { + chatApiLogger.info("[Chat API] Agent scene generation persisted:", { chatId: id, agentPresetId: selectedAgentPreset.id, agentPresetName: selectedAgentPreset.name, @@ -4800,7 +4696,7 @@ export async function POST(request: Request) { "agent-preset:image:scene-generation:canvas-media", ); } - console.info("[Chat API] Agent scene generation response streamed:", { + chatApiLogger.info("[Chat API] Agent scene generation response streamed:", { chatId: id, agentPresetId: selectedAgentPreset.id, agentPresetName: selectedAgentPreset.name, @@ -4811,8 +4707,8 @@ export async function POST(request: Request) { successCount = result.images.length; } catch (sceneError) { - console.error("[Chat API] Agent preset scene generation failed:", sceneError); - console.error("[Chat API] Agent scene generation failed detail:", { + chatApiLogger.error("[Chat API] Agent preset scene generation failed:", sceneError); + chatApiLogger.error("[Chat API] Agent scene generation failed detail:", { chatId: id, agentPresetId: selectedAgentPreset.id, agentPresetName: selectedAgentPreset.name, @@ -5103,10 +4999,7 @@ export async function POST(request: Request) { temporaryVideoUrl: videoUrl, }); } catch (memoryError) { - console.warn( - "[Chat API] Failed to update working state after agent preset video generation:", - memoryError, - ); + chatApiLogger.warn("[Chat API] Failed to update working state after agent preset video generation:", memoryError); } await consumeGeneratedVideoPoints({ @@ -5159,7 +5052,7 @@ export async function POST(request: Request) { successCount += 1; } catch (slotError) { - console.error("[Chat API] Agent preset slot execution failed:", { + chatApiLogger.error("[Chat API] Agent preset slot execution failed:", { slotIndex: slot.slotIndex, slotLabel, error: slotError, @@ -5199,10 +5092,7 @@ export async function POST(request: Request) { error: slotError instanceof Error ? slotError.message : String(slotError), }); } catch (videoMemoryError) { - console.warn( - "[Chat API] Failed to persist agent preset video failure state:", - videoMemoryError, - ); + chatApiLogger.warn("[Chat API] Failed to persist agent preset video failure state:", videoMemoryError); } } writeAssistantTextChunk( @@ -5229,7 +5119,7 @@ export async function POST(request: Request) { successCount, }); } catch (agentPresetMemoryError) { - console.warn("[Chat API] Failed to persist agent preset working state:", agentPresetMemoryError); + chatApiLogger.warn("[Chat API] Failed to persist agent preset working state:", agentPresetMemoryError); } if (selectedAgentPreset.type === "image") { @@ -5363,7 +5253,7 @@ export async function POST(request: Request) { "agent:analyze:progress-completed", ); } catch (directAnalyzeError) { - console.error("[Chat API] Direct agent image analysis failed:", directAnalyzeError); + chatApiLogger.error("[Chat API] Direct agent image analysis failed:", directAnalyzeError); const errorMessage = getDirectAgentToolErrorMessage("analyze", directAnalyzeError); await saveAssistantTextOnlyMessage({ @@ -5528,7 +5418,7 @@ export async function POST(request: Request) { "agent:generate_image:end", ); } catch (directToolError) { - console.error("[Chat API] Direct agent image generation failed:", directToolError); + chatApiLogger.error("[Chat API] Direct agent image generation failed:", directToolError); const errorMessage = getDirectAgentToolErrorMessage( "generate_image", directToolError, @@ -5688,7 +5578,7 @@ export async function POST(request: Request) { "agent:generate_video:progress-completed", ); } catch (directToolError) { - console.error("[Chat API] Direct agent video generation failed:", directToolError); + chatApiLogger.error("[Chat API] Direct agent video generation failed:", directToolError); const errorMessage = getDirectAgentToolErrorMessage( "generate_video", directToolError, @@ -5852,9 +5742,7 @@ export async function POST(request: Request) { }); if (directAgentExecution.publishToCanvas && contextPayload?.source === "canvas") { - console.log( - `[Chat API] Agent publishToCanvas satisfied by assistant media auto-sync (${directAgentToolCapability})`, - ); + chatApiLogger.info(`[Chat API] Agent publishToCanvas satisfied by assistant media auto-sync (${directAgentToolCapability})`); } writeAssistantTextChunk( @@ -5885,15 +5773,10 @@ export async function POST(request: Request) { `agent:${directAgentToolCapability}:progress-completed`, ); } catch (directToolError) { - console.error( - `[Chat API] Direct agent tool ${directAgentToolCapability} failed:`, - directToolError, - ); + chatApiLogger.error(`[Chat API] Direct agent tool ${directAgentToolCapability} failed:`, directToolError); if (!isDirectAgentImageEditServiceError(directToolError)) { - console.warn( - `[Chat API] Direct agent tool ${directAgentToolCapability} threw unexpected error type`, - ); + chatApiLogger.warn(`[Chat API] Direct agent tool ${directAgentToolCapability} threw unexpected error type`); } const errorMessage = getDirectAgentToolErrorMessage( @@ -5960,14 +5843,14 @@ export async function POST(request: Request) { hasImage: hasImageInputForAutoFallback, }); finalModelId = fallbackRoute.id; - console.warn("[Chat API] Auto model was unresolved, routed to fallback model:", { + chatApiLogger.warn("[Chat API] Auto model was unresolved, routed to fallback model:", { intent: autoFallbackIntent, modelId: fallbackRoute.id, displayName: fallbackRoute.displayName, reason: fallbackRoute.reason, }); } catch (autoModelRouteError) { - console.error("[Chat API] Failed to route unresolved auto model:", autoModelRouteError); + chatApiLogger.error("[Chat API] Failed to route unresolved auto model:", autoModelRouteError); const enabledModels = await getEnabledAiModelsWithProvider(false); const nonAgentModels = enabledModels.filter(({ model }) => !isAiModelAgentAuto(model)); const candidates = nonAgentModels.length > 0 ? nonAgentModels : enabledModels; @@ -5996,7 +5879,7 @@ export async function POST(request: Request) { } finalModelId = fallbackModel.model.id; - console.warn("[Chat API] Auto model fallback used first available model:", { + chatApiLogger.warn("[Chat API] Auto model fallback used first available model:", { intent: autoFallbackIntent, modelId: fallbackModel.model.id, displayName: fallbackModel.model.displayName, @@ -6027,31 +5910,29 @@ export async function POST(request: Request) { const aiModelProvider = aiModelData ? await getAiProviderById({ id: aiModelData.providerId }).catch(() => null) : null; - console.log("[Chat API] Model data:", { id: finalModelId, isSubModel: aiModelData?.isSubModel }); + chatApiLogger.info("[Chat API] Model data:", { id: finalModelId, isSubModel: aiModelData?.isSubModel }); if (aiModelData && !aiModelData.isSubModel && aiModelProvider?.type === "volcano-video") { // 检查是否有子模型 const subModels = await getSubModelsByParentModelId(finalModelId); - console.log("[Chat API] Found sub-models:", subModels.length); + chatApiLogger.info("[Chat API] Found sub-models:", subModels.length); if (subModels.length > 0) { // 这是一个主模型,需要根据 videoParams 选择子模型 const videoParams = effectiveVideoParams; - console.log("[Chat API] Video params:", videoParams); + chatApiLogger.info("[Chat API] Video params:", videoParams); // 如果没有 videoParams 或没有 mode,使用默认模式 const mode = (videoParams?.mode || "text-to-video") as VideoModeType; - console.log("[Chat API] Using mode:", mode); + chatApiLogger.info("[Chat API] Using mode:", mode); const matchedSubModel = selectBestVideoSubModelForMode(subModels as any, mode); if (matchedSubModel) { - console.log( - `[Chat API] 视频模式 ${mode} → 选择子模型: ${matchedSubModel.model.displayName} (${matchedSubModel.model.modelId})` - ); + chatApiLogger.info(`[Chat API] 视频模式 ${mode} → 选择子模型: ${matchedSubModel.model.displayName} (${matchedSubModel.model.modelId})`); targetModelId = matchedSubModel.model.id; } else { - console.warn(`[Chat API] 未找到可用子模型,继续使用主模型`); + chatApiLogger.warn(`[Chat API] 未找到可用子模型,继续使用主模型`); } } } @@ -6169,7 +6050,7 @@ export async function POST(request: Request) { const quota = await checkUserImageQuota(session.user.id); if (!quota.allowed) { - console.log(`[Chat API] ⛔ 图片配额已用完: ${quota.used}/${quota.limit}`); + chatApiLogger.info(`[Chat API] ⛔ 图片配额已用完: ${quota.used}/${quota.limit}`); return NextResponse.json( { error: "quota_exceeded", @@ -6181,7 +6062,7 @@ export async function POST(request: Request) { ); } - console.log(`[Chat API] ✅ 图片配额检查通过: ${quota.used}/${quota.limit ?? '无限制'}`); + chatApiLogger.info(`[Chat API] ✅ 图片配额检查通过: ${quota.used}/${quota.limit ?? '无限制'}`); const pointsConfig = await getPointsSystemConfig(); const normalizedUnitCost = Number.isFinite(modelCreditCostPerImage) @@ -6272,8 +6153,8 @@ export async function POST(request: Request) { // 支持 gemini-image 和 huanke-gemini 两种图片生成 provider const isGeminiImageProvider = ["gemini-image", "huanke-gemini"].includes((languageModel as any).provider); if (isGeminiImageProvider && typeof (languageModel as any).doGenerate === "function") { - console.log("[Chat API] Using Gemini image generation, provider:", (languageModel as any).provider); - console.log("[Chat API] Image params:", effectiveImageParams); + chatApiLogger.info("[Chat API] Using Gemini image generation, provider:", (languageModel as any).provider); + chatApiLogger.info("[Chat API] Image params:", effectiveImageParams); // 🆕 获取备用模型配置 const currentModelConfig = await getAiModelById({ id: finalModelId }); @@ -6293,10 +6174,7 @@ export async function POST(request: Request) { currentModelKey: actualModelId, configuredFallbackIds: configuredFallbacks, }); - console.log( - "[Chat API] Gemini fallback candidates:", - fallbackCandidates.map((candidate) => `${candidate.model.displayName}(${candidate.provider.type})`) - ); + chatApiLogger.info("[Chat API] Gemini fallback candidates:", fallbackCandidates.map((candidate) => `${candidate.model.displayName}(${candidate.provider.type})`)); const geminiStream = createUIMessageStream({ execute: async ({ writer }) => { @@ -6306,7 +6184,7 @@ export async function POST(request: Request) { if (conversationMessage) { const chatMessageId = generateUUID(); - console.log("[Chat API] 💬 Gemini: Sending conversational reply first:", smartAutoFriendlyMessage); + chatApiLogger.info("[Chat API] 💬 Gemini: Sending conversational reply first:", smartAutoFriendlyMessage); // 发送带标记的对话消息 writeAssistantTextChunk( @@ -6349,16 +6227,16 @@ export async function POST(request: Request) { // 🆕 尝试生成图片的函数(支持备用模型切换) const tryGenerateImage = async (modelIdToUse: string, isRetry = false): Promise => { - console.log(`[Chat API] ${isRetry ? "🔄 Retry with fallback" : "🚀 Trying"} model: ${modelIdToUse}`); + chatApiLogger.info(`[Chat API] ${isRetry ? "🔄 Retry with fallback" : "🚀 Trying"} model: ${modelIdToUse}`); // 只传递最后一条用户消息,避免上下文历史干扰生图效果 const messagesForGemini = buildMessagesForGemini(); - console.log("[Chat API] Gemini: Using only last user message (no history context)"); + chatApiLogger.info("[Chat API] Gemini: Using only last user message (no history context)"); // 转换消息:gemini-image 需要 base64 格式,huanke-gemini 需要 URL 格式 const providerForConvert = (languageModel as any).provider === "huanke-gemini" ? "huanke-gemini" : "gemini"; const modelMessages = await convertMessagesWithImages(messagesForGemini, providerForConvert); - console.log("[Chat API] Message conversion provider:", providerForConvert); + chatApiLogger.info("[Chat API] Message conversion provider:", providerForConvert); // 调用 doGenerate 获取图片(如果是备用模型,传入 overrideModelId) const result = await (languageModel as any).doGenerate({ @@ -6404,7 +6282,7 @@ export async function POST(request: Request) { // 首先尝试主模型 imageMarkdown = await tryGenerateImage(actualModelId, false); } catch (primaryError) { - console.error("[Chat API] Primary model failed:", primaryError); + chatApiLogger.error("[Chat API] Primary model failed:", primaryError); await recordAiModelHealthFailure({ model: currentModelEntry?.model || currentModelConfig, provider: currentModelEntry?.provider, @@ -6423,7 +6301,7 @@ export async function POST(request: Request) { 1, }, }).catch((healthError) => { - console.warn("[Chat API] Record Gemini primary health failure failed:", healthError); + chatApiLogger.warn("[Chat API] Record Gemini primary health failure failed:", healthError); }); // 🆕 尝试备用模型(支持跨服务商切换) @@ -6432,9 +6310,7 @@ export async function POST(request: Request) { for (const candidate of fallbackCandidates) { try { triedFallbackModelIds.add(String(candidate.model.id || "")); - console.log( - `[Chat API] 🔄 Trying fallback model: ${candidate.model.displayName} (${candidate.provider.type})` - ); + chatApiLogger.info(`[Chat API] 🔄 Trying fallback model: ${candidate.model.displayName} (${candidate.provider.type})`); const fallbackResult = await generateImageWithFailoverCandidate({ candidate, messages: buildMessagesForGemini(), @@ -6447,9 +6323,7 @@ export async function POST(request: Request) { imageMarkdown = fallbackResult.text; usedModelId = fallbackResult.usedModelId; fallbackSuccess = true; - console.log( - `[Chat API] ✅ Fallback model ${fallbackResult.displayName} succeeded!` - ); + chatApiLogger.info(`[Chat API] ✅ Fallback model ${fallbackResult.displayName} succeeded!`); break; } catch (fallbackError) { const fallbackErrorMessage = normalizeFailoverErrorMessage(fallbackError); @@ -6470,12 +6344,9 @@ export async function POST(request: Request) { imageSize: effectiveImageParams?.imageSize, }, }).catch((healthError) => { - console.warn("[Chat API] Record Gemini fallback health failure failed:", healthError); + chatApiLogger.warn("[Chat API] Record Gemini fallback health failure failed:", healthError); }); - console.error( - `[Chat API] ❌ Fallback model ${candidate.model.displayName} (${candidate.provider.type}) failed:`, - fallbackError - ); + chatApiLogger.error(`[Chat API] ❌ Fallback model ${candidate.model.displayName} (${candidate.provider.type}) failed:`, fallbackError); } } @@ -6503,9 +6374,7 @@ export async function POST(request: Request) { for (const candidate of crossProviderCandidates) { try { triedFallbackModelIds.add(String(candidate.model.id || "")); - console.log( - `[Chat API] 🔁 Gemini cross-provider failover: ${candidate.model.displayName} (${candidate.provider.type})` - ); + chatApiLogger.info(`[Chat API] 🔁 Gemini cross-provider failover: ${candidate.model.displayName} (${candidate.provider.type})`); const fallbackResult = await generateImageWithFailoverCandidate({ candidate, messages: buildMessagesForGemini(), @@ -6519,9 +6388,7 @@ export async function POST(request: Request) { imageMarkdown = fallbackResult.text; usedModelId = fallbackResult.usedModelId; fallbackSuccess = true; - console.log( - `[Chat API] ✅ Gemini cross-provider fallback model ${fallbackResult.displayName} succeeded!` - ); + chatApiLogger.info(`[Chat API] ✅ Gemini cross-provider fallback model ${fallbackResult.displayName} succeeded!`); break; } catch (fallbackError) { const fallbackErrorMessage = normalizeFailoverErrorMessage(fallbackError); @@ -6542,12 +6409,9 @@ export async function POST(request: Request) { imageSize: effectiveImageParams?.imageSize, }, }).catch((healthError) => { - console.warn("[Chat API] Record Gemini cross-provider health failure failed:", healthError); + chatApiLogger.warn("[Chat API] Record Gemini cross-provider health failure failed:", healthError); }); - console.error( - `[Chat API] ❌ Gemini cross-provider fallback model ${candidate.model.displayName} (${candidate.provider.type}) failed:`, - fallbackError - ); + chatApiLogger.error(`[Chat API] ❌ Gemini cross-provider fallback model ${candidate.model.displayName} (${candidate.provider.type}) failed:`, fallbackError); } } } @@ -6558,9 +6422,9 @@ export async function POST(request: Request) { } } - console.log("[Chat API] Gemini generated, length:", imageMarkdown.length); - console.log("[Chat API] Gemini image markdown:", imageMarkdown.substring(0, 200)); - console.log("[Chat API] Used model ID:", usedModelId); + chatApiLogger.info("[Chat API] Gemini generated, length:", imageMarkdown.length); + chatApiLogger.info("[Chat API] Gemini image markdown:", imageMarkdown.substring(0, 200)); + chatApiLogger.info("[Chat API] Used model ID:", usedModelId); const usedModelEntry = resolveModelEntryByRuntimeModelId( allModels, @@ -6570,7 +6434,7 @@ export async function POST(request: Request) { await recordAiModelHealthSuccess({ model: usedModelEntry?.model || (usedModelId === actualModelId ? currentModelConfig : null), }).catch((healthError) => { - console.warn("[Chat API] Record Gemini health success failed:", healthError); + chatApiLogger.warn("[Chat API] Record Gemini health success failed:", healthError); }); const usedModelDisplayName = @@ -6643,7 +6507,7 @@ export async function POST(request: Request) { }, ], }); - console.log("[Chat API] ✅ Gemini message saved successfully!"); + chatApiLogger.info("[Chat API] ✅ Gemini message saved successfully!"); // 提取用户 prompt(最后一条用户消息的文本) const lastUserMessage = uiMessages.filter((m) => m.role === "user").pop(); @@ -6674,31 +6538,31 @@ export async function POST(request: Request) { }, ); } catch (saveError) { - console.error("[Chat API] ❌ Failed to save Gemini message to database:", saveError); - console.error("[Chat API] Message content that failed:", imageMarkdown.substring(0, 300)); + chatApiLogger.error("[Chat API] ❌ Failed to save Gemini message to database:", saveError); + chatApiLogger.error("[Chat API] Message content that failed:", imageMarkdown.substring(0, 300)); } } catch (error) { - console.error("[Chat API] Gemini generation error:", error); - console.log("[Chat API] Attempting failover to Volcano Vision..."); + chatApiLogger.error("[Chat API] Gemini generation error:", error); + chatApiLogger.info("[Chat API] Attempting failover to Volcano Vision..."); // 故障转移:尝试使用火山引擎模型 try { // 查找火山引擎模型 const allModels = await getEnabledAiModelsWithProvider(); - console.log("[Chat API] Total enabled models:", allModels.length); + chatApiLogger.info("[Chat API] Total enabled models:", allModels.length); const volcanoModel = allModels.find( (m: any) => m.provider.type === "volcano-vision" && m.model.isEnabled ); if (volcanoModel) { - console.log("[Chat API] Found Volcano Vision model for failover:", volcanoModel.model.id); + chatApiLogger.info("[Chat API] Found Volcano Vision model for failover:", volcanoModel.model.id); // 获取火山引擎模型实例 const volcanoLanguageModel = await getLanguageModelById(volcanoModel.model.id); if (volcanoLanguageModel && typeof (volcanoLanguageModel as any).doGenerate === "function") { - console.log("[Chat API] Executing Volcano Vision failover..."); + chatApiLogger.info("[Chat API] Executing Volcano Vision failover..."); // 转换消息(火山引擎会自动处理 Base64) const volcanoMessages = await convertMessagesWithImages( @@ -6723,7 +6587,7 @@ export async function POST(request: Request) { imageMarkdown, volcanoModel.model.displayName || volcanoModel.model.modelId, ); - console.log("[Chat API] Volcano Vision failover success, length:", imageMarkdown.length); + chatApiLogger.info("[Chat API] Volcano Vision failover success, length:", imageMarkdown.length); // 生成消息 ID const messageId = generateUUID(); @@ -6786,7 +6650,7 @@ export async function POST(request: Request) { }, ], }); - console.log("[Chat API] ✅ Volcano Vision failover message saved!"); + chatApiLogger.info("[Chat API] ✅ Volcano Vision failover message saved!"); // 提取用户 prompt const lastUserMessage = uiMessages.filter((m) => m.role === "user").pop(); @@ -6813,16 +6677,16 @@ export async function POST(request: Request) { }, ); } catch (saveError) { - console.error("[Chat API] Failed to save failover message:", saveError); + chatApiLogger.error("[Chat API] Failed to save failover message:", saveError); } return; // 成功,直接返回 } } - console.log("[Chat API] No Volcano Vision model available for failover"); + chatApiLogger.info("[Chat API] No Volcano Vision model available for failover"); } catch (failoverError) { - console.error("[Chat API] Failover to Volcano Vision also failed:", failoverError); + chatApiLogger.error("[Chat API] Failover to Volcano Vision also failed:", failoverError); } // 如果故障转移也失败,返回错误消息 @@ -6861,7 +6725,7 @@ export async function POST(request: Request) { ], }); } catch (saveError) { - console.error("[Chat API] Failed to save error message:", saveError); + chatApiLogger.error("[Chat API] Failed to save error message:", saveError); } } finally { stopKeepalive?.(); @@ -6888,8 +6752,8 @@ export async function POST(request: Request) { "krea", ].includes((languageModel as any).provider); if (isAlibabaLikeImageProvider && typeof (languageModel as any).doGenerate === "function") { - console.log("[Chat API] Using image generation provider:", (languageModel as any).provider); - console.log("[Chat API] Image params:", effectiveImageParams); + chatApiLogger.info("[Chat API] Using image generation provider:", (languageModel as any).provider); + chatApiLogger.info("[Chat API] Image params:", effectiveImageParams); // 🆕 获取模型显示名称,用于错误提示 const alibabaModelConfig = await getAiModelById({ id: finalModelId }); @@ -6905,10 +6769,7 @@ export async function POST(request: Request) { currentModelKey: actualModelId, configuredFallbackIds: configuredFallbacks, }); - console.log( - "[Chat API] Alibaba fallback candidates:", - fallbackCandidates.map((candidate) => `${candidate.model.displayName}(${candidate.provider.type})`) - ); + chatApiLogger.info("[Chat API] Alibaba fallback candidates:", fallbackCandidates.map((candidate) => `${candidate.model.displayName}(${candidate.provider.type})`)); const alibabaStream = createUIMessageStream({ execute: async ({ writer }) => { @@ -6919,7 +6780,7 @@ export async function POST(request: Request) { if (conversationMessage) { const chatMessageId = generateUUID(); - console.log("[Chat API] 💬 Sending conversational reply first:", smartAutoFriendlyMessage); + chatApiLogger.info("[Chat API] 💬 Sending conversational reply first:", smartAutoFriendlyMessage); // 发送带标记的对话消息 writeAssistantTextChunk( @@ -6952,11 +6813,11 @@ export async function POST(request: Request) { // 只传递最后一条用户消息 const lastUserMessage = uiMessagesForModel.filter((m) => m.role === "user").pop(); let messagesForAlibaba = lastUserMessage ? [lastUserMessage] : uiMessagesForModel; - console.log("[Chat API] Alibaba: Using only last user message"); + chatApiLogger.info("[Chat API] Alibaba: Using only last user message"); // 🆕 如果有智能模式优化后的提示词,替换消息中的文本(仅用于API调用) if (smartAutoOptimizedPrompt) { - console.log("[Chat API] Using optimized prompt for API call"); + chatApiLogger.info("[Chat API] Using optimized prompt for API call"); messagesForAlibaba = applyOptimizedPromptToLatestUserMessage( messagesForAlibaba, smartAutoOptimizedPrompt, @@ -6972,7 +6833,7 @@ export async function POST(request: Request) { messagesForAlibaba, resolvedTargetImageUrlsForProvider ); - console.log("[Chat API] Image provider target images:", { + chatApiLogger.info("[Chat API] Image provider target images:", { resolutionMode: requestTargetResolution?.resolutionMode || null, imageCount: resolvedTargetImageUrlsForProvider.length, firstImageUrl: summarizeTargetImageUrl(resolvedTargetImageUrlsForProvider[0]), @@ -7089,7 +6950,7 @@ export async function POST(request: Request) { ], }); - console.log("[Chat API] ✅ Queued FAL GPT Image 2 Edit task", { + chatApiLogger.info("[Chat API] ✅ Queued FAL GPT Image 2 Edit task", { requestId: queuedTask.requestId, endpointId: queuedTask.endpointId, messageId: placeholderMessageId, @@ -7165,14 +7026,12 @@ export async function POST(request: Request) { try { imageMarkdown = await tryGenerateImage(actualModelId, false); } catch (primaryError) { - console.error("[Chat API] Alibaba primary model failed:", primaryError); + chatApiLogger.error("[Chat API] Alibaba primary model failed:", primaryError); let fallbackSuccess = false; for (const candidate of fallbackCandidates) { try { - console.log( - `[Chat API] 🔄 Alibaba fallback model: ${candidate.model.displayName} (${candidate.provider.type})` - ); + chatApiLogger.info(`[Chat API] 🔄 Alibaba fallback model: ${candidate.model.displayName} (${candidate.provider.type})`); const fallbackResult = await generateImageWithFailoverCandidate({ candidate, messages: messagesForAlibaba, @@ -7186,19 +7045,14 @@ export async function POST(request: Request) { imageMarkdown = fallbackResult.text; usedModelId = fallbackResult.usedModelId; fallbackSuccess = true; - console.log( - `[Chat API] ✅ Alibaba fallback model ${fallbackResult.displayName} succeeded!` - ); + chatApiLogger.info(`[Chat API] ✅ Alibaba fallback model ${fallbackResult.displayName} succeeded!`); break; } catch (fallbackError) { const fallbackErrorMessage = normalizeFailoverErrorMessage(fallbackError); if (shouldCooldownImageFallbackModel(fallbackErrorMessage)) { setImageFallbackModelCooldown(candidate.model.id, fallbackErrorMessage); } - console.error( - `[Chat API] ❌ Alibaba fallback model ${candidate.model.displayName} (${candidate.provider.type}) failed:`, - fallbackError - ); + chatApiLogger.error(`[Chat API] ❌ Alibaba fallback model ${candidate.model.displayName} (${candidate.provider.type}) failed:`, fallbackError); } } @@ -7224,24 +7078,20 @@ export async function POST(request: Request) { for (const candidate of crossProviderCandidates) { try { - console.log( - `[Chat API] 🔁 Cross-provider failover attempt: ${candidate.model.displayName} (${candidate.provider.type})` - ); + chatApiLogger.info(`[Chat API] 🔁 Cross-provider failover attempt: ${candidate.model.displayName} (${candidate.provider.type})`); if ( candidate.provider.type === "fal-image" && isFalGptImage2EditModelId( String(candidate.model?.modelId || candidate.model?.id || "") ) ) { - console.log( - `[Chat API] Skip async-only failover candidate: ${candidate.model.displayName}` - ); + chatApiLogger.info(`[Chat API] Skip async-only failover candidate: ${candidate.model.displayName}`); continue; } const candidateLanguageModel = await getLanguageModelById(candidate.model.id); if (!candidateLanguageModel || typeof (candidateLanguageModel as any).doGenerate !== "function") { - console.log(`[Chat API] Skip candidate without doGenerate: ${candidate.model.id}`); + chatApiLogger.info(`[Chat API] Skip candidate without doGenerate: ${candidate.model.id}`); continue; } @@ -7294,19 +7144,14 @@ export async function POST(request: Request) { imageMarkdown = candidateResult.text || "图片生成失败"; usedModelId = candidate.model.modelId; fallbackSuccess = true; - console.log( - `[Chat API] ✅ Cross-provider failover succeeded: ${candidate.model.displayName} (${candidate.provider.type})` - ); + chatApiLogger.info(`[Chat API] ✅ Cross-provider failover succeeded: ${candidate.model.displayName} (${candidate.provider.type})`); break; } catch (crossError) { const crossErrorMessage = normalizeFailoverErrorMessage(crossError); if (shouldCooldownImageFallbackModel(crossErrorMessage)) { setImageFallbackModelCooldown(candidate.model.id, crossErrorMessage); } - console.error( - `[Chat API] ❌ Cross-provider failover failed: ${candidate.model.displayName} (${candidate.provider.type})`, - crossError - ); + chatApiLogger.error(`[Chat API] ❌ Cross-provider failover failed: ${candidate.model.displayName} (${candidate.provider.type})`, crossError); } } } @@ -7316,8 +7161,8 @@ export async function POST(request: Request) { } } - console.log("[Chat API] Alibaba generated, length:", imageMarkdown.length); - console.log("[Chat API] Alibaba used model:", usedModelId); + chatApiLogger.info("[Chat API] Alibaba generated, length:", imageMarkdown.length); + chatApiLogger.info("[Chat API] Alibaba used model:", usedModelId); const usedModelDisplayName = resolveModelDisplayNameByModelId(allModels, usedModelId) || @@ -7389,7 +7234,7 @@ export async function POST(request: Request) { }, ], }); - console.log("[Chat API] ✅ Alibaba message saved successfully!"); + chatApiLogger.info("[Chat API] ✅ Alibaba message saved successfully!"); // 提取用户 prompt const userPrompt = lastUserMessage?.parts?.find((p): p is { type: "text"; text: string } => p.type === "text")?.text || ""; @@ -7419,10 +7264,10 @@ export async function POST(request: Request) { }, ); } catch (saveError) { - console.error("[Chat API] ❌ Failed to save Alibaba message:", saveError); + chatApiLogger.error("[Chat API] ❌ Failed to save Alibaba message:", saveError); } } catch (error) { - console.error("[Chat API] Alibaba generation error:", error); + chatApiLogger.error("[Chat API] Alibaba generation error:", error); // 返回错误消息 const errorMessageId = generateUUID(); @@ -7460,7 +7305,7 @@ export async function POST(request: Request) { ], }); } catch (saveError) { - console.error("[Chat API] Failed to save error message:", saveError); + chatApiLogger.error("[Chat API] Failed to save error message:", saveError); } } finally { stopKeepalive?.(); @@ -7474,7 +7319,7 @@ export async function POST(request: Request) { // ========== 火山引擎视觉图片生成独立处理 ========== if ((languageModel as any).provider === "volcano-vision" && typeof (languageModel as any).doGenerate === "function") { - console.log("[Chat API] Using Volcano Vision image generation"); + chatApiLogger.info("[Chat API] Using Volcano Vision image generation"); // 🆕 检测是否有标注图片,如果有则在消息中注入系统提示 const hasAnnotation = hasAnnotatedImage(uiMessages); @@ -7495,13 +7340,10 @@ export async function POST(request: Request) { currentModelKey: actualModelId, configuredFallbackIds: configuredFallbacks, }); - console.log( - "[Chat API] Volcano fallback candidates:", - fallbackCandidates.map((candidate) => `${candidate.model.displayName}(${candidate.provider.type})`) - ); + chatApiLogger.info("[Chat API] Volcano fallback candidates:", fallbackCandidates.map((candidate) => `${candidate.model.displayName}(${candidate.provider.type})`)); if (hasAnnotation) { - console.log("[Chat API] 🎨 Volcano Vision: 检测到标注图片,将注入系统提示"); + chatApiLogger.info("[Chat API] 🎨 Volcano Vision: 检测到标注图片,将注入系统提示"); // 创建消息副本,修改最后一条用户消息的文本 messagesForVolcano = messagesForVolcano.map((msg, idx) => { if (msg.role === "user" && idx === messagesForVolcano.length - 1) { @@ -7532,7 +7374,7 @@ export async function POST(request: Request) { if (conversationMessage) { const chatMessageId = generateUUID(); - console.log("[Chat API] 💬 Volcano: Sending conversational reply first:", smartAutoFriendlyMessage); + chatApiLogger.info("[Chat API] 💬 Volcano: Sending conversational reply first:", smartAutoFriendlyMessage); // 发送带标记的对话消息 writeAssistantTextChunk( @@ -7607,13 +7449,11 @@ export async function POST(request: Request) { try { imageMarkdown = await tryGenerateImage(actualModelId, false); } catch (primaryError) { - console.error("[Chat API] Volcano primary model failed:", primaryError); + chatApiLogger.error("[Chat API] Volcano primary model failed:", primaryError); let fallbackSuccess = false; for (const candidate of fallbackCandidates) { try { - console.log( - `[Chat API] 🔄 Volcano fallback model: ${candidate.model.displayName} (${candidate.provider.type})` - ); + chatApiLogger.info(`[Chat API] 🔄 Volcano fallback model: ${candidate.model.displayName} (${candidate.provider.type})`); const fallbackResult = await generateImageWithFailoverCandidate({ candidate, messages: messagesForVolcano, @@ -7627,19 +7467,14 @@ export async function POST(request: Request) { imageMarkdown = fallbackResult.text; usedModelId = fallbackResult.usedModelId; fallbackSuccess = true; - console.log( - `[Chat API] ✅ Volcano fallback model ${fallbackResult.displayName} succeeded!` - ); + chatApiLogger.info(`[Chat API] ✅ Volcano fallback model ${fallbackResult.displayName} succeeded!`); break; } catch (fallbackError) { const fallbackErrorMessage = normalizeFailoverErrorMessage(fallbackError); if (shouldCooldownImageFallbackModel(fallbackErrorMessage)) { setImageFallbackModelCooldown(candidate.model.id, fallbackErrorMessage); } - console.error( - `[Chat API] ❌ Volcano fallback model ${candidate.model.displayName} (${candidate.provider.type}) failed:`, - fallbackError - ); + chatApiLogger.error(`[Chat API] ❌ Volcano fallback model ${candidate.model.displayName} (${candidate.provider.type}) failed:`, fallbackError); } } if (!fallbackSuccess) { @@ -7664,24 +7499,20 @@ export async function POST(request: Request) { for (const candidate of crossProviderCandidates) { try { - console.log( - `[Chat API] 🔁 Volcano cross-provider failover attempt: ${candidate.model.displayName} (${candidate.provider.type})` - ); + chatApiLogger.info(`[Chat API] 🔁 Volcano cross-provider failover attempt: ${candidate.model.displayName} (${candidate.provider.type})`); if ( candidate.provider.type === "fal-image" && isFalGptImage2EditModelId( String(candidate.model?.modelId || candidate.model?.id || "") ) ) { - console.log( - `[Chat API] Skip async-only failover candidate: ${candidate.model.displayName}` - ); + chatApiLogger.info(`[Chat API] Skip async-only failover candidate: ${candidate.model.displayName}`); continue; } const candidateLanguageModel = await getLanguageModelById(candidate.model.id); if (!candidateLanguageModel || typeof (candidateLanguageModel as any).doGenerate !== "function") { - console.log(`[Chat API] Skip candidate without doGenerate: ${candidate.model.id}`); + chatApiLogger.info(`[Chat API] Skip candidate without doGenerate: ${candidate.model.id}`); continue; } @@ -7734,19 +7565,14 @@ export async function POST(request: Request) { imageMarkdown = candidateResult.text || "图片生成失败"; usedModelId = candidate.model.modelId; fallbackSuccess = true; - console.log( - `[Chat API] ✅ Volcano cross-provider failover succeeded: ${candidate.model.displayName} (${candidate.provider.type})` - ); + chatApiLogger.info(`[Chat API] ✅ Volcano cross-provider failover succeeded: ${candidate.model.displayName} (${candidate.provider.type})`); break; } catch (crossError) { const crossErrorMessage = normalizeFailoverErrorMessage(crossError); if (shouldCooldownImageFallbackModel(crossErrorMessage)) { setImageFallbackModelCooldown(candidate.model.id, crossErrorMessage); } - console.error( - `[Chat API] ❌ Volcano cross-provider failover failed: ${candidate.model.displayName} (${candidate.provider.type})`, - crossError - ); + chatApiLogger.error(`[Chat API] ❌ Volcano cross-provider failover failed: ${candidate.model.displayName} (${candidate.provider.type})`, crossError); } } } @@ -7754,8 +7580,8 @@ export async function POST(request: Request) { throw primaryError; } } - console.log("[Chat API] Volcano Vision generated, length:", imageMarkdown.length); - console.log("[Chat API] Volcano Vision image markdown:", imageMarkdown.substring(0, 200)); + chatApiLogger.info("[Chat API] Volcano Vision generated, length:", imageMarkdown.length); + chatApiLogger.info("[Chat API] Volcano Vision image markdown:", imageMarkdown.substring(0, 200)); const usedModelDisplayName = resolveModelDisplayNameByModelId(allModels, usedModelId) || @@ -7827,7 +7653,7 @@ export async function POST(request: Request) { }, ], }); - console.log("[Chat API] ✅ Volcano Vision message saved successfully!"); + chatApiLogger.info("[Chat API] ✅ Volcano Vision message saved successfully!"); // 提取用户 prompt const lastUserMessage = uiMessages.filter((m) => m.role === "user").pop(); @@ -7858,11 +7684,11 @@ export async function POST(request: Request) { }, ); } catch (saveError) { - console.error("[Chat API] ❌ Failed to save Volcano Vision message to database:", saveError); - console.error("[Chat API] Message content that failed:", imageMarkdown.substring(0, 300)); + chatApiLogger.error("[Chat API] ❌ Failed to save Volcano Vision message to database:", saveError); + chatApiLogger.error("[Chat API] Message content that failed:", imageMarkdown.substring(0, 300)); } } catch (error) { - console.error("[Chat API] Volcano Vision generation error:", error); + chatApiLogger.error("[Chat API] Volcano Vision generation error:", error); const errorMessageId = generateUUID(); writeAssistantTextChunk( writer, @@ -7898,7 +7724,7 @@ export async function POST(request: Request) { ], }); } catch (saveError) { - console.error("[Chat API] Failed to save error message:", saveError); + chatApiLogger.error("[Chat API] Failed to save error message:", saveError); } } finally { stopKeepalive?.(); @@ -7922,7 +7748,7 @@ export async function POST(request: Request) { | "runway" | "krea" | "bltcy-video"; - console.log(`[Chat API] Using ${currentVideoProvider} video generation`); + chatApiLogger.info(`[Chat API] Using ${currentVideoProvider} video generation`); const videoGenerationStream = createUIMessageStream({ execute: async ({ writer }) => { @@ -7969,7 +7795,7 @@ export async function POST(request: Request) { // 千问/FAL 视频直接使用原始 URL,不转换为 base64 const modelMessages = convertToModelMessages(messagesForVideo); - console.log(`[Chat API] ${currentVideoProvider} messages prepared, count:`, modelMessages.length); + chatApiLogger.info(`[Chat API] ${currentVideoProvider} messages prepared, count:`, modelMessages.length); let videoMarkdown = "视频生成失败"; let tempVideoUrl = ""; @@ -8070,10 +7896,7 @@ export async function POST(request: Request) { tempVideoUrl = extractVideoUrlFromText(videoMarkdown) || ""; } - console.log( - `[Chat API] ${currentVideoProvider} video generated, length:`, - videoMarkdown.length - ); + chatApiLogger.info(`[Chat API] ${currentVideoProvider} video generated, length:`, videoMarkdown.length); // 生成一个统一的消息 ID const messageId = generateUUID(); @@ -8114,13 +7937,10 @@ export async function POST(request: Request) { taskId: storyboardTaskId, messageId, }).catch((taskAttachError) => { - console.warn( - "[Chat API] Failed to attach storyboard task with message:", - taskAttachError - ); + chatApiLogger.warn("[Chat API] Failed to attach storyboard task with message:", taskAttachError); }); } - console.log(`[Chat API] ✅ ${currentVideoProvider} video message saved successfully!`); + chatApiLogger.info(`[Chat API] ✅ ${currentVideoProvider} video message saved successfully!`); if ((videoMetadata as any)?.storyboard?.enabled) { try { @@ -8146,10 +7966,7 @@ export async function POST(request: Request) { : undefined, }); } catch (storyboardMemoryPersistError) { - console.warn( - "[Chat API] Failed to persist storyboard memory after assistant response:", - storyboardMemoryPersistError - ); + chatApiLogger.warn("[Chat API] Failed to persist storyboard memory after assistant response:", storyboardMemoryPersistError); } } else { try { @@ -8176,10 +7993,7 @@ export async function POST(request: Request) { temporaryVideoUrl: tempVideoUrl || undefined, }); } catch (videoWorkflowPersistError) { - console.warn( - "[Chat API] Failed to persist native video workflow state:", - videoWorkflowPersistError, - ); + chatApiLogger.warn("[Chat API] Failed to persist native video workflow state:", videoWorkflowPersistError); } } const shouldConsumeVideoPoints = @@ -8209,10 +8023,10 @@ export async function POST(request: Request) { }); } } catch (saveError) { - console.error(`[Chat API] ❌ Failed to save ${currentVideoProvider} video message:`, saveError); + chatApiLogger.error(`[Chat API] ❌ Failed to save ${currentVideoProvider} video message:`, saveError); } } catch (error) { - console.error(`[Chat API] ${currentVideoProvider} video generation error:`, error); + chatApiLogger.error(`[Chat API] ${currentVideoProvider} video generation error:`, error); const errorMessageId = generateUUID(); const errorText = "视频生成失败,请稍后重试"; writer.write({ @@ -8259,10 +8073,7 @@ export async function POST(request: Request) { error: error instanceof Error ? error.message : String(error), }); } catch (videoFailurePersistError) { - console.warn( - "[Chat API] Failed to persist native video failure state:", - videoFailurePersistError, - ); + chatApiLogger.warn("[Chat API] Failed to persist native video failure state:", videoFailurePersistError); } } }, @@ -8356,11 +8167,11 @@ export async function POST(request: Request) { tools.generateVideo = generateVideo({ dataStream }); activeTools.push("generateVideo"); } else if (enabledTools.includes("generateVideo") && shouldRunAgentConversation) { - console.log("[Smart Auto Mode] 🚫 generateVideo tool disabled (manual video mode not selected)"); + chatApiLogger.info("[Smart Auto Mode] 🚫 generateVideo tool disabled (manual video mode not selected)"); } - console.log("[Chat API] Calling streamText with model:", (languageModel as any).modelId, (languageModel as any).provider); // 调试日志 - console.log("[Chat API] Provider type:", (languageModel as any).provider); // 调试日志 + chatApiLogger.info("[Chat API] Calling streamText with model:", (languageModel as any).modelId, (languageModel as any).provider); // 调试日志 + chatApiLogger.info("[Chat API] Provider type:", (languageModel as any).provider); // 调试日志 // 转换消息,对于 Gemini 和千问视频将图片 URL 转换为 base64 const convertedMessages = await convertMessagesWithImages( @@ -8379,12 +8190,12 @@ export async function POST(request: Request) { loggerPrefix: "[Chat API] Stream text vision inline", } ); - console.log("[Chat API] Messages converted, count:", convertedMessages.length); // 调试日志 + chatApiLogger.info("[Chat API] Messages converted, count:", convertedMessages.length); // 调试日志 // 🆕 检测是否是视频模型 const providerType = (languageModel as any).provider; const effectiveProviderType = resolvedProviderType || providerType; - console.log("[Chat API] Provider type for tool detection:", { + chatApiLogger.info("[Chat API] Provider type for tool detection:", { runtime: providerType, resolved: resolvedProviderType, effective: effectiveProviderType, @@ -8397,11 +8208,11 @@ export async function POST(request: Request) { resolvedModelSupportsImageGen && providerType === "openai.chat" && !isVolcanoVideoModel; - console.log("[Chat API] Is volcano video model:", isVolcanoVideoModel); + chatApiLogger.info("[Chat API] Is volcano video model:", isVolcanoVideoModel); // 🆕 处理 OpenAI 兼容的生图模型输出(防止返回 data:image;base64 原文) if (isOpenAICompatImageModel) { - console.log("[Chat API] Using generateText for OpenAI-compatible image model"); + chatApiLogger.info("[Chat API] Using generateText for OpenAI-compatible image model"); const configuredFallbacks = [ currentModelConfig?.fallbackModelId1, currentModelConfig?.fallbackModelId2, @@ -8413,10 +8224,7 @@ export async function POST(request: Request) { currentModelKey: actualModelId, configuredFallbackIds: configuredFallbacks, }); - console.log( - "[Chat API] OpenAI-compatible fallback candidates:", - fallbackCandidates.map((candidate) => `${candidate.model.displayName}(${candidate.provider.type})`) - ); + chatApiLogger.info("[Chat API] OpenAI-compatible fallback candidates:", fallbackCandidates.map((candidate) => `${candidate.model.displayName}(${candidate.provider.type})`)); const lastUserMessage = uiMessagesForModel.filter((m) => m.role === "user").pop(); let messagesForCrossProvider = lastUserMessage ? [lastUserMessage] : uiMessagesForModel; @@ -8475,14 +8283,12 @@ export async function POST(request: Request) { try { normalizedText = await tryGenerateWithOpenAICompatModel(languageModel); } catch (primaryError) { - console.error("[Chat API] OpenAI-compatible primary model failed:", primaryError); + chatApiLogger.error("[Chat API] OpenAI-compatible primary model failed:", primaryError); let fallbackSuccess = false; for (const candidate of fallbackCandidates) { try { - console.log( - `[Chat API] 🔄 OpenAI-compatible fallback model: ${candidate.model.displayName} (${candidate.provider.type})` - ); + chatApiLogger.info(`[Chat API] 🔄 OpenAI-compatible fallback model: ${candidate.model.displayName} (${candidate.provider.type})`); const shouldUseOpenAICompatFallback = candidate.sameProvider && !IMAGE_FAILOVER_PROVIDER_ALLOWLIST.has(String(candidate.provider?.type || "")); @@ -8496,9 +8302,7 @@ export async function POST(request: Request) { fallbackRuntimeModelId ); if (!fallbackLanguageModel) { - console.log( - `[Chat API] Skip unavailable OpenAI-compatible fallback model: ${fallbackRuntimeModelId}` - ); + chatApiLogger.info(`[Chat API] Skip unavailable OpenAI-compatible fallback model: ${fallbackRuntimeModelId}`); continue; } normalizedText = await tryGenerateWithOpenAICompatModel(fallbackLanguageModel); @@ -8518,19 +8322,14 @@ export async function POST(request: Request) { usedModelId = fallbackResult.usedModelId; } fallbackSuccess = true; - console.log( - `[Chat API] ✅ OpenAI-compatible fallback model ${candidate.model.displayName} succeeded!` - ); + chatApiLogger.info(`[Chat API] ✅ OpenAI-compatible fallback model ${candidate.model.displayName} succeeded!`); break; } catch (fallbackError) { const fallbackErrorMessage = normalizeFailoverErrorMessage(fallbackError); if (shouldCooldownImageFallbackModel(fallbackErrorMessage)) { setImageFallbackModelCooldown(candidate.model.id, fallbackErrorMessage); } - console.error( - `[Chat API] ❌ OpenAI-compatible fallback model ${candidate.model.displayName} (${candidate.provider.type}) failed:`, - fallbackError - ); + chatApiLogger.error(`[Chat API] ❌ OpenAI-compatible fallback model ${candidate.model.displayName} (${candidate.provider.type}) failed:`, fallbackError); } } @@ -8556,18 +8355,14 @@ export async function POST(request: Request) { for (const candidate of crossProviderCandidates) { try { - console.log( - `[Chat API] 🔁 OpenAI-compatible cross-provider failover: ${candidate.model.displayName} (${candidate.provider.type})` - ); + chatApiLogger.info(`[Chat API] 🔁 OpenAI-compatible cross-provider failover: ${candidate.model.displayName} (${candidate.provider.type})`); if ( candidate.provider.type === "fal-image" && isFalGptImage2EditModelId( String(candidate.model?.modelId || candidate.model?.id || "") ) ) { - console.log( - `[Chat API] Skip async-only failover candidate: ${candidate.model.displayName}` - ); + chatApiLogger.info(`[Chat API] Skip async-only failover candidate: ${candidate.model.displayName}`); continue; } @@ -8576,9 +8371,7 @@ export async function POST(request: Request) { !candidateLanguageModel || typeof (candidateLanguageModel as any).doGenerate !== "function" ) { - console.log( - `[Chat API] Skip cross-provider candidate without doGenerate: ${candidate.model.id}` - ); + chatApiLogger.info(`[Chat API] Skip cross-provider candidate without doGenerate: ${candidate.model.id}`); continue; } @@ -8631,19 +8424,14 @@ export async function POST(request: Request) { normalizedText = candidateResult.text || "图片生成失败"; usedModelId = candidate.model.modelId; fallbackSuccess = true; - console.log( - `[Chat API] ✅ OpenAI-compatible cross-provider failover succeeded: ${candidate.model.displayName} (${candidate.provider.type})` - ); + chatApiLogger.info(`[Chat API] ✅ OpenAI-compatible cross-provider failover succeeded: ${candidate.model.displayName} (${candidate.provider.type})`); break; } catch (crossError) { const crossErrorMessage = normalizeFailoverErrorMessage(crossError); if (shouldCooldownImageFallbackModel(crossErrorMessage)) { setImageFallbackModelCooldown(candidate.model.id, crossErrorMessage); } - console.error( - `[Chat API] ❌ OpenAI-compatible cross-provider failover failed: ${candidate.model.displayName} (${candidate.provider.type})`, - crossError - ); + chatApiLogger.error(`[Chat API] ❌ OpenAI-compatible cross-provider failover failed: ${candidate.model.displayName} (${candidate.provider.type})`, crossError); } } } @@ -8754,7 +8542,7 @@ export async function POST(request: Request) { ); return; } catch (error) { - console.error("[Chat API] OpenAI-compatible image model generation error:", error); + chatApiLogger.error("[Chat API] OpenAI-compatible image model generation error:", error); const errorMessageId = generateUUID(); const errorText = @@ -8812,7 +8600,7 @@ export async function POST(request: Request) { // 🎬 视频模型使用专门的生成流程 if (isVolcanoVideoModel) { - console.log("[Chat API] Using video generation API"); + chatApiLogger.info("[Chat API] Using video generation API"); // 导入视频生成函数 const { doGenerateStream } = await import("@/lib/ai/providers/volcano-video"); @@ -8879,7 +8667,7 @@ export async function POST(request: Request) { if (lastUserMessage) { // 🆕 处理 parts 数组(AI SDK v4 格式) if ((lastUserMessage as any).parts && Array.isArray((lastUserMessage as any).parts)) { - console.log("[Chat API] Video input parts:", (lastUserMessage as any).parts.length); + chatApiLogger.info("[Chat API] Video input parts:", (lastUserMessage as any).parts.length); for (const part of (lastUserMessage as any).parts) { if (part.type === "text" && part.text) { @@ -8915,7 +8703,7 @@ export async function POST(request: Request) { } } - console.log("[Chat API] Video input extracted:", { + chatApiLogger.info("[Chat API] Video input extracted:", { promptLength: prompt.trim().length, imageCount: imageUrls.length, imageRefs: imageUrls.slice(0, 4).map(summarizeImageRef), @@ -8935,7 +8723,7 @@ export async function POST(request: Request) { }; try { - console.log("[Chat API] Video generation params:", { + chatApiLogger.info("[Chat API] Video generation params:", { promptLength: prompt.trim().length, imageCount: imageUrls.length, videoParams: effectiveVideoParams, @@ -8957,25 +8745,21 @@ export async function POST(request: Request) { selectedModelProvider?.type === "volcano-video" ) { const videoSubModels = await getSubModelsByParentModelId(finalModelId); - console.log(`[Chat API] Video: Found ${videoSubModels.length} sub-models for master model`); + chatApiLogger.info(`[Chat API] Video: Found ${videoSubModels.length} sub-models for master model`); if (videoSubModels.length > 0) { const matchedModel = selectBestVideoSubModelForMode(videoSubModels as any, videoMode); if (matchedModel) { videoModelId = matchedModel.model.id; - console.log( - `[Chat API] Video: Selected sub-model ${matchedModel.model.displayName} (${matchedModel.model.modelId}) for mode ${videoMode}` - ); + chatApiLogger.info(`[Chat API] Video: Selected sub-model ${matchedModel.model.displayName} (${matchedModel.model.modelId}) for mode ${videoMode}`); } else { - console.log( - `[Chat API] Video: No compatible sub-model found for mode ${videoMode}, keep current model` - ); + chatApiLogger.info(`[Chat API] Video: No compatible sub-model found for mode ${videoMode}, keep current model`); } } } - console.log("[Chat API] Getting model config for:", videoModelId); + chatApiLogger.info("[Chat API] Getting model config for:", videoModelId); const aiModelData = await getAiModelById({ id: videoModelId }); if (!aiModelData) { throw new Error("视频模型配置未找到"); @@ -9003,9 +8787,7 @@ export async function POST(request: Request) { } if (fallbackModel) { - console.warn( - `[Chat API] Video: Model ${aiModelData.modelId} does not support ${videoMode}, fallback to ${fallbackModel.model.modelId}` - ); + chatApiLogger.warn(`[Chat API] Video: Model ${aiModelData.modelId} does not support ${videoMode}, fallback to ${fallbackModel.model.modelId}`); videoModelId = fallbackModel.model.id; } } @@ -9020,17 +8802,14 @@ export async function POST(request: Request) { // 如果是子模型,获取父模型的 Provider 配置 let providerModelData = finalVideoModelData; if (finalVideoModelData.isSubModel && finalVideoModelData.parentModelId) { - console.log( - "[Chat API] This is a sub-model, getting parent model config:", - finalVideoModelData.parentModelId - ); + chatApiLogger.info("[Chat API] This is a sub-model, getting parent model config:", finalVideoModelData.parentModelId); const parentModel = await getAiModelById({ id: finalVideoModelData.parentModelId }); if (parentModel) { providerModelData = parentModel; } } - console.log("[Chat API] Getting provider config for:", providerModelData.providerId); + chatApiLogger.info("[Chat API] Getting provider config for:", providerModelData.providerId); const providerData = await getAiProviderById({ id: providerModelData.providerId }); if (!providerData) { throw new Error("Provider 配置未找到"); @@ -9063,7 +8842,7 @@ export async function POST(request: Request) { videoOptions.referenceImages = imageUrls; } - console.log("[Chat API] Video options constructed:", { + chatApiLogger.info("[Chat API] Video options constructed:", { model: videoOptions.model, mode: videoOptions.mode, resolution: videoOptions.resolution, @@ -9113,10 +8892,7 @@ export async function POST(request: Request) { status: "running", }); } catch (videoWorkflowStartError) { - console.warn( - "[Chat API] Failed to persist stream video start state:", - videoWorkflowStartError, - ); + chatApiLogger.warn("[Chat API] Failed to persist stream video start state:", videoWorkflowStartError); } dataStream.write({ @@ -9131,26 +8907,24 @@ export async function POST(request: Request) { const apiKey = providerData.apiKey; const baseURL = providerData.baseUrl || "https://ark.cn-beijing.volces.com/api/v3"; - console.log("[Chat API] Provider configured:", { baseURL, hasApiKey: !!apiKey }); + chatApiLogger.info("[Chat API] Provider configured:", { baseURL, hasApiKey: !!apiKey }); // 调用视频生成流 - console.log("[Chat API] Starting video generation stream..."); + chatApiLogger.info("[Chat API] Starting video generation stream..."); const videoStream = doGenerateStream(apiKey, baseURL, videoOptions); // 收集所有流输出 - console.log("[Chat API] Processing video stream..."); + chatApiLogger.info("[Chat API] Processing video stream..."); let fullText = ""; let chunkCount = 0; for await (const chunk of videoStream) { chunkCount++; fullText += chunk; - console.log(`[Chat API] Received chunk ${chunkCount}, length: ${chunk.length}`); + chatApiLogger.info(`[Chat API] Received chunk ${chunkCount}, length: ${chunk.length}`); } - console.log( - `[Chat API] Video stream completed. Total chunks: ${chunkCount}, total text length: ${fullText.length}` - ); + chatApiLogger.info(`[Chat API] Video stream completed. Total chunks: ${chunkCount}, total text length: ${fullText.length}`); // 提取流中的元数据并清理输出文案 const metadataMatch = fullText.match(//s); @@ -9159,7 +8933,7 @@ export async function POST(request: Request) { try { streamMetadata = JSON.parse(metadataMatch[1]); } catch (parseError) { - console.warn("[Chat API] Failed to parse VIDEO_METADATA from stream", parseError); + chatApiLogger.warn("[Chat API] Failed to parse VIDEO_METADATA from stream", parseError); } } const cleanedText = fullText @@ -9212,10 +8986,7 @@ export async function POST(request: Request) { temporaryVideoUrl: temporaryVideoUrl || undefined, }); } catch (videoWorkflowCompletedError) { - console.warn( - "[Chat API] Failed to persist stream video completion state:", - videoWorkflowCompletedError, - ); + chatApiLogger.warn("[Chat API] Failed to persist stream video completion state:", videoWorkflowCompletedError); } await consumeGeneratedVideoPoints({ userId: session.user.id, @@ -9236,9 +9007,9 @@ export async function POST(request: Request) { }), }); - console.log("[Chat API] ✅ Video message updated successfully"); + chatApiLogger.info("[Chat API] ✅ Video message updated successfully"); if (temporaryVideoUrl) { - console.log("[Chat API] 📹 临时视频URL已保存,开始异步归档到S3"); + chatApiLogger.info("[Chat API] 📹 临时视频URL已保存,开始异步归档到S3"); scheduleVideoArchive({ chatId: id, messageId: videoMessageId, @@ -9252,11 +9023,11 @@ export async function POST(request: Request) { }); } - console.log("[Chat API] Video generation finished successfully"); + chatApiLogger.info("[Chat API] Video generation finished successfully"); return; } catch (error: any) { - console.error("[Chat API] ❌ Video generation error:", error); - console.error("[Chat API] Error stack:", error.stack); + chatApiLogger.error("[Chat API] ❌ Video generation error:", error); + chatApiLogger.error("[Chat API] Error stack:", error.stack); const errorMessage = `❌ 视频生成失败:${error.message}\n\n请检查配置或稍后重试。`; const failedMetadata = { @@ -9295,10 +9066,7 @@ export async function POST(request: Request) { error: error?.message || "未知错误", }); } catch (videoWorkflowFailedError) { - console.warn( - "[Chat API] Failed to persist stream video failure state:", - videoWorkflowFailedError, - ); + chatApiLogger.warn("[Chat API] Failed to persist stream video failure state:", videoWorkflowFailedError); } dataStream.write({ @@ -9311,7 +9079,7 @@ export async function POST(request: Request) { }), }); } catch (updateError) { - console.error("[Chat API] Failed to update placeholder video message:", updateError); + chatApiLogger.error("[Chat API] Failed to update placeholder video message:", updateError); const fallbackMessageId = generateUUID(); dataStream.write({ type: "data-appendMessage", @@ -9357,10 +9125,7 @@ export async function POST(request: Request) { error: error?.message || "未知错误", }); } catch (videoWorkflowFailedError) { - console.warn( - "[Chat API] Failed to persist fallback stream video failure state:", - videoWorkflowFailedError, - ); + chatApiLogger.warn("[Chat API] Failed to persist fallback stream video failure state:", videoWorkflowFailedError); } } @@ -9428,7 +9193,7 @@ export async function POST(request: Request) { } as AppUsage; dataStream.write({ type: "data-usage", data: finalMergedUsage }); } catch (err) { - console.warn("TokenLens enrichment failed", err); + chatApiLogger.warn("TokenLens enrichment failed", err); finalMergedUsage = usage; dataStream.write({ type: "data-usage", data: finalMergedUsage }); } @@ -9437,7 +9202,7 @@ export async function POST(request: Request) { result.consumeStream({ onError: (error) => { - console.error("[Chat API] streamText consume error:", error); + chatApiLogger.error("[Chat API] streamText consume error:", error); if (activeRuntimeModelDescriptor?.providerKey) { recordProviderHealthFailure({ providerKey: activeRuntimeModelDescriptor.providerKey, @@ -9452,7 +9217,7 @@ export async function POST(request: Request) { result.toUIMessageStream({ sendReasoning: true, onError: (error) => { - console.error("[Chat API] streamText ui stream error:", error); + chatApiLogger.error("[Chat API] streamText ui stream error:", error); if (activeRuntimeModelDescriptor?.providerKey) { recordProviderHealthFailure({ providerKey: activeRuntimeModelDescriptor.providerKey, @@ -9563,10 +9328,7 @@ export async function POST(request: Request) { temporaryVideoUrl: tempVideoUrl, }); } catch (videoWorkflowCompletedError) { - console.warn( - "[Chat API] Failed to persist streamed assistant video state:", - videoWorkflowCompletedError, - ); + chatApiLogger.warn("[Chat API] Failed to persist streamed assistant video state:", videoWorkflowCompletedError); } scheduleVideoArchive({ @@ -9588,7 +9350,7 @@ export async function POST(request: Request) { context: finalMergedUsage, }); } catch (err) { - console.warn("Unable to persist last usage for chat", id, err); + chatApiLogger.warn("Unable to persist last usage for chat", id, err); } } }, @@ -9619,7 +9381,7 @@ export async function POST(request: Request) { if (isRateLimitError(error)) { const detailMessage = getRequestErrorMessage(error); - console.warn("[Chat API] Upstream rate limited request:", { + chatApiLogger.warn("[Chat API] Upstream rate limited request:", { vercelId, error: detailMessage, }); diff --git a/scripts/check-log-hygiene.mjs b/scripts/check-log-hygiene.mjs index 3d7a2cac2..65e8b5b2c 100644 --- a/scripts/check-log-hygiene.mjs +++ b/scripts/check-log-hygiene.mjs @@ -3,6 +3,19 @@ import { readFileSync } from "node:fs"; const files = [ + "app/(chat)/api/chat/route.ts", + "app/(chat)/api/chat/_lib/agent-output.ts", + "app/(chat)/api/chat/_lib/agent-scene-workflow.ts", + "app/(chat)/api/chat/_lib/billing.ts", + "app/(chat)/api/chat/_lib/detail-replacement.ts", + "app/(chat)/api/chat/_lib/errors.ts", + "app/(chat)/api/chat/_lib/image-failover.ts", + "app/(chat)/api/chat/_lib/image-media.ts", + "app/(chat)/api/chat/_lib/message-preparation.ts", + "app/(chat)/api/chat/_lib/model-resolver.ts", + "app/(chat)/api/chat/_lib/persistence.ts", + "app/(chat)/api/chat/_lib/stream.ts", + "app/(chat)/api/chat/_lib/video-models.ts", "lib/storage/service.ts", "app/(chat)/api/files/upload/route.ts", "app/(auth)/login/page.tsx",