import React, { useState, useEffect, useRef } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { fetchMessages } from '../../store/chat/chat.messages.thunks'; import { resetMessages, resetSendMessageStatus, addMessage } from '../../store/chat/chat.slice'; import { showNotification } from '../../store/notification.slice'; import { createChatRecord, fetchAvailableDatasets, fetchConversationDetail } from '../../store/chat/chat.thunks'; import { fetchKnowledgeBases } from '../../store/knowledgeBase/knowledgeBase.thunks'; import SvgIcon from '../../components/SvgIcon'; import { get } from '../../services/api'; export default function ChatWindow({ chatId, knowledgeBaseId }) { const dispatch = useDispatch(); const [inputMessage, setInputMessage] = useState(''); const [loading, setLoading] = useState(false); const messagesEndRef = useRef(null); // 从 Redux store 获取消息 const messages = useSelector((state) => state.chat.messages.items); const messageStatus = useSelector((state) => state.chat.messages.status); const messageError = useSelector((state) => state.chat.messages.error); const { status: sendStatus, error: sendError } = useSelector((state) => state.chat.sendMessage); // 使用新的Redux状态结构 const knowledgeBases = useSelector((state) => state.knowledgeBase.knowledgeBases || []); const knowledgeBase = knowledgeBases.find((kb) => kb.id === knowledgeBaseId); const isLoadingKnowledgeBases = useSelector((state) => state.knowledgeBase.loading); // 获取可用数据集列表 const availableDatasets = useSelector((state) => state.chat.availableDatasets.items || []); const availableDatasetsLoading = useSelector((state) => state.chat.availableDatasets.status === 'loading'); // 获取会话详情 const conversation = useSelector((state) => state.chat.currentChat.data); const conversationStatus = useSelector((state) => state.chat.currentChat.status); const conversationError = useSelector((state) => state.chat.currentChat.error); // 获取聊天详情 useEffect(() => { if (chatId) { setLoading(true); dispatch(fetchConversationDetail(chatId)) .unwrap() .catch((error) => { // 如果是新聊天,API会返回404,此时不显示错误 if (error && error !== 'Error: Request failed with status code 404') { dispatch( showNotification({ message: `获取聊天详情失败: ${error || '未知错误'}`, type: 'danger', }) ); } }) .finally(() => { setLoading(false); }); } // 组件卸载时清空消息 return () => { dispatch(resetMessages()); }; }, [chatId, dispatch]); // 新会话自动添加欢迎消息 useEffect(() => { // 如果是新聊天且没有任何消息,添加一条系统欢迎消息 if (chatId && messages.length === 0 && !loading && messageStatus !== 'loading') { const selectedKb = knowledgeBase || availableDatasets.find((ds) => ds.id === knowledgeBaseId) || { name: '知识库' }; dispatch( addMessage({ id: 'welcome-' + Date.now(), role: 'assistant', content: `欢迎使用${selectedKb.name}。您可以向我提问任何相关问题。`, created_at: new Date().toISOString(), }) ); } }, [chatId, messages.length, loading, messageStatus, knowledgeBase, knowledgeBaseId, availableDatasets, dispatch]); // 监听发送消息状态 useEffect(() => { if (sendStatus === 'failed' && sendError) { dispatch( showNotification({ message: `发送失败: ${sendError}`, type: 'danger', }) ); dispatch(resetSendMessageStatus()); } }, [sendStatus, sendError, dispatch]); // 滚动到底部 useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]); // 获取当前会话的知识库信息 useEffect(() => { // 如果conversation有数据集信息,优先使用它 if (conversation && conversation.datasets && conversation.datasets.length > 0) { return; } // 如果没有会话数据集信息,但有knowledgeBaseId,尝试从知识库列表中查找 if (knowledgeBaseId && knowledgeBases.length === 0 && !availableDatasets.length) { dispatch(fetchAvailableDatasets()); } }, [dispatch, knowledgeBaseId, knowledgeBases, conversation, availableDatasets]); const handleSendMessage = (e) => { e.preventDefault(); if (!inputMessage.trim() || sendStatus === 'loading') return; // 获取知识库ID列表 let dataset_id_list = []; if (conversation && conversation.datasets) { // 如果已有会话,使用会话中的知识库 dataset_id_list = conversation.datasets.map((ds) => ds.id.replace(/-/g, '')); } else if (knowledgeBaseId) { // 如果是新会话,使用当前选择的知识库 dataset_id_list = [knowledgeBaseId.replace(/-/g, '')]; } else if (availableDatasets.length > 0) { // 如果都没有,尝试使用可用知识库列表中的第一个 dataset_id_list = [availableDatasets[0].id.replace(/-/g, '')]; } if (dataset_id_list.length === 0) { dispatch( showNotification({ message: '发送失败:未选择知识库', type: 'danger', }) ); return; } // 发送消息到服务器 dispatch( createChatRecord({ dataset_id_list: dataset_id_list, question: inputMessage, conversation_id: chatId, }) ) .unwrap() .then(() => { // 成功发送后,可以执行任何需要的操作 // 例如:在用户发送第一条消息后更新URL中的会话ID }) .catch((error) => { // 发送失败,显示错误信息 dispatch( showNotification({ message: `发送失败: ${error}`, type: 'danger', }) ); }); // 清空输入框 setInputMessage(''); }; // 渲染加载状态 const renderLoading = () => (
加载消息失败
{messageError}
暂无消息,开始发送第一条消息吧