# backend/voice/stt.py # Real STT using faster-whisper (local) with Deepgram fallback import os APP_DATA_DIR = os.environ.get("JARVIS_APP_DATA_DIR", ".") class STTPipeline: def __init__(self, model_size="large-v3"): import torch from faster_whisper import WhisperModel # Downloads real Whisper model to {app_data_dir}/models/whisper/ self.model = WhisperModel(model_size, device="cuda" if torch.cuda.is_available() else "cpu", compute_type="float16" if torch.cuda.is_available() else "int8", download_root=f"{APP_DATA_DIR}/models/whisper") async def transcribe(self, audio_bytes: bytes) -> tuple[str, str]: # language=None forces auto-detection segments, info = self.model.transcribe(audio_bytes, beam_size=5, language=None) text = " ".join(s.text for s in segments) detected_lang = info.language if info.duration < 2.0 and hasattr(self, "last_known_language"): detected_lang = self.last_known_language else: self.last_known_language = detected_lang import gc, torch del segments gc.collect() if torch.cuda.is_available(): torch.cuda.empty_cache() return text, detected_lang def unload(self): import gc import torch if hasattr(self, 'model'): del self.model gc.collect() if torch.cuda.is_available(): torch.cuda.empty_cache()