mattrguerra/transcription-pipelinemainPrivate on GitHub, published here in full

test_real_audio.py

Language Python3.1 KB76 lines

tests/integration/test_real_audio.py

  1. """Integration tier: real models on real speech. Not run in CI (model downloads).
  2. TP_INTEGRATION=1 pytest tests/integration # local engine + alignment
  3. TP_INTEGRATION=1 HF_TOKEN=hf_... pytest tests/integration # adds real pyannote
  4. The clip is four LibriSpeech utterances from two readers (tests/fixtures), so
  5. the words and the speaker boundaries are known.
  6. """
  7. import json
  8. import os
  9. from pathlib import Path
  10. import pytest
  11. from transcription_pipeline import steps
  12. from transcription_pipeline.pipeline import Options, process
  13. from transcription_pipeline.secrets import get_secret
  14. pytestmark = pytest.mark.skipif(os.environ.get("TP_INTEGRATION") != "1",
  15. reason="set TP_INTEGRATION=1 to run the model tier")
  16. FIXTURES = Path(__file__).resolve().parents[1] / "fixtures"
  17. CLIP = FIXTURES / "two-speakers.flac"
  18. TRUTH = json.loads((FIXTURES / "two-speakers.json").read_text())["turns"]
  19. def norm(text):
  20. # The model hears LibriSpeech's "ANGOR" as "anger"; either is right.
  21. return [w.strip(".,?!").replace("angor", "anger") for w in text.lower().split()]
  22. def check(res, expect_speakers):
  23. data = json.loads(res.outputs["json"].read_text())
  24. sents = data["sentences"]
  25. words = [w for s in data["segments"] for w in s.get("words", []) if "start" in w]
  26. got = [w for s in sents for w in norm(s["text"])]
  27. assert [w for t in TRUTH for w in norm(t["text"]) if w not in got] == []
  28. starts = [w["start"] for w in words]
  29. assert starts == sorted(starts) and words[-1]["end"] <= res.duration + 0.05
  30. if not expect_speakers:
  31. return sents
  32. assert [s["speaker"] for s in sents] == ["Speaker 1", "Speaker 2", "Speaker 1", "Speaker 2"]
  33. for s, t in zip(sents, TRUTH):
  34. assert norm(s["text"])[0] == norm(t["text"])[0]
  35. assert t["start"] - 0.3 <= s["start"] <= t["end"]
  36. return sents
  37. def test_local_engine_and_alignment(tmp_path):
  38. opts = Options(language="en", diarize=False)
  39. res = process(CLIP, tmp_path, opts, steps.transcriber(opts), steps.aligner(opts), None)
  40. check(res, expect_speakers=False)
  41. def test_speaker_assignment_on_real_words(tmp_path):
  42. """Real transcription, alignment and whisperx.assign_word_speakers; only the
  43. diarizer is replaced by the known turns."""
  44. import pandas as pd
  45. import whisperx
  46. turns = pd.DataFrame([{"start": t["start"], "end": t["end"],
  47. "speaker": f"SPEAKER_0{'AB'.index(t['speaker'])}"} for t in TRUTH])
  48. def known(result, wav, o):
  49. return whisperx.assign_word_speakers(turns, result)
  50. opts = Options(language="en")
  51. res = process(CLIP, tmp_path, opts, steps.transcriber(opts), steps.aligner(opts), known)
  52. check(res, expect_speakers=True)
  53. @pytest.mark.skipif(not get_secret("HF_TOKEN"), reason="needs a Hugging Face token for pyannote")
  54. def test_pyannote_diarization(tmp_path):
  55. opts = Options(language="en", min_speakers=2, max_speakers=2)
  56. res = process(CLIP, tmp_path, opts, steps.transcriber(opts), steps.aligner(opts),
  57. steps.diarizer(opts))
  58. check(res, expect_speakers=True)