:lightning: further chat performance tweaks
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useRef, useEffect, useState } from 'react'
|
||||
import { useRef, useEffect, useState, memo } from 'react'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import { useEditorStore } from '../../store/editorStore'
|
||||
import { ChatMessageItem } from './ChatMessageItem'
|
||||
import { ChatInput } from './ChatInput'
|
||||
@@ -7,6 +8,35 @@ import { parseAnnotationsFromAIResponse } from '../../utils/annotationParser'
|
||||
import type { Attachment, TextAnnotation } from '../../types/editor'
|
||||
import './Chat.css'
|
||||
|
||||
const StreamingBubble = memo(function StreamingBubble({ scrollContainerRef }: { scrollContainerRef: React.RefObject<HTMLDivElement> }) {
|
||||
const streamingContent = useEditorStore(s => s.streamingContent)
|
||||
const isAILoading = useEditorStore(s => s.isAILoading)
|
||||
const rafRef = useRef<number | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAILoading) return
|
||||
if (rafRef.current !== null) return
|
||||
rafRef.current = requestAnimationFrame(() => {
|
||||
rafRef.current = null
|
||||
const el = scrollContainerRef.current
|
||||
if (el) el.scrollTop = el.scrollHeight
|
||||
})
|
||||
}, [streamingContent, isAILoading, scrollContainerRef])
|
||||
|
||||
if (!isAILoading) return null
|
||||
return (
|
||||
<div className="chat-message chat-message-assistant">
|
||||
<div className="chat-message-label">Editor AI</div>
|
||||
<div className="chat-message-content">
|
||||
{streamingContent
|
||||
? <span>{streamingContent}</span>
|
||||
: <div className="chat-typing"><span /><span /><span /></div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
function formatSessionTime(createdAt: number): string {
|
||||
const date = new Date(createdAt)
|
||||
const now = new Date()
|
||||
@@ -34,7 +64,6 @@ export function ChatPanel(): JSX.Element {
|
||||
addUserMessage,
|
||||
finalizeAssistantMessage,
|
||||
setStreamingContent,
|
||||
streamingContent,
|
||||
setAILoading,
|
||||
setAIError,
|
||||
setAnnotations,
|
||||
@@ -43,7 +72,29 @@ export function ChatPanel(): JSX.Element {
|
||||
setActiveSession,
|
||||
rightPanelTab,
|
||||
setRightPanelTab,
|
||||
} = useEditorStore()
|
||||
} = useEditorStore(useShallow(s => ({
|
||||
chatHistory: s.chatHistory,
|
||||
chatSessionsByFile: s.chatSessionsByFile,
|
||||
activeSessionIdByFile: s.activeSessionIdByFile,
|
||||
isAILoading: s.isAILoading,
|
||||
aiError: s.aiError,
|
||||
activeFileContent: s.activeFileContent,
|
||||
activeFilePath: s.activeFilePath,
|
||||
analysisMode: s.analysisMode,
|
||||
annotations: s.annotations,
|
||||
annotationsByFile: s.annotationsByFile,
|
||||
addUserMessage: s.addUserMessage,
|
||||
finalizeAssistantMessage: s.finalizeAssistantMessage,
|
||||
setStreamingContent: s.setStreamingContent,
|
||||
setAILoading: s.setAILoading,
|
||||
setAIError: s.setAIError,
|
||||
setAnnotations: s.setAnnotations,
|
||||
linkAnnotationsToMessage: s.linkAnnotationsToMessage,
|
||||
newChat: s.newChat,
|
||||
setActiveSession: s.setActiveSession,
|
||||
rightPanelTab: s.rightPanelTab,
|
||||
setRightPanelTab: s.setRightPanelTab,
|
||||
})))
|
||||
|
||||
const tab = rightPanelTab
|
||||
const setTab = setRightPanelTab
|
||||
@@ -138,7 +189,7 @@ export function ChatPanel(): JSX.Element {
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-scroll to bottom when new content arrives
|
||||
// Auto-scroll to bottom when a new chat message is added
|
||||
useEffect(() => {
|
||||
if (scrollRafRef.current !== null) return
|
||||
scrollRafRef.current = requestAnimationFrame(() => {
|
||||
@@ -146,7 +197,7 @@ export function ChatPanel(): JSX.Element {
|
||||
const el = scrollRef.current
|
||||
if (el) el.scrollTop = el.scrollHeight
|
||||
})
|
||||
}, [chatHistory, streamingContent])
|
||||
}, [chatHistory])
|
||||
|
||||
const hasFile = Boolean(activeFilePath)
|
||||
const allAnnotationsForFile: TextAnnotation[] =
|
||||
@@ -252,17 +303,7 @@ export function ChatPanel(): JSX.Element {
|
||||
/>
|
||||
)
|
||||
})}
|
||||
{isAILoading && (
|
||||
<div className="chat-message chat-message-assistant">
|
||||
<div className="chat-message-label">Editor AI</div>
|
||||
<div className="chat-message-content">
|
||||
{streamingContent
|
||||
? <span>{streamingContent}</span>
|
||||
: <div className="chat-typing"><span /><span /><span /></div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<StreamingBubble scrollContainerRef={scrollRef} />
|
||||
{aiError && (
|
||||
<div className="chat-error">{aiError}</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user