import React, { useState, useEffect, useRef } from 'react'; import { useAuth } from '../context/AuthContext'; import aiService from '../services/aiService'; import { toast } from 'react-toastify'; import { renderMd } from '../utils/sanitizeMarkdown'; const WELCOME_MSG = { role: 'assistant', content: 'Hallo! Ich bin dein KI-Assistent für IT-Support. Du kannst mich nach Lösungen für bekannte Probleme, Troubleshooting-Schritten oder Ticket-Einschätzungen fragen.', }; const CATEGORY_LIST = ['Software', 'Hardware', 'Allgemein', 'SelectLine']; export default function AiPage() { const { isAdmin } = useAuth(); const [activeTab, setActiveTab] = useState('chat'); // Chat State const [messages, setMessages] = useState([WELCOME_MSG]); const [input, setInput] = useState(''); const [chatLoading, setChatLoading] = useState(false); const [configured, setConfigured] = useState(true); const bottomRef = useRef(null); const inputRef = useRef(null); // Knowledge Base State const [kbEntries, setKbEntries] = useState([]); const [kbLoading, setKbLoading] = useState(false); const [showKbForm, setShowKbForm] = useState(false); const [kbForm, setKbForm] = useState({ problem: '', solution: '', category: 'Allgemein', tags: '' }); const [kbSaving, setKbSaving] = useState(false); useEffect(() => { aiService.getStatus() .then(s => setConfigured(s.configured)) .catch(() => setConfigured(false)); }, []); useEffect(() => { if (activeTab === 'kb') loadKb(); }, [activeTab]); useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]); async function loadKb() { setKbLoading(true); try { const data = await aiService.getKnowledgeBase(); setKbEntries(data); } catch (err) { toast.error('Wissensdatenbank konnte nicht geladen werden'); } finally { setKbLoading(false); } } async function sendMessage() { const text = input.trim(); if (!text || chatLoading) return; const userMsg = { role: 'user', content: text }; const newMessages = [...messages, userMsg]; setMessages(newMessages); setInput(''); setChatLoading(true); try { const contextMsgs = newMessages.filter(m => m !== WELCOME_MSG).slice(-20); const reply = await aiService.chat(contextMsgs); setMessages(prev => [...prev, { role: 'assistant', content: reply }]); } catch (err) { setMessages(prev => [...prev, { role: 'assistant', content: `Fehler: ${err.response?.data?.message || err.message}`, isError: true, }]); } finally { setChatLoading(false); setTimeout(() => inputRef.current?.focus(), 50); } } async function saveKbEntry() { if (!kbForm.problem.trim() || !kbForm.solution.trim()) { toast.error('Problem und Lösung sind pflichtfelder'); return; } setKbSaving(true); try { await aiService.addKnowledgeEntry(kbForm); toast.success('Eintrag gespeichert'); setKbForm({ problem: '', solution: '', category: 'Allgemein', tags: '' }); setShowKbForm(false); loadKb(); } catch (err) { toast.error('Fehler beim Speichern'); } finally { setKbSaving(false); } } async function deleteKbEntry(id) { if (!window.confirm('Eintrag wirklich löschen?')) return; try { await aiService.deleteKnowledgeEntry(id); toast.success('Eintrag gelöscht'); setKbEntries(prev => prev.filter(e => e.id !== id)); } catch { toast.error('Fehler beim Löschen'); } } const TAB = (active) => ({ padding: '10px 16px', border: 'none', background: 'transparent', cursor: 'pointer', fontSize: '0.875rem', fontWeight: active ? 600 : 400, color: active ? 'var(--cereda-primary)' : 'var(--text-muted)', borderBottom: active ? '2px solid var(--cereda-primary)' : '2px solid transparent', }); return (
{/* Header */}
🤖

KI-Assistent

{!configured && ( Nicht konfiguriert )}

Claude claude-sonnet-4-6 · IT-Support-Assistent mit Wissensdatenbank

{!configured && (
⚠️ ANTHROPIC_API_KEY fehlt

Füge ANTHROPIC_API_KEY=sk-ant-... in der docker-compose.yml als Umgebungsvariable hinzu und deploye neu.

)}
{/* Tabs */}
{/* Chat Tab */} {activeTab === 'chat' && (
{/* Messages */}
{messages.map((msg, i) => (
{msg.role === 'assistant' ?
: msg.content}
))} {chatLoading && (
KI denkt nach…
)}
{/* Input */}