diarize.py
Language Python2.9 KB70 lines
"""Who spoke when: pyannote speaker diarization through WhisperX.The default model is WhisperX's own default, pyannote/speaker-diarization-community-1(the successor to speaker-diarization-3.1); set TP_DIARIZE_MODEL to use another.It needs a Hugging Face token whose account has accepted that model's terms(docs/SETUP.md). The model downloads once, then runs locally. Each aligned wordis given the speaker whose turn overlaps it most; shape.py turns that intosentences."""from __future__ import annotationsimport inspectimport osfrom functools import lru_cachefrom pathlib import Pathfrom .audio import load_wav16kDEFAULT_MODEL = os.environ.get("TP_DIARIZE_MODEL") or "pyannote/speaker-diarization-community-1"class DiarizeError(RuntimeError):passdef explain_load_error(err: Exception, model: str) -> DiarizeError | None:"""Turn Hugging Face's access errors into what to do about them."""name = type(err).__name__text = str(err)if name == "GatedRepoError" or "gated repo" in text.lower() or "authorized list" in text:return DiarizeError(f"Your Hugging Face account has not accepted the terms for {model}. "f"Open https://huggingface.co/{model} while signed in, accept them, then try again ""(or run with --no-diarize).")if "401" in text or "Invalid credentials" in text or "invalid user token" in text.lower():return DiarizeError("Hugging Face rejected the token. Make a new read token and store it ""again (docs/SETUP.md, step 2).")return None@lru_cache(maxsize=1)def _pipeline(model: str, token: str, device: str):from whisperx.diarize import DiarizationPipelineparams = inspect.signature(DiarizationPipeline.__init__).parameters# Older WhisperX called this argument use_auth_token.key = "token" if "token" in params else "use_auth_token"try:return DiarizationPipeline(model_name=model, device=device, **{key: token})except Exception as err:explained = explain_load_error(err, model)if explained is None:raiseraise explained from errdef diarize(result: dict, wav: Path, token: str | None, min_speakers: int | None = None,max_speakers: int | None = None, device: str = "cpu",model: str = DEFAULT_MODEL) -> dict:if not token:raise DiarizeError("No Hugging Face token: set HF_TOKEN or add it to the Keychain, or run ""with --no-diarize (see docs/SETUP.md).")import whisperxaudio = load_wav16k(wav)if min_speakers and min_speakers == max_speakers:speakers = {"num_speakers": min_speakers}else:speakers = {"min_speakers": min_speakers, "max_speakers": max_speakers}turns = _pipeline(model, token, device)(audio, **speakers)return {**whisperx.assign_word_speakers(turns, result), "diarized": True}