fix: 修复智能自动模式占位图提前消失问题
问题: - appendMessage 放入队列延迟处理导致 GENERATING_IMAGE 标记无法被及时检测 - status 变成 ready 时占位图消失,但图片还在生成中 解决方案: - 添加 isGeneratingImageFlag 状态来跟踪图片生成进度 - 在收到包含 GENERATING_IMAGE 标记的消息时立即设置标志 - 在收到包含图片的消息时清除标志 - 将标志传递给 Messages 组件用于占位图显示判断 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
ed4c2fe8cd
commit
c6180e8610
@ -69,6 +69,12 @@ export function Chat({
|
||||
// 🆕 标记是否已经尝试刷新过(避免无限刷新)
|
||||
const hasTriedRefreshRef = useRef(false);
|
||||
|
||||
// 🆕 存储待处理的 appendMessage(避免与 useChat 内部状态冲突)
|
||||
const pendingAppendMessagesRef = useRef<any[]>([]);
|
||||
|
||||
// 🆕 跟踪是否正在生成图片(用于占位图显示)
|
||||
const [isGeneratingImageFlag, setIsGeneratingImageFlag] = useState(false);
|
||||
|
||||
// 🆕 当检测到恢复的 pendingGeneration 时,刷新页面获取最新消息
|
||||
useEffect(() => {
|
||||
if (pendingGeneration && !hasTriedRefreshRef.current) {
|
||||
@ -280,48 +286,44 @@ export function Chat({
|
||||
setUsage(dataPart.data);
|
||||
}
|
||||
|
||||
// 处理后端返回的自定义消息(用于图片/视频生成的非流式响应)
|
||||
// 🆕 处理后端返回的自定义消息(用于图片/视频生成的非流式响应)
|
||||
// 注意:不要在这里调用 setMessages,因为会与 useChat 内部状态冲突
|
||||
// 改为存储到待处理队列,在 onFinish 时统一处理
|
||||
if (dataPart.type === "data-appendMessage") {
|
||||
try {
|
||||
// dataPart.data 是 JSON 字符串
|
||||
const messageData = typeof dataPart.data === 'string'
|
||||
? JSON.parse(dataPart.data)
|
||||
: dataPart.data;
|
||||
|
||||
console.log("[Chat] Received appendMessage:", messageData);
|
||||
console.log("[Chat] Received appendMessage (queued):", messageData);
|
||||
|
||||
// 🆕 检测是否包含 GENERATING_IMAGE 标记
|
||||
const hasGeneratingMarker = messageData.parts?.some(
|
||||
(part: any) => part.type === "text" && part.text?.includes("<!-- GENERATING_IMAGE -->")
|
||||
);
|
||||
if (hasGeneratingMarker) {
|
||||
console.log("[Chat] 🖼️ Detected GENERATING_IMAGE marker, showing placeholder");
|
||||
setIsGeneratingImageFlag(true);
|
||||
}
|
||||
|
||||
// 🆕 检测是否包含图片(生成完成)
|
||||
const hasImage = messageData.parts?.some(
|
||||
(part: any) => part.type === "text" && part.text && (
|
||||
part.text.includes("![thumb|") ||
|
||||
part.text.includes("![thumb|||") ||
|
||||
part.text.includes("![Generated Image")
|
||||
)
|
||||
);
|
||||
if (hasImage) {
|
||||
console.log("[Chat] 🎉 Image generated, hiding placeholder");
|
||||
setIsGeneratingImageFlag(false);
|
||||
}
|
||||
|
||||
// 存储到待处理队列
|
||||
pendingAppendMessagesRef.current.push(messageData);
|
||||
|
||||
// 🆕 收到消息,清除持久化状态
|
||||
completeGeneration();
|
||||
|
||||
setMessages((prevMessages) => {
|
||||
console.log("[Chat] 📋 setMessages 调用前:", prevMessages.map(m => ({
|
||||
id: m.id?.substring(0, 8),
|
||||
role: m.role
|
||||
})));
|
||||
|
||||
if (prevMessages.some(m => m.id === messageData.id)) {
|
||||
console.log("[Chat] ⚠️ 消息已存在,跳过");
|
||||
return prevMessages;
|
||||
}
|
||||
|
||||
// 构造 ChatMessage 对象
|
||||
// 注意:这里需要确保符合 ChatMessage 类型定义
|
||||
const newMessage: any = {
|
||||
id: messageData.id,
|
||||
role: messageData.role,
|
||||
content: messageData.parts?.[0]?.text || "",
|
||||
createdAt: new Date(),
|
||||
parts: messageData.parts || [],
|
||||
attachments: [],
|
||||
};
|
||||
|
||||
const newMessages = [...prevMessages, newMessage];
|
||||
console.log("[Chat] 📋 setMessages 调用后:", newMessages.map(m => ({
|
||||
id: m.id?.substring(0, 8),
|
||||
role: m.role
|
||||
})));
|
||||
return newMessages;
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("[Chat] Failed to parse data-appendMessage:", e);
|
||||
}
|
||||
@ -331,6 +333,35 @@ export function Chat({
|
||||
mutate(unstable_serialize(getChatHistoryPaginationKey));
|
||||
// 🆕 生成完成,清除持久化状态
|
||||
completeGeneration();
|
||||
|
||||
// 🆕 处理待处理的 appendMessage(在流结束后安全地添加)
|
||||
if (pendingAppendMessagesRef.current.length > 0) {
|
||||
console.log("[Chat] Processing pending appendMessages:", pendingAppendMessagesRef.current.length);
|
||||
const pendingMessages = [...pendingAppendMessagesRef.current];
|
||||
pendingAppendMessagesRef.current = [];
|
||||
|
||||
// 使用 setTimeout 延迟处理,确保 useChat 内部状态已稳定
|
||||
setTimeout(() => {
|
||||
setMessages((prevMessages) => {
|
||||
let newMessages = [...prevMessages];
|
||||
for (const messageData of pendingMessages) {
|
||||
if (!newMessages.some(m => m.id === messageData.id)) {
|
||||
const newMessage: any = {
|
||||
id: messageData.id,
|
||||
role: messageData.role,
|
||||
content: messageData.parts?.[0]?.text || "",
|
||||
createdAt: new Date(),
|
||||
parts: messageData.parts || [],
|
||||
attachments: [],
|
||||
};
|
||||
newMessages = [...newMessages, newMessage];
|
||||
}
|
||||
}
|
||||
console.log("[Chat] After processing pending messages:", newMessages.length);
|
||||
return newMessages;
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
if (error instanceof ChatSDKError) {
|
||||
@ -1066,6 +1097,7 @@ export function Chat({
|
||||
isProcessingAngleEdit={isProcessingAngleEdit}
|
||||
pendingGeneration={pendingGeneration}
|
||||
imageCount={imageParams?.imageCount || 1}
|
||||
isGeneratingImageFlag={isGeneratingImageFlag}
|
||||
/>
|
||||
|
||||
<div className="sticky bottom-0 z-1 mx-auto w-full max-w-4xl bg-background px-2 pb-3 md:px-4 md:pb-4">
|
||||
|
||||
@ -48,6 +48,7 @@ type MessagesProps = {
|
||||
isProcessingAngleEdit?: boolean;
|
||||
pendingGeneration?: PendingGeneration | null; // 🆕 持久化的生成状态
|
||||
imageCount?: number; // 🆕 用户选择的图片数量
|
||||
isGeneratingImageFlag?: boolean; // 🆕 正在生成图片的标志(来自 Chat 组件)
|
||||
};
|
||||
|
||||
function PureMessages({
|
||||
@ -72,6 +73,7 @@ function PureMessages({
|
||||
isProcessingAngleEdit = false,
|
||||
pendingGeneration,
|
||||
imageCount = 1,
|
||||
isGeneratingImageFlag = false,
|
||||
}: MessagesProps) {
|
||||
const {
|
||||
containerRef: messagesContainerRef,
|
||||
@ -226,8 +228,9 @@ function PureMessages({
|
||||
setShowThinkingWithDelay(false);
|
||||
}, delayTime);
|
||||
return () => clearTimeout(timer);
|
||||
} else if (isGeneratingImage) {
|
||||
} else if (isGeneratingImage || isGeneratingImageFlag) {
|
||||
// 收到 GENERATING_IMAGE 标记(对话消息已发送),继续显示占位图等待图片
|
||||
// 使用 isGeneratingImageFlag 来解决消息延迟添加时标记检测不到的问题
|
||||
setShowThinkingWithDelay(true);
|
||||
} else if (status === "streaming" || status === "submitted") {
|
||||
// 正在处理中(分析意图或流式传输),显示占位图
|
||||
@ -251,7 +254,7 @@ function PureMessages({
|
||||
setShowThinkingWithDelay(false);
|
||||
}
|
||||
}
|
||||
}, [status, messages, isGeminiModel, isQianwenVideoModel, isVolcanoVisionModel, isVideoModel, isAlibabaImageModel, selectedModelId]);
|
||||
}, [status, messages, isGeminiModel, isQianwenVideoModel, isVolcanoVisionModel, isVideoModel, isAlibabaImageModel, selectedModelId, isGeneratingImageFlag]);
|
||||
|
||||
// 🆕 监听新消息添加,当用户发送带图片的消息或添加加载消息时,强制滚动到底部
|
||||
const prevMessagesLengthRef = useRef(messages.length);
|
||||
@ -411,8 +414,8 @@ function PureMessages({
|
||||
|
||||
// 🆕 智能自动模式占位图
|
||||
if (isAutoMode && userMessageHasImage) {
|
||||
// 如果已经收到了 GENERATING_IMAGE 标记,显示生图占位图
|
||||
if (hasGeneratingMarker) {
|
||||
// 如果已经收到了 GENERATING_IMAGE 标记 或 isGeneratingImageFlag 为 true,显示生图占位图
|
||||
if (hasGeneratingMarker || isGeneratingImageFlag) {
|
||||
return <ImageGenerationLoading imageCount={imageCount} maxImages={6} providerType="alibaba-image" modelName="智能处理" />;
|
||||
}
|
||||
// 否则显示思考动画
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user