fix: trigger image placeholder after analysis
Send a dedicated generation-start marker when image generation begins and stop embedding markers in assistant text.
This commit is contained in:
parent
2e6f421b6d
commit
20efbbbb53
@ -794,11 +794,9 @@ export async function POST(request: Request) {
|
||||
execute: async ({ writer }) => {
|
||||
// 🆕 如果是智能模式且有对话回复,先发送对话消息让用户看到
|
||||
// 在消息末尾加上特殊标记,告诉前端"图片正在生成中"
|
||||
const messageWithMarker = smartAutoFriendlyMessage
|
||||
? `${smartAutoFriendlyMessage}\n\n<!-- GENERATING_IMAGE -->`
|
||||
: null;
|
||||
const conversationMessage = smartAutoFriendlyMessage || null;
|
||||
|
||||
if (messageWithMarker) {
|
||||
if (conversationMessage) {
|
||||
const chatMessageId = generateUUID();
|
||||
console.log("[Chat API] 💬 Gemini: Sending conversational reply first:", smartAutoFriendlyMessage);
|
||||
|
||||
@ -808,7 +806,7 @@ export async function POST(request: Request) {
|
||||
data: JSON.stringify({
|
||||
id: chatMessageId,
|
||||
role: "assistant",
|
||||
parts: [{ type: "text", text: messageWithMarker }],
|
||||
parts: [{ type: "text", text: conversationMessage }],
|
||||
}),
|
||||
});
|
||||
|
||||
@ -859,6 +857,16 @@ export async function POST(request: Request) {
|
||||
try {
|
||||
let imageMarkdown = ""; // 初始化为空字符串
|
||||
let usedModelId = actualModelId;
|
||||
|
||||
// 🆕 图片生成真正开始时发出标记(用于前端显示占位图)
|
||||
writer.write({
|
||||
type: "data-appendMessage",
|
||||
data: JSON.stringify({
|
||||
id: generateUUID(),
|
||||
role: "assistant",
|
||||
parts: [{ type: "text", text: "<!-- IMAGE_GENERATION_START -->" }],
|
||||
}),
|
||||
});
|
||||
|
||||
try {
|
||||
// 首先尝试主模型
|
||||
@ -1109,12 +1117,9 @@ export async function POST(request: Request) {
|
||||
execute: async ({ writer }) => {
|
||||
try {
|
||||
// 🆕 如果是智能模式且有对话回复,先发送对话消息让用户看到
|
||||
// 在消息末尾加上特殊标记,告诉前端"图片正在生成中"
|
||||
const messageWithMarker = smartAutoFriendlyMessage
|
||||
? `${smartAutoFriendlyMessage}\n\n<!-- GENERATING_IMAGE -->`
|
||||
: null;
|
||||
const conversationMessage = smartAutoFriendlyMessage || null;
|
||||
|
||||
if (messageWithMarker) {
|
||||
if (conversationMessage) {
|
||||
const chatMessageId = generateUUID();
|
||||
console.log("[Chat API] 💬 Sending conversational reply first:", smartAutoFriendlyMessage);
|
||||
|
||||
@ -1124,7 +1129,7 @@ export async function POST(request: Request) {
|
||||
data: JSON.stringify({
|
||||
id: chatMessageId,
|
||||
role: "assistant",
|
||||
parts: [{ type: "text", text: messageWithMarker }],
|
||||
parts: [{ type: "text", text: conversationMessage }],
|
||||
}),
|
||||
});
|
||||
|
||||
@ -1215,6 +1220,16 @@ export async function POST(request: Request) {
|
||||
|
||||
let imageMarkdown = "";
|
||||
let usedModelId = actualModelId;
|
||||
|
||||
// 🆕 图片生成真正开始时发出标记(用于前端显示占位图)
|
||||
writer.write({
|
||||
type: "data-appendMessage",
|
||||
data: JSON.stringify({
|
||||
id: generateUUID(),
|
||||
role: "assistant",
|
||||
parts: [{ type: "text", text: "<!-- IMAGE_GENERATION_START -->" }],
|
||||
}),
|
||||
});
|
||||
|
||||
try {
|
||||
imageMarkdown = await tryGenerateImage(actualModelId, false);
|
||||
@ -1388,12 +1403,9 @@ export async function POST(request: Request) {
|
||||
execute: async ({ writer }) => {
|
||||
try {
|
||||
// 🆕 如果是智能模式且有对话回复,先发送对话消息让用户看到
|
||||
// 在消息末尾加上特殊标记,告诉前端"图片正在生成中"
|
||||
const messageWithMarker = smartAutoFriendlyMessage
|
||||
? `${smartAutoFriendlyMessage}\n\n<!-- GENERATING_IMAGE -->`
|
||||
: null;
|
||||
const conversationMessage = smartAutoFriendlyMessage || null;
|
||||
|
||||
if (messageWithMarker) {
|
||||
if (conversationMessage) {
|
||||
const chatMessageId = generateUUID();
|
||||
console.log("[Chat API] 💬 Volcano: Sending conversational reply first:", smartAutoFriendlyMessage);
|
||||
|
||||
@ -1403,7 +1415,7 @@ export async function POST(request: Request) {
|
||||
data: JSON.stringify({
|
||||
id: chatMessageId,
|
||||
role: "assistant",
|
||||
parts: [{ type: "text", text: messageWithMarker }],
|
||||
parts: [{ type: "text", text: conversationMessage }],
|
||||
}),
|
||||
});
|
||||
|
||||
@ -1443,6 +1455,16 @@ export async function POST(request: Request) {
|
||||
|
||||
let imageMarkdown = "";
|
||||
let usedModelId = actualModelId;
|
||||
|
||||
// 🆕 图片生成真正开始时发出标记(用于前端显示占位图)
|
||||
writer.write({
|
||||
type: "data-appendMessage",
|
||||
data: JSON.stringify({
|
||||
id: generateUUID(),
|
||||
role: "assistant",
|
||||
parts: [{ type: "text", text: "<!-- IMAGE_GENERATION_START -->" }],
|
||||
}),
|
||||
});
|
||||
try {
|
||||
imageMarkdown = await tryGenerateImage(actualModelId, false);
|
||||
} catch (primaryError) {
|
||||
|
||||
@ -1067,7 +1067,7 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
|
||||
const isLoading = status === 'streaming' || status === 'submitted';
|
||||
const hasGeneratingMarker = messages.some(msg =>
|
||||
msg.role === "assistant" && msg.parts?.some(
|
||||
(part: any) => part.type === "text" && part.text?.includes("<!-- GENERATING_IMAGE -->")
|
||||
(part: any) => part.type === "text" && part.text?.includes("<!-- IMAGE_GENERATION_START -->")
|
||||
)
|
||||
);
|
||||
const currentModel = allModels.find(m => m.id === selectedModelId);
|
||||
@ -1181,7 +1181,10 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
|
||||
if (part.type === 'text' && part.text) {
|
||||
return {
|
||||
...part,
|
||||
text: part.text.replace(/\n*<!-- GENERATING_IMAGE -->\n*/g, '').trim()
|
||||
text: part.text
|
||||
.replace(/\n*<!-- GENERATING_IMAGE -->\n*/g, "")
|
||||
.replace(/\n*<!-- IMAGE_GENERATION_START -->\n*/g, "")
|
||||
.trim()
|
||||
};
|
||||
}
|
||||
return part;
|
||||
|
||||
@ -308,12 +308,33 @@ export function Chat({
|
||||
|
||||
console.log("[Chat] Received appendMessage:", messageData);
|
||||
|
||||
// 🆕 检测是否包含 GENERATING_IMAGE 标记
|
||||
const hasGeneratingMarker = messageData.parts?.some(
|
||||
const hasImageGenStartMarker = messageData.parts?.some(
|
||||
(part: any) => part.type === "text" && part.text?.includes("<!-- IMAGE_GENERATION_START -->")
|
||||
);
|
||||
const hasLegacyGeneratingMarker = messageData.parts?.some(
|
||||
(part: any) => part.type === "text" && part.text?.includes("<!-- GENERATING_IMAGE -->")
|
||||
);
|
||||
if (hasGeneratingMarker) {
|
||||
console.log("[Chat] 🖼️ Detected GENERATING_IMAGE marker, will show placeholder after delay");
|
||||
const isMarkerOnlyMessage = messageData.parts?.every((part: any) => {
|
||||
if (part.type !== "text" || !part.text) return false;
|
||||
const cleanedText = part.text
|
||||
.replace(/\n*<!-- IMAGE_GENERATION_START -->\n*/g, "")
|
||||
.replace(/\n*<!-- GENERATING_IMAGE -->\n*/g, "")
|
||||
.trim();
|
||||
return cleanedText.length === 0;
|
||||
});
|
||||
|
||||
if (hasImageGenStartMarker && isMarkerOnlyMessage) {
|
||||
console.log("[Chat] 🖼️ Image generation started, show placeholder");
|
||||
if (imagePlaceholderTimerRef.current) {
|
||||
clearTimeout(imagePlaceholderTimerRef.current);
|
||||
imagePlaceholderTimerRef.current = null;
|
||||
}
|
||||
setIsGeneratingImageFlag(true);
|
||||
return; // 不渲染标记消息
|
||||
}
|
||||
|
||||
if (hasLegacyGeneratingMarker) {
|
||||
console.log("[Chat] 🖼️ Detected legacy marker, will show placeholder after delay");
|
||||
const hasDisplayText = messageData.parts?.some((part: any) => {
|
||||
if (part.type !== "text" || !part.text) return false;
|
||||
const cleanedText = part.text.replace(/\n*<!-- GENERATING_IMAGE -->\n*/g, "").trim();
|
||||
@ -323,8 +344,6 @@ export function Chat({
|
||||
console.log("[Chat] ⚠️ Marker message has no display text, skip image placeholder timer");
|
||||
return;
|
||||
}
|
||||
// 🆕 延迟显示占位图,让用户先看到 AI 的文字回复
|
||||
// 消息会立即添加到 appendedMessages 并显示,3 秒后再显示动态占位图
|
||||
if (imagePlaceholderTimerRef.current) {
|
||||
clearTimeout(imagePlaceholderTimerRef.current);
|
||||
imagePlaceholderTimerRef.current = null;
|
||||
@ -333,7 +352,7 @@ export function Chat({
|
||||
console.log("[Chat] 🖼️ Now showing placeholder after 3s delay");
|
||||
setIsGeneratingImageFlag(true);
|
||||
imagePlaceholderTimerRef.current = null;
|
||||
}, 3000); // 延迟 3 秒,让用户有时间阅读文字
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// 🆕 检测是否包含图片(生成完成)
|
||||
|
||||
@ -179,7 +179,7 @@ function PureMessages({
|
||||
// 🆕 检查是否有"图片正在生成"的标记(表示对话消息已发送,正在等待图片生成)
|
||||
const isGeneratingImage = messages.some(msg =>
|
||||
msg.role === "assistant" && msg.parts?.some(
|
||||
(part: any) => part.type === "text" && part.text?.includes("<!-- GENERATING_IMAGE -->")
|
||||
(part: any) => part.type === "text" && part.text?.includes("<!-- IMAGE_GENERATION_START -->")
|
||||
)
|
||||
);
|
||||
|
||||
@ -319,8 +319,10 @@ function PureMessages({
|
||||
const hasAssistantTextReplyWithContent = messages.some(msg =>
|
||||
msg.role === "assistant" && msg.parts?.some((part: any) => {
|
||||
if (part.type !== "text" || !part.text) return false;
|
||||
if (!part.text.includes("<!-- GENERATING_IMAGE -->")) return false;
|
||||
const cleanedText = part.text.replace(/\n*<!-- GENERATING_IMAGE -->\n*/g, "").trim();
|
||||
const cleanedText = part.text
|
||||
.replace(/\n*<!-- GENERATING_IMAGE -->\n*/g, "")
|
||||
.replace(/\n*<!-- IMAGE_GENERATION_START -->\n*/g, "")
|
||||
.trim();
|
||||
return cleanedText.length > 0;
|
||||
})
|
||||
);
|
||||
@ -418,7 +420,10 @@ function PureMessages({
|
||||
if (part.type === "text" && part.text) {
|
||||
return {
|
||||
...part,
|
||||
text: part.text.replace(/\n*<!-- GENERATING_IMAGE -->\n*/g, "").trim()
|
||||
text: part.text
|
||||
.replace(/\n*<!-- GENERATING_IMAGE -->\n*/g, "")
|
||||
.replace(/\n*<!-- IMAGE_GENERATION_START -->\n*/g, "")
|
||||
.trim()
|
||||
};
|
||||
}
|
||||
return part;
|
||||
@ -484,9 +489,14 @@ function PureMessages({
|
||||
// 恢复的待处理状态:有 pendingGeneration 且最后一条是用户消息
|
||||
// 🆕 但如果收到了 AI 回复(包含 GENERATING_IMAGE 标记),不应该再显示恢复的占位图
|
||||
const hasAssistantReply = messages.some(msg =>
|
||||
msg.role === "assistant" && msg.parts?.some(
|
||||
(part: any) => part.type === "text" && part.text?.includes("<!-- GENERATING_IMAGE -->")
|
||||
)
|
||||
msg.role === "assistant" && msg.parts?.some((part: any) => {
|
||||
if (part.type !== "text" || !part.text) return false;
|
||||
const cleanedText = part.text
|
||||
.replace(/\n*<!-- GENERATING_IMAGE -->\n*/g, "")
|
||||
.replace(/\n*<!-- IMAGE_GENERATION_START -->\n*/g, "")
|
||||
.trim();
|
||||
return cleanedText.length > 0;
|
||||
})
|
||||
);
|
||||
const hasRestoredPending = pendingGeneration && isWaitingForResponse && !hasAssistantReply;
|
||||
|
||||
@ -527,14 +537,16 @@ function PureMessages({
|
||||
// 🆕 检查是否收到了 GENERATING_IMAGE 标记(表示对话已发送,开始生图)
|
||||
const hasGeneratingMarker = messages.some(msg =>
|
||||
msg.role === "assistant" && msg.parts?.some(
|
||||
(part: any) => part.type === "text" && part.text?.includes("<!-- GENERATING_IMAGE -->")
|
||||
(part: any) => part.type === "text" && part.text?.includes("<!-- IMAGE_GENERATION_START -->")
|
||||
)
|
||||
);
|
||||
const hasAssistantTextReplyWithContent = messages.some(msg =>
|
||||
msg.role === "assistant" && msg.parts?.some((part: any) => {
|
||||
if (part.type !== "text" || !part.text) return false;
|
||||
if (!part.text.includes("<!-- GENERATING_IMAGE -->")) return false;
|
||||
const cleanedText = part.text.replace(/\n*<!-- GENERATING_IMAGE -->\n*/g, "").trim();
|
||||
const cleanedText = part.text
|
||||
.replace(/\n*<!-- GENERATING_IMAGE -->\n*/g, "")
|
||||
.replace(/\n*<!-- IMAGE_GENERATION_START -->\n*/g, "")
|
||||
.trim();
|
||||
return cleanedText.length > 0;
|
||||
})
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user