test_transcriber.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. """Tests for the Whisper segment confidence gate."""
  2. import numpy as np
  3. import pytest
  4. from stt_daemon import transcriber as transcriber_mod
  5. from stt_daemon.transcriber import Transcriber, accept_segment
  6. class _Seg:
  7. def __init__(self, text="hello", no_speech_prob=0.1, avg_logprob=-0.3):
  8. self.text = text
  9. self.no_speech_prob = no_speech_prob
  10. self.avg_logprob = avg_logprob
  11. def test_accepts_confident_speech():
  12. assert accept_segment(_Seg(), 0.6, -1.0)
  13. def test_rejects_high_no_speech_prob():
  14. assert not accept_segment(_Seg(no_speech_prob=0.9), 0.6, -1.0)
  15. def test_rejects_low_avg_logprob():
  16. assert not accept_segment(_Seg(avg_logprob=-1.5), 0.6, -1.0)
  17. def test_threshold_boundary_is_accepted():
  18. assert accept_segment(_Seg(no_speech_prob=0.6, avg_logprob=-1.0), 0.6, -1.0)
  19. def test_missing_attributes_default_to_accept():
  20. class Bare:
  21. text = "x"
  22. assert accept_segment(Bare(), 0.6, -1.0)
  23. class _Info:
  24. language = "en"
  25. language_probability = 1.0
  26. class _FakeWhisperModel:
  27. """Records constructor/transcribe kwargs without loading a real model."""
  28. last = None
  29. def __init__(self, model, device, compute_type, cpu_threads=0):
  30. self.init_kwargs = {
  31. "model": model,
  32. "device": device,
  33. "compute_type": compute_type,
  34. "cpu_threads": cpu_threads,
  35. }
  36. self.transcribe_kwargs = None
  37. _FakeWhisperModel.last = self
  38. def transcribe(self, audio, **kwargs):
  39. self.transcribe_kwargs = kwargs
  40. return [], _Info()
  41. @pytest.fixture
  42. def fake_model(monkeypatch):
  43. monkeypatch.setattr(transcriber_mod, "WhisperModel", _FakeWhisperModel)
  44. return _FakeWhisperModel
  45. def _audio():
  46. return np.zeros(16000, dtype=np.float32)
  47. def test_cpu_threads_forwarded_to_model(fake_model):
  48. t = Transcriber(
  49. "small", device="cpu", compute_type="int8", language=None, cpu_threads=16
  50. )
  51. assert t.cpu_threads == 16
  52. assert fake_model.last.init_kwargs["cpu_threads"] == 16
  53. def test_cpu_threads_default_is_auto(fake_model):
  54. Transcriber("small", device="cpu", compute_type="int8", language=None)
  55. assert fake_model.last.init_kwargs["cpu_threads"] == 0
  56. def test_transcribe_disables_timestamps(fake_model):
  57. t = Transcriber("small", device="cpu", compute_type="int8", language=None)
  58. t.transcribe(_audio())
  59. kwargs = fake_model.last.transcribe_kwargs
  60. assert kwargs["without_timestamps"] is True
  61. assert kwargs["condition_on_previous_text"] is False
  62. def test_auto_language_stays_none_for_bilingual(fake_model):
  63. """language=auto must reach the engine as None so es/en both keep working."""
  64. t = Transcriber("small", device="cpu", compute_type="int8", language=None)
  65. t.transcribe(_audio())
  66. assert fake_model.last.transcribe_kwargs["language"] is None
  67. def test_explicit_language_is_preserved(fake_model):
  68. t = Transcriber("small", device="cpu", compute_type="int8", language="es")
  69. t.transcribe(_audio())
  70. assert fake_model.last.transcribe_kwargs["language"] == "es"