From 26cf79a0f72afbc0350383fd30da37a7153a1dcf Mon Sep 17 00:00:00 2001 From: balex Date: Mon, 9 Mar 2026 14:46:34 +0100 Subject: [PATCH] fix bug --- src/public/js/app.js | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/public/js/app.js b/src/public/js/app.js index ea6c3a7..a936f1f 100644 --- a/src/public/js/app.js +++ b/src/public/js/app.js @@ -150,6 +150,11 @@ function createRecognition() { r.interimResults = true; r.maxAlternatives = 1; + // Android Chrome bug: onresult re-fires old results with e.resultIndex=0. + // highestFinalIndex guards against processing the same final result twice. + let highestFinalIndex = -1; + let sessionFinal = ''; // final text committed within this recognition session + r.onstart = () => { recordBtn.classList.add('recording'); recordHint.textContent = 'Tippen zum Stoppen'; @@ -158,18 +163,19 @@ function createRecognition() { r.onresult = (e) => { let interim = ''; - let finalChunk = ''; - for (let i = e.resultIndex; i < e.results.length; i++) { + for (let i = 0; i < e.results.length; i++) { if (e.results[i].isFinal) { - finalChunk += (finalChunk ? ' ' : '') + e.results[i][0].transcript; + if (i > highestFinalIndex) { + sessionFinal += (sessionFinal ? ' ' : '') + e.results[i][0].transcript; + highestFinalIndex = i; + } } else { - interim += e.results[i][0].transcript; + interim = e.results[i][0].transcript; // only the latest interim matters } } - if (finalChunk) { - state.finalTranscript += (state.finalTranscript ? ' ' : '') + finalChunk; - } - const display = state.finalTranscript + (interim ? (state.finalTranscript ? ' ' : '') + interim : ''); + const base = state.finalTranscript; + const combined = base + (base && sessionFinal ? ' ' : '') + sessionFinal; + const display = combined + (interim ? (combined ? ' ' : '') + interim : ''); if (display.trim().split(/\s+/).length >= MAX_RECORD_WORDS) { stopRecording(); return; @@ -181,12 +187,15 @@ function createRecognition() { r.onend = () => { if (!state.isRecording) return; - // Android/Chrome ends session after each phrase — restart to keep listening + // Merge this session's final text into the persistent accumulator before restarting + if (sessionFinal) { + state.finalTranscript += (state.finalTranscript ? ' ' : '') + sessionFinal; + } setTimeout(() => { if (!state.isRecording) return; recognition = createRecognition(); try { recognition.start(); } catch (_) { stopRecording(); } - }, 80); + }, 100); }; // 'aborted' fires during normal restart cycle — ignore it