fix: 使用特殊标记保持占位图显示
问题:对话消息发送后占位图消失 解决: 1. 后端在对话消息末尾加上 <!-- GENERATING_IMAGE --> 标记 2. 前端检测到此标记时继续显示占位图 3. 渲染时清理掉这个标记(用户看不到) 4. 数据库保存时不带标记(纯对话) 流程: 1. 用户发送请求 2. AI回复对话(带标记)+ 占位图继续显示 3. 图片生成后显示 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
920fb5aa95
commit
ddada59db1
@ -987,21 +987,26 @@ export async function POST(request: Request) {
|
||||
execute: async ({ writer }) => {
|
||||
try {
|
||||
// 🆕 如果是智能模式且有对话回复,先发送对话消息让用户看到
|
||||
if (smartAutoFriendlyMessage) {
|
||||
// 在消息末尾加上特殊标记,告诉前端"图片正在生成中"
|
||||
const messageWithMarker = smartAutoFriendlyMessage
|
||||
? `${smartAutoFriendlyMessage}\n\n<!-- GENERATING_IMAGE -->`
|
||||
: 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<!-- GENERATING_IMAGE -->`
|
||||
: 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
|
||||
|
||||
@ -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("<!-- GENERATING_IMAGE -->")
|
||||
);
|
||||
|
||||
// 对于图片模型,检查是否有图片内容(包含 ![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({
|
||||
<div className="mx-auto flex min-w-0 max-w-4xl flex-col gap-4 px-2 py-4 md:gap-6 md:px-4">
|
||||
{messages.length === 0 && <Greeting />}
|
||||
|
||||
{messages.map((message, index) => (
|
||||
{messages.map((message, index) => {
|
||||
// 🆕 清理消息中的内部标记(如 <!-- GENERATING_IMAGE -->)
|
||||
const cleanedMessage = {
|
||||
...message,
|
||||
parts: message.parts?.map((part: any) => {
|
||||
if (part.type === "text" && part.text) {
|
||||
return {
|
||||
...part,
|
||||
text: part.text.replace(/\n*<!-- GENERATING_IMAGE -->\n*/g, "")
|
||||
};
|
||||
}
|
||||
return part;
|
||||
})
|
||||
};
|
||||
|
||||
return (
|
||||
<PreviewMessage
|
||||
chatId={chatId}
|
||||
isLoading={
|
||||
@ -275,7 +300,7 @@ function PureMessages({
|
||||
}
|
||||
isReadonly={isReadonly}
|
||||
key={message.id}
|
||||
message={message}
|
||||
message={cleanedMessage}
|
||||
regenerate={regenerate}
|
||||
sendMessage={sendMessage}
|
||||
requiresScrollPadding={
|
||||
@ -298,7 +323,8 @@ function PureMessages({
|
||||
isProcessingExtend={isProcessingExtend}
|
||||
isProcessingAngleEdit={isProcessingAngleEdit}
|
||||
/>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
|
||||
{/* 等待动画:根据模型类型显示不同的加载效果 */}
|
||||
{/* 🆕 支持恢复的生成状态(用户离开再返回) */}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user