fix(voxtral): Speech-Endpoint gegen laute Umgebungsmusik
Problem (Stefan): laeuft Musik, endet eine Aufnahme nie von selbst — die Energie bleibt oben, der RMS-Stille-Endpoint feuert nicht (last_voice_at immer frisch). Erst Stop druecken oder Musik leiser (dann echte Stille) beendet. Fix: waehrend lauter Phasen (rms ueber Schwelle) periodisch (~700ms, gedrosselt) mit Silero pruefen, ob im letzten endpoint_ms-Fenster ueberhaupt Sprache ist. Nur Musik/Stille → Turn beenden (finalize endpoint). Real gesprochene Turns haben Sprache im Fenster → laufen normal weiter; eine kurze Denk-Pause auch, solange innerhalb der Toleranz noch Sprache im Fenster liegt. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -126,6 +126,11 @@ SILERO_VAD_ENABLED = os.getenv("SILERO_VAD_ENABLED", "true").lower() in ("1", "t
|
|||||||
SILERO_VAD_THRESHOLD = float(os.getenv("SILERO_VAD_THRESHOLD", "0.5"))
|
SILERO_VAD_THRESHOLD = float(os.getenv("SILERO_VAD_THRESHOLD", "0.5"))
|
||||||
SILERO_MIN_SPEECH_MS = int(os.getenv("SILERO_MIN_SPEECH_MS", "150"))
|
SILERO_MIN_SPEECH_MS = int(os.getenv("SILERO_MIN_SPEECH_MS", "150"))
|
||||||
SILERO_PAD_MS = int(os.getenv("SILERO_PAD_MS", "200"))
|
SILERO_PAD_MS = int(os.getenv("SILERO_PAD_MS", "200"))
|
||||||
|
# Speech-Endpoint gegen laute Umgebungsmusik: der RMS-Stille-Endpoint feuert bei
|
||||||
|
# durchgehender Musik NIE (Energie bleibt oben). Deshalb waehrend lauter Phasen
|
||||||
|
# periodisch (alle X ms) mit Silero pruefen, ob im letzten endpoint_ms-Fenster
|
||||||
|
# ueberhaupt noch Sprache ist — wenn nicht (nur Musik/Stille), Turn beenden.
|
||||||
|
STREAM_SPEECH_ENDPOINT_CHECK_MS = int(os.getenv("STREAM_SPEECH_ENDPOINT_CHECK_MS", "700"))
|
||||||
|
|
||||||
_vad_state = {"model": None, "get_ts": None, "failed": False}
|
_vad_state = {"model": None, "get_ts": None, "failed": False}
|
||||||
|
|
||||||
@@ -281,6 +286,7 @@ class StreamSession:
|
|||||||
last_growth_at: float = 0.0
|
last_growth_at: float = 0.0
|
||||||
last_transcribe_at: float = 0.0
|
last_transcribe_at: float = 0.0
|
||||||
last_voice_at: float = 0.0
|
last_voice_at: float = 0.0
|
||||||
|
last_speech_check_at: float = 0.0 # Drossel fuer den Silero-Speech-Endpoint
|
||||||
noise_floor: float = 0.0
|
noise_floor: float = 0.0
|
||||||
closed: bool = False
|
closed: bool = False
|
||||||
endpoint_sent: bool = False
|
endpoint_sent: bool = False
|
||||||
@@ -506,6 +512,26 @@ class SessionManager:
|
|||||||
"audioRequestId": sess.audio_request_id,
|
"audioRequestId": sess.audio_request_id,
|
||||||
"text": "",
|
"text": "",
|
||||||
})
|
})
|
||||||
|
# Speech-Endpoint gegen laute Umgebungsmusik: es ist gerade laut (rms
|
||||||
|
# ueber Schwelle) — aber ist es Sprache oder Musik? Der RMS-Endpoint
|
||||||
|
# unten wuerde bei Musik NIE feuern (last_voice_at bleibt frisch).
|
||||||
|
# Deshalb gedrosselt mit Silero das letzte endpoint_ms-Fenster pruefen:
|
||||||
|
# KEINE Sprache drin (nur Musik) → Turn ist zu Ende. Real gesprochene
|
||||||
|
# Turns haben Sprache im Fenster → laufen weiter.
|
||||||
|
if (self._buffer_ms(sess) >= sess.endpoint_ms
|
||||||
|
and (now - sess.last_speech_check_at) * 1000.0 >= STREAM_SPEECH_ENDPOINT_CHECK_MS):
|
||||||
|
sess.last_speech_check_at = now
|
||||||
|
try:
|
||||||
|
tail_bytes = int(sess.endpoint_ms / 1000.0 * sess.sample_rate) * 2
|
||||||
|
tail = pcm_s16le_to_float32(bytes(sess.pcm_buffer[-tail_bytes:]))
|
||||||
|
segs = _speech_segments(tail)
|
||||||
|
if segs is not None and len(segs) == 0:
|
||||||
|
logger.info("Stream %s: Speech-Endpoint (keine Sprache im letzten %dms — Musik/Stille) → finalize",
|
||||||
|
sess.request_id[:8], sess.endpoint_ms)
|
||||||
|
await self._finalize(sess, "endpoint")
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Speech-Endpoint-Check fehlgeschlagen — ignoriert")
|
||||||
else:
|
else:
|
||||||
self._update_noise_floor(sess, rms)
|
self._update_noise_floor(sess, rms)
|
||||||
# No-Speech-Timeout: wurde die GANZE Zeit KEINE Stimme erkannt
|
# No-Speech-Timeout: wurde die GANZE Zeit KEINE Stimme erkannt
|
||||||
|
|||||||
Reference in New Issue
Block a user