"""Transcription Whisper (PC) du segment de référence — tourne sous cv_venv. Important : on transcrit le **segment préparé** (mono/16k/~15 s), PAS la capture brute. Le texte du `.cvps` doit correspondre à ce qui est parlé DANS le segment enrôlé (§3/§4) ; transcrire les 111 s d'origine donnerait un texte qui ne colle pas aux ~15 s réellement extraits. `prepare_wav` étant déterministe, le segment transcrit ici == le segment enrôlé. """ from __future__ import annotations import os import tempfile from .enroll import prepare_wav # Défaut "small" : "base" transcrit mal le FR (validé), "small" est le bon compromis # qualité/CPU ; "medium" encore mieux mais lourd. La transcription est de toute façon # relue par l'opérateur. Configurable via CV_WHISPER_MODEL. CV_WHISPER_MODEL = os.environ.get("CV_WHISPER_MODEL", "small") _model_cache: dict[str, object] = {} def _model(size: str): if size not in _model_cache: import whisper # openai-whisper (présent dans cv_venv) _model_cache[size] = whisper.load_model(size) return _model_cache[size] def transcribe(wav_path: str, model: str | None = None) -> dict: """Transcrit le segment de référence. Renvoie {text, language, model, prep}.""" size = model or CV_WHISPER_MODEL m = _model(size) with tempfile.TemporaryDirectory() as td: prep = os.path.join(td, "prep.wav") prep_info = prepare_wav(wav_path, prep) result = m.transcribe(prep, fp16=False) # CPU → fp16 off return { "text": (result.get("text") or "").strip(), "language": result.get("language"), "model": size, "prep": prep_info, }