fix(voxtral): "Sprache erkannt"-Ping — No-Speech-Watchdog schneidet nicht mehr ab
Im Ohr-Modus (Wake/Passiv/Barge) beendete die App die Aufnahme am Konversations- fenster (~conv window), obwohl Stefan noch redete — nur dort, nicht beim normalen Button. Ursache: der App-No-Speech-Watchdog cancelt, solange KEIN stt_partial kam (streamGotPartial=false). Voxtral schickt aber seit dem Cutoff-Fix keine Live- Partials mehr → streamGotPartial blieb immer false → Timer feuerte mitten im Satz. Der normale Button nutzt noSpeechTimeoutMs=0 (Watchdog aus) → dort nie aufgefallen. Fix: Voxtral-Bridge feuert EIN leeres stt_partial beim ersten Voice-Frame (nach der Speaker-ID-Pruefung, fremde Stimmen signalisieren also nicht). Die App setzt darauf streamGotPartial=true und loescht den Watchdog — bestehender Handler, keine App-Aenderung. Der akustische Endpoint (Stille >= endpointMs) bleibt der einzige Turn-Ende-Ausloeser. Deploy: docker compose up -d --build voxtral-bridge (keine neue APK noetig). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -168,6 +168,11 @@ class StreamSession:
|
||||
noise_floor: float = 0.0
|
||||
closed: bool = False
|
||||
endpoint_sent: bool = False
|
||||
# Einmaliges "Sprache erkannt"-Signal an die App gesendet? Voxtral schickt
|
||||
# keine Live-Partials, aber der App-No-Speech-Watchdog wartet auf ein
|
||||
# stt_partial, um "der User redet" zu erkennen — sonst cancelt er mitten im
|
||||
# Satz. Wir feuern EIN leeres stt_partial beim ersten Voice-Frame.
|
||||
speech_signaled: bool = False
|
||||
# Speaker-ID Gating (einmalig auf die ersten ~1.5s der Aufnahme)
|
||||
speaker_checked: bool = False
|
||||
speaker_match: Optional[bool] = None
|
||||
@@ -361,6 +366,20 @@ class SessionManager:
|
||||
rms = self._tail_rms(sess)
|
||||
if rms >= self._voice_threshold(sess):
|
||||
sess.last_voice_at = now
|
||||
# Einmalig der App melden, dass Sprache begonnen hat. Ohne Live-Partials
|
||||
# wuerde ihr No-Speech-Watchdog die Aufnahme sonst am Konversations-
|
||||
# fenster canceln, obwohl der User noch redet (Stefans Reproduktion:
|
||||
# "beendet nach ~4s, obwohl ich weiterrede — nur im Ohr-Modus"). Ein
|
||||
# leeres stt_partial reicht: die App setzt streamGotPartial=true und
|
||||
# loescht den Watchdog. Nach der Speaker-ID-Pruefung (oben) → fremde
|
||||
# Stimmen signalisieren NICHT.
|
||||
if not sess.speech_signaled and self._ws is not None:
|
||||
sess.speech_signaled = True
|
||||
await _send(self._ws, "stt_partial", {
|
||||
"requestId": sess.request_id,
|
||||
"audioRequestId": sess.audio_request_id,
|
||||
"text": "",
|
||||
})
|
||||
else:
|
||||
self._update_noise_floor(sess, rms)
|
||||
# Endpoint: hat der User schon gesprochen UND ist es seit endpoint_ms still?
|
||||
|
||||
Reference in New Issue
Block a user