fix: deduplicate cumulative voice results (Closes #935)
All checks were successful
CI / lint (pull_request) Successful in 2m3s
CI / build-release (pull_request) Successful in 6s
CI / browser-journey (pull_request) Successful in 1m1s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy 2026-08-16 03:56:50 +00:00
parent c4715fc95c
commit 2bb155a9e4
2 changed files with 9 additions and 3 deletions

View File

@ -43,6 +43,7 @@ function createVoiceIssueCapture({
recognition.interimResults = false; recognition.interimResults = false;
recognition.onresult = event => { recognition.onresult = event => {
const finalText = Array.from(event.results || []) const finalText = Array.from(event.results || [])
.slice(event.resultIndex ?? 0)
.filter(result => result.isFinal) .filter(result => result.isFinal)
.map(result => result[0]?.transcript || '').join(' ').replace(/\s+/g, ' ').trim(); .map(result => result[0]?.transcript || '').join(' ').replace(/\s+/g, ' ').trim();
if (finalText) { if (finalText) {

View File

@ -157,7 +157,7 @@ const loads=[];
} }
def test_multiple_final_segments_accumulate_in_one_bounded_checkpoint(): def test_cumulative_recognition_events_append_each_new_final_segment_once():
script = f""" script = f"""
const {{createVoiceIssueCapture}} = require({json.dumps(str(VOICE_CAPTURE))}); const {{createVoiceIssueCapture}} = require({json.dumps(str(VOICE_CAPTURE))});
class Element {{ class Element {{
@ -165,6 +165,7 @@ class Element {{
addEventListener(name, callback) {{ this.listeners[name]=callback; }} addEventListener(name, callback) {{ this.listeners[name]=callback; }}
click() {{ this.listeners.click?.(); }} dispatchEvent() {{}} click() {{ this.listeners.click?.(); }} dispatchEvent() {{}}
}} }}
const result=(transcript,isFinal)=>Object.assign([{{transcript}}],{{isFinal}});
let recognition; let recognition;
class Recognition {{ constructor() {{ recognition=this; }} start() {{}} stop() {{}} abort() {{}} }} class Recognition {{ constructor() {{ recognition=this; }} start() {{}} stop() {{}} abort() {{}} }}
const elements=Object.fromEntries( const elements=Object.fromEntries(
@ -176,8 +177,12 @@ const saved=[];
async load() {{ return ''; }}, async save(login,text) {{ saved.push(text); }}, async clear() {{}}, async load() {{ return ''; }}, async save(login,text) {{ saved.push(text); }}, async clear() {{}},
}}}}); }}}});
await controller.ready; elements.start.click(); await controller.ready; elements.start.click();
recognition.onresult({{results:[Object.assign([{{transcript:'Lift outage.'}}],{{isFinal:true}})]}}); const first=result('Lift outage.',true);
recognition.onresult({{results:[Object.assign([{{transcript:'Elevator B is trapped.'}}],{{isFinal:true}})]}}); recognition.onresult({{resultIndex:0,results:[first]}});
recognition.onresult({{
resultIndex:1,
results:[first,result('Elevator B',false),result('Elevator B is trapped.',true)],
}});
await Promise.resolve(); await Promise.resolve();
process.stdout.write(JSON.stringify({{transcript:elements.transcript.value,saved}})); process.stdout.write(JSON.stringify({{transcript:elements.transcript.value,saved}}));
}})().catch(error=>{{console.error(error);process.exit(1);}}); }})().catch(error=>{{console.error(error);process.exit(1);}});