🛠️ fix(chat): enhance message generation stop behavior
This commit improves the handling of message generation interruption in the playground chat interface, ensuring both content and thinking process are properly preserved. Key changes: - Preserve existing content when stopping message generation - Handle both direct reasoningContent and <think> tag formats - Extract and merge thinking process from unclosed <think> tags - Maintain consistent thinking chain format with separators - Auto-collapse reasoning panel after stopping for cleaner UI Technical details: - Modified onStopGenerator to properly handle SSE connection closure - Added regex pattern to extract thinking content from <think> tags - Implemented proper state management for incomplete messages - Ensured all content types are preserved in their respective fields This fix resolves the issue where thinking chain content would be lost when stopping message generation mid-stream.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
||||
import React, { useCallback, useContext, useEffect, useState, useRef } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { UserContext } from '../../context/User/index.js';
|
||||
import {
|
||||
@@ -100,6 +100,7 @@ const Playground = () => {
|
||||
const [groups, setGroups] = useState([]);
|
||||
const [showSettings, setShowSettings] = useState(true);
|
||||
const [styleState, styleDispatch] = useContext(StyleContext);
|
||||
const sseSourceRef = useRef(null);
|
||||
|
||||
const handleInputChange = (name, value) => {
|
||||
setInputs((inputs) => ({ ...inputs, [name]: value }));
|
||||
@@ -210,9 +211,13 @@ const Playground = () => {
|
||||
payload: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
// 保存 source 引用以便后续停止生成
|
||||
sseSourceRef.current = source;
|
||||
|
||||
source.addEventListener('message', (e) => {
|
||||
if (e.data === '[DONE]') {
|
||||
source.close();
|
||||
sseSourceRef.current = null;
|
||||
completeMessage();
|
||||
return;
|
||||
}
|
||||
@@ -240,6 +245,7 @@ const Playground = () => {
|
||||
const errorMessage = e.data || t('请求发生错误');
|
||||
streamMessageUpdate(errorMessage, 'content');
|
||||
completeMessage('error');
|
||||
sseSourceRef.current = null;
|
||||
source.close();
|
||||
});
|
||||
|
||||
@@ -352,6 +358,51 @@ const Playground = () => {
|
||||
});
|
||||
}, [setMessage]);
|
||||
|
||||
const onStopGenerator = useCallback(() => {
|
||||
if (sseSourceRef.current) {
|
||||
sseSourceRef.current.close();
|
||||
sseSourceRef.current = null;
|
||||
setMessage((prevMessage) => {
|
||||
const lastMessage = prevMessage[prevMessage.length - 1];
|
||||
if (lastMessage.status === 'loading' || lastMessage.status === 'incomplete') {
|
||||
let content = lastMessage.content || '';
|
||||
let reasoningContent = lastMessage.reasoningContent || '';
|
||||
|
||||
// 处理 <think> 标签格式的思维链
|
||||
if (content.includes('<think>')) {
|
||||
const thinkTagRegex = /<think>([\s\S]*?)(?:<\/think>|$)/g;
|
||||
let thoughts = [];
|
||||
let replyParts = [];
|
||||
let lastIndex = 0;
|
||||
let match;
|
||||
|
||||
while ((match = thinkTagRegex.exec(content)) !== null) {
|
||||
replyParts.push(content.substring(lastIndex, match.index));
|
||||
thoughts.push(match[1]);
|
||||
lastIndex = match.index + match[0].length;
|
||||
}
|
||||
replyParts.push(content.substring(lastIndex));
|
||||
|
||||
// 更新内容和思维链
|
||||
content = replyParts.join('').trim();
|
||||
if (thoughts.length > 0) {
|
||||
reasoningContent = thoughts.join('\n\n---\n\n');
|
||||
}
|
||||
}
|
||||
|
||||
return [...prevMessage.slice(0, -1), {
|
||||
...lastMessage,
|
||||
status: 'complete',
|
||||
reasoningContent: reasoningContent,
|
||||
content: content,
|
||||
isReasoningExpanded: false // 停止时折叠思维链面板
|
||||
}];
|
||||
}
|
||||
return prevMessage;
|
||||
});
|
||||
}
|
||||
}, [setMessage]);
|
||||
|
||||
const SettingsToggle = () => {
|
||||
if (!styleState.isMobile) return null;
|
||||
return (
|
||||
@@ -664,6 +715,8 @@ const Playground = () => {
|
||||
chats={message}
|
||||
onMessageSend={onMessageSend}
|
||||
showClearContext
|
||||
showStopGenerate
|
||||
onStopGenerator={onStopGenerator}
|
||||
onClear={() => {
|
||||
setMessage([]);
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user