import speech_recognition as sr import streamlit as st from typing import Optional, Tuple import platform import sys class VoiceHandler: def __init__(self): self.recognizer = sr.Recognizer() self.recognizer.energy_threshold = 4000 self.recognizer.dynamic_energy_threshold = True self.recognizer.pause_threshold = 0.8 self.permission_granted = False # Initialize microphone without device selection self.mic = sr.Microphone() def check_microphone_access(self) -> Tuple[bool, str]: """Check if microphone is accessible and return status with message""" try: with self.mic as source: # Quick test to verify microphone access self.recognizer.adjust_for_ambient_noise(source, duration=0.1) return True, "Microphone access granted" except (OSError, AttributeError) as e: return False, """ Could not access microphone. Please: 1. Click the lock icon in your browser's address bar 2. Allow microphone access for this site 3. Refresh the page after granting access 4. Ensure your microphone is properly connected """ except sr.RequestError as e: return False, f"Speech recognition service error: {str(e)}" except Exception as e: return False, f"Unexpected error: {str(e)}" def request_permissions(self) -> Tuple[bool, str]: """Request microphone permissions from the browser""" success, message = self.check_microphone_access() if success: self.permission_granted = True return True, "Microphone access granted successfully" return False, message def listen_for_voice(self, language: str = "mixed") -> str: """ Listen for voice input in specified language. language can be: - "ar-SA" for Arabic - "en-US" for English - "mixed" for both Arabic and English """ if not self.permission_granted: success, message = self.request_permissions() if not success: st.error(message) st.markdown(""" ### 🎤 Troubleshooting Steps: 1. Check browser compatibility (Chrome/Firefox/Edge recommended) 2. Verify microphone connection 3. Check system sound settings 4. Try a different microphone if available 5. Restart browser if needed """) return message try: with self.mic as source: st.info("Adjusting for ambient noise... Please wait.") self.recognizer.adjust_for_ambient_noise(source, duration=1) st.info("🎤 Listening... Speak now!") audio = self.recognizer.listen(source, timeout=5, phrase_time_limit=10) st.info("Processing speech...") return self._process_audio(audio, language) except sr.RequestError as e: error_msg = f"Could not request results from speech service: {str(e)}" st.error(error_msg) return error_msg except sr.UnknownValueError: error_msg = "Could not understand audio. Please speak clearly and try again." st.warning(error_msg) return error_msg except sr.WaitTimeoutError: error_msg = "Listening timed out. Please try again." st.warning(error_msg) return error_msg except Exception as e: error_msg = f"Error: {str(e)}" st.error(error_msg) return error_msg def _process_audio(self, audio, language: str) -> str: """Process audio input and convert to text""" if language in ["ar-SA", "mixed"]: try: return self.recognizer.recognize_google(audio, language="ar-SA") except sr.UnknownValueError: if language == "mixed": return self.recognizer.recognize_google(audio, language="en-US") raise return self.recognizer.recognize_google(audio, language="en-US")