import os import logging import asyncio from concurrent.futures import ThreadPoolExecutor from typing import Optional logger = logging.getLogger('Superviseur') class WhisperWorker: """Handles local STT transcription using faster-whisper.""" def __init__(self, model_size="base", device="cpu"): self.model_size = model_size self.device = device self.model = None self.executor = ThreadPoolExecutor(max_workers=2) self.initialized = False def initialize(self): """Load the model into RAM/VRAM.""" try: from faster_whisper import WhisperModel logger.info(f"◈ SYSTEM: Initializing Whisper ({self.model_size}) on {self.device}...") # On tente le chargement. Si device="cuda" échoue (AMD), on bascule sur CPU. try: self.model = WhisperModel(self.model_size, device=self.device, compute_type="int8") except Exception as e: if self.device != "cpu": logger.warning(f"◈ GPU failure ({e}). Falling back to CPU.") self.device = "cpu" self.model = WhisperModel(self.model_size, device="cpu", compute_type="int8") else: raise e self.initialized = True logger.info(f"◈ SYSTEM: Whisper Model Loaded on {self.device}. Ear Protocol Active.") except Exception as e: logger.error(f"Failed to initialize Whisper: {e}") self.initialized = False async def transcribe(self, audio_path: str) -> Optional[str]: """Transcribe an audio file asynchronously.""" if not self.initialized or not self.model: return None def _run(): try: segments, info = self.model.transcribe(audio_path, beam_size=5) text = " ".join([segment.text for segment in segments]).strip() logger.debug(f"◈ Whisper: Transcription result: '{text}' (lang: {info.language})") return text except Exception as e: logger.error(f"Transcription error: {e}") return None loop = asyncio.get_event_loop() return await loop.run_in_executor(self.executor, _run)