From 859da2fc0cd5cd91eec137352d2e0c0a1face80a Mon Sep 17 00:00:00 2001 From: leubeem Date: Mon, 29 Jun 2026 11:35:47 +0200 Subject: [PATCH] feat(pm): ignore sub-threshold voice transmissions (STT noise gate) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Whisper hallucinates short real words ("Test", "Thank you", "Okay") on near-silent or noisy audio. Unfiltered these reached the backend as a wrong readback attempt — counting toward the 3x-skip — and triggered paid LLM-router calls. Drop voice (PTT) transcripts below NUXT_PUBLIC_PTT_MIN_WORDS (default 2); text input is exempt so deliberate short commands still work. Co-Authored-By: Claude Opus 4.8 --- .env.example | 6 ++++++ app/pages/pm.vue | 14 ++++++++++++++ nuxt.config.ts | 4 ++++ 3 files changed, 24 insertions(+) diff --git a/.env.example b/.env.example index 523fae8..d602d26 100644 --- a/.env.example +++ b/.env.example @@ -27,6 +27,12 @@ ROUTER_LLM_MODEL=gpt-5-mini # disabled (the backend falls back to deterministic bad_next routing). SERVICE_SECRET=CHANGE_ME +# PM radio training +# Minimum word count for a voice (PTT) transmission to be used; shorter +# transcripts are treated as STT noise/hallucination and ignored. Set to 1 to +# disable. See the "STT MINIMUM-WORD GATE" in app/pages/pm.vue. +NUXT_PUBLIC_PTT_MIN_WORDS=2 + # ATC audio generation ATC_OUT_DIR=./storage/atc FLIGHTLAB_TTS_CACHE_DIR=./.cache/flightlab-tts diff --git a/app/pages/pm.vue b/app/pages/pm.vue index 49b2f19..99eb150 100644 --- a/app/pages/pm.vue +++ b/app/pages/pm.vue @@ -3365,6 +3365,20 @@ const handlePilotTransmission = async (message: string, source: 'text' | 'ptt' = // ("roger", "wilco") still contains letters/digits and passes. if (!transcript || !/[a-z0-9]/i.test(transcript)) return + // STT MINIMUM-WORD GATE — search here if a spoken transmission was ignored. + // Voice (PTT) only: drop transcripts shorter than the configured minimum. + // Whisper hallucinates short real words ("Test", "Thank you", "Okay") on + // near-silent or noisy audio; left unfiltered those reach the backend as a + // (wrong) readback attempt — counting toward the 3x-skip — and now also + // trigger a paid LLM-router call. Text input is exempt so deliberate short + // commands still work. Threshold is the NUXT_PUBLIC_PTT_MIN_WORDS env var + // (default 2); set it to 1 to effectively disable the gate. + const minPttWords = Number(config.public.pttMinWords ?? 2) + if (source === 'ptt' && transcript.split(/\s+/).filter(Boolean).length < minPttWords) { + pmLog.info(`IGNORED short PTT transcript (<${minPttWords} words):`, transcript) + return + } + const prefix = source === 'ptt' ? 'Pilot (PTT)' : 'Pilot' setLastTransmission(`${prefix}: ${transcript}`) diff --git a/nuxt.config.ts b/nuxt.config.ts index ed61029..5c62d5e 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -58,6 +58,10 @@ export default defineNuxtConfig({ public: { apiDocumentationUrl: '/api-docs', radioBackendUrl: process.env.NUXT_PUBLIC_RADIO_BACKEND_URL || 'http://127.0.0.1:8000', + // Minimum word count for a voice (PTT) transmission to be used. Below + // this the transcript is treated as STT noise/hallucination and + // ignored. See the "STT MINIMUM-WORD GATE" in pages/pm.vue. + pttMinWords: Number(process.env.NUXT_PUBLIC_PTT_MIN_WORDS || 2), }, }, vuetify: {