'use client' import { useState, useRef, useEffect } from 'react' import { motion, AnimatePresence } from 'framer-motion' import { Send, Bot, User, Sparkles } from 'lucide-react' import { ChatMessage, Language } from '@/lib/types' import { t } from '@/lib/i18n' interface ChatInterfaceProps { lang: Language } export default function ChatInterface({ lang }: ChatInterfaceProps) { const i = t(lang) const [messages, setMessages] = useState([]) const [input, setInput] = useState('') const [isStreaming, setIsStreaming] = useState(false) const messagesEndRef = useRef(null) const inputRef = useRef(null) useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }) }, [messages]) async function sendMessage(text?: string) { const message = text || input.trim() if (!message || isStreaming) return setInput('') setMessages(prev => [...prev, { role: 'user', content: message }]) setIsStreaming(true) try { const res = await fetch('/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message, history: messages.slice(-10), lang, }), }) if (!res.ok) throw new Error(`HTTP ${res.status}`) const reader = res.body!.getReader() const decoder = new TextDecoder() let content = '' setMessages(prev => [...prev, { role: 'assistant', content: '' }]) while (true) { const { done, value } = await reader.read() if (done) break content += decoder.decode(value, { stream: true }) setMessages(prev => { const updated = [...prev] updated[updated.length - 1] = { role: 'assistant', content } return updated }) } } catch (err) { console.error('Chat error:', err) setMessages(prev => [ ...prev, { role: 'assistant', content: lang === 'de' ? 'Verbindung fehlgeschlagen. Bitte versuchen Sie es erneut.' : 'Connection failed. Please try again.' }, ]) } finally { setIsStreaming(false) } } return (
{/* Messages */}
{messages.length === 0 && (
{lang === 'de' ? 'Vorgeschlagene Fragen:' : 'Suggested questions:'}
{i.aiqa.suggestions.map((q, idx) => ( sendMessage(q)} className="block w-full text-left px-4 py-3 rounded-xl bg-white/[0.05] border border-white/10 hover:bg-white/[0.1] transition-colors text-sm text-white/70 hover:text-white" > {q} ))}
)} {messages.map((msg, idx) => ( {msg.role === 'assistant' && (
)}
{msg.content}
{isStreaming && idx === messages.length - 1 && msg.role === 'assistant' && ( )}
{msg.role === 'user' && (
)}
))}
{/* Input */}
setInput(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && sendMessage()} placeholder={i.aiqa.placeholder} disabled={isStreaming} className="flex-1 bg-white/[0.06] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-white/30 outline-none focus:border-indigo-500/50 focus:ring-1 focus:ring-indigo-500/20 disabled:opacity-50 transition-all" />
) }