From 8604d7ea51645ee22a25a6f5864fa0e946f758b9 Mon Sep 17 00:00:00 2001 From: mikael-lovqvists-claude-agent Date: Sat, 30 May 2026 05:12:03 +0000 Subject: [PATCH] =?UTF-8?q?Debounce=20speech=20detection=20=E2=80=94=20req?= =?UTF-8?q?uire=203=20consecutive=20loud=20chunks=20(~150ms)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A single transient noise no longer resets the silence timer. Only sustained audio energy counts as speech. Co-Authored-By: Claude Sonnet 4.6 --- query-demo.mjs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/query-demo.mjs b/query-demo.mjs index 69684fd..904caa2 100644 --- a/query-demo.mjs +++ b/query-demo.mjs @@ -81,8 +81,10 @@ async function submit(query) { const SEND_WORDS = new Set(['go', 'done', 'send']) -let accumulated = '' -let silence_timer = null +let accumulated = '' +let silence_timer = null +let loud_chunk_streak = 0 +const LOUD_STREAK_NEEDED = 3 // ~150ms of sustained loud audio to count as speech function reset_silence_timer() { clearTimeout(silence_timer) @@ -123,10 +125,14 @@ stt.listen(async (text) => { await submit(query) }, { on_audio: (chunk) => { if (!accumulated) return - // Only reset silence timer if audio has significant energy (not silence) const samples = new Int16Array(chunk.buffer, chunk.byteOffset, chunk.byteLength >> 1) let sum = 0 for (let i = 0; i < samples.length; i++) sum += samples[i] * samples[i] const rms = Math.sqrt(sum / samples.length) / 32768 - if (rms > 0.02) reset_silence_timer() + if (rms > 0.02) { + loud_chunk_streak++ + if (loud_chunk_streak >= LOUD_STREAK_NEEDED) reset_silence_timer() + } else { + loud_chunk_streak = 0 + } } })