:lightning: optimize chat streaming
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useMemo, memo } from 'react'
|
||||
import { marked } from 'marked'
|
||||
import DOMPurify from 'dompurify'
|
||||
import type { ChatMessage, TextAnnotation } from '../../types/editor'
|
||||
@@ -30,7 +30,7 @@ interface Props {
|
||||
linkedAnnotations?: TextAnnotation[]
|
||||
}
|
||||
|
||||
export function ChatMessageItem({ message, linkedAnnotations }: Props): JSX.Element {
|
||||
function ChatMessageItemInner({ message, linkedAnnotations }: Props): JSX.Element {
|
||||
const { activeFilePath, markSaved } = useEditorStore()
|
||||
|
||||
const html = useMemo(() => {
|
||||
@@ -123,3 +123,13 @@ export function ChatMessageItem({ message, linkedAnnotations }: Props): JSX.Elem
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function areEqual(prev: Props, next: Props): boolean {
|
||||
if (prev.message.content !== next.message.content) return false
|
||||
if (prev.message.id !== next.message.id) return false
|
||||
const prevIds = prev.linkedAnnotations?.map(a => a.id).join(',') ?? ''
|
||||
const nextIds = next.linkedAnnotations?.map(a => a.id).join(',') ?? ''
|
||||
return prevIds === nextIds
|
||||
}
|
||||
|
||||
export const ChatMessageItem = memo(ChatMessageItemInner, areEqual)
|
||||
|
||||
@@ -50,6 +50,7 @@ export function ChatPanel(): JSX.Element {
|
||||
const [pendingAttachmentCount, setPendingAttachmentCount] = useState(0)
|
||||
const [feedbackNotice, setFeedbackNotice] = useState<string | null>(null)
|
||||
const scrollRef = useRef<HTMLDivElement>(null)
|
||||
const scrollRafRef = useRef<number | null>(null)
|
||||
const prevAnnotationCountRef = useRef(annotations.length)
|
||||
|
||||
// Collapse history when switching files
|
||||
@@ -119,12 +120,14 @@ export function ChatPanel(): JSX.Element {
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-scroll to bottom when new content arrives
|
||||
// Auto-scroll to bottom when new content arrives (coalesced to one scroll per animation frame)
|
||||
useEffect(() => {
|
||||
const el = scrollRef.current
|
||||
if (el) {
|
||||
el.scrollTop = el.scrollHeight
|
||||
}
|
||||
if (scrollRafRef.current !== null) return
|
||||
scrollRafRef.current = requestAnimationFrame(() => {
|
||||
scrollRafRef.current = null
|
||||
const el = scrollRef.current
|
||||
if (el) el.scrollTop = el.scrollHeight
|
||||
})
|
||||
}, [chatHistory])
|
||||
|
||||
const hasFile = Boolean(activeFilePath)
|
||||
|
||||
Reference in New Issue
Block a user