🐛 fix(playground): ensure proper streaming updates & safeguard message handling
Summary This commit addresses two critical issues affecting the real-time chat experience in the Playground: 1. Optimized re-rendering of reasoning content • Added `reasoningContent` to the comparison function of `OptimizedMessageContent` (`web/src/components/playground/OptimizedComponents.js`). • Ensures the component re-renders while reasoning text streams, resolving the bug where only the first characters (“好,”) were shown until the stream finished. 2. Defensive checks for SSE message updates • Added early-return guards in `streamMessageUpdate` (`web/src/hooks/useApiRequest.js`). • Skips updates when `lastMessage` is undefined or the last message isn’t from the assistant, preventing `TypeError: Cannot read properties of undefined (reading 'status')` during rapid SSE responses. Impact • Real-time reasoning content now appears progressively, enhancing user feedback. • Eliminates runtime crashes caused by undefined message references, improving overall stability.
This commit is contained in:
@@ -12,6 +12,7 @@ export const OptimizedMessageContent = React.memo(MessageContent, (prevProps, ne
|
||||
prevProps.message.content === nextProps.message.content &&
|
||||
prevProps.message.status === nextProps.message.status &&
|
||||
prevProps.message.role === nextProps.message.role &&
|
||||
prevProps.message.reasoningContent === nextProps.message.reasoningContent &&
|
||||
prevProps.message.isReasoningExpanded === nextProps.message.isReasoningExpanded &&
|
||||
prevProps.isEditing === nextProps.isEditing &&
|
||||
prevProps.editValue === nextProps.editValue &&
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { Typography } from '@douyinfe/semi-ui';
|
||||
import MarkdownRenderer from '../common/markdown/MarkdownRenderer';
|
||||
import { ChevronRight, ChevronUp, Brain, Loader2 } from 'lucide-react';
|
||||
@@ -12,12 +12,19 @@ const ThinkingContent = ({
|
||||
onToggleReasoningExpansion
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const scrollRef = useRef(null);
|
||||
|
||||
if (!finalExtractedThinkingContent) return null;
|
||||
|
||||
const isThinkingStatus = message.status === 'loading' || message.status === 'incomplete';
|
||||
const headerText = (isThinkingStatus && !message.isThinkingComplete) ? t('思考中...') : t('思考过程');
|
||||
|
||||
useEffect(() => {
|
||||
if (scrollRef.current) {
|
||||
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
|
||||
}
|
||||
}, [finalExtractedThinkingContent, message.isReasoningExpanded]);
|
||||
|
||||
return (
|
||||
<div className="rounded-xl sm:rounded-2xl mb-2 sm:mb-4 overflow-hidden shadow-sm backdrop-blur-sm">
|
||||
<div
|
||||
@@ -73,6 +80,7 @@ const ThinkingContent = ({
|
||||
{message.isReasoningExpanded && (
|
||||
<div className="p-3 sm:p-5 pt-2 sm:pt-4">
|
||||
<div
|
||||
ref={scrollRef}
|
||||
className="bg-white/70 backdrop-blur-sm rounded-lg sm:rounded-xl p-2 shadow-inner overflow-x-auto overflow-y-auto thinking-content-scroll"
|
||||
style={{
|
||||
maxHeight: '200px',
|
||||
|
||||
@@ -38,6 +38,8 @@ export const useApiRequest = (
|
||||
const streamMessageUpdate = useCallback((textChunk, type) => {
|
||||
setMessage(prevMessage => {
|
||||
const lastMessage = prevMessage[prevMessage.length - 1];
|
||||
if (!lastMessage) return prevMessage;
|
||||
if (lastMessage.role !== 'assistant') return prevMessage;
|
||||
if (lastMessage.status === MESSAGE_STATUS.ERROR) {
|
||||
return prevMessage;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user