import type { SpeechToText, SpeechToTextStartOptions } from "./types.js"; interface SpeechRecognitionResultEvent extends Event { readonly results: ArrayLike<{ readonly 0: { readonly transcript: string }; }>; } interface SpeechRecognitionInstance { continuous: boolean; interimResults: boolean; lang: string; onend: (() => void) | null; onerror: (() => void) | null; onresult: ((event: SpeechRecognitionResultEvent) => void) | null; start(): void; stop(): void; } interface SpeechRecognitionConstructor { new (): SpeechRecognitionInstance; } type SpeechRecognitionWindow = Window & { SpeechRecognition?: SpeechRecognitionConstructor; webkitSpeechRecognition?: SpeechRecognitionConstructor; }; /** * Adapts standard and WebKit-prefixed recognition into the small capability * consumed by SurfaceView, without exposing browser-specific event shapes. */ export function createSpeechToText(): SpeechToText { const speechWindow = window as SpeechRecognitionWindow; const Recognition = speechWindow.SpeechRecognition ?? speechWindow.webkitSpeechRecognition; return { isSupported: Recognition !== undefined, start(options: SpeechToTextStartOptions) { if (Recognition === undefined) return undefined; const recognition = new Recognition(); recognition.continuous = false; recognition.interimResults = false; recognition.lang = document.documentElement.lang || "it-IT"; // Only the final first alternative is used; interim transcripts would // repeatedly overwrite text the visitor may already be editing. recognition.onresult = (event) => { const transcript = event.results[0]?.[0]?.transcript.trim(); if (transcript) options.onTranscript(transcript); }; recognition.onerror = () => options.onError(); recognition.onend = () => options.onEnd(); recognition.start(); return { stop: () => recognition.stop() }; }, }; }