From c5e1c79e1b71fa24bb80dc7e5e8c57006e3eac21 Mon Sep 17 00:00:00 2001 From: Christian Gick Date: Mon, 23 Feb 2026 13:48:14 +0200 Subject: [PATCH] fix(voice): reduce phantom speech responses from ambient noise MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Raise VAD activation_threshold 0.50→0.65, min_speech_duration 0.2→0.4s - Add ghost phrase filter: suppress 1-2 word hallucinations (Danke, Ja, etc) - Strengthen prompt: stay silent unless clearly addressed Co-Authored-By: Claude Opus 4.6 --- voice.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/voice.py b/voice.py index 1a2c2a3..b2d400a 100644 --- a/voice.py +++ b/voice.py @@ -46,7 +46,7 @@ STRIKTE Regeln: - Sei direkt und praezise, keine Fuellwoerter - Erfinde NICHTS - keine Geschichten, keine Musik, keine Fantasie - Beantworte nur was gefragt wird -- Wenn niemand etwas fragt, sage nur kurz Hallo +- Wenn niemand etwas fragt oder du dir nicht sicher bist ob jemand mit dir spricht, SCHWEIGE. Antworte NUR auf klare, direkte Fragen oder Anweisungen. Kein Smalltalk, kein "Danke", kein "Wie kann ich helfen" von dir aus - Schreibe Zahlen und Jahreszahlen IMMER als Woerter aus (z.B. "zweitausendundzwanzig" statt "2026", "zweiundzwanzigsten Februar" statt "22. Februar") - Bei zeitrelevanten Fragen (Uhrzeit, Termine, Geschaeftszeiten): frage kurz nach ob der Nutzer noch in seiner gespeicherten Zeitzone ist, bevor du antwortest. Nutze set_user_timezone wenn sich der Standort geaendert hat. - Wenn der Nutzer seinen Standort oder seine Stadt erwaehnt, nutze set_user_timezone um die Zeitzone zu speichern. @@ -84,11 +84,27 @@ _STT_ARTIFACT_PATTERNS = [ ] +_STT_GHOST_PHRASES = { + "danke", "ja", "nein", "okay", "ok", "tschüss", "hallo", "bye", + "mhm", "hmm", "aha", "oh", "ah", "ähm", "hm", "tschüss", + "thanks", "thank you", "yes", "no", "bye bye", "hello", "hi", + "bitte", "genau", "gut", "so", "na", "ne", "ach", "doch", + "vielen dank", "alles klar", "schön", "super", "richtig", +} + + def _is_stt_artifact(text: str) -> bool: - """Check if text is an STT artifact (noise annotation or metadata leak).""" + """Check if text is an STT artifact (noise annotation, metadata leak, or ghost phrase).""" if _NOISE_ANNOTATION_RE.match(text): return True - return any(p.match(text) for p in _STT_ARTIFACT_PATTERNS) + if any(p.match(text) for p in _STT_ARTIFACT_PATTERNS): + return True + # Short phantom transcriptions from ambient noise — ElevenLabs hallucinates + # common German/English filler words when it hears background sounds + words = text.split() + if len(words) <= 2 and text.lower().strip().rstrip(".!?,") in _STT_GHOST_PHRASES: + return True + return False class _NoiseFilterAgent(Agent): @@ -115,8 +131,8 @@ def _get_vad(): global _vad if _vad is None: _vad = silero.VAD.load( - activation_threshold=0.50, - min_speech_duration=0.2, + activation_threshold=0.65, + min_speech_duration=0.4, min_silence_duration=0.55, ) return _vad