fix(web): prevent speech result duplication on mobile browsers (#187)
This commit is contained in:
@@ -126,8 +126,6 @@ export function LiveDemo() {
|
||||
const [detectedLanguage, setDetectedLanguage] = useState<string>("en-US");
|
||||
const recognitionRef = useRef<SpeechRecognition | null>(null);
|
||||
const isListeningRef = useRef(false);
|
||||
// Track the index up to which results have been processed to prevent duplicates on mobile
|
||||
const processedResultIndexRef = useRef(0);
|
||||
|
||||
// Keep ref in sync with state for use in event handlers
|
||||
useEffect(() => {
|
||||
@@ -165,33 +163,19 @@ export function LiveDemo() {
|
||||
};
|
||||
|
||||
recognition.onresult = (event: SpeechRecognitionEvent) => {
|
||||
// Get the base index - on some browsers (especially mobile), resultIndex
|
||||
// may be 0 but the array contains all previous results. We need to
|
||||
// track which results we've already processed to avoid duplicates.
|
||||
const startIndex = Math.max(event.resultIndex, processedResultIndexRef.current);
|
||||
// On mobile browsers, the Web Speech API returns all previous results in the array
|
||||
// with resultIndex staying at 0. Only process the LAST result which is the new one.
|
||||
// This prevents the exponential duplication bug where text repeats like:
|
||||
// "Hey Hey how Hey how are Hey how are you..."
|
||||
const lastResultIndex = event.results.length - 1;
|
||||
const result = event.results[lastResultIndex];
|
||||
const transcript = result[0].transcript;
|
||||
|
||||
let interim = "";
|
||||
let final = "";
|
||||
|
||||
// Only process new results (from startIndex to end)
|
||||
for (let i = startIndex; i < event.results.length; i++) {
|
||||
const transcript = event.results[i][0].transcript;
|
||||
if (event.results[i].isFinal) {
|
||||
final += transcript + " ";
|
||||
} else {
|
||||
interim += transcript;
|
||||
}
|
||||
}
|
||||
|
||||
// Update processed index to the end of current results
|
||||
// Any results before this have been handled
|
||||
processedResultIndexRef.current = event.results.length;
|
||||
|
||||
if (final) {
|
||||
setTranscript((prev) => prev + final);
|
||||
if (result.isFinal) {
|
||||
setTranscript((prev) => prev + transcript + " ");
|
||||
setInterimTranscript("");
|
||||
} else {
|
||||
setInterimTranscript(interim);
|
||||
setInterimTranscript(transcript);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -218,7 +202,6 @@ export function LiveDemo() {
|
||||
if (recognitionRef.current) {
|
||||
setTranscript("");
|
||||
setInterimTranscript("");
|
||||
processedResultIndexRef.current = 0; // Reset processed result index
|
||||
try {
|
||||
recognitionRef.current.start();
|
||||
} catch (e) {
|
||||
|
||||
Reference in New Issue
Block a user