💄 feat(playground): Enhance the fade-in animation for the chat
This commit is contained in:
@@ -315,6 +315,7 @@ function _MarkdownContent(props) {
|
||||
content,
|
||||
className,
|
||||
animated = false,
|
||||
previousContentLength = 0,
|
||||
} = props;
|
||||
|
||||
const escapedContent = useMemo(() => {
|
||||
@@ -336,10 +337,10 @@ function _MarkdownContent(props) {
|
||||
],
|
||||
];
|
||||
if (animated) {
|
||||
base.push(rehypeSplitWordsIntoSpans);
|
||||
base.push([rehypeSplitWordsIntoSpans, { previousContentLength }]);
|
||||
}
|
||||
return base;
|
||||
}, [animated]);
|
||||
}, [animated, previousContentLength]);
|
||||
|
||||
return (
|
||||
<ReactMarkdown
|
||||
@@ -463,6 +464,7 @@ export function MarkdownRenderer(props) {
|
||||
className,
|
||||
style,
|
||||
animated = false,
|
||||
previousContentLength = 0,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
@@ -498,7 +500,12 @@ export function MarkdownRenderer(props) {
|
||||
正在渲染...
|
||||
</div>
|
||||
) : (
|
||||
<MarkdownContent content={content} className={className} animated={animated} />
|
||||
<MarkdownContent
|
||||
content={content}
|
||||
className={className}
|
||||
animated={animated}
|
||||
previousContentLength={previousContentLength}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
import {
|
||||
Typography,
|
||||
TextArea,
|
||||
@@ -25,6 +25,8 @@ const MessageContent = ({
|
||||
onEditValueChange
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const previousContentLengthRef = useRef(0);
|
||||
const lastContentRef = useRef('');
|
||||
|
||||
if (message.status === 'error') {
|
||||
let errorText;
|
||||
@@ -128,6 +130,14 @@ const MessageContent = ({
|
||||
const finalExtractedThinkingContent = currentExtractedThinkingContent;
|
||||
const finalDisplayableFinalContent = currentDisplayableFinalContent;
|
||||
|
||||
// 流式状态结束时重置
|
||||
useEffect(() => {
|
||||
if (!isThinkingStatus) {
|
||||
previousContentLengthRef.current = 0;
|
||||
lastContentRef.current = '';
|
||||
}
|
||||
}, [isThinkingStatus]);
|
||||
|
||||
if (message.role === 'assistant' &&
|
||||
isThinkingStatus &&
|
||||
!finalExtractedThinkingContent &&
|
||||
@@ -243,6 +253,7 @@ const MessageContent = ({
|
||||
content={textContent.text}
|
||||
className={message.role === 'user' ? 'user-message' : ''}
|
||||
animated={false}
|
||||
previousContentLength={0}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -253,12 +264,27 @@ const MessageContent = ({
|
||||
if (typeof message.content === 'string') {
|
||||
if (message.role === 'assistant') {
|
||||
if (finalDisplayableFinalContent && finalDisplayableFinalContent.trim() !== '') {
|
||||
// 获取上一次的内容长度
|
||||
let prevLength = 0;
|
||||
if (isThinkingStatus && lastContentRef.current) {
|
||||
// 只有当前内容包含上一次内容时,才使用上一次的长度
|
||||
if (finalDisplayableFinalContent.startsWith(lastContentRef.current)) {
|
||||
prevLength = lastContentRef.current.length;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新最后内容的引用
|
||||
if (isThinkingStatus) {
|
||||
lastContentRef.current = finalDisplayableFinalContent;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="prose prose-xs sm:prose-sm prose-gray max-w-none overflow-x-auto text-xs sm:text-sm">
|
||||
<MarkdownRenderer
|
||||
content={finalDisplayableFinalContent}
|
||||
className=""
|
||||
animated={isThinkingStatus}
|
||||
previousContentLength={prevLength}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -270,6 +296,7 @@ const MessageContent = ({
|
||||
content={message.content}
|
||||
className={message.role === 'user' ? 'user-message' : ''}
|
||||
animated={false}
|
||||
previousContentLength={0}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -13,6 +13,7 @@ const ThinkingContent = ({
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const scrollRef = useRef(null);
|
||||
const lastContentRef = useRef('');
|
||||
|
||||
if (!finalExtractedThinkingContent) return null;
|
||||
|
||||
@@ -25,6 +26,26 @@ const ThinkingContent = ({
|
||||
}
|
||||
}, [finalExtractedThinkingContent, message.isReasoningExpanded]);
|
||||
|
||||
// 流式状态结束时重置
|
||||
useEffect(() => {
|
||||
if (!isThinkingStatus) {
|
||||
lastContentRef.current = '';
|
||||
}
|
||||
}, [isThinkingStatus]);
|
||||
|
||||
// 获取上一次的内容长度
|
||||
let prevLength = 0;
|
||||
if (isThinkingStatus && lastContentRef.current) {
|
||||
if (finalExtractedThinkingContent.startsWith(lastContentRef.current)) {
|
||||
prevLength = lastContentRef.current.length;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新最后内容的引用
|
||||
if (isThinkingStatus) {
|
||||
lastContentRef.current = finalExtractedThinkingContent;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rounded-xl sm:rounded-2xl mb-2 sm:mb-4 overflow-hidden shadow-sm backdrop-blur-sm">
|
||||
<div
|
||||
@@ -93,6 +114,7 @@ const ThinkingContent = ({
|
||||
content={finalExtractedThinkingContent}
|
||||
className=""
|
||||
animated={isThinkingStatus}
|
||||
previousContentLength={prevLength}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user