Classroom-Ai-Assistant / backend /voice_processor.py
0xarchit's picture
Initial commit
25e6afd
import speech_recognition as sr
import logging
import threading
import time
import queue
from typing import Optional, Callable
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger("VoiceProcessor")
class VoiceProcessor:
def __init__(self):
"""Initialize voice components for backend use."""
# Voice recognition components
self.recognizer = sr.Recognizer()
self.recognizer.pause_threshold = 1.0 # Longer pauses allowed
self.recognizer.energy_threshold = 3000 # Better for different voice volumes
# Control variables
self.is_running = False
self.last_detected_text = "No text detected yet."
self.voice_lock = threading.Lock()
self.voice_queue = queue.Queue()
self.callback = None
def set_callback(self, callback: Callable[[str], None]):
"""Set a callback function to be called when text is detected."""
self.callback = callback
def voice_listener(self):
"""Voice listener thread function."""
try:
with sr.Microphone() as source:
self.recognizer.adjust_for_ambient_noise(source, duration=1)
logger.info("Voice listener started")
while self.is_running:
try:
logger.info("Listening for speech...")
audio = self.recognizer.listen(source, timeout=5, phrase_time_limit=7)
text = self.recognizer.recognize_google(audio)
logger.info(f"Detected speech: {text}")
with self.voice_lock:
self.last_detected_text = text
self.voice_queue.put(text)
# Call the callback if set
if self.callback:
self.callback(text)
except sr.WaitTimeoutError:
continue
except sr.UnknownValueError:
logger.info("Speech not recognized")
continue
except Exception as e:
logger.error(f"Voice recognition error: {e}")
continue
except Exception as e:
logger.error(f"Error in voice listener: {e}")
def start_listening(self):
"""Start the voice-to-text system."""
if self.is_running:
logger.info("Voice processor is already running")
return False
try:
self.is_running = True
# Start voice listener thread
listener_thread = threading.Thread(target=self.voice_listener, daemon=True)
listener_thread.start()
logger.info("Voice processor started")
return True
except Exception as e:
logger.error(f"Error starting voice processor: {e}")
self.is_running = False
return False
def stop_listening(self):
"""Stop the voice-to-text system."""
logger.info("Stopping voice processor...")
self.is_running = False
return True
def get_last_detected_text(self) -> str:
"""Get the last detected text in a thread-safe manner."""
with self.voice_lock:
return self.last_detected_text
def get_next_text(self, timeout: float = 1.0) -> Optional[str]:
"""Get the next detected text from the queue."""
try:
return self.voice_queue.get(timeout=timeout)
except queue.Empty:
return None
# For testing
if __name__ == "__main__":
processor = VoiceProcessor()
processor.start_listening()
try:
while True:
text = processor.get_next_text()
if text:
print(f"Detected: {text}")
time.sleep(0.1)
except KeyboardInterrupt:
processor.stop_listening()
print("Stopped")