661 lines
20 KiB
Markdown
661 lines
20 KiB
Markdown
# 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` + `AudioWorklet` oder `MediaRecorder`
|
|
- 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`, `muted` orthogonal)
|
|
|
|
### 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-whisper` als Runtime (GPU empfohlen, CPU möglich)
|
|
- Sprachen konfigurierbar (z. B. `de`, `en`)
|
|
- Ausgabe:
|
|
- `interim` Events (optional, je nach Latenzbudget)
|
|
- `final` Segmente
|
|
- 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 `SpeechRecognition` direkt.
|
|
- Auto-Restart bei `onend` mit `REC_AUTORESTART_DELAY_MS = 300`.
|
|
- `SILENCE_TIMEOUT_MS = 1000` finalisiert User-Text.
|
|
- Mobile-Problem entsteht hier durch Browser-`onend`-Zwang (alle ~5-7s).
|
|
|
|
- `src/pages/views/commcoach/CommcoachDossierView.tsx`
|
|
- Bindet Voice-State-Machine an UI/TTS.
|
|
- `voice.liveTranscript` wird 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.
|
|
|
|
- `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.py`
|
|
- `POST .../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.py`
|
|
- `processAudioMessage(...)`: STT auf gesamtem Blob, danach `processMessage(...)`.
|
|
- 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 `recognize` auf Einzeldateien (nicht Streaming).
|
|
- Damit strukturell ungeeignet für kontinuierliche Mobile-Spracheingabe.
|
|
|
|
## 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
|
|
|
|
1. Neue API-Funktion in `src/api/commcoachApi.ts`
|
|
- `openSttStreamApi(instanceId, sessionId, handlers, options)` via WebSocket.
|
|
- Handler: `onStatus`, `onInterim`, `onFinal`, `onError`, `onClose`.
|
|
|
|
2. Neues Hook `src/hooks/useAudioStreamTranscription.ts`
|
|
- Mikrofon aufnehmen (`MediaStream` + `AudioWorklet` oder `MediaRecorder`).
|
|
- Audio in 100-250ms Chunks an WS senden.
|
|
- Event-Rückkanal verarbeiten (interim/final/status/error).
|
|
- Reconnect-Mechanismus für Mobile-Netzwechsel.
|
|
|
|
3. `src/pages/views/commcoach/useVoiceController.ts` refactor
|
|
- Provider-Interface einführen:
|
|
- `browserSpeech` (legacy)
|
|
- `streamedStt` (neu)
|
|
- `transcriptPartsRef` und `liveTranscript` aus Serverevents speisen.
|
|
- `SILENCE_TIMEOUT_MS` nur noch als optionales Guard-Rail, nicht als Kernsegmentierung.
|
|
|
|
4. `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
|
|
|
|
1. 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.
|
|
|
|
2. 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.
|
|
|
|
3. Anpassung `modules/features/commcoach/serviceCommcoach.py`
|
|
- `processAudioMessage` bleibt für Legacy/Upload kompatibel.
|
|
- Neue Streaming-Nutzung erfolgt über den neuen STT-Stream-Service.
|
|
|
|
4. Erweiterung `modules/interfaces/interfaceVoiceObjects.py`
|
|
- Neue Methoden ergänzen:
|
|
- `startSttStream(...)`
|
|
- `pushSttAudioChunk(...)`
|
|
- `stopSttStream(...)`
|
|
- Bestehende Methoden (`speechToText`, `textToSpeech`) unverändert lassen.
|
|
|
|
### C) STT Worker (self-hosted)
|
|
|
|
1. Neuer Connector (z. B.) `modules/connectors/connectorVoiceWhisper.py`
|
|
- `faster-whisper` Integration.
|
|
- Modell, Sprache, VAD-Parameter konfigurierbar.
|
|
|
|
2. 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)
|
|
|
|
1. Feature-Flag `commcoachVoiceProvider` auf Instanzebene
|
|
- Werte: `browserSpeech` | `streamedStt`.
|
|
|
|
2. Rolloutpfad
|
|
- Schritt 1: intern auf Mobile aktivieren.
|
|
- Schritt 2: nach Stabilisierung global aktivieren.
|
|
- Schritt 3: Browser-STT-Code entfernen.
|
|
|
|
3. Expliziter Fehlerpfad
|
|
- Kein stiller Fallback auf Browser-STT, wenn `streamedStt` aktiv ist.
|
|
- Fehler wird sichtbar im UI (Banner + Debuglog).
|
|
|
|
## Konkrete Taskliste pro Repository
|
|
|
|
### Repo `frontend_nyla`
|
|
|
|
1. `commcoachApi.ts`: `openSttStreamApi` ergänzen.
|
|
2. Neues Hook `useAudioStreamTranscription.ts` implementieren.
|
|
3. `useVoiceController.ts`: Provider-Abstraktion + streamed Provider integrieren.
|
|
4. `CommcoachDossierView.tsx`: Provider-Init + Debug-Events anzeigen.
|
|
5. Tests:
|
|
- unit: Segment-Assembler
|
|
- integration: state transitions bei interim/final/error
|
|
|
|
### Repo `gateway`
|
|
|
|
1. WS-Route für STT-Stream in `routeFeatureCommcoach.py`.
|
|
2. Neuer Stream-Service `serviceCommcoachSttStream.py`.
|
|
3. `interfaceVoiceObjects.py` um Streaming-Methoden erweitern.
|
|
4. Neuer Whisper-Connector `connectorVoiceWhisper.py`.
|
|
5. 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
|
|
|
|
1. STT-Worker als eigener Service im Gateway-Umfeld bereitstellen
|
|
2. Streaming-Protokoll definieren (Events: `audio`, `interim`, `final`, `status`, `error`, `close`)
|
|
3. WS-Route im Gateway für CommCoach implementieren
|
|
4. Test-Client mit Beispielaudio aufbauen (ohne UI) zur Last-/Latenzprüfung
|
|
|
|
### Phase 2: Frontend Integration
|
|
|
|
1. Neues Modul `useAudioStreamTranscription` einführen
|
|
2. `useVoiceController` auf Provider-Abstraktion umstellen:
|
|
- Provider `browserSpeech` (bestehend)
|
|
- Provider `streamedStt` (neu)
|
|
3. Transcript-Handling auf Serverevents umstellen:
|
|
- Interim in `liveTranscript`
|
|
- Final in `transcriptParts`
|
|
4. State-Transitions unverändert belassen, nur STT-Quelle ersetzen
|
|
|
|
### Phase 3: Segmentierung und Qualität
|
|
|
|
1. Serverseitige VAD aktivieren
|
|
2. Segment-Ende sauber in `onMessage` überführen
|
|
3. Doppelungen/Fragmentverluste mit Session-IDs und Segment-Counter verhindern
|
|
4. Mobile Netzwechsel/WS-Reconnect robust behandeln
|
|
|
|
### Phase 4: Rollout
|
|
|
|
1. Feature-Flag: zuerst intern, dann Pilotmandanten
|
|
2. Optionale Stufen:
|
|
- Stufe 1: Nur Mobile
|
|
- Stufe 2: Alle Plattformen
|
|
3. 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 (`ffmpeg` Laufzeit)
|
|
|
|
### 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.
|
|
|
|
---
|
|
|
|
## Implementierungsfreigabe (Ready for Build)
|
|
|
|
Dieser Abschnitt ist die verbindliche Umsetzungsvorlage.
|
|
|
|
### Verbindliche Entscheidungen
|
|
|
|
1. **Scope**
|
|
- Umsetzung als **Variante B** (ein Stack fuer Mobile + Desktop).
|
|
|
|
2. **Transport**
|
|
- STT-Eingang erfolgt ueber **WebSocket**.
|
|
- Text-/Assistant-Antworten bleiben vorerst auf bestehendem **SSE**-Pfad.
|
|
|
|
3. **STT-Engine**
|
|
- Self-hosted Whisper-Pfad (`faster-whisper`) wird als neue Connector-Linie eingefuehrt.
|
|
- Bestehender Google-One-Shot-Pfad bleibt nur als Legacy fuer `audio/stream`.
|
|
|
|
4. **Fehlerbehandlung**
|
|
- Keine stillen Fallbacks.
|
|
- Bei aktivem `streamedStt` wird ein STT-Fehler sichtbar ins UI gemeldet.
|
|
|
|
5. **Feature Flag**
|
|
- `commcoachVoiceProvider = browserSpeech | streamedStt`.
|
|
- Default initial: `browserSpeech`, Pilot: `streamedStt`.
|
|
|
|
### Verbindliche API Spezifikation
|
|
|
|
#### WS Endpoint
|
|
|
|
- `GET ws /api/commcoach/{instanceId}/sessions/{sessionId}/stt/stream`
|
|
|
|
#### Client -> Server Nachrichten
|
|
|
|
1. `open`
|
|
```json
|
|
{
|
|
"type": "open",
|
|
"sessionId": "string",
|
|
"language": "de-DE",
|
|
"codec": "pcm16",
|
|
"sampleRate": 16000,
|
|
"channels": 1
|
|
}
|
|
```
|
|
|
|
2. `audio`
|
|
```json
|
|
{
|
|
"type": "audio",
|
|
"seq": 1,
|
|
"chunk": "base64-encoded-audio-bytes",
|
|
"durationMs": 200
|
|
}
|
|
```
|
|
|
|
3. `commit`
|
|
```json
|
|
{
|
|
"type": "commit",
|
|
"reason": "silence"
|
|
}
|
|
```
|
|
|
|
4. `close`
|
|
```json
|
|
{
|
|
"type": "close"
|
|
}
|
|
```
|
|
|
|
#### Server -> Client Nachrichten
|
|
|
|
1. `status`
|
|
```json
|
|
{
|
|
"type": "status",
|
|
"label": "Sprache wird erkannt..."
|
|
}
|
|
```
|
|
|
|
2. `ack`
|
|
```json
|
|
{
|
|
"type": "ack",
|
|
"seq": 1
|
|
}
|
|
```
|
|
|
|
3. `interim`
|
|
```json
|
|
{
|
|
"type": "interim",
|
|
"segmentId": "seg-uuid",
|
|
"text": "teiltranskript"
|
|
}
|
|
```
|
|
|
|
4. `final`
|
|
```json
|
|
{
|
|
"type": "final",
|
|
"segmentId": "seg-uuid",
|
|
"text": "finales segment",
|
|
"confidence": 0.91
|
|
}
|
|
```
|
|
|
|
5. `error`
|
|
```json
|
|
{
|
|
"type": "error",
|
|
"code": "stt_failed",
|
|
"message": "Transkription fehlgeschlagen"
|
|
}
|
|
```
|
|
|
|
6. `closed`
|
|
```json
|
|
{
|
|
"type": "closed",
|
|
"reason": "server"
|
|
}
|
|
```
|
|
|
|
### Orchestrierungsregeln (verbindlich)
|
|
|
|
1. `useVoiceController` bleibt Owner der Zustandsmaschine.
|
|
2. `streamedStt` liefert nur Transkript-Ereignisse, steuert keine State-Transitions direkt.
|
|
3. Nur `final` Texte duerfen `onMessage(...)` triggern.
|
|
4. `interim` aktualisiert nur `liveTranscript`.
|
|
5. Bei `ttsPlaying` wird STT-Stream pausiert/geschlossen.
|
|
6. Bei `ttsEnded` wird STT-Stream wieder geoeffnet.
|
|
7. `muted=true` blockiert Senden von `audio` Chunks.
|
|
|
|
### Konkrete Datei- und Funktionsaenderungen
|
|
|
|
#### Frontend `frontend_nyla`
|
|
|
|
1. `src/api/commcoachApi.ts`
|
|
- Neue Funktion `openSttStreamApi(instanceId, sessionId, handlers, options)`.
|
|
- Rueckgabeobjekt mit `sendAudioChunk`, `sendCommit`, `close`.
|
|
|
|
2. `src/hooks/useAudioStreamTranscription.ts` (neu)
|
|
- Intern:
|
|
- `_startMicCapture()`
|
|
- `_stopMicCapture()`
|
|
- `_encodePcm16Chunk()`
|
|
- `_pushChunkToWs()`
|
|
- Extern:
|
|
- `startStream()`
|
|
- `stopStream()`
|
|
- `commitSegment(reason)`
|
|
|
|
3. `src/pages/views/commcoach/useVoiceController.ts`
|
|
- Provider-Layer einfuegen:
|
|
- `browserSpeechProvider`
|
|
- `streamedSttProvider`
|
|
- `streamedSttProvider` auf neues Hook mappen.
|
|
- Bestehende State-Transitionen unveraendert lassen.
|
|
|
|
4. `src/pages/views/commcoach/CommcoachDossierView.tsx`
|
|
- Debugpanel um STT-WS Events erweitern (`STT-OPEN`, `STT-INTERIM`, `STT-FINAL`, `STT-ERR`, `STT-CLOSE`).
|
|
|
|
#### Gateway `gateway`
|
|
|
|
1. `modules/features/commcoach/routeFeatureCommcoach.py`
|
|
- Neue WS-Route `.../stt/stream`.
|
|
- Auth/Ownership-Pruefung identisch zu bestehenden Session-Endpunkten.
|
|
|
|
2. `modules/features/commcoach/serviceCommcoachSttStream.py` (neu)
|
|
- Session-Stream-Manager:
|
|
- `_openSessionStream()`
|
|
- `_handleAudioChunk()`
|
|
- `_flushSegment()`
|
|
- `_closeSessionStream()`
|
|
- Final-Segmente an `CommcoachService.processMessage(...)` uebergeben.
|
|
|
|
3. `modules/interfaces/interfaceVoiceObjects.py`
|
|
- Streaming API erweitern:
|
|
- `startSttStream(...)`
|
|
- `pushSttAudioChunk(...)`
|
|
- `finalizeSttSegment(...)`
|
|
- `stopSttStream(...)`
|
|
|
|
4. `modules/connectors/connectorVoiceWhisper.py` (neu)
|
|
- Whisper-basierte Implementierung fuer Streaming-Segmente.
|
|
- Config fuer Modellgroesse, Sprache, VAD.
|
|
|
|
### Reihenfolge fuer die Umsetzung
|
|
|
|
1. Gateway WS Route + Dummy-Events (ohne echte STT).
|
|
2. Frontend WS Client + Mikrofondaten senden.
|
|
3. Connector/Whisper Integration im Gateway.
|
|
4. Segmentierung und `final -> processMessage`.
|
|
5. Feature-Flag Integration und Pilot-Rollout.
|
|
6. Legacy-Bereinigung.
|
|
|
|
### Abnahmekriterien (Definition of Done)
|
|
|
|
1. **Mobile Stabilitaet**
|
|
- 60 Sekunden durchgehendes Sprechen ohne erzwungenen 5-Sekunden-Reset.
|
|
|
|
2. **Textintegritaet**
|
|
- Keine abgeschnittenen Saetze zwischen Segmenten.
|
|
- Keine Duplikate bei finalen Segmenten.
|
|
|
|
3. **State Machine Integritaet**
|
|
- Keine User-Transkripte waehrend `botSpeaking`.
|
|
- `muted` blockiert Audio-Chunks sofort.
|
|
|
|
4. **Fehlertransparenz**
|
|
- STT- oder WS-Fehler werden im UI sichtbar angezeigt.
|
|
- Kein stiller Fallback auf Browser-STT im `streamedStt` Modus.
|
|
|
|
5. **Performance**
|
|
- Time to first interim <= 1200 ms (WLAN Referenz).
|
|
- Time to first final <= 2500 ms fuer kurze Saetze.
|
|
|
|
### Testplan (verbindlich)
|
|
|
|
1. Unit Tests
|
|
- Segment-Assembler und Seq-Handling.
|
|
- State Transition Tests fuer `ttsPlaying`, `ttsEnded`, `muted`.
|
|
|
|
2. Integration Tests
|
|
- WS Open -> Audio -> Interim -> Final -> Close.
|
|
- Reconnect nach Netzunterbruch.
|
|
|
|
3. Manuelle Geraetetests
|
|
- iOS Safari (aktuell + 1 Vorversion).
|
|
- Android Chrome (aktuell + 1 Vorversion).
|
|
- Desktop Chrome/Edge.
|
|
|
|
4. Regression
|
|
- Bestehende Text-SSE Flows unveraendert funktionsfaehig.
|
|
- TTS Wiedergabe und Stop/Resume weiterhin stabil.
|
|
|
|
### Rollout und Backout
|
|
|
|
1. Rollout
|
|
- Feature-Flag pilotweise pro Instanz aktivieren.
|
|
- Metriken mindestens 3 Tage beobachten.
|
|
|
|
2. Backout
|
|
- Bei kritischen Fehlern Flag auf `browserSpeech` zuruecksetzen.
|
|
- Keine DB-Migrationen erforderlich.
|
|
|
|
### Aufwandsschaetzung
|
|
|
|
- Gateway WS + Stream Service: 2-3 Tage
|
|
- Whisper Connector + Tuning: 2-4 Tage
|
|
- Frontend Hook + Provider Refactor: 2-3 Tage
|
|
- Tests + Pilot-Hardening: 2-3 Tage
|
|
|
|
Gesamt: **8-13 Arbeitstage** fuer produktionsreife Erstversion.
|
|
|
|
## Reuse Snippet (AI Workspace und weitere Views)
|
|
|
|
Der Hook `useSpeechAudioCapture` ist generisch und kann ausserhalb von CommCoach wiederverwendet werden.
|
|
Er kapselt Mikrofonzugriff, VAD, Segmentierung und Chunk-Emission.
|
|
|
|
Beispielintegration in einer anderen View:
|
|
|
|
```tsx
|
|
import React, { useState } from 'react';
|
|
import { useSpeechAudioCapture } from '../../hooks/useSpeechAudioCapture';
|
|
|
|
export default function WorkspaceVoiceInput() {
|
|
const [isMicActive, setIsMicActive] = useState(false);
|
|
const [isMuted, setIsMuted] = useState(false);
|
|
|
|
const speech = useSpeechAudioCapture(
|
|
{
|
|
// Controller-Bedingung: nur aufnehmen wenn aktiv und nicht stumm
|
|
isCaptureAllowed: () => isMicActive && !isMuted,
|
|
|
|
// Laufende Audio-Chunks an den eigenen Stream senden
|
|
onChunk: async (audioChunk) => {
|
|
await wsSendChunk(audioChunk); // eigene WS/API Implementierung
|
|
},
|
|
|
|
// Segmentabschluss bei Stille oder manuellem Stop
|
|
onSegment: async ({ reason }) => {
|
|
wsSendCommit(reason); // z. B. 'silence' oder 'manual'
|
|
},
|
|
|
|
// Optionales Debugging
|
|
onDebug: (tag, info) => console.log(tag, info),
|
|
onError: (error) => console.error('Speech capture error', error),
|
|
},
|
|
{
|
|
silenceTimeoutMs: 1200,
|
|
vadRmsThreshold: 0.03,
|
|
vadIntervalMs: 120,
|
|
minSegmentDurationMs: 450,
|
|
recordingChunkMs: 250,
|
|
},
|
|
);
|
|
|
|
const startMic = async () => {
|
|
setIsMicActive(true);
|
|
await speech.startCapture();
|
|
};
|
|
|
|
const stopMic = () => {
|
|
setIsMicActive(false);
|
|
speech.stopCapture('manual', true);
|
|
};
|
|
|
|
return (
|
|
<div>
|
|
<button onClick={startMic}>Mic Start</button>
|
|
<button onClick={stopMic}>Mic Stop</button>
|
|
<button onClick={() => setIsMuted(v => !v)}>{isMuted ? 'Unmute' : 'Mute'}</button>
|
|
<div>{speech.liveTranscript || 'Mikrofon bereit'}</div>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
Minimalanforderungen fuer Reuse:
|
|
- `isCaptureAllowed` muss den lokalen UI-State korrekt abbilden.
|
|
- `onChunk` und `onSegment` muessen auf den Ziel-Transport (WS/SSE/API) gemappt werden.
|
|
- `stopCapture(..., true)` soll bei View-Wechsel oder Unmount aufgerufen werden, um Mic sauber freizugeben.
|