diff --git a/transcribe_server.py b/transcribe_server.py index 8635209..cece0ba 100644 --- a/transcribe_server.py +++ b/transcribe_server.py @@ -47,9 +47,18 @@ def get_model(): def get_diarize(): global _diarize if _diarize is None: - from whisperx.diarize import DiarizationPipeline - print("Loading diarization model...") - _diarize = DiarizationPipeline(token=os.environ["HF_TOKEN"], device="cpu", model_name="pyannote/speaker-diarization-3.1") + # BUGFIX (2026-08-12): whisperx 3.8.5's DiarizationPipeline wrapper has a bug + # with pyannote.audio 4.0.4 (returns empty segs, speaker=""). Use raw pyannote + # Pipeline directly — confirmed working: 60s audio → 1 seg with SPEAKER_00. + from pyannote.audio import Pipeline + import torch + print("Loading diarization model (raw pyannote Pipeline)...") + pipeline = Pipeline.from_pretrained( + "pyannote/speaker-diarization-3.1", + token=os.environ["HF_TOKEN"], + ) + pipeline.to(torch.device("cpu")) + _diarize = pipeline print("Diarization loaded!") return _diarize @@ -103,15 +112,22 @@ def _do_transcribe(audio_path: str, language: str, do_diarize: bool): if do_diarize: try: import torch - diarize_model = get_diarize() - # BUGFIX (2026-08-11): pyannote's torchcodec can't load (FFmpeg 8 only has - # libavutil.60, venv needs .59). Pre-load audio as tensor dict to bypass. - if isinstance(audio, np.ndarray): - audio_input = {"waveform": torch.from_numpy(audio).unsqueeze(0).float(), - "sample_rate": 16000} - diar_segments = diarize_model(audio_input) - else: - diar_segments = diarize_model(audio) + import pandas as pd + diarize_pipeline = get_diarize() + # BUGFIX (2026-08-12): raw pyannote Pipeline; bypass whisperx wrapper. + # Pass dict {waveform, sample_rate} — same shape whisperx used internally. + audio_input = {"waveform": torch.from_numpy(audio).unsqueeze(0).float(), + "sample_rate": 16000} + diarize_output = diarize_pipeline(audio_input, min_speakers=1, max_speakers=4) + # Raw pyannote returns DiarizeOutput; convert Annotation → DataFrame + # the same way whisperx/diarize.py does. + diarization = diarize_output.speaker_diarization + diar_segments = pd.DataFrame( + diarization.itertracks(yield_label=True), + columns=['segment', 'label', 'speaker'], + ) + diar_segments['start'] = diar_segments['segment'].apply(lambda x: x.start) + diar_segments['end'] = diar_segments['segment'].apply(lambda x: x.end) result = whisperx.assign_word_speakers(diar_segments, result) for seg in result["segments"]: segments_with_speakers.append({