import { useState, useRef, useEffect } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { ScrollArea } from "@/components/ui/scroll-area"; import { User, Loader2, Sparkles, Search, ArrowUp, ChevronDown, Table, Paperclip } from "lucide-react"; import { api } from "@/lib/api"; import { useVisualizationStore } from "@/store/visualizationStore"; interface Message { id: string; role: 'user' | 'assistant'; content: string; } export function ChatInterface() { const [messages, setMessages] = useState([ { id: '1', role: 'assistant', content: 'Hello! I am DataClaw. How can I help you analyze your data today?' } ]); const [input, setInput] = useState(""); const selectedSkill = "sql-generator"; const selectedDataSource = "postgres-main"; const [isLoading, setIsLoading] = useState(false); const scrollRef = useRef(null); const { setVisualization, setLoading: setVizLoading, setError: setVizError } = useVisualizationStore(); const capabilities = [ { icon: Sparkles, label: "智能问答", color: "text-purple-500", bg: "bg-purple-50" }, { icon: Table, label: "表格问答", color: "text-orange-500", bg: "bg-orange-50" }, { icon: Search, label: "深度问数", color: "text-blue-500", bg: "bg-blue-50" }, ]; useEffect(() => { if (scrollRef.current) { scrollRef.current.scrollIntoView({ behavior: 'smooth' }); } }, [messages]); const handleSend = async () => { if (!input.trim() || isLoading) return; const newMessage: Message = { id: Date.now().toString(), role: 'user', content: input }; setMessages(prev => [...prev, newMessage]); setInput(""); setIsLoading(true); setVizLoading(true); setVizError(null); try { if (selectedSkill === 'sql-generator' || selectedSkill === 'chart-creator') { // Use NL2SQL agent const source = selectedDataSource.split('-')[0]; // postgres-main -> postgres const response = await api.post<{sql?: string, result?: unknown, error?: string}>('/api/v1/agent/nl2sql', { query: newMessage.content, source: source }); if (response.error) { setMessages(prev => [...prev, { id: (Date.now() + 1).toString(), role: 'assistant', content: `Error: ${response.error}` }]); setVizError(response.error); } else { const rows = Array.isArray(response.result) ? response.result : []; const sql = typeof response.sql === "string" ? response.sql : ""; setMessages(prev => [...prev, { id: (Date.now() + 1).toString(), role: 'assistant', content: `I've generated a SQL query and fetched ${rows.length} rows for you. Check the visualization panel.` }]); setVisualization(rows, sql); } } else { // General Chat const response = await api.post<{response: string}>('/nanobot/chat', { message: newMessage.content, skill_ids: [selectedSkill] }); setMessages(prev => [...prev, { id: (Date.now() + 1).toString(), role: 'assistant', content: response.response }]); } } catch (error: any) { setMessages(prev => [...prev, { id: (Date.now() + 1).toString(), role: 'assistant', content: `Sorry, something went wrong: ${error.message}` }]); setVizError(error.message); } finally { setIsLoading(false); setVizLoading(false); } }; return (
{/* Top Bar */}
{messages.length <= 1 ? (
{/* Logo Area */}
🦞

DataClaw

{/* Input Area */}