import queue from collections import deque import numpy as np import sounddevice as sd import speech_recognition as sr RATE = 16000 CHUNK = RATE // 20 # 50 ms CHUNK_S = CHUNK / RATE class NothingHeard(Exception): pass def _rms(block): return float(np.sqrt(np.mean(block.astype(np.float32) ** 2))) def record(wait_for_speech=5.0, max_len=10.0, trailing_silence=0.9): """Record from the default mic until the speaker pauses. Returns raw int16 PCM.""" q = queue.Queue() noise = [] preroll = deque(maxlen=6) frames = [] quiet = elapsed = 0.0 def on_audio(data, frames_, time_, status): q.put(data[:, 0].copy()) with sd.InputStream(samplerate=RATE, channels=1, dtype="int16", blocksize=CHUNK, callback=on_audio): while elapsed < max_len: block = q.get(timeout=2) elapsed += CHUNK_S level = _rms(block) if len(noise) < 6: noise.append(level) preroll.append(block) continue threshold = max(float(np.median(noise)) * 2.5, 250.0) if not frames: if level < threshold: preroll.append(block) if elapsed > wait_for_speech: raise NothingHeard() continue frames.extend(preroll) frames.append(block) quiet = quiet + CHUNK_S if level < threshold else 0.0 if quiet > trailing_silence: break if not frames: raise NothingHeard() return np.concatenate(frames).tobytes() def transcribe(pcm, language): audio = sr.AudioData(pcm, RATE, 2) try: return sr.Recognizer().recognize_google(audio, language=language) except sr.UnknownValueError: raise NothingHeard() def listen(language): return transcribe(record(), language)