// File: frontend/app/chat/page.tsx (重构布局) // Description: AI 聊天界面组件,包含左侧助手面板、中间聊天区、右侧会话面板 'use client'; import React, { useState, useRef, useEffect } from 'react'; import { SendHorizontal, Loader2, PanelRightOpen, PanelRightClose, UserPlus, Settings2 } from 'lucide-react'; // 添加图标 import { sendChatMessage } from '@/lib/api'; // --- 数据接口定义 --- interface Message { id: string; text: string; sender: 'user' | 'ai'; isError?: boolean; } interface ChatSession { id: string; title: string; createdAt: Date; } // 定义助手接口 (示例) interface Assistant { id: string; name: string; description: string; avatar?: string; // 可选头像 URL 或 emoji systemPrompt: string; // 核心:系统提示 model: string; // 例如 'gpt-3.5-turbo', 'gemini-pro' temperature: number; // 可以添加 top_p, max_tokens 等其他参数 } export default function ChatPage() { // --- State Variables --- const [inputMessage, setInputMessage] = useState(''); const [messages, setMessages] = useState([ { id: 'init-1', text: '你好!我是默认助手,有什么可以帮你的吗?', sender: 'ai' }, ]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const [isSessionPanelOpen, setIsSessionPanelOpen] = useState(true); // 右侧会话面板状态 // --- Mock Data --- // 助手列表 Mock 数据 const [assistants, setAssistants] = useState([ { id: 'asst-default', name: '默认助手', description: '通用聊天助手', avatar: '🤖', systemPrompt: '你是一个乐于助人的 AI 助手。', model: 'gpt-3.5-turbo', temperature: 0.7 }, { id: 'asst-coder', name: '代码助手', description: '帮助编写和解释代码', avatar: '💻', systemPrompt: '你是一个专业的代码助手,精通多种编程语言。请提供清晰、准确的代码示例和解释。', model: 'gpt-4', temperature: 0.5 }, { id: 'asst-writer', name: '写作助手', description: '协助进行创意写作', avatar: '✍️', systemPrompt: '你是一位富有创意的写作伙伴,擅长构思情节、润色文字。', model: 'gemini-pro', temperature: 0.9 }, ]); const [currentAssistantId, setCurrentAssistantId] = useState('asst-default'); // 当前选中的助手 // 会话列表 Mock 数据 const [sessions, setSessions] = useState([ {id: 'session-1', title: '关于 RAG 技术的讨论', createdAt: new Date(Date.now() - 3600000)}, {id: 'session-2', title: 'Python FastAPI 项目构思', createdAt: new Date(Date.now() - 7200000)}, {id: 'session-3', title: '如何学习 LangChain', createdAt: new Date()}, ]); const [currentSessionId, setCurrentSessionId] = useState('session-3'); // 当前选中的会话 // --- Refs --- const messagesEndRef = useRef(null); // --- Effects --- useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]); // --- Event Handlers --- const handleSendMessage = async (e?: React.FormEvent) => { e?.preventDefault(); const trimmedMessage = inputMessage.trim(); if (!trimmedMessage || isLoading) return; setError(null); const userMessage: Message = { id: Date.now().toString(), text: trimmedMessage, sender: 'user', }; setMessages((prevMessages) => [...prevMessages, userMessage]); setInputMessage(''); setIsLoading(true); try { // TODO: 调用后端时需要传递 currentAssistantId 和 currentSessionId // const aiReply = await sendChatMessage(trimmedMessage, currentSessionId, currentAssistantId); const aiReply = await sendChatMessage(trimmedMessage); // 暂时保持不变 const aiMessage: Message = { id: Date.now().toString() + '_ai', text: aiReply, sender: 'ai', }; setMessages((prevMessages) => [...prevMessages, aiMessage]); } catch (err: any) { console.error("Failed to send message:", err); const errorMessageText = err.message || 'An unknown error occurred.'; setError(errorMessageText); const errorMessage: Message = { id: Date.now().toString() + '_err', text: `错误: ${errorMessageText}`, sender: 'ai', isError: true, }; setMessages((prevMessages) => [...prevMessages, errorMessage]); } finally { setIsLoading(false); } }; const handleInputChange = (e: React.ChangeEvent) => { setInputMessage(e.target.value); }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey && !isLoading) { e.preventDefault(); handleSendMessage(); } }; const toggleSessionPanel = () => { setIsSessionPanelOpen(!isSessionPanelOpen); }; const handleSelectAssistant = (assistantId: string) => { setCurrentAssistantId(assistantId); // TODO: 可能需要清空当前消息或开始新会话 console.log("Selected assistant:", assistantId); // 可以在这里加载助手的初始消息或更新聊天标题 const selectedAssistant = assistants.find(a => a.id === assistantId); setMessages([ { id: `init-${assistantId}`, text: `你好!我是${selectedAssistant?.name || '助手'}。${selectedAssistant?.description || ''}`, sender: 'ai' }, ]); setCurrentSessionId(`new-${Date.now()}`); // 切换助手时通常开始新会话 setSessions(prev => [...prev, {id: `new-${Date.now()}`, title: `与 ${selectedAssistant?.name} 的新对话`, createdAt: new Date()}]); // 添加新会话到列表 } // --- JSX Rendering --- return ( // 最外层 Flex 容器
{/* 使用 gap 添加间距 */} {/* 左侧助手面板 */} {/* 中间主聊天区域 */}
{/* 聊天窗口标题 - 显示当前助手和切换会话按钮 */}
{assistants.find(a => a.id === currentAssistantId)?.avatar || '👤'}

{assistants.find(a => a.id === currentAssistantId)?.name || '助手'}

{/* TODO: 显示模型、温度等信息 */} {/* {assistants.find(a => a.id === currentAssistantId)?.model} */}
{/* 消息显示区域 */}
{messages.map((message) => (

{message.text}

))} {isLoading && (
AI 正在思考...
)}
{/* 消息输入区域 */}
{/* 右侧会话管理面板 */}
); }