@swankylegg/voice-io
Version:
A browser-based speech recognition and synthesis assistant
1 lines • 28 kB
Source Map (JSON)
{"version":3,"file":"voice-io.mjs","sources":["../src/constants.ts","../src/voice-io.ts"],"sourcesContent":["export const STATES = {\n IDLE: 'IDLE',\n LISTENING: 'LISTENING',\n THINKING: 'THINKING',\n RESPONDING: 'RESPONDING'\n} as const; ","import { STATES } from './constants';\nimport { VoiceIOState, VoiceIOConfig, SynthesisConfig, RecognitionConfig, RecognitionResult, LanguageInfo } from './types/voice-io';\nimport { SpeechRecognition, SpeechRecognitionEvent, SpeechRecognitionErrorEvent, SpeechRecognitionResult, SpeechSynthesisVoice, SpeechSynthesisErrorEvent } from './types/web-speech-api';\n\n// Add type assertion for SpeechRecognition\nconst SpeechRecognitionAPI = (window.SpeechRecognition || window.webkitSpeechRecognition) as typeof SpeechRecognition;\n\n/**\n * Default configuration for VoiceIO instance\n * @type {VoiceIOConfig}\n */\nconst DEFAULT_CONFIG: VoiceIOConfig = {\n // Event handlers\n onListenStart: undefined,\n onListenEnd: undefined,\n onRecognitionResult: undefined,\n onVoiceStart: undefined,\n onVoiceEnd: undefined,\n onError: undefined,\n\n // Synthesis settings\n synthesis: {\n pitch: 1,\n rate: 1\n },\n\n // Recognition settings\n recognition: {\n continuous: true,\n interimResults: true,\n lang: 'en-US',\n maxAlternatives: 3\n },\n\n // Add new callbacks\n onLanguagesLoaded: undefined,\n onVoicesLoaded: undefined,\n};\n\n/**\n * VoiceIO - A class to handle browser-based speech recognition and synthesis\n * @class\n * @throws {Error} If speech recognition or synthesis is not supported by the browser\n */\nexport class VoiceIO {\n private readonly config: VoiceIOConfig;\n private readonly states: typeof STATES = STATES;\n private state: VoiceIOState = STATES.IDLE;\n private recognizer!: SpeechRecognition;\n private synthesizer!: SpeechSynthesis;\n private recognitionResults: RecognitionResult[][] = [];\n private accumulatedTranscript: string = '';\n private selectedLanguage: string;\n private selectedVoice: SpeechSynthesisVoice | null = null;\n private voices: SpeechSynthesisVoice[] = [];\n private voicesLoaded: boolean = false;\n private readonly recognitionLanguages: LanguageInfo[] = [\n { code: 'en-US', name: 'English' },\n { code: 'es-ES', name: 'Español' },\n { code: 'fr-FR', name: 'Français' },\n { code: 'de-DE', name: 'Deutsch' },\n { code: 'it-IT', name: 'Italiano' },\n { code: 'ja-JP', name: '日本語' },\n { code: 'ko-KR', name: '한국어' },\n { code: 'zh-CN', name: '中文' }\n ];\n\n /**\n * Creates a new VoiceIO instance\n * @param {Partial<VoiceIOConfig>} config - Configuration options\n * @param {(() => void)} [config.onListenStart] - Callback when speech recognition starts\n * @param {(() => void)} [config.onListenEnd] - Callback when speech recognition ends\n * @param {((results: RecognitionResult[][], bestTranscript: string, accumulatedTranscript: string) => void)} [config.onRecognitionResult] - Callback for speech recognition results\n * @param {((utterance: SpeechSynthesisUtterance) => void)} [config.onVoiceStart] - Callback when speech synthesis starts\n * @param {((utterance: SpeechSynthesisUtterance) => void)} [config.onVoiceEnd] - Callback when speech synthesis ends\n * @param {((error: SpeechRecognitionErrorEvent | SpeechSynthesisErrorEvent) => void)} [config.onError] - Callback for error handling\n * @param {((languages: LanguageInfo[]) => void)} [config.onLanguagesLoaded] - Callback when available languages are loaded\n * @param {((voices: SpeechSynthesisVoice[]) => void)} [config.onVoicesLoaded] - Callback when available voices are loaded\n */\n constructor(config: Partial<VoiceIOConfig> = {}) {\n // Check browser support first\n if (!('SpeechRecognition' in window) && !('webkitSpeechRecognition' in window)) {\n throw new Error('Speech recognition is not supported in this browser');\n }\n if (!('speechSynthesis' in window)) {\n throw new Error('Speech synthesis is not supported in this browser');\n }\n\n // So these can be accessed directly without a separate import\n this.states = STATES;\n this.state = this.states.IDLE;\n\n // Merge configs\n this.config = {\n ...DEFAULT_CONFIG,\n synthesis: { ...DEFAULT_CONFIG.synthesis, ...config.synthesis },\n recognition: { ...DEFAULT_CONFIG.recognition, ...config.recognition },\n ...config\n };\n\n this.selectedLanguage = this.config.recognition!.lang!;\n\n // Initialize recognizer first\n this.initRecognizer();\n\n // Initialize synthesizer and set up voice loading\n this.synthesizer = window.speechSynthesis;\n\n // Set up voice changed listener first\n this.synthesizer.onvoiceschanged = () => {\n this.voices = this.synthesizer.getVoices();\n this.handleVoicesLoaded();\n };\n\n // Try loading voices immediately as well (for browsers that load synchronously)\n this.voices = this.synthesizer.getVoices();\n this.handleVoicesLoaded();\n\n // Clean up on page unload\n window.addEventListener('beforeunload', () => this.cleanup());\n }\n\n /**\n * Initializes the speech recognition system\n * @private\n * @throws {Error} If speech recognition is not supported\n */\n private initRecognizer(): void {\n if (!SpeechRecognitionAPI) {\n throw new Error('Speech recognition not supported');\n }\n this.recognizer = new SpeechRecognitionAPI();\n Object.assign(this.recognizer, this.config.recognition);\n\n this.recognizer.onstart = () => {\n this.config.onListenStart?.();\n };\n\n this.recognizer.onresult = (evt) => this.handleRecognitionResult(evt);\n\n this.recognizer.onspeechend = () => {\n this.recognizer.stop();\n };\n\n this.recognizer.onend = () => {\n // Only call onListenEnd here, when recognition fully ends\n this.config.onListenEnd?.();\n };\n\n this.recognizer.onerror = (error: SpeechRecognitionErrorEvent) => {\n this.handleError(error, 'recognizer');\n };\n }\n\n /**\n * Handles the loading of speech synthesis voices\n * @private\n * Note: Some browsers (like Chrome) load voices asynchronously, which is why we need this handler\n */\n private handleVoicesLoaded(): void {\n this.voicesLoaded = true;\n \n // Force refresh voices list\n this.voices = this.synthesizer.getVoices();\n\n // Get available languages based on available voices\n const availableLanguages = this.getAvailableLanguages();\n\n // Always notify about languages, even if empty\n this.config.onLanguagesLoaded?.(availableLanguages);\n\n if (availableLanguages.length > 0) {\n // If no language selected or current language isn't available,\n // select first available language\n const currentLanguageIsValid = availableLanguages.some(\n l => l.code === this.selectedLanguage\n );\n\n if (!this.selectedLanguage || !currentLanguageIsValid) {\n // Select first available language\n this.setLanguage(availableLanguages[0].code);\n } else {\n // Current language is valid, just update voices\n const availableVoices = this.getVoicesForCurrentLanguage();\n \n // Select first voice if none selected\n if (availableVoices.length > 0 && !this.selectedVoice) {\n this.setVoice(availableVoices[0].name);\n }\n \n // Always notify about voices for current language, even if empty\n this.config.onVoicesLoaded?.(availableVoices);\n }\n } else {\n // Notify with empty voices list if no languages available\n this.config.onVoicesLoaded?.([]);\n }\n }\n\n /**\n * Processes speech recognition results\n * @private\n * @param {SpeechRecognitionEvent} evt - The recognition event\n * Note: Accumulates final transcripts and manages recognition state\n */\n private handleRecognitionResult(evt: SpeechRecognitionEvent): void {\n // Convert results to a more usable format\n const results = Array.from(evt.results).map(resultArray => {\n return Array.from(resultArray).map(result => ({\n transcript: result.transcript,\n confidence: result.confidence,\n isFinal: resultArray.isFinal\n }));\n });\n\n // Get the best transcript by taking highest confidence result from each group\n const bestTranscript = results\n .map(alternatives => alternatives.reduce((best, current) =>\n current.confidence > best.confidence ? current : best\n ))\n .map(result => result.transcript)\n .join(' ');\n\n // Accumulate final transcripts\n const lastResult = results[results.length - 1];\n // Stop recognizing if we have final results\n if (lastResult && lastResult[0].isFinal) {\n this.accumulatedTranscript = (this.accumulatedTranscript + ' ' + bestTranscript).trim();\n this.stopRecognizing();\n // Use setState but skip cleanup since we just stopped recognizing\n this.state = this.states.IDLE; // Directly set state to avoid cleanup\n }\n\n this.recognitionResults = results;\n this.config.onRecognitionResult?.(results, bestTranscript, this.accumulatedTranscript);\n }\n\n /**\n * Sets the state to IDLE and performs cleanup\n * @private\n * Note: Resets accumulated transcript when starting new session\n */\n private setIdle(): void {\n this.cleanup();\n }\n\n /**\n * Starts listening for speech input\n * @private\n * Note: Resets accumulated transcript when starting new session\n */\n private setListening(): void {\n // If we're currently speaking, just stop that\n // No need for full cleanup which would also stop recognition\n if (this.state === STATES.RESPONDING) {\n this.stopSpeaking();\n } else {\n this.cleanup();\n }\n\n this.accumulatedTranscript = ''; // Reset accumulated transcript when starting new session\n this.recognizer.start();\n }\n\n /**\n * Sets the state to THINKING (transitional state)\n * @private\n */\n private setThinking(): void {\n this.cleanup();\n }\n\n /**\n * Initiates speech synthesis\n * @private\n * @param {string} text - The text to synthesize\n */\n private setSpeaking(text: string): void {\n this.cleanup();\n const utterance = new SpeechSynthesisUtterance(text);\n\n // Apply config settings\n Object.assign(utterance, this.config.synthesis);\n\n // Set the voice and language\n if (this.selectedVoice) {\n utterance.voice = this.selectedVoice;\n utterance.lang = this.selectedVoice.lang; // Use full language code from voice\n } else {\n utterance.lang = this.selectedLanguage;\n }\n\n // Add event handlers\n utterance.onend = () => {\n this.setState(STATES.IDLE);\n this.config.onVoiceEnd?.(utterance);\n };\n utterance.onstart = () => {\n this.config.onVoiceStart?.(utterance);\n };\n utterance.onerror = (error) => {\n this.handleError(error, 'utterance');\n };\n this.synthesizer.speak(utterance);\n }\n\n /**\n * Changes the current state of the VoiceIO instance\n * @param {VoiceIOState} newState - The state to transition to\n * @param {string} [textToSynthesize] - Text to speak when transitioning to RESPONDING state\n * @throws {Error} If the state is invalid\n */\n setState(newState: VoiceIOState, textToSynthesize?: string): void {\n // Don't do anything if state is invalid or same\n if (!(newState in STATES)) {\n throw new Error(`Invalid state: ${newState}`);\n }\n if (this.state === newState) {\n return console.log('No Voice I/O state change');\n }\n\n // Update the state first\n this.state = newState;\n\n // Then handle the state change\n switch (newState) {\n case STATES.IDLE:\n return this.setIdle();\n case STATES.RESPONDING:\n return this.setSpeaking(textToSynthesize!);\n case STATES.LISTENING:\n return this.setListening();\n case STATES.THINKING:\n return this.setThinking();\n }\n }\n\n /**\n * Handles errors from speech recognition or synthesis\n * @private\n * @param {SpeechRecognitionErrorEvent | SpeechSynthesisErrorEvent} error - The error that occurred\n * @param {string} label - Label identifying the error source\n */\n private handleError(error: SpeechRecognitionErrorEvent | SpeechSynthesisErrorEvent, label: string): void {\n console.info(`Voice I/O ${label} error`, error);\n this.config.onError?.(error);\n this.stopRecognizing();\n this.setState(STATES.IDLE);\n }\n\n /**\n * Stops the speech recognition process\n * @private\n */\n private stopRecognizing(): void {\n if (this.recognizer) {\n try {\n this.recognizer.stop();\n } catch (err) {\n console.warn('Error stopping recognition:', err);\n }\n }\n }\n\n /**\n * Stops any ongoing speech synthesis\n * @private\n */\n private stopSpeaking(): void {\n if (this.synthesizer.speaking) {\n this.synthesizer.cancel();\n }\n }\n\n /**\n * Performs cleanup of speech recognition and synthesis\n * @public\n */\n cleanup(): void {\n try {\n this.stopSpeaking();\n this.stopRecognizing();\n } catch (err) {\n this.handleError(err as SpeechRecognitionErrorEvent | SpeechSynthesisErrorEvent, \"cleanup\");\n }\n }\n\n /**\n * Gets all available speech synthesis voices\n * @returns {SpeechSynthesisVoice[]} Array of available voices\n */\n getVoices(): SpeechSynthesisVoice[] {\n return this.voices;\n }\n\n /**\n * Gets the current state of the VoiceIO instance\n * @returns {VoiceIOState} Current state from STATES enum\n */\n getState(): VoiceIOState {\n return this.state;\n }\n\n /**\n * Sets the language for both speech recognition and synthesis\n * @param {string} languageCode - Language code (e.g., 'en-US')\n * Note: Automatically selects the first available voice for the new language\n */\n setLanguage(languageCode: string): void {\n this.selectedLanguage = languageCode;\n this.config.recognition!.lang = languageCode;\n\n // Get voices for new language\n const availableVoices = this.getVoicesForCurrentLanguage();\n\n // Reset voice selection\n this.selectedVoice = null;\n this.config!.synthesis!.voice = undefined;\n\n // Always select first available voice for this language\n if (availableVoices.length > 0) {\n this.setVoice(availableVoices[0].name);\n }\n\n // Notify about available voices for this language\n this.config.onVoicesLoaded?.(availableVoices);\n\n // Reinitialize recognizer\n this.initRecognizer();\n }\n\n /**\n * Gets available voices for the currently selected language\n * @private\n * @returns {SpeechSynthesisVoice[]} Array of voices matching current language\n * Note: Matches based on language prefix (e.g., 'en' for 'en-US')\n */\n private getVoicesForCurrentLanguage(): SpeechSynthesisVoice[] {\n // Get language prefix (e.g., 'en' from 'en-US')\n const currentLangPrefix = this.selectedLanguage.split('-')[0].toLowerCase();\n\n return this.voices.filter(voice => {\n const voiceLangPrefix = voice.lang.split('-')[0].toLowerCase();\n return voiceLangPrefix === currentLangPrefix;\n });\n }\n\n /**\n * Sets the voice for speech synthesis\n * @param {string} voiceName - Name of the voice to use\n * Note: Only allows voices that match the current language\n */\n setVoice(voiceName: string): void {\n const validVoices = this.getVoicesForCurrentLanguage();\n const voice = validVoices.find(v => v.name === voiceName);\n if (voice) {\n this.selectedVoice = voice;\n this.config.synthesis!.voice = voice;\n } else {\n console.warn('Selected voice is not available for current language');\n }\n }\n\n /**\n * Gets the currently selected language code\n * @returns {string} Selected language code\n */\n getSelectedLanguage(): string {\n return this.selectedLanguage;\n }\n\n /**\n * Gets the currently selected voice\n * @returns {SpeechSynthesisVoice|null} Selected voice or null if none selected\n */\n getSelectedVoice(): SpeechSynthesisVoice | null {\n return this.selectedVoice;\n }\n\n /**\n * Gets available languages that have both recognition and synthesis support\n * @returns {Array<{code: string, name: string, prefix: string}>} Array of available languages\n * Note: Only returns languages that have both recognition and synthesis support\n */\n getAvailableLanguages(): LanguageInfo[] {\n // Ensure we have the latest voices list\n const currentVoices = this.synthesizer.getVoices();\n if (currentVoices.length > 0) {\n this.voices = currentVoices;\n }\n\n if (!this.voices || this.voices.length === 0) {\n return [];\n }\n\n // Get languages that have synthesis voices\n const synthLanguages = new Set(\n this.voices.map(voice => voice.lang.split('-')[0].toLowerCase())\n );\n\n // Filter recognition languages to only those that also have synthesis support\n return this.recognitionLanguages\n .filter(lang => {\n const langPrefix = lang.code.split('-')[0].toLowerCase();\n return synthLanguages.has(langPrefix);\n })\n .map(lang => ({\n code: lang.code,\n name: lang.name,\n prefix: lang.code.split('-')[0].toLowerCase()\n }));\n }\n}"],"names":[],"mappings":"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"}