'use client' /** * Voice Service Admin Page * * Displays: * - Voice-First Architecture Overview * - Developer Guide Content * - Live Voice Demo (embedded from studio-v2) * - Task State Machine Documentation * - DSGVO Compliance Information */ import { useState } from 'react' import AdminLayout from '@/components/admin/AdminLayout' import Link from 'next/link' type TabType = 'overview' | 'demo' | 'tasks' | 'intents' | 'dsgvo' | 'api' // Task State Machine data const TASK_STATES = [ { state: 'DRAFT', description: 'Task erstellt, noch nicht verarbeitet', color: 'bg-gray-100 text-gray-800', next: ['QUEUED', 'PAUSED'] }, { state: 'QUEUED', description: 'In Warteschlange fuer Verarbeitung', color: 'bg-blue-100 text-blue-800', next: ['RUNNING', 'PAUSED'] }, { state: 'RUNNING', description: 'Wird aktuell verarbeitet', color: 'bg-yellow-100 text-yellow-800', next: ['READY', 'PAUSED'] }, { state: 'READY', description: 'Fertig, wartet auf User-Bestaetigung', color: 'bg-green-100 text-green-800', next: ['APPROVED', 'REJECTED', 'PAUSED'] }, { state: 'APPROVED', description: 'Vom User bestaetigt', color: 'bg-emerald-100 text-emerald-800', next: ['COMPLETED'] }, { state: 'REJECTED', description: 'Vom User abgelehnt', color: 'bg-red-100 text-red-800', next: ['DRAFT'] }, { state: 'COMPLETED', description: 'Erfolgreich abgeschlossen', color: 'bg-teal-100 text-teal-800', next: [] }, { state: 'EXPIRED', description: 'TTL ueberschritten', color: 'bg-orange-100 text-orange-800', next: [] }, { state: 'PAUSED', description: 'Vom User pausiert', color: 'bg-purple-100 text-purple-800', next: ['DRAFT', 'QUEUED', 'RUNNING', 'READY'] }, ] // Intent Types (22 types organized by group) const INTENT_GROUPS = [ { group: 'Notizen', color: 'bg-blue-50 border-blue-200', intents: [ { type: 'student_observation', example: 'Notiz zu Max: heute wiederholt gestoert', description: 'Schuelerbeobachtungen' }, { type: 'reminder', example: 'Erinner mich morgen an Konferenz', description: 'Erinnerungen setzen' }, { type: 'homework_check', example: '7b Mathe Hausaufgabe kontrollieren', description: 'Hausaufgaben pruefen' }, { type: 'conference_topic', example: 'Thema Lehrerkonferenz: iPad-Regeln', description: 'Konferenzthemen' }, { type: 'correction_thought', example: 'Aufgabe 3: haeufiger Fehler erklaeren', description: 'Korrekturgedanken' }, ] }, { group: 'Content-Generierung', color: 'bg-green-50 border-green-200', intents: [ { type: 'worksheet_generate', example: 'Erstelle 3 Lueckentexte zu Vokabeln', description: 'Arbeitsblaetter erstellen' }, { type: 'quiz_generate', example: '10-Minuten Vokabeltest mit Loesungen', description: 'Quiz/Tests erstellen' }, { type: 'quick_activity', example: '10 Minuten Einstieg, 5 Aufgaben', description: 'Schnelle Aktivitaeten' }, { type: 'differentiation', example: 'Zwei Schwierigkeitsstufen: Basis und Plus', description: 'Differenzierung' }, ] }, { group: 'Kommunikation', color: 'bg-yellow-50 border-yellow-200', intents: [ { type: 'parent_letter', example: 'Neutraler Elternbrief wegen Stoerungen', description: 'Elternbriefe erstellen' }, { type: 'class_message', example: 'Nachricht an 8a: Hausaufgaben bis Mittwoch', description: 'Klassennachrichten' }, ] }, { group: 'Canvas-Editor', color: 'bg-purple-50 border-purple-200', intents: [ { type: 'canvas_edit', example: 'Ueberschriften groesser, Zeilenabstand kleiner', description: 'Formatierung aendern' }, { type: 'canvas_layout', example: 'Alles auf eine Seite, Drucklayout A4', description: 'Layout anpassen' }, { type: 'canvas_element', example: 'Kasten fuer Merke hinzufuegen', description: 'Elemente hinzufuegen' }, { type: 'canvas_image', example: 'Bild 2 nach links, Pfeil auf Aufgabe 3', description: 'Bilder positionieren' }, ] }, { group: 'RAG & Korrektur', color: 'bg-pink-50 border-pink-200', intents: [ { type: 'operator_checklist', example: 'Operatoren-Checkliste fuer diese Aufgabe', description: 'Operatoren abrufen' }, { type: 'eh_passage', example: 'Erwartungshorizont-Passage zu diesem Thema', description: 'EH-Passagen suchen' }, { type: 'feedback_suggestion', example: 'Kurze Feedbackformulierung vorschlagen', description: 'Feedback vorschlagen' }, ] }, { group: 'Follow-up (TaskOrchestrator)', color: 'bg-teal-50 border-teal-200', intents: [ { type: 'task_summary', example: 'Fasse alle offenen Tasks zusammen', description: 'Task-Uebersicht' }, { type: 'convert_note', example: 'Mach aus der Notiz von gestern einen Elternbrief', description: 'Notizen konvertieren' }, { type: 'schedule_reminder', example: 'Erinner mich morgen an das Gespraech mit Max', description: 'Erinnerungen planen' }, ] }, ] // DSGVO Data Categories const DSGVO_CATEGORIES = [ { category: 'Audio', processing: 'NUR transient im RAM, NIEMALS persistiert', storage: 'Keine', ttl: '-', icon: '🎤', risk: 'low' }, { category: 'PII (Schuelernamen)', processing: 'NUR auf Lehrergeraet', storage: 'Client-side', ttl: '-', icon: '👤', risk: 'high' }, { category: 'Pseudonyme', processing: 'Server erlaubt (student_ref, class_ref)', storage: 'Valkey Cache', ttl: '24h', icon: '🔢', risk: 'low' }, { category: 'Transkripte', processing: 'NUR verschluesselt (AES-256-GCM)', storage: 'PostgreSQL', ttl: '7 Tage', icon: '📝', risk: 'medium' }, { category: 'Task States', processing: 'TaskOrchestrator', storage: 'Valkey', ttl: '30 Tage', icon: '📋', risk: 'low' }, { category: 'Audit Logs', processing: 'Nur truncated IDs, keine PII', storage: 'PostgreSQL', ttl: '90 Tage', icon: '📊', risk: 'low' }, ] // API Endpoints const API_ENDPOINTS = [ { method: 'POST', path: '/api/v1/sessions', description: 'Voice Session erstellen' }, { method: 'GET', path: '/api/v1/sessions/{id}', description: 'Session Status abrufen' }, { method: 'DELETE', path: '/api/v1/sessions/{id}', description: 'Session beenden' }, { method: 'GET', path: '/api/v1/sessions/{id}/tasks', description: 'Pending Tasks abrufen' }, { method: 'POST', path: '/api/v1/tasks', description: 'Task erstellen' }, { method: 'GET', path: '/api/v1/tasks/{id}', description: 'Task Status abrufen' }, { method: 'PUT', path: '/api/v1/tasks/{id}/transition', description: 'Task State aendern' }, { method: 'DELETE', path: '/api/v1/tasks/{id}', description: 'Task loeschen' }, { method: 'WS', path: '/ws/voice', description: 'Voice Streaming (WebSocket)' }, { method: 'GET', path: '/health', description: 'Health Check' }, ] export default function VoicePage() { const [activeTab, setActiveTab] = useState('overview') const [demoLoaded, setDemoLoaded] = useState(false) const tabs = [ { id: 'overview', name: 'Architektur', icon: '🏗️' }, { id: 'demo', name: 'Live Demo', icon: '🎤' }, { id: 'tasks', name: 'Task States', icon: '📋' }, { id: 'intents', name: 'Intents (22)', icon: '🎯' }, { id: 'dsgvo', name: 'DSGVO', icon: '🔒' }, { id: 'api', name: 'API', icon: '🔌' }, ] return ( {/* Quick Links */}
Voice Test (Studio) Health Check Developer Docs
{/* Stats Overview */}
8091
Port
22
Task Types
9
Task States
24kHz
Audio Rate
80ms
Frame Size
0
Audio Persist
{/* Tabs */}
{tabs.map((tab) => ( ))}
{/* Overview Tab */} {activeTab === 'overview' && (

Voice-First Architektur

{/* Architecture Diagram */}
{`
┌──────────────────────────────────────────────────────────────────┐
│                    LEHRERGERAET (PWA / App)                       │
│  ┌────────────────────────────────────────────────────────────┐  │
│  │ VoiceCapture.tsx │ voice-encryption.ts │ voice-api.ts      │  │
│  │ Mikrofon         │ AES-256-GCM         │ WebSocket Client  │  │
│  └────────────────────────────────────────────────────────────┘  │
└───────────────────────────┬──────────────────────────────────────┘
                            │ WebSocket (wss://)
                            ▼
┌──────────────────────────────────────────────────────────────────┐
│                    VOICE SERVICE (Port 8091)                      │
│  ┌────────────────────────────────────────────────────────────┐  │
│  │ main.py │ streaming.py │ sessions.py │ tasks.py            │  │
│  └────────────────────────────────────────────────────────────┘  │
│  ┌────────────────────────────────────────────────────────────┐  │
│  │ task_orchestrator.py │ intent_router.py │ encryption        │  │
│  └────────────────────────────────────────────────────────────┘  │
└───────────────────────────┬──────────────────────────────────────┘
                            │
         ┌──────────────────┼──────────────────┐
         ▼                  ▼                  ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ PersonaPlex-7B  │ │ Ollama Fallback │ │ Valkey Cache    │
│ (A100 GPU)      │ │ (Mac Mini)      │ │ (Sessions)      │
└─────────────────┘ └─────────────────┘ └─────────────────┘
`}
{/* Technology Stack */}

Voice Model (Produktion)

PersonaPlex-7B (NVIDIA)

Full-Duplex Speech-to-Speech

Lizenz: MIT + NVIDIA Open Model

Agent Orchestration

TaskOrchestrator

Task State Machine

Lizenz: Proprietary

Audio Codec

Mimi (24kHz, 80ms)

Low-Latency Streaming

Lizenz: MIT

{/* Key Files */}

Wichtige Dateien

Datei Beschreibung
voice-service/main.pyFastAPI Entry, WebSocket Handler
voice-service/services/task_orchestrator.pyTask State Machine
voice-service/services/intent_router.pyIntent Detection (22 Types)
voice-service/services/encryption_service.pyNamespace Key Management
studio-v2/components/voice/VoiceCapture.tsxFrontend Mikrofon + Crypto
studio-v2/lib/voice/voice-encryption.tsAES-256-GCM Client-side
)} {/* Demo Tab */} {activeTab === 'demo' && (

Live Voice Demo

In neuem Tab oeffnen

Hinweis: Die Demo erfordert, dass der Voice Service (Port 8091) und das Studio-v2 Frontend (Port 3001) laufen.

docker compose up -d voice-service && cd studio-v2 && npm run dev
{/* Embedded Demo */}
{!demoLoaded && (
)} {demoLoaded && (