fix(web/chat): gate assistant animation to live stream state
This commit is contained in:
parent
8260f743cd
commit
432d8adbbf
2 changed files with 12 additions and 9 deletions
|
|
@ -12,20 +12,18 @@ const STREAM_FRAME_MS = 18
|
||||||
const STREAM_STEPS = 60
|
const STREAM_STEPS = 60
|
||||||
|
|
||||||
interface AssistantMessageProps {
|
interface AssistantMessageProps {
|
||||||
messageId?: string
|
|
||||||
content: string
|
content: string
|
||||||
timestamp?: string | number
|
timestamp?: string | number
|
||||||
|
isStreaming?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AssistantMessage({
|
export function AssistantMessage({
|
||||||
messageId = "",
|
|
||||||
content,
|
content,
|
||||||
timestamp = "",
|
timestamp = "",
|
||||||
|
isStreaming = false,
|
||||||
}: AssistantMessageProps) {
|
}: AssistantMessageProps) {
|
||||||
const [isCopied, setIsCopied] = useState(false)
|
const [isCopied, setIsCopied] = useState(false)
|
||||||
const [displayedContent, setDisplayedContent] = useState(
|
const [displayedContent, setDisplayedContent] = useState(content)
|
||||||
messageId.startsWith("hist-") ? content : "",
|
|
||||||
)
|
|
||||||
const timerRef = useRef<number | null>(null)
|
const timerRef = useRef<number | null>(null)
|
||||||
const displayedRef = useRef(displayedContent)
|
const displayedRef = useRef(displayedContent)
|
||||||
const formattedTimestamp =
|
const formattedTimestamp =
|
||||||
|
|
@ -50,13 +48,12 @@ export function AssistantMessage({
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const isHistoryMessage = messageId.startsWith("hist-")
|
|
||||||
if (timerRef.current !== null) {
|
if (timerRef.current !== null) {
|
||||||
window.clearInterval(timerRef.current)
|
window.clearInterval(timerRef.current)
|
||||||
timerRef.current = null
|
timerRef.current = null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isHistoryMessage || content.trim() === "") {
|
if (!isStreaming || content.trim() === "") {
|
||||||
queueMicrotask(() => syncDisplayedContent(content))
|
queueMicrotask(() => syncDisplayedContent(content))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -86,7 +83,7 @@ export function AssistantMessage({
|
||||||
timerRef.current = null
|
timerRef.current = null
|
||||||
}
|
}
|
||||||
}, STREAM_FRAME_MS)
|
}, STREAM_FRAME_MS)
|
||||||
}, [content, messageId])
|
}, [content, isStreaming])
|
||||||
|
|
||||||
const handleCopy = () => {
|
const handleCopy = () => {
|
||||||
navigator.clipboard.writeText(content).then(() => {
|
navigator.clipboard.writeText(content).then(() => {
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,12 @@ export function ChatPage() {
|
||||||
setIsAtBottom(scrollHeight - scrollTop <= clientHeight + 10)
|
setIsAtBottom(scrollHeight - scrollTop <= clientHeight + 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const liveAssistantMessageId = isTyping
|
||||||
|
? [...messages]
|
||||||
|
.reverse()
|
||||||
|
.find((message) => message.role === "assistant")?.id
|
||||||
|
: undefined
|
||||||
|
|
||||||
const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
|
const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
|
||||||
syncScrollState(e.currentTarget)
|
syncScrollState(e.currentTarget)
|
||||||
}
|
}
|
||||||
|
|
@ -150,9 +156,9 @@ export function ChatPage() {
|
||||||
<div key={msg.id} className="flex w-full">
|
<div key={msg.id} className="flex w-full">
|
||||||
{msg.role === "assistant" ? (
|
{msg.role === "assistant" ? (
|
||||||
<AssistantMessage
|
<AssistantMessage
|
||||||
messageId={msg.id}
|
|
||||||
content={msg.content}
|
content={msg.content}
|
||||||
timestamp={msg.timestamp}
|
timestamp={msg.timestamp}
|
||||||
|
isStreaming={msg.id === liveAssistantMessageId}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<UserMessage content={msg.content} />
|
<UserMessage content={msg.content} />
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue