// components/Chat/MCPChat.tsx - 集成 MCP 的聊天组件 'use client'; import React, { useState, useRef, useEffect } from 'react'; import { mcpService } from '../../services/mcp-real'; import { useAuth } from '../../hooks/useAuth'; import styles from './MCPChat.module.css'; interface Message { id: string; role: 'user' | 'assistant' | 'system'; content: string; timestamp: Date; isStreaming?: boolean; } export default function MCPChat() { const [messages, setMessages] = useState([]); const [input, setInput] = useState(''); const [isLoading, setIsLoading] = useState(false); const [streamingMessage, setStreamingMessage] = useState(''); const [tools, setTools] = useState([]); const messagesEndRef = useRef(null); const { user, isAuthenticated, canAccessChat, loading: authLoading } = useAuth(); // 加载可用工具 useEffect(() => { if (isAuthenticated && canAccessChat) { loadTools(); } }, [isAuthenticated, canAccessChat]); // 自动滚动到底部 useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages, streamingMessage]); const loadTools = async () => { try { const availableTools = await mcpService.getTools(); setTools(availableTools); console.log('Available tools:', availableTools); } catch (error) { console.error('Failed to load tools:', error); } }; const handleSend = async () => { if (!input.trim() || isLoading) return; const userMessage: Message = { id: Date.now().toString(), role: 'user', content: input, timestamp: new Date(), }; setMessages(prev => [...prev, userMessage]); setInput(''); setIsLoading(true); setStreamingMessage(''); try { // 创建助手消息占位符 const assistantMessage: Message = { id: (Date.now() + 1).toString(), role: 'assistant', content: '', timestamp: new Date(), isStreaming: true, }; setMessages(prev => [...prev, assistantMessage]); // 流式接收回复 let fullContent = ''; for await (const chunk of mcpService.streamMessage(input)) { fullContent += chunk; setStreamingMessage(fullContent); } // 更新最终消息 setMessages(prev => prev.map(msg => msg.id === assistantMessage.id ? { ...msg, content: fullContent, isStreaming: false } : msg ) ); setStreamingMessage(''); } catch (error) { console.error('Send message error:', error); setMessages(prev => [ ...prev, { id: Date.now().toString(), role: 'system', content: '抱歉,发送消息时出错了。请稍后重试。', timestamp: new Date(), }, ]); } finally { setIsLoading(false); } }; const handleToolCall = async (toolName: string) => { // 示例:调用工具 try { setIsLoading(true); const result = await mcpService.callTool(toolName, {}); console.log('Tool result:', result); // 显示工具结果 setMessages(prev => [ ...prev, { id: Date.now().toString(), role: 'system', content: `工具 ${toolName} 执行结果:${JSON.stringify(result.result, null, 2)}`, timestamp: new Date(), }, ]); } catch (error) { console.error('Tool call error:', error); } finally { setIsLoading(false); } }; // 权限检查 if (authLoading) { return (
加载中...
); } if (!isAuthenticated) { const mainAppUrl = process.env.NEXT_PUBLIC_MAIN_APP_URL || 'https://valuefrontier.cn'; return (

请先登录

前往登录
); } if (!canAccessChat) { return (

需要订阅才能使用 AI 助手

升级到高级版解锁所有功能

查看订阅方案
); } return (
{/* 侧边栏 - 工具列表 */}

可用工具

{tools.map(tool => ( ))}
{/* 用户信息 */}
{user?.username?.[0]?.toUpperCase()}
{user?.username}
{user?.subscription_tier}
{/* 主聊天区域 */}
{/* 消息列表 */}
{messages.map(msg => (
{msg.isStreaming ? (
{streamingMessage || ( 思考中... )}
) : (
{msg.content}
)}
{msg.timestamp.toLocaleTimeString()}
))}
{/* 输入区域 */}
setInput(e.target.value)} onKeyPress={e => e.key === 'Enter' && handleSend()} disabled={isLoading} placeholder="输入消息..." className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-800 dark:text-white" />
{/* 快捷操作 */}
); } // CSS 模块文件需要单独创建