/** * Phase 2: 重构后的智能问答页面 * 支持:通用对话、全文阅读、逐篇精读三种模式 */ import { useState, useEffect } from 'react' import { message as antdMessage } from 'antd' import chatApi, { type GeneralMessage } from '../api/chatApi' import { documentSelectionApi, documentApi } from '../api/knowledgeBaseApi' import { useChatMode } from '../hooks/useChatMode' import { useDeepReadState } from '../hooks/useDeepReadState' import { ModeSelector } from '../components/chat/ModeSelector' import { FullTextMode } from '../components/chat/FullTextMode' import { DeepReadMode } from '../components/chat/DeepReadMode' import { DocumentSelector } from '../components/chat/DocumentSelector' import MessageList from '../components/chat/MessageList' import MessageInput from '../components/chat/MessageInput' import ModelSelector, { type ModelType } from '../components/chat/ModelSelector' import { useKnowledgeBaseStore } from '../stores/useKnowledgeBaseStore' import { ChatMessage } from '../types/chat' import type { Document } from '../types/index' const ChatPage = () => { const { knowledgeBases, fetchKnowledgeBases } = useKnowledgeBaseStore() // 聊天模式状态 const { state: modeState, setBaseMode, selectKnowledgeBase, setKnowledgeBaseMode, loadFullTextMode, loadDeepReadMode, } = useChatMode() // 通用对话状态 const [generalMessages, setGeneralMessages] = useState([]) const [selectedModel, setSelectedModel] = useState('deepseek-v3') const [sending, setSending] = useState(false) const [streamingContent, setStreamingContent] = useState('') const [currentConversationId, setCurrentConversationId] = useState() // 逐篇精读状态 const [deepReadState, setDeepReadState] = useState | null>(null) const [showDocSelector, setShowDocSelector] = useState(false) const [allDocuments, setAllDocuments] = useState([]) // 加载知识库列表 useEffect(() => { fetchKnowledgeBases() }, [fetchKnowledgeBases]) // 当选择知识库时,加载文档选择结果(全文阅读模式) useEffect(() => { if (modeState.selectedKbId && modeState.kbMode === 'full_text') { loadFullTextData() } }, [modeState.selectedKbId, modeState.kbMode]) // 当切换到逐篇精读模式时,显示文献选择器 useEffect(() => { if (modeState.selectedKbId && modeState.kbMode === 'deep_read' && !modeState.deepReadState) { loadDocumentsForSelection() } }, [modeState.selectedKbId, modeState.kbMode]) // 加载全文阅读模式数据 const loadFullTextData = async () => { if (!modeState.selectedKbId) return try { const result = await documentSelectionApi.getSelection(modeState.selectedKbId) loadFullTextMode({ loadedDocs: result.selectedDocuments || [], totalFiles: result.limits.maxFiles, selectedFiles: result.selection.selectedCount, totalTokens: result.limits.maxTokens, usedTokens: result.selection.selectedTokens, availableTokens: result.selection.availableTokens, reason: result.selection.reason, }) } catch (error) { console.error('Failed to load document selection:', error) antdMessage.error('加载文档选择失败') } } // 加载文献列表供选择 const loadDocumentsForSelection = async () => { if (!modeState.selectedKbId) return try { const result = await documentSelectionApi.getSelection(modeState.selectedKbId) setAllDocuments(result.selectedDocuments || []) setShowDocSelector(true) } catch (error) { console.error('Failed to load documents:', error) antdMessage.error('加载文献列表失败') } } // 确认文献选择(逐篇精读模式) const handleConfirmDocSelection = (selectedDocs: Document[]) => { const deepRead = useDeepReadState(selectedDocs) setDeepReadState(deepRead as any) loadDeepReadMode({ selectedDocs, currentDocId: selectedDocs[0].id, conversationPerDoc: new Map(selectedDocs.map(doc => [doc.id, []])), totalTokens: selectedDocs.reduce((sum, doc) => sum + (doc.tokensCount || 0), 0), }) setShowDocSelector(false) } // 发送消息(通用对话) const handleSendGeneralMessage = async (content: string, knowledgeBaseIds: string[]) => { if (sending) return setSending(true) setStreamingContent('') const userMessage: GeneralMessage = { id: `temp-${Date.now()}`, conversationId: currentConversationId || 'temp', role: 'user', content, createdAt: new Date().toISOString(), } setGeneralMessages(prev => [...prev, userMessage]) try { let fullContent = '' await chatApi.sendMessageStream( { content, modelType: selectedModel, knowledgeBaseIds, conversationId: currentConversationId, }, (chunk) => { fullContent += chunk setStreamingContent(fullContent) }, (conversationId) => { if (!currentConversationId && conversationId) { setCurrentConversationId(conversationId) } const assistantMessage: GeneralMessage = { id: `temp-assistant-${Date.now()}`, conversationId: conversationId || currentConversationId || 'temp', role: 'assistant', content: fullContent, model: selectedModel, createdAt: new Date().toISOString(), } setGeneralMessages(prev => [...prev, assistantMessage]) setStreamingContent('') setSending(false) }, (error) => { console.error('Send failed:', error) antdMessage.error('发送消息失败:' + error.message) setStreamingContent('') setSending(false) } ) } catch (err) { console.error('Send message exception:', err) antdMessage.error('发送消息失败') setStreamingContent('') setSending(false) } } // 发送消息(逐篇精读模式) const handleSendDeepReadMessage = async (content: string) => { if (!deepReadState || !deepReadState.currentDoc) return setSending(true) // 添加用户消息 const userMsg: ChatMessage = { id: `temp-${Date.now()}`, role: 'user', content, timestamp: new Date(), } deepReadState.addMessage(userMsg) try { // TODO: 调用实际的API(支持documentIds参数) // 当前先使用通用API let fullContent = '' await chatApi.sendMessageStream( { content: `[当前文献: ${deepReadState.currentDoc.filename}]\n\n${content}`, modelType: selectedModel, knowledgeBaseIds: modeState.selectedKbId ? [modeState.selectedKbId] : [], }, (chunk) => { fullContent += chunk setStreamingContent(fullContent) }, () => { const assistantMsg: ChatMessage = { id: `temp-assistant-${Date.now()}`, role: 'assistant', content: fullContent, timestamp: new Date(), } deepReadState.addMessage(assistantMsg) setStreamingContent('') setSending(false) }, (error) => { console.error('Send failed:', error) antdMessage.error('发送消息失败') setStreamingContent('') setSending(false) } ) } catch (error) { console.error('Send error:', error) antdMessage.error('发送消息失败') setSending(false) } } // 渲染内容区域 const renderContent = () => { const kb = knowledgeBases.find(k => k.id === modeState.selectedKbId) const kbName = kb?.name || '未选择' // 通用对话模式 if (modeState.baseMode === 'general') { return (
{generalMessages.length === 0 && !sending ? (
💬
与AI自由对话
直接提问,或使用@知识库引用文献
) : ( )}
) } // 全文阅读模式 if (modeState.baseMode === 'knowledge_base' && modeState.kbMode === 'full_text') { if (!modeState.fullTextState) { return (
加载中...
) } return ( handleSendGeneralMessage(content, [modeState.selectedKbId!])} messages={generalMessages} loading={sending} streamingContent={streamingContent} /> ) } // 逐篇精读模式 if (modeState.baseMode === 'knowledge_base' && modeState.kbMode === 'deep_read') { if (!modeState.deepReadState || !deepReadState) { return (
请选择要精读的文献...
) } return ( ) } return null } return (
{/* 左侧模式选择器 */} {/* 主内容区 */}
{/* 顶部工具栏 */}
{/* 模型选择器 */}
{/* 内容区域 */} {renderContent()}
{/* 文献选择器弹窗 */} {showDocSelector && ( setShowDocSelector(false)} /> )}
) } export default ChatPage