12 KiB
CommCoach Voice Recording Streaming Konzept
Ausgangslage
Die aktuelle CommCoach-Spracheingabe basiert auf Browser SpeechRecognition (webkitSpeechRecognition).
Auf Mobile-Browsern wird die Aufnahme typischerweise alle ca. 5-7 Sekunden automatisch beendet und neu gestartet.
Das ist kein sauber behebbarer App-Bug, sondern eine Browser/API-Limitation.
Zielbild
Die Spracheingabe soll auf Mobile und Desktop stabil laufen, ohne erzwungene 5-Sekunden-Resets, ohne Textverlust zwischen Restart-Gaps und ohne MSFT-Abhängigkeiten.
Antwort auf die Kernfragen
1) Ist Option 3 ein genereller Umbau oder nur Mobile?
Beides ist möglich:
- Variante A (Mobile-only Umbau): Neue Audio-Streaming-Pipeline nur auf Mobile aktivieren, Desktop bleibt vorerst bei Browser STT.
- Variante B (Genereller Umbau): Neue Pipeline für alle Clients (Mobile + Desktop), einheitliches Verhalten und weniger Wartung.
Empfehlung: Variante B, da nur ein Stack gepflegt werden muss und CommCoach-Logik konsistent bleibt.
2) Kann das komplett in unserer Plattform umgesetzt werden?
Ja. Vollständig in eigener Plattform ist möglich.
Notwendig sind:
- Eigene UI- und Gateway-Implementierung (WebSocket Streaming)
- Eigener STT-Service (self-hosted), z. B.
faster-whisper - Optional eigene VAD (Voice Activity Detection), z. B.
webrtcvad
Nicht zwingend notwendig:
- Externe SaaS-STT Provider
- MSFT/Azure Speech
Zielarchitektur (MSFT-frei)
UI (Frontend CommCoach)
- Mikrofonaufnahme via
MediaStream+AudioWorkletoderMediaRecorder - Chunking (z. B. 100-250 ms)
- Streaming per WebSocket an Gateway
- Lokaler Live-Preview-Text kommt nicht mehr aus Browser-STT, sondern aus Server-Interims
- Bestehende State-Machine bleibt als Steuerlogik erhalten (
idle,listening,botSpeaking,interrupted,mutedorthogonal)
Gateway
- Neuer Endpoint, z. B.
ws /api/feature/commcoach/{instanceId}/stt/stream - Sessiongebundene Stream-Verarbeitung
- Weiterleitung der Audio-Chunks an STT-Worker
- Rückkanal von Interims + Final-Text zum UI
- Serverseitige Segmentierung (Silence / VAD) statt Browser
onend
STT-Service (self-hosted)
faster-whisperals Runtime (GPU empfohlen, CPU möglich)- Sprachen konfigurierbar (z. B.
de,en) - Ausgabe:
interimEvents (optional, je nach Latenzbudget)finalSegmente- Zeitmarken für Debug und Nachvollziehbarkeit
Optional: VAD-Service
- Entweder im Gateway oder STT-Worker
- Trigger für Segment-Ende statt fester 1s-Timer
- Stabiler als browserseitige
onspeechstart/onspeechend
Ist-Analyse der bestehenden Codebase (UI + Gateway)
Frontend (frontend_nyla)
-
src/pages/views/commcoach/useVoiceController.ts- Nutzt Browser
SpeechRecognitiondirekt. - Auto-Restart bei
onendmitREC_AUTORESTART_DELAY_MS = 300. SILENCE_TIMEOUT_MS = 1000finalisiert User-Text.- Mobile-Problem entsteht hier durch Browser-
onend-Zwang (alle ~5-7s).
- Nutzt Browser
-
src/pages/views/commcoach/CommcoachDossierView.tsx- Bindet Voice-State-Machine an UI/TTS.
voice.liveTranscriptwird als Live-User-Bubble angezeigt.- Debuglog existiert bereits via
window.__dlog.
-
src/hooks/useCommcoach.ts- Text läuft über
sendMessageStreamApi(SSE). - Audio läuft derzeit nur als One-Shot Blob über
sendAudioStreamApi(SSE). - Kein echtes bidirektionales Low-Latency Audio-Streaming.
- Text läuft über
-
src/api/commcoachApi.ts- Bestehende Endpunkte sind HTTP + SSE.
- Es gibt noch keinen WebSocket-Endpunkt für chunkweises Audio.
Gateway (gateway)
-
modules/features/commcoach/routeFeatureCommcoach.pyPOST .../message/stream(SSE) für Text.POST .../audio/stream(SSE) für Audio-One-Shot.- Audio-Endpoint liest
await request.body()komplett und startet danach STT.
-
modules/features/commcoach/serviceCommcoach.pyprocessAudioMessage(...): STT auf gesamtem Blob, danachprocessMessage(...).- Keine Segment-/Chunk-Logik für laufende Erkennung.
-
modules/interfaces/interfaceVoiceObjects.py- Kapselt STT/TTS aktuell über Google Connector.
- API ist bereits zentralisiert und damit gut erweiterbar.
-
modules/connectors/connectorVoiceGoogle.py- Verwendet
recognizeauf Einzeldateien (nicht Streaming). - Damit strukturell ungeeignet für kontinuierliche Mobile-Spracheingabe.
- Verwendet
Implementierung im bestehenden System (konkret)
Ziel: bestehende CommCoach-Pipeline beibehalten, nur STT-Eingang ersetzen
Unverändert bleiben:
- Session- und Message-Processing in
serviceCommcoach.py(processMessage, Events, TTS). - UI-State-Machine-Fachlogik (
idle,listening,botSpeaking,interrupted,muted).
Ersetzt wird:
- Browser-STT (
SpeechRecognition) durch Streaming-STT Provider. - One-Shot Audio-Upload durch WebSocket-Audio-Stream.
A) Frontend Änderungen
-
Neue API-Funktion in
src/api/commcoachApi.tsopenSttStreamApi(instanceId, sessionId, handlers, options)via WebSocket.- Handler:
onStatus,onInterim,onFinal,onError,onClose.
-
Neues Hook
src/hooks/useAudioStreamTranscription.ts- Mikrofon aufnehmen (
MediaStream+AudioWorkletoderMediaRecorder). - Audio in 100-250ms Chunks an WS senden.
- Event-Rückkanal verarbeiten (interim/final/status/error).
- Reconnect-Mechanismus für Mobile-Netzwechsel.
- Mikrofon aufnehmen (
-
src/pages/views/commcoach/useVoiceController.tsrefactor- Provider-Interface einführen:
browserSpeech(legacy)streamedStt(neu)
transcriptPartsRefundliveTranscriptaus Serverevents speisen.SILENCE_TIMEOUT_MSnur noch als optionales Guard-Rail, nicht als Kernsegmentierung.
- Provider-Interface einführen:
-
src/pages/views/commcoach/CommcoachDossierView.tsx- Keine Verhaltensänderung in Tabs/State nötig.
- Nur Provider initialisieren und vorhandene Debuganzeige um STT-WS Events erweitern.
B) Gateway Änderungen
-
Neue WS-Route in
modules/features/commcoach/routeFeatureCommcoach.py- Beispiel:
ws /api/commcoach/{instanceId}/sessions/{sessionId}/stt/stream - Ownership-/Session-Checks analog zu
message/stream. - WebSocket akzeptieren, Audio-Chunks entgegennehmen, Events zurücksenden.
- Beispiel:
-
Neuer Service
modules/features/commcoach/serviceCommcoachSttStream.py- Sessiongebundene Streamverwaltung.
- Chunk-Buffer, VAD/Silence-Regeln, Segmentbildung.
- Für jedes finale Segment:
processMessage(sessionId, contextId, finalText, interface)aufrufen.
-
Anpassung
modules/features/commcoach/serviceCommcoach.pyprocessAudioMessagebleibt für Legacy/Upload kompatibel.- Neue Streaming-Nutzung erfolgt über den neuen STT-Stream-Service.
-
Erweiterung
modules/interfaces/interfaceVoiceObjects.py- Neue Methoden ergänzen:
startSttStream(...)pushSttAudioChunk(...)stopSttStream(...)
- Bestehende Methoden (
speechToText,textToSpeech) unverändert lassen.
- Neue Methoden ergänzen:
C) STT Worker (self-hosted)
-
Neuer Connector (z. B.)
modules/connectors/connectorVoiceWhisper.pyfaster-whisperIntegration.- Modell, Sprache, VAD-Parameter konfigurierbar.
-
Optional separater Worker-Prozess
- Entkoppelt Gateway-Latenz von STT-Rechenlast.
- Kommunikation intern über Queue/IPC oder internen WS.
WS Event Contract (verbindlich)
Client -> Server
open{ "type": "open", "sessionId": "...", "language": "de-DE", "codec": "pcm16" }
audio{ "type": "audio", "seq": 123, "chunk": "<base64>" }
commit{ "type": "commit", "reason": "silence|manual|stateChange" }
close{ "type": "close" }
Server -> Client
status{ "type": "status", "label": "Sprache wird erkannt..." }
interim{ "type": "interim", "text": "...", "segmentId": "..." }
final{ "type": "final", "text": "...", "segmentId": "...", "confidence": 0.0 }
ack{ "type": "ack", "seq": 123 }
error{ "type": "error", "code": "stt_failed", "message": "..." }
closed{ "type": "closed", "reason": "client|server|timeout" }
Migrationsstrategie (ohne doppelte Logikfalle)
-
Feature-Flag
commcoachVoiceProviderauf Instanzebene- Werte:
browserSpeech|streamedStt.
- Werte:
-
Rolloutpfad
- Schritt 1: intern auf Mobile aktivieren.
- Schritt 2: nach Stabilisierung global aktivieren.
- Schritt 3: Browser-STT-Code entfernen.
-
Expliziter Fehlerpfad
- Kein stiller Fallback auf Browser-STT, wenn
streamedSttaktiv ist. - Fehler wird sichtbar im UI (Banner + Debuglog).
- Kein stiller Fallback auf Browser-STT, wenn
Konkrete Taskliste pro Repository
Repo frontend_nyla
commcoachApi.ts:openSttStreamApiergänzen.- Neues Hook
useAudioStreamTranscription.tsimplementieren. useVoiceController.ts: Provider-Abstraktion + streamed Provider integrieren.CommcoachDossierView.tsx: Provider-Init + Debug-Events anzeigen.- Tests:
- unit: Segment-Assembler
- integration: state transitions bei interim/final/error
Repo gateway
- WS-Route für STT-Stream in
routeFeatureCommcoach.py. - Neuer Stream-Service
serviceCommcoachSttStream.py. interfaceVoiceObjects.pyum Streaming-Methoden erweitern.- Neuer Whisper-Connector
connectorVoiceWhisper.py. - Telemetrie + Logs:
- stream open/close
- first interim latency
- first final latency
- reconnect count
Variante A vs. Variante B
| Kriterium | Variante A: Nur Mobile | Variante B: Alle Plattformen |
|---|---|---|
| Time-to-first-fix | schneller | mittel |
| Komplexität gesamt | höher langfristig (2 Stacks) | niedriger langfristig (1 Stack) |
| UX-Konsistenz | unterschiedlich je Device | einheitlich |
| Wartung | doppelt | einfach |
| Risiko | mittelhoch (Divergenz) | mittel (einmaliger Umbau) |
Empfehlung: Variante B.
Implementierungsplan
Phase 1: Infrastruktur und Prototyp
- STT-Worker als eigener Service im Gateway-Umfeld bereitstellen
- Streaming-Protokoll definieren (Events:
audio,interim,final,status,error,close) - WS-Route im Gateway für CommCoach implementieren
- Test-Client mit Beispielaudio aufbauen (ohne UI) zur Last-/Latenzprüfung
Phase 2: Frontend Integration
- Neues Modul
useAudioStreamTranscriptioneinführen useVoiceControllerauf Provider-Abstraktion umstellen:- Provider
browserSpeech(bestehend) - Provider
streamedStt(neu)
- Provider
- Transcript-Handling auf Serverevents umstellen:
- Interim in
liveTranscript - Final in
transcriptParts
- Interim in
- State-Transitions unverändert belassen, nur STT-Quelle ersetzen
Phase 3: Segmentierung und Qualität
- Serverseitige VAD aktivieren
- Segment-Ende sauber in
onMessageüberführen - Doppelungen/Fragmentverluste mit Session-IDs und Segment-Counter verhindern
- Mobile Netzwechsel/WS-Reconnect robust behandeln
Phase 4: Rollout
- Feature-Flag: zuerst intern, dann Pilotmandanten
- Optionale Stufen:
- Stufe 1: Nur Mobile
- Stufe 2: Alle Plattformen
- Browser-STT nach Stabilitätsphase vollständig entfernen
Technische Leitplanken
- Keine stillen Fallbacks, die Fehler verdecken
- Explizite Fehlerzustände im UI (Mikrofon, Netzwerk, STT nicht verfügbar)
- Klares Telemetrie-Set:
- Time to first interim
- Time to first final
- Segment-Länge
- Abbruchgründe
- WS-Reconnect-Rate
Drittkomponenten
Minimal erforderlich
- Python Packages (self-hosted):
faster-whisper- optional
webrtcvad - Audio-Decode (
ffmpegLaufzeit)
Nicht erforderlich
- MSFT/Azure Speech
- Externe STT-SaaS
Risiken und Gegenmassnahmen
- GPU-Kapazität fehlt: zunächst kleines Modell und Queueing, später GPU-Skalierung
- Latenz zu hoch: Chunk-Grösse reduzieren, VAD feinjustieren, Modellwahl anpassen
- Mobile Netz instabil: robustes Reconnect-Handling + Segment-ACKs
- Drift zwischen UI und Backend: eindeutige Stream-/Segment-IDs und Idempotenzregeln
Fazit
Der Umbau ist vollständig in der eigenen Plattform machbar und löst das Mobile-5-Sekunden-Problem an der Wurzel. Für Wartbarkeit und konsistentes Verhalten ist ein genereller Umbau (Variante B) sinnvoll. Ein stufenweiser Rollout mit Feature-Flag minimiert Risiko.