fix: web speech STT repeating previous transcriptions and inserting text on cancel (#26793)

The VoiceRecording component stays mounted (hidden) between recordings, and the web speech engine accumulated every session's transcript into the never-reset transcription variable. Each new recording therefore confirmed all previous utterances again, so the inserted text repeated once per session and previously deleted text reappeared in the input.

Additionally, cancelling a recording (X button, Escape or a recognition error) called stopRecording(), which stops the SpeechRecognition instance and fires its onend handler, which unconditionally confirms the transcription. Cancelled recordings therefore still inserted the accumulated transcript.

Reset the transcription at the start of each web speech session and detach the onend handler on cancel so cancelled recordings no longer confirm.

Fixes #26784
This commit is contained in:
Classic298
2026-07-24 00:40:02 -05:00
committed by GitHub
parent ce831f7b85
commit b6acd3cc45
@@ -300,6 +300,9 @@
if (transcribe) {
if ($config.audio.stt.engine === 'web' || ($settings?.audio?.stt?.engine ?? '') === 'web') {
if ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window) {
// reset accumulated transcription from previous sessions
transcription = '';
// Create a SpeechRecognition object
speechRecognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
@@ -353,13 +356,21 @@
toast.error($i18n.t(`Speech recognition error: {{error}}`, { error: event.error }));
onCancel();
stopRecording();
cancelRecording();
};
}
}
}
};
const cancelRecording = async () => {
if (speechRecognition) {
// detach onend so cancelling does not confirm the transcription
speechRecognition.onend = null;
}
await stopRecording();
};
const stopRecording = async () => {
if (recording && mediaRecorder) {
await mediaRecorder.stop();
@@ -411,7 +422,7 @@
const handleKeyDown = (e) => {
if (e.key === 'Escape') {
e.preventDefault();
stopRecording();
cancelRecording();
onCancel();
}
};
@@ -468,7 +479,7 @@
rounded-full"
on:click={async () => {
stopRecording();
cancelRecording();
onCancel();
}}
>