'use client' import { useState } from 'react' import AdminLayout from '@/components/admin/AdminLayout' import { WizardStepper, WizardNavigation, EducationCard, ArchitectureContext, TestRunner, TestSummary, type WizardStep, type TestCategoryResult, type FullTestResults, type EducationContent, type ArchitectureContextType, } from '@/components/wizard' // ============================================== // Constants // ============================================== const BACKEND_URL = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000' const STEPS: WizardStep[] = [ { id: 'welcome', name: 'Willkommen', icon: '👋', status: 'pending' }, { id: 'byoeh', name: 'BYOEH Encryption', icon: '🔐', status: 'pending', category: 'byoeh' }, { id: 'vector-db', name: 'Vector DB', icon: '🗄️', status: 'pending', category: 'vector-db' }, { id: 'embeddings', name: 'Embeddings', icon: '🔢', status: 'pending', category: 'embeddings' }, { id: 'rag-pipeline', name: 'RAG Pipeline', icon: '🔍', status: 'pending', category: 'rag-pipeline' }, { id: 'summary', name: 'Zusammenfassung', icon: '📊', status: 'pending' }, ] const EDUCATION_CONTENT: Record = { 'welcome': { title: 'Willkommen zum RAG & BYOEH Wizard', content: [ 'RAG (Retrieval Augmented Generation) verbessert LLM-Antworten mit eigenen Daten.', '', 'So funktioniert RAG in BreakPilot:', '1. Lehrer laedt Erwartungshorizont hoch (Client-Side Encryption)', '2. EH wird in Chunks aufgeteilt und als Embeddings gespeichert', '3. Bei der Korrektur: Relevante EH-Abschnitte werden gefunden', '4. Korrekturvorschlaege basieren auf dem eigenen EH', '', 'Besonderheit: BYOEH (Bring Your Own EH)', '• Ende-zu-Ende-Verschluesselung im Browser', '• BreakPilot hat KEINEN Zugriff auf Klartext-EH', '• Passphrase verbleibt nur auf dem Geraet des Lehrers', ], }, 'byoeh': { title: 'BYOEH - Client-Side Encryption', content: [ 'BYOEH schuetzt Erwartungshorizonte mit Ende-zu-Ende-Verschluesselung.', '', 'Sicherheitsarchitektur:', '• AES-256-GCM Verschluesselung (NIST-Standard)', '• PBKDF2 Key Derivation (100.000 Iterationen)', '• Passphrase wird automatisch generiert (32 Zeichen)', '• Schluessel verbleibt im localStorage des Browsers', '', 'Was wird verschluesselt?', '• Die komplette EH-Datei vor dem Upload', '• Jeder Chunk einzeln (fuer RAG-Suche)', '', 'Was wird NICHT an den Server gesendet?', '• Die Passphrase (nur Key-Hash zur Verifizierung)', '• Klartext-Inhalte des EH', '', 'Audit-relevant: BreakPilot-Mitarbeiter haben keinen Zugriff!', ], }, 'vector-db': { title: 'Vector Datenbank - Qdrant', content: [ 'Qdrant speichert Embeddings fuer schnelle Aehnlichkeitssuche.', '', 'Konzepte:', '• Collection: Gruppe von Vektoren (z.B. "edu-docs")', '• Point: Ein Dokument mit Vektor + Payload', '• Payload: Metadaten (Titel, URL, Datum)', '', 'Warum Vector DB?', '• Millisekunden-Suche in Millionen Dokumenten', '• Semantische Suche (nicht nur Keywords)', '• Skaliert horizontal', '', 'Alternative: pgvector (PostgreSQL Extension)', ], }, 'embeddings': { title: 'Embeddings - Text zu Vektoren', content: [ 'Embeddings wandeln Text in numerische Vektoren um.', '', 'Modelle:', '• OpenAI text-embedding-3-small (1536 dim)', '• OpenAI text-embedding-3-large (3072 dim)', '• Lokale Modelle via Ollama', '', 'Wichtig:', '• Gleiches Modell fuer Indexierung und Suche', '• Chunk-Groesse beeinflusst Qualitaet', '• Overlap zwischen Chunks fuer Kontext', '', 'Kosten: ~$0.02 pro 1M Tokens (OpenAI small)', ], }, 'rag-pipeline': { title: 'RAG Pipeline - Ende-zu-Ende', content: [ 'Die Pipeline verbindet alle Komponenten.', '', 'Indexierung:', '1. Dokument laden (PDF, HTML, MD)', '2. In Chunks aufteilen (z.B. 500 Tokens)', '3. Embeddings generieren', '4. In Qdrant speichern', '', 'Abfrage:', '1. Frage in Embedding umwandeln', '2. Aehnlichste Chunks finden (Top-K)', '3. Chunks als Kontext an LLM', '4. LLM generiert Antwort mit Quellen', '', 'EduSearch nutzt diese Pipeline fuer Bildungssuche.', ], }, 'summary': { title: 'Test-Zusammenfassung', content: [ 'Hier sehen Sie eine Uebersicht aller durchgefuehrten Tests:', '• Vector DB Konnektivitaet', '• Embedding-Generierung', '• RAG Pipeline Status', '• Training Infrastructure', ], }, } const ARCHITECTURE_CONTEXTS: Record = { 'byoeh': { layer: 'frontend', services: ['klausur-frontend', 'browser'], dependencies: ['Web Crypto API', 'AES-256-GCM', 'PBKDF2', 'localStorage'], dataFlow: ['Passphrase Generation', 'Key Derivation', 'Encryption', 'Upload', 'Key Storage'], }, 'vector-db': { layer: 'database', services: ['backend'], dependencies: ['Qdrant', 'PostgreSQL'], dataFlow: ['FastAPI', 'Qdrant Client', 'Qdrant Server', 'Storage'], }, 'embeddings': { layer: 'service', services: ['backend'], dependencies: ['BGE-M3 (lokal)', 'Sentence-Transformers'], dataFlow: ['Text', 'Semantic Chunking', 'BGE-M3 Model', 'Vector (1024 dim)'], }, 'rag-pipeline': { layer: 'service', services: ['backend', 'klausur-frontend'], dependencies: ['Qdrant', 'BGE Reranker', 'Hybrid Search'], dataFlow: ['Query', 'Embedding', 'Vector Search', 'Re-Ranking', 'Decryption', 'Response'], }, } // ============================================== // Main Component // ============================================== export default function RAGWizardPage() { const [currentStep, setCurrentStep] = useState(0) const [steps, setSteps] = useState(STEPS) const [categoryResults, setCategoryResults] = useState>({}) const [fullResults, setFullResults] = useState(null) const [isLoading, setIsLoading] = useState(false) const [error, setError] = useState(null) const currentStepData = steps[currentStep] const isTestStep = currentStepData?.category !== undefined const isWelcome = currentStepData?.id === 'welcome' const isSummary = currentStepData?.id === 'summary' const runCategoryTest = async (category: string) => { setIsLoading(true) setError(null) try { const response = await fetch(`${BACKEND_URL}/api/admin/rag-tests/${category}`, { method: 'POST', }) if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`) } const result: TestCategoryResult = await response.json() setCategoryResults((prev) => ({ ...prev, [category]: result })) setSteps((prev) => prev.map((step) => step.category === category ? { ...step, status: result.failed === 0 ? 'completed' : 'failed' } : step ) ) } catch (err) { setError(err instanceof Error ? err.message : 'Unbekannter Fehler') } finally { setIsLoading(false) } } const runAllTests = async () => { setIsLoading(true) setError(null) try { const response = await fetch(`${BACKEND_URL}/api/admin/rag-tests/run-all`, { method: 'POST', }) if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`) } const results: FullTestResults = await response.json() setFullResults(results) setSteps((prev) => prev.map((step) => { if (step.category) { const catResult = results.categories.find((c) => c.category === step.category) if (catResult) { return { ...step, status: catResult.failed === 0 ? 'completed' : 'failed' } } } return step }) ) const newCategoryResults: Record = {} results.categories.forEach((cat) => { newCategoryResults[cat.category] = cat }) setCategoryResults(newCategoryResults) } catch (err) { setError(err instanceof Error ? err.message : 'Unbekannter Fehler') } finally { setIsLoading(false) } } const goToNext = () => { if (currentStep < steps.length - 1) { setSteps((prev) => prev.map((step, idx) => idx === currentStep && step.status === 'pending' ? { ...step, status: 'completed' } : step ) ) setCurrentStep((prev) => prev + 1) } } const goToPrev = () => { if (currentStep > 0) { setCurrentStep((prev) => prev - 1) } } const handleStepClick = (index: number) => { if (index <= currentStep || steps[index - 1]?.status !== 'pending') { setCurrentStep(index) } } return ( {/* Header */}
🧠

RAG & Training Wizard

Vector DB, Embeddings & Fine-Tuning

← Zurueck zu RAG & Training
{/* Stepper */}
{/* Content */}
{currentStepData?.icon}

Schritt {currentStep + 1}: {currentStepData?.name}

{currentStep + 1} von {steps.length}

{isTestStep && currentStepData?.category && ARCHITECTURE_CONTEXTS[currentStepData.category] && ( )} {error && (
Fehler: {error}
)} {isWelcome && (
)} {isTestStep && currentStepData?.category && ( runCategoryTest(currentStepData.category!)} /> )} {isSummary && (
{!fullResults ? (

Fuehren Sie alle Tests aus um eine Zusammenfassung zu sehen.

) : ( )}
)}
Diese Tests pruefen die RAG- und Training-Infrastruktur. Bei Fragen wenden Sie sich an das KI-Team.
) }