'use client' /** * Test Quality Dashboard - BQAS (Breakpilot Quality Assurance System) * * Umfassendes Qualitaetssicherungs-Dashboard mit: * - Golden Test Suite Ergebnisse * - Synthetic Test Generierung * - Regression Tracking * - Test Run Historie * - RAG Correction Tests */ import { useState, useEffect, useCallback, useRef } from 'react' import Link from 'next/link' import { PagePurpose } from '@/components/common/PagePurpose' import { AIToolsSidebarResponsive } from '@/components/ai/AIToolsSidebar' import type { TestRun, BQASMetrics, TrendData, TabType } from './types' // API Configuration - Use internal proxy to avoid CORS issues const BQAS_API_BASE = '/api/bqas' // ============================================================================ // Toast Notification Component // ============================================================================ interface Toast { id: number type: 'success' | 'error' | 'info' | 'loading' message: string } function ToastContainer({ toasts, onDismiss }: { toasts: Toast[]; onDismiss: (id: number) => void }) { return (
{toasts.map((toast) => (
{toast.type === 'loading' ? ( ) : toast.type === 'success' ? ( ) : toast.type === 'error' ? ( ) : ( )} {toast.message} {toast.type !== 'loading' && ( )}
))}
) } // ============================================================================ // Helper Components // ============================================================================ function MetricCard({ title, value, subtitle, trend, color = 'blue', }: { title: string value: string | number subtitle?: string trend?: 'up' | 'down' | 'stable' color?: 'blue' | 'green' | 'red' | 'yellow' | 'purple' }) { const colorClasses = { blue: 'bg-blue-50 border-blue-200', green: 'bg-emerald-50 border-emerald-200', red: 'bg-red-50 border-red-200', yellow: 'bg-amber-50 border-amber-200', purple: 'bg-purple-50 border-purple-200', } const trendIcons = { up: ( ), down: ( ), stable: ( ), } return (

{title}

{value}

{subtitle &&

{subtitle}

}
{trend &&
{trendIcons[trend]}
}
) } function TestSuiteCard({ title, description, metrics, onRun, isRunning, lastRun, }: { title: string description: string metrics?: BQASMetrics onRun: () => void isRunning: boolean lastRun?: string }) { const passRate = metrics ? (metrics.passed_tests / metrics.total_tests) * 100 : 0 return (

{title}

{description}

{metrics && (
Pass Rate {passRate.toFixed(1)}%
= 80 ? 'bg-emerald-500' : passRate >= 60 ? 'bg-amber-500' : 'bg-red-500' }`} style={{ width: `${passRate}%` }} />

{metrics.total_tests}

Tests

{metrics.passed_tests}

Bestanden

{metrics.failed_tests}

Fehlgeschlagen

Durchschnittlicher Score: {metrics.avg_composite_score.toFixed(2)}

)} {lastRun && (

Letzter Lauf: {new Date(lastRun).toLocaleString('de-DE')}

)}
) } function TrendChart({ data }: { data: TrendData }) { if (!data || data.dates.length === 0) { return (
Keine Trend-Daten verfuegbar
) } const maxScore = Math.max(...data.scores, 5) const minScore = Math.min(...data.scores, 0) const range = maxScore - minScore || 1 return (
{maxScore.toFixed(1)} {((maxScore + minScore) / 2).toFixed(1)} {minScore.toFixed(1)}
{ const x = (i / (data.scores.length - 1 || 1)) * 100 const y = 100 - ((score - minScore) / range) * 100 return `${x},${y}` }) .join(' ')} /> {data.scores.map((score, i) => { const x = (i / (data.scores.length - 1 || 1)) * 100 const y = 100 - ((score - minScore) / range) * 100 return })}
{data.dates.slice(0, 5).map((date, i) => ( {new Date(date).toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit' })} ))}
{data.trend === 'improving' ? 'Verbessernd' : data.trend === 'declining' ? 'Verschlechternd' : 'Stabil'}
) } function TestRunsTable({ runs }: { runs: TestRun[] }) { if (runs.length === 0) { return (
Keine Test-Laeufe vorhanden
) } return (
{runs.map((run) => ( ))}
ID Zeitpunkt Commit Golden Score Tests Bestanden Dauer
#{run.id} {new Date(run.timestamp).toLocaleString('de-DE')} {run.git_commit?.slice(0, 7) || '-'} = 4 ? 'text-emerald-600' : run.golden_score >= 3 ? 'text-amber-600' : 'text-red-600' }`} > {run.golden_score.toFixed(2)} {run.total_tests} {run.passed_tests} / {run.failed_tests} {run.duration_seconds.toFixed(1)}s
) } function IntentScoresChart({ scores }: { scores: Record }) { const entries = Object.entries(scores).sort((a, b) => b[1] - a[1]) if (entries.length === 0) { return (
Keine Intent-Scores verfuegbar
) } return (
{entries.map(([intent, score]) => (
{intent.replace(/_/g, ' ')} = 4 ? 'text-emerald-600' : score >= 3 ? 'text-amber-600' : 'text-red-600' }`} > {score.toFixed(2)}
= 4 ? 'bg-emerald-500' : score >= 3 ? 'bg-amber-500' : 'bg-red-500' }`} style={{ width: `${(score / 5) * 100}%` }} />
))}
) } // Demo failed test details for illustration const FAILED_TEST_DETAILS: Record = { // Golden Suite - Intent Tests 'INT-001': { description: 'Student Observation - Simple', cause: 'Notiz zu Max wird nicht korrekt als student_observation erkannt', action: 'Training-Daten fuer kurze Notiz-Befehle erweitern', }, 'INT-002': { description: 'Student Observation - Needs Help', cause: 'Anfrage "Anna braucht extra Uebungsblatt" wird falsch klassifiziert', action: 'Intent-Erkennung fuer Hilfe-Anfragen verbessern', }, 'INT-003': { description: 'Reminder - Simple', cause: 'Erinnerungs-Intent nicht erkannt', action: 'Trigger-Woerter fuer Erinnerungen pruefen', }, 'INT-010': { description: 'Quick Activity - With Time', cause: '"10 Minuten Einstieg" wird nicht als quick_activity erkannt', action: 'Zeitmuster in Quick-Activity-Intent aufnehmen', }, 'INT-011': { description: 'Quiz Generate - Vocabulary', cause: 'Vokabeltest wird nicht als quiz_generate klassifiziert', action: 'Quiz-Keywords wie "Test", "Vokabel" staerker gewichten', }, 'INT-012': { description: 'Quiz Generate - Short Test', cause: '"Kurzer Test zu Kapitel 5" falsch erkannt', action: 'Kontext-Keywords fuer Quiz verbessern', }, 'INT-015': { description: 'Class Message', cause: 'Nachricht an Klasse wird als anderer Intent erkannt', action: 'Klassen-Nachrichten-Patterns erweitern', }, 'INT-019': { description: 'Operator Checklist', cause: 'Operatoren-Anfrage nicht korrekt klassifiziert', action: 'EH/Operator-bezogene Intents pruefen', }, 'INT-021': { description: 'Feedback Suggest', cause: 'Feedback-Vorschlag Intent nicht erkannt', action: 'Feedback-Synonyme hinzufuegen', }, 'INT-022': { description: 'Reminder Schedule - Tomorrow', cause: 'Zeitbasierte Erinnerung falsch klassifiziert', action: 'Zeitausdrucke wie "morgen" besser verarbeiten', }, 'INT-023': { description: 'Task Summary', cause: 'Zusammenfassungs-Intent nicht erkannt', action: 'Summary-Trigger erweitern', }, // RAG Tests 'RAG-EH-001': { description: 'EH Passage Retrieval - Textanalyse Sachtext', cause: 'EH-Passage nicht gefunden oder unvollstaendig', action: 'RAG-Retrieval fuer Textanalyse optimieren', }, 'RAG-HAL-002': { description: 'No Fictional EH Passages', cause: 'System generiert fiktive EH-Inhalte', action: 'Hallucination-Control verstaerken', }, 'RAG-HAL-004': { description: 'Grounded Response Only', cause: 'Antwort basiert nicht auf vorhandenen Daten', action: 'Grounding-Check im Response-Flow einbauen', }, 'RAG-CIT-003': { description: 'Multiple Source Attribution', cause: 'Mehrere Quellen nicht korrekt zugeordnet', action: 'Multi-Source Citation verbessern', }, 'RAG-EDGE-002': { description: 'Ambiguous Operator Query', cause: 'Bei mehrdeutiger Anfrage keine Klaerung angefordert', action: 'Clarification-Flow implementieren', }, // Synthetic Tests 'SYN-STUD-003': { description: 'Synthetic Student Observation', cause: 'Generierte Variante nicht erkannt', action: 'Robustheit gegen Variationen erhoehen', }, 'SYN-WORK-002': { description: 'Synthetic Worksheet Generate', cause: 'Arbeitsblatt-Intent bei Variation nicht erkannt', action: 'Mehr Variationen ins Training aufnehmen', }, 'SYN-WORK-005': { description: 'Synthetic Worksheet mit Tippfehler', cause: 'Tippfehler fuehrt zu Fehlklassifikation', action: 'Tippfehler-Normalisierung pruefen', }, 'SYN-REM-001': { description: 'Synthetic Reminder', cause: 'Reminder-Variante nicht erkannt', action: 'Reminder-Patterns erweitern', }, 'SYN-REM-004': { description: 'Synthetic Reminder mit Dialekt', cause: 'Dialekt-Formulierung nicht verstanden', action: 'Dialekt-Normalisierung verbessern', }, } function FailedTestsList({ testIds }: { testIds: string[] }) { const [expandedTest, setExpandedTest] = useState(null) if (testIds.length === 0) { return (
Alle Tests bestanden!
) } return (
{testIds.map((testId) => { const details = FAILED_TEST_DETAILS[testId] const isExpanded = expandedTest === testId return (
{isExpanded && details && (

Ursache

{details.cause}

Empfohlene Aktion

{details.action}

Test-ID: {testId}

)}
) })}

Tipp: Klicken Sie auf einen Test um Details zur Ursache und empfohlene Aktionen zu sehen. Fehlgeschlagene Tests sollten vor dem naechsten Release behoben werden.

) } // ============================================================================ // Guide Tab Component // ============================================================================ function GuideTab() { return (
{/* Introduction */}

Was ist BQAS?

Das Breakpilot Quality Assurance System (BQAS) ist unser automatisiertes Test-Framework zur kontinuierlichen Qualitaetssicherung der KI-Komponenten. Es stellt sicher, dass Aenderungen am Voice-Service, den Prompts oder den RAG-Pipelines keine Regressionen verursachen.

{/* For Whom */}

Fuer wen ist dieses Dashboard?

Entwickler

Pruefen Sie nach Code-Aenderungen ob alle Tests noch bestehen. Analysieren Sie fehlgeschlagene Tests und implementieren Sie Fixes.

Data Scientists

Analysieren Sie Intent-Scores, Faithfulness und Relevance. Identifizieren Sie Schwachstellen in den ML-Modellen und RAG-Pipelines.

Auditoren / QA

Dokumentieren Sie die Testabdeckung und Qualitaetsmetriken. Nutzen Sie die Historie fuer Audit-Trails und Compliance-Nachweise.

{/* Test Suites Explained */}

Die drei Test-Suites

1

Golden Suite (97 Tests)

Was: Manuell validierte Referenz-Tests mit definierten Erwartungen. Jeder Test hat eine Eingabe, eine erwartete Ausgabe und Bewertungskriterien.

Wann ausfuehren: Nach jeder Aenderung am Voice-Service oder den Prompts. Automatisch taeglich um 07:00 Uhr via launchd.

Ziel-Score: {'>'}= 4.0 (von 5.0)

2

RAG/Korrektur Tests

Was: Tests fuer das Retrieval-Augmented Generation System. Pruefen ob der richtige Erwartungshorizont gefunden wird und ob Antworten korrekt zitiert werden.

Wann ausfuehren: Nach Aenderungen an Qdrant, Chunking-Strategien oder EH-Uploads.

Kategorien: EH-Retrieval, Operator-Alignment, Hallucination-Control, Citation-Enforcement, Privacy-Compliance, Namespace-Isolation

3

Synthetic Tests

Was: LLM-generierte Variationen der Golden-Tests. Testet Robustheit gegenueber Umformulierungen, Tippfehlern, Dialekt und Edge-Cases.

Wann ausfuehren: Woechentlich oder vor Major-Releases.

Hinweis: Generierung dauert laenger da LLM-Calls benoetigt werden.

{/* Metrics Explained */}

Metriken verstehen

Metrik Beschreibung Zielwert
Composite Score Gewichteter Durchschnitt aller Einzelmetriken (1-5) {'>'}= 4.0
Intent Accuracy Wie oft wird die richtige Nutzerabsicht erkannt? {'>'}= 90%
Faithfulness Ist die Antwort dem EH treu? Keine Halluzinationen? {'>'}= 4.0
Relevance Beantwortet die Antwort die Frage des Nutzers? {'>'}= 4.0
Coherence Ist die Antwort logisch aufgebaut und verstaendlich? {'>'}= 4.0
Safety Pass Rate Werden kritische Inhalte korrekt gefiltert? 100%
{/* Workflow */}

Typischer Workflow

{[ { step: 1, title: 'Tests starten', desc: 'Klicken Sie auf "Tests starten" bei der gewuenschten Suite. Eine Benachrichtigung zeigt den Status.' }, { step: 2, title: 'Ergebnisse pruefen', desc: 'Nach Abschluss werden Pass Rate und Score angezeigt. Pruefen Sie ob der Zielwert erreicht wurde.' }, { step: 3, title: 'Fehlgeschlagene Tests analysieren', desc: 'Klicken Sie auf fehlgeschlagene Tests um Ursache und empfohlene Aktionen zu sehen.' }, { step: 4, title: 'Fixes implementieren', desc: 'Beheben Sie die identifizierten Probleme im Code, Prompts oder Training-Daten.' }, { step: 5, title: 'Erneut testen', desc: 'Fuehren Sie die Tests erneut aus um zu verifizieren dass die Fixes wirksam sind.' }, { step: 6, title: 'Dokumentieren', desc: 'Nutzen Sie die Historie als Audit-Trail. Exportieren Sie Reports fuer Compliance-Nachweise.' }, ].map((item) => (
{item.step}

{item.title}

{item.desc}

))}
{/* FAQ */}

Haeufige Fragen

{[ { q: 'Wie lange dauert ein Test-Lauf?', a: 'Golden Suite: ca. 45 Sekunden. RAG Tests: ca. 60 Sekunden. Synthetic Tests: 2-5 Minuten (abhaengig von LLM-Verfuegbarkeit).', }, { q: 'Was passiert wenn Tests fehlschlagen?', a: 'Fehlgeschlagene Tests werden rot markiert. Klicken Sie darauf um Details zu sehen. Bei kritischen Regressionen wird automatisch eine Desktop-Benachrichtigung gesendet.', }, { q: 'Wann werden Tests automatisch ausgefuehrt?', a: 'Die Golden Suite laeuft taeglich um 07:00 Uhr via launchd. Zusaetzlich bei jedem Commit im voice-service via Git-Hook (Quick-Tests).', }, { q: 'Wie kann ich einen neuen Golden-Test hinzufuegen?', a: 'Tests werden in /voice-service/bqas/golden_tests.json definiert. Jeder Test braucht: ID, Input, Expected Intent, Bewertungskriterien.', }, { q: 'Was bedeutet "Demo-Daten"?', a: 'Wenn die Voice-Service API nicht erreichbar ist, werden Demo-Daten angezeigt. Dies ist normal in der Entwicklungsumgebung wenn der Service nicht laeuft.', }, ].map((faq, i) => (

{faq.q}

{faq.a}

))}
{/* Links */}

CI/CD Scheduler

Automatische Test-Planung konfigurieren

RAG Management

Erwartungshorizonte und Chunking verwalten

) } // ============================================================================ // Main Component // ============================================================================ export default function TestQualityPage() { const [activeTab, setActiveTab] = useState('overview') const [isLoading, setIsLoading] = useState(true) const [error, setError] = useState(null) // Toast state - using useRef for stable ID counter const [toasts, setToasts] = useState([]) const toastIdRef = useRef(0) const addToast = useCallback((type: Toast['type'], message: string) => { const id = ++toastIdRef.current console.log('Adding toast:', id, type, message) // Debug log setToasts((prev) => [...prev, { id, type, message }]) if (type !== 'loading') { setTimeout(() => { setToasts((prev) => prev.filter((t) => t.id !== id)) }, 5000) } return id }, []) const removeToast = useCallback((id: number) => { setToasts((prev) => prev.filter((t) => t.id !== id)) }, []) const updateToast = useCallback((id: number, type: Toast['type'], message: string) => { console.log('Updating toast:', id, type, message) // Debug log setToasts((prev) => prev.map((t) => (t.id === id ? { ...t, type, message } : t)) ) if (type !== 'loading') { setTimeout(() => { setToasts((prev) => prev.filter((t) => t.id !== id)) }, 5000) } }, []) // Data states const [goldenMetrics, setGoldenMetrics] = useState(null) const [syntheticMetrics, setSyntheticMetrics] = useState(null) const [ragMetrics, setRagMetrics] = useState(null) const [testRuns, setTestRuns] = useState([]) const [trendData, setTrendData] = useState(null) // Running states const [isRunningGolden, setIsRunningGolden] = useState(false) const [isRunningSynthetic, setIsRunningSynthetic] = useState(false) const [isRunningRag, setIsRunningRag] = useState(false) // Demo data for when API is not available const DEMO_GOLDEN_METRICS: BQASMetrics = { total_tests: 97, passed_tests: 89, failed_tests: 8, avg_intent_accuracy: 91.7, avg_faithfulness: 4.2, avg_relevance: 4.1, avg_coherence: 4.3, safety_pass_rate: 0.98, avg_composite_score: 4.15, scores_by_intent: { korrektur_anfrage: 4.5, erklaerung_anfrage: 4.3, hilfe_anfrage: 4.1, feedback_anfrage: 3.9, smalltalk: 4.2, }, failed_test_ids: ['GT-023', 'GT-045', 'GT-067', 'GT-072', 'GT-081', 'GT-089', 'GT-092', 'GT-095'], } const DEMO_TREND: TrendData = { dates: ['2026-01-02', '2026-01-09', '2026-01-16', '2026-01-23', '2026-01-30'], scores: [3.9, 4.0, 4.1, 4.15, 4.15], trend: 'improving', } const DEMO_RUNS: TestRun[] = [ { id: 1, timestamp: '2026-01-30T07:00:00Z', git_commit: 'abc1234', golden_score: 4.15, synthetic_score: 3.9, total_tests: 97, passed_tests: 89, failed_tests: 8, duration_seconds: 45.2 }, { id: 2, timestamp: '2026-01-29T07:00:00Z', git_commit: 'def5678', golden_score: 4.12, synthetic_score: 3.85, total_tests: 97, passed_tests: 88, failed_tests: 9, duration_seconds: 44.8 }, { id: 3, timestamp: '2026-01-28T07:00:00Z', git_commit: '9ab0123', golden_score: 4.10, synthetic_score: 3.82, total_tests: 97, passed_tests: 87, failed_tests: 10, duration_seconds: 46.1 }, ] // Fetch data const fetchData = useCallback(async () => { setIsLoading(true) setError(null) try { const runsResponse = await fetch(`${BQAS_API_BASE}/runs`) if (runsResponse.ok) { const runsData = await runsResponse.json() if (runsData.runs && runsData.runs.length > 0) { setTestRuns(runsData.runs) } else { setTestRuns(DEMO_RUNS) } } else { setTestRuns(DEMO_RUNS) } const trendResponse = await fetch(`${BQAS_API_BASE}/trend?days=30`) if (trendResponse.ok) { const trend = await trendResponse.json() if (trend.dates && trend.dates.length > 0) { setTrendData(trend) } else { setTrendData(DEMO_TREND) } } else { setTrendData(DEMO_TREND) } const metricsResponse = await fetch(`${BQAS_API_BASE}/latest-metrics`) if (metricsResponse.ok) { const metrics = await metricsResponse.json() setGoldenMetrics(metrics.golden || DEMO_GOLDEN_METRICS) setSyntheticMetrics(metrics.synthetic || null) setRagMetrics(metrics.rag || null) } else { setGoldenMetrics(DEMO_GOLDEN_METRICS) } } catch (err) { console.error('Failed to fetch BQAS data, using demo data:', err) setTestRuns(DEMO_RUNS) setTrendData(DEMO_TREND) setGoldenMetrics(DEMO_GOLDEN_METRICS) } finally { setIsLoading(false) } }, []) useEffect(() => { fetchData() }, [fetchData]) // Run test suites with toast feedback const runGoldenTests = async () => { setIsRunningGolden(true) const loadingToast = addToast('loading', 'Golden Suite wird ausgefuehrt...') try { const response = await fetch(`${BQAS_API_BASE}/run/golden`, { method: 'POST', }) if (response.ok) { const result = await response.json() setGoldenMetrics(result.metrics) updateToast(loadingToast, 'success', `Golden Suite abgeschlossen: ${result.metrics?.passed_tests || 89}/${result.metrics?.total_tests || 97} bestanden`) await fetchData() } else { updateToast(loadingToast, 'info', 'Golden Suite: Demo-Modus (API nicht verfuegbar)') } } catch (err) { console.error('Failed to run golden tests:', err) updateToast(loadingToast, 'info', 'Golden Suite: Demo-Modus (API nicht verfuegbar)') } finally { setIsRunningGolden(false) } } const runSyntheticTests = async () => { setIsRunningSynthetic(true) const loadingToast = addToast('loading', 'Synthetic Tests werden generiert und ausgefuehrt...') try { const response = await fetch(`${BQAS_API_BASE}/run/synthetic`, { method: 'POST', }) if (response.ok) { const result = await response.json() setSyntheticMetrics(result.metrics) updateToast(loadingToast, 'success', 'Synthetic Tests abgeschlossen') await fetchData() } else { updateToast(loadingToast, 'info', 'Synthetic Tests: Demo-Modus (API nicht verfuegbar)') } } catch (err) { console.error('Failed to run synthetic tests:', err) updateToast(loadingToast, 'info', 'Synthetic Tests: Demo-Modus (API nicht verfuegbar)') } finally { setIsRunningSynthetic(false) } } const runRagTests = async () => { setIsRunningRag(true) const loadingToast = addToast('loading', 'RAG/Korrektur Tests werden ausgefuehrt...') try { const response = await fetch(`${BQAS_API_BASE}/run/rag`, { method: 'POST', }) if (response.ok) { const result = await response.json() setRagMetrics(result.metrics) updateToast(loadingToast, 'success', 'RAG Tests abgeschlossen') await fetchData() } else { updateToast(loadingToast, 'info', 'RAG Tests: Demo-Modus (API nicht verfuegbar)') } } catch (err) { console.error('Failed to run RAG tests:', err) updateToast(loadingToast, 'info', 'RAG Tests: Demo-Modus (API nicht verfuegbar)') } finally { setIsRunningRag(false) } } // Tab content renderer const renderTabContent = () => { switch (activeTab) { case 'overview': return (

Score-Trend (30 Tage)

{/* Quick Help */}

Neu hier? Wechseln Sie zum Tab "Anleitung" fuer eine ausfuehrliche Erklaerung des BQAS-Systems und wie Sie es nutzen koennen.

) case 'golden': return (

Golden Test Suite

Validierte Referenz-Tests gegen definierte Erwartungen

{goldenMetrics && ( <>

{goldenMetrics.total_tests}

Tests

{goldenMetrics.passed_tests}

Bestanden

{goldenMetrics.failed_tests}

Fehlgeschlagen

{goldenMetrics.avg_intent_accuracy.toFixed(0)}%

Intent Accuracy

{goldenMetrics.avg_composite_score.toFixed(2)}

Composite Score

Scores nach Intent

Fehlgeschlagene Tests ({goldenMetrics.failed_tests})

)}
) case 'rag': return (

RAG/Korrektur Test Suite

Erwartungshorizont-Retrieval, Operatoren-Alignment, Citations

{ragMetrics ? ( <>

{ragMetrics.total_tests}

Tests

{ragMetrics.avg_faithfulness.toFixed(2)}

Faithfulness

{ragMetrics.avg_relevance.toFixed(2)}

Relevance

{(ragMetrics.safety_pass_rate * 100).toFixed(0)}%

Safety Pass

RAG Kategorien

Fehlgeschlagene Tests

) : (

Noch keine RAG-Test-Ergebnisse

Klicke "Tests starten" um die RAG-Suite auszufuehren

)}

Test-Kategorien

EH Retrieval

Korrektes Abrufen von Erwartungshorizont-Passagen

Operator Alignment

Passende Operatoren fuer Abitur-Aufgaben

Hallucination Control

Keine erfundenen Fakten oder Inhalte

Citation Enforcement

Quellenangaben bei EH-Bezuegen

Privacy Compliance

Keine PII-Leaks, DSGVO-Konformitaet

Namespace Isolation

Strikte Trennung zwischen Lehrern

) case 'synthetic': return (

Synthetic Test Suite

LLM-generierte Variationen fuer Robustheit-Tests

{syntheticMetrics ? ( <>

{syntheticMetrics.total_tests}

Generierte Tests

{syntheticMetrics.passed_tests}

Bestanden

{syntheticMetrics.avg_composite_score.toFixed(2)}

Avg Score

{syntheticMetrics.avg_coherence.toFixed(2)}

Coherence

Intent-Variationen

Fehlgeschlagene Tests

) : (

Noch keine synthetischen Tests ausgefuehrt

Klicke "Tests starten" um Variationen zu generieren

)}
) case 'history': return (

Test Run Historie

) case 'guide' as TabType: return default: return null } } return (
{/* KI-Werkzeuge Sidebar */} {error && (
{error}
)}
{isLoading ? (
) : ( renderTabContent() )}
Voice Service: voice-service:8091
Scheduler (CI/CD) Compliance Audit
) }