fix
This commit is contained in:
parent
7f5f31db30
commit
ebaaf77942
2 changed files with 327 additions and 0 deletions
|
|
@ -332,3 +332,330 @@ Ersetzt wird:
|
|||
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.
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in a new issue