fix(voice): stop wake re-fire loop and empty-transcript error spam
Two bugs surfaced by the desktop wake conversation:
1. Runaway loop: wake -> voice -> resume -> wake fired again within
~200ms. openWakeWord keeps its rolling feature buffer across
pause/resume, so on resume it immediately re-scored the "hey jarvis"
captured before the pause and re-fired, reopening a session and
restarting voice in a tight cycle. Reset the engine buffer on every
detector (re)start so resume begins from clean audio.
2. Empty-transcript toast: a silent re-listen returns
success:false / "… STT returned empty transcript", which the desktop
transcribe endpoint turned into a 400 -> thrown error -> "Voice
transcription failed" notification on every silent gap. Treat an empty
transcript as no-speech: return {ok, transcript: ""} so the voice loop
quietly re-listens. Real failures still 4xx/5xx.
This commit is contained in:
committed by
Teknium
parent
c597b4c47b
commit
edb12bf423
+18
-1
@@ -140,6 +140,10 @@ class _Engine:
|
||||
def process(self, frame) -> bool: # frame: 1-D int16 ndarray
|
||||
raise NotImplementedError
|
||||
|
||||
def reset(self) -> None:
|
||||
"""Clear any internal audio/feature buffer (called on every (re)start)."""
|
||||
pass
|
||||
|
||||
def close(self) -> None:
|
||||
pass
|
||||
|
||||
@@ -189,12 +193,17 @@ class _OpenWakeWordEngine(_Engine):
|
||||
scores = self._model.predict(frame)
|
||||
return any(score >= self._threshold for score in scores.values())
|
||||
|
||||
def close(self) -> None:
|
||||
def reset(self) -> None:
|
||||
# Clears openWakeWord's rolling feature/prediction buffer so stale audio
|
||||
# captured before a pause can't re-fire the moment we resume.
|
||||
try:
|
||||
self._model.reset()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def close(self) -> None:
|
||||
self.reset()
|
||||
|
||||
|
||||
class _PorcupineEngine(_Engine):
|
||||
"""Picovoice Porcupine — premium, on-device, needs an access key."""
|
||||
@@ -356,6 +365,14 @@ class WakeWordDetector:
|
||||
logger.error("wake word: failed to open microphone: %s", e)
|
||||
return
|
||||
|
||||
# Drop any buffered audio/feature state so a resume right after a voice
|
||||
# turn can't immediately re-fire on audio captured before the pause (the
|
||||
# wake → voice → resume → wake runaway loop).
|
||||
try:
|
||||
self.engine.reset()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
logger.info("wake word: listening (frame=%d, rate=%d)", frame_length, SAMPLE_RATE)
|
||||
try:
|
||||
while not self._stop.is_set():
|
||||
|
||||
Reference in New Issue
Block a user