From ddada59db12fcd9d3f5f3c0fadbe44ac3c9b21a7 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 1 Feb 2026 02:12:08 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BD=BF=E7=94=A8=E7=89=B9=E6=AE=8A?= =?UTF-8?q?=E6=A0=87=E8=AE=B0=E4=BF=9D=E6=8C=81=E5=8D=A0=E4=BD=8D=E5=9B=BE?= =?UTF-8?q?=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题:对话消息发送后占位图消失 解决: 1. 后端在对话消息末尾加上 标记 2. 前端检测到此标记时继续显示占位图 3. 渲染时清理掉这个标记(用户看不到) 4. 数据库保存时不带标记(纯对话) 流程: 1. 用户发送请求 2. AI回复对话(带标记)+ 占位图继续显示 3. 图片生成后显示 Co-authored-by: Cursor --- app/(chat)/api/chat/route.ts | 32 ++++++++++++++++++-------------- components/messages.tsx | 32 +++++++++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/app/(chat)/api/chat/route.ts b/app/(chat)/api/chat/route.ts index ece237cd6..4bde3500f 100644 --- a/app/(chat)/api/chat/route.ts +++ b/app/(chat)/api/chat/route.ts @@ -987,21 +987,26 @@ export async function POST(request: Request) { execute: async ({ writer }) => { try { // 🆕 如果是智能模式且有对话回复,先发送对话消息让用户看到 - if (smartAutoFriendlyMessage) { + // 在消息末尾加上特殊标记,告诉前端"图片正在生成中" + const messageWithMarker = smartAutoFriendlyMessage + ? `${smartAutoFriendlyMessage}\n\n` + : null; + + if (messageWithMarker) { const chatMessageId = generateUUID(); console.log("[Chat API] 💬 Sending conversational reply first:", smartAutoFriendlyMessage); - // 发送对话消息 + // 发送带标记的对话消息 writer.write({ type: "data-appendMessage", data: JSON.stringify({ id: chatMessageId, role: "assistant", - parts: [{ type: "text", text: smartAutoFriendlyMessage }], + parts: [{ type: "text", text: messageWithMarker }], }), }); - // 保存对话消息到数据库 + // 保存对话消息到数据库(不带标记,纯对话) await saveMessages({ messages: [ { @@ -1014,9 +1019,6 @@ export async function POST(request: Request) { }, ], }); - - // 🆕 给前端一点时间渲染第一条消息 - await new Promise(resolve => setTimeout(resolve, 500)); } // 只传递最后一条用户消息 @@ -1204,21 +1206,26 @@ export async function POST(request: Request) { execute: async ({ writer }) => { try { // 🆕 如果是智能模式且有对话回复,先发送对话消息让用户看到 - if (smartAutoFriendlyMessage) { + // 在消息末尾加上特殊标记,告诉前端"图片正在生成中" + const messageWithMarker = smartAutoFriendlyMessage + ? `${smartAutoFriendlyMessage}\n\n` + : null; + + if (messageWithMarker) { const chatMessageId = generateUUID(); console.log("[Chat API] 💬 Volcano: Sending conversational reply first:", smartAutoFriendlyMessage); - // 发送对话消息 + // 发送带标记的对话消息 writer.write({ type: "data-appendMessage", data: JSON.stringify({ id: chatMessageId, role: "assistant", - parts: [{ type: "text", text: smartAutoFriendlyMessage }], + parts: [{ type: "text", text: messageWithMarker }], }), }); - // 保存对话消息到数据库 + // 保存对话消息到数据库(不带标记,纯对话) await saveMessages({ messages: [ { @@ -1231,9 +1238,6 @@ export async function POST(request: Request) { }, ], }); - - // 🆕 给前端一点时间渲染第一条消息 - await new Promise(resolve => setTimeout(resolve, 500)); } // 转换消息,火山引擎支持 URL 和 base64 diff --git a/components/messages.tsx b/components/messages.tsx index 2262d1515..dc3208742 100644 --- a/components/messages.tsx +++ b/components/messages.tsx @@ -158,6 +158,11 @@ function PureMessages({ const isAutoModeWithImage = selectedModelId === "auto" && lastUserMessage?.parts?.some((p: any) => p.type === "file" || p.type === "image"); + // 🆕 检查是否有"图片正在生成"的标记 + const isGeneratingImage = lastMessage?.parts?.some( + (part: any) => part.type === "text" && part.text?.includes("") + ); + // 对于图片模型,检查是否有图片内容(包含 ![thumb| 或 ![thumb||| 标记) // 🆕 在智能自动模式下,需要检查最后一条用户消息之后的所有 assistant 消息 let hasImageContent = false; @@ -173,6 +178,11 @@ function PureMessages({ part.text.includes("![Generated Image") )) ); + + // 🆕 如果有"正在生成"标记,强制认为没有图片内容(继续显示占位图) + if (isGeneratingImage) { + hasImageContent = false; + } } else { // 普通模式:只检查最后一条消息 hasImageContent = lastMessage?.parts && lastMessage.parts.some( @@ -267,7 +277,22 @@ function PureMessages({
{messages.length === 0 && } - {messages.map((message, index) => ( + {messages.map((message, index) => { + // 🆕 清理消息中的内部标记(如 ) + const cleanedMessage = { + ...message, + parts: message.parts?.map((part: any) => { + if (part.type === "text" && part.text) { + return { + ...part, + text: part.text.replace(/\n*\n*/g, "") + }; + } + return part; + }) + }; + + return ( - ))} + ); + })} {/* 等待动画:根据模型类型显示不同的加载效果 */} {/* 🆕 支持恢复的生成状态(用户离开再返回) */}