basyx commited on
Commit
96d8b2e
·
verified ·
1 Parent(s): b3cae4d

Test speaker alignment and schema v1.1

Browse files
Files changed (1) hide show
  1. tests/test_whisper_service.py +76 -8
tests/test_whisper_service.py CHANGED
@@ -3,6 +3,7 @@ from __future__ import annotations
3
  import json
4
  from pathlib import Path
5
 
 
6
  from app.services.whisper_service import WhisperService
7
 
8
 
@@ -60,12 +61,6 @@ def test_transcribe_sync_includes_word_timestamps() -> None:
60
 
61
 
62
  def test_word_cues_are_clamped_to_segment() -> None:
63
- from app.models.transcript import (
64
- Transcript,
65
- TranscriptSegment,
66
- TranscriptWord,
67
- )
68
-
69
  transcript = Transcript(
70
  language="en",
71
  language_probability=1.0,
@@ -95,6 +90,79 @@ def test_word_caption_formats() -> None:
95
  assert vtt.startswith("WEBVTT\n")
96
 
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  async def test_word_caption_output(tmp_path, settings) -> None:
99
  service = WhisperService(settings)
100
  source = tmp_path / "sample.wav"
@@ -126,7 +194,7 @@ async def test_json_output_preserves_words(tmp_path, settings) -> None:
126
  payload = json.loads(result.path.read_text())
127
  assert payload["word_timestamps"] is True
128
  assert payload["segments"][0]["words"][0]["word"] == " hello"
129
- assert payload["schema_version"] == "1.0"
130
 
131
 
132
  async def test_all_text_formats_are_derived_from_canonical_transcript(tmp_path, settings) -> None:
@@ -152,7 +220,7 @@ async def test_transcript_metadata_uses_canonical_schema(tmp_path, settings) ->
152
  source, tmp_path / "out", model_name="tiny", task="translate"
153
  )
154
  transcript = result.metadata["transcript"]
155
- assert transcript["schema_version"] == "1.0"
156
  assert transcript["task"] == "translate"
157
  assert transcript["model"] == "tiny"
158
  assert transcript["segments"][0]["words"][1]["end"] == 1.988
 
3
  import json
4
  from pathlib import Path
5
 
6
+ from app.models.transcript import DiarizationSpan, Transcript, TranscriptSegment, TranscriptWord
7
  from app.services.whisper_service import WhisperService
8
 
9
 
 
61
 
62
 
63
  def test_word_cues_are_clamped_to_segment() -> None:
 
 
 
 
 
 
64
  transcript = Transcript(
65
  language="en",
66
  language_probability=1.0,
 
90
  assert vtt.startswith("WEBVTT\n")
91
 
92
 
93
+ def test_diarization_schema_and_alignment() -> None:
94
+ transcript = Transcript(
95
+ language="en",
96
+ language_probability=1.0,
97
+ duration=4.0,
98
+ task="transcribe",
99
+ model="tiny",
100
+ text="hello world",
101
+ segments=[
102
+ TranscriptSegment(
103
+ id=0,
104
+ start=0.0,
105
+ end=2.0,
106
+ text=" hello world ",
107
+ words=[
108
+ TranscriptWord(word=" hello", start=0.2, end=0.8),
109
+ TranscriptWord(word=" world", start=1.2, end=1.8),
110
+ ],
111
+ )
112
+ ],
113
+ )
114
+ aligned = WhisperService.apply_diarization(
115
+ transcript,
116
+ [
117
+ {"speaker": "SPEAKER_00", "start": 0.0, "end": 1.0},
118
+ {"speaker": "SPEAKER_01", "start": 1.0, "end": 2.0},
119
+ ],
120
+ )
121
+ assert aligned.schema_version == "1.1"
122
+ assert aligned.speakers == ["SPEAKER_00", "SPEAKER_01"]
123
+ assert aligned.segments[0].speaker == "SPEAKER_00"
124
+ assert aligned.segments[0].words[0].speaker == "SPEAKER_00"
125
+ assert aligned.segments[0].words[1].speaker == "SPEAKER_01"
126
+
127
+
128
+ def test_diarization_overlap_prefers_longest_overlap() -> None:
129
+ transcript = Transcript(
130
+ language="en",
131
+ language_probability=1.0,
132
+ duration=3.0,
133
+ task="transcribe",
134
+ model="tiny",
135
+ text="test",
136
+ segments=[
137
+ TranscriptSegment(
138
+ id=0,
139
+ start=0.0,
140
+ end=2.0,
141
+ text=" test ",
142
+ words=[TranscriptWord(word=" test", start=0.5, end=1.5)],
143
+ )
144
+ ],
145
+ )
146
+ aligned = WhisperService.apply_diarization(
147
+ transcript,
148
+ [
149
+ DiarizationSpan(speaker="A", start=0.0, end=0.9),
150
+ DiarizationSpan(speaker="B", start=0.9, end=1.5),
151
+ ],
152
+ )
153
+ assert aligned.segments[0].speaker == "B"
154
+ assert aligned.segments[0].words[0].speaker == "B"
155
+
156
+
157
+ def test_diarization_rejects_invalid_span() -> None:
158
+ try:
159
+ DiarizationSpan(speaker="A", start=2.0, end=2.0)
160
+ except ValueError as exc:
161
+ assert "end must be greater" in str(exc)
162
+ else:
163
+ raise AssertionError("invalid diarization span was accepted")
164
+
165
+
166
  async def test_word_caption_output(tmp_path, settings) -> None:
167
  service = WhisperService(settings)
168
  source = tmp_path / "sample.wav"
 
194
  payload = json.loads(result.path.read_text())
195
  assert payload["word_timestamps"] is True
196
  assert payload["segments"][0]["words"][0]["word"] == " hello"
197
+ assert payload["schema_version"] == "1.1"
198
 
199
 
200
  async def test_all_text_formats_are_derived_from_canonical_transcript(tmp_path, settings) -> None:
 
220
  source, tmp_path / "out", model_name="tiny", task="translate"
221
  )
222
  transcript = result.metadata["transcript"]
223
+ assert transcript["schema_version"] == "1.1"
224
  assert transcript["task"] == "translate"
225
  assert transcript["model"] == "tiny"
226
  assert transcript["segments"][0]["words"][1]["end"] == 1.988