feat: enable diarization by default with an opt-out
Request speaker diarization through OpenRouter's Azure provider options for all transcription uploads. Add --no-diarization to explicitly disable it for both plain text and SRT output; returned speaker labels let existing SRT cue generation split at speaker changes. Default to 10-minute chunks when diarization is enabled because Microsoft reports failures around 15 minutes and longer. Preserve the 30-minute default with the opt-out and honor explicit --chunk-minutes values in both modes. Document the options, duration limits, and output behavior. Test Plan: - python3 -B -m unittest -v: all 32 tests passed, including request options, default upload limits, opt-out combinations, and SRT speaker boundaries. - bash -n transcribe: passed. - ./transcribe --help: verified the new option and chunk defaults. - git diff --cached --check: passed. - Provider responses were mocked; no live API request was made.
This commit is contained in:
1 parent
a5c535cfb9
commit
24b1030776
4 files changed
+121
-10
No files matched your search
@@ -41,6 +41,15 @@ class TranscribeTests(unittest.TestCase):
|
||||
def assert_cleaned(self):
|
||||
self.assertTrue(all(not Path(r["staging"]).exists() for r in self.requests()))
|
||||
|
||||
def assert_diarization(self, enabled):
|
||||
for request in self.requests():
|
||||
self.assertEqual(request["provider"], {
|
||||
"options": {"azure": {"diarization": {"enabled": enabled}}},
|
||||
})
|
||||
self.assertIs(
|
||||
request["provider"]["options"]["azure"]["diarization"]["enabled"], enabled,
|
||||
)
|
||||
|
||||
def test_long_text_uploads_bounded_mp3_and_stitches_once(self):
|
||||
result = self.run_cli("--chunk-minutes", "1")
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
@@ -48,7 +57,9 @@ class TranscribeTests(unittest.TestCase):
|
||||
self.assertIn("chunk 2/2", result.stderr)
|
||||
requests = self.requests()
|
||||
self.assertEqual(len(requests), 2)
|
||||
self.assertTrue(all(r["upload_duration"] <= 60 for r in requests))
|
||||
self.assertAlmostEqual(requests[0]["chunk"]["end"] - requests[1]["chunk"]["start"], 6)
|
||||
self.assert_diarization(True)
|
||||
self.assert_cleaned()
|
||||
|
||||
def test_long_srt_uses_original_timeline_and_continuous_numbers(self):
|
||||
@@ -59,6 +70,7 @@ class TranscribeTests(unittest.TestCase):
|
||||
"2\n00:00:56,700 --> 00:00:57,800\nboundary continues.\n\n"
|
||||
"3\n00:01:05,000 --> 00:01:05,400\nLast.\n\n"
|
||||
))
|
||||
self.assert_diarization(True)
|
||||
self.assert_cleaned()
|
||||
|
||||
def test_short_text_retains_provider_formatting(self):
|
||||
@@ -66,12 +78,74 @@ class TranscribeTests(unittest.TestCase):
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertEqual(result.stdout, "Provider's original formatting.\nNext line.\n")
|
||||
self.assertEqual(len(self.requests()), 1)
|
||||
self.assertIsNone(self.requests()[0]["response_format"])
|
||||
self.assert_diarization(True)
|
||||
self.assert_cleaned()
|
||||
|
||||
def test_short_srt_still_requests_word_timestamps(self):
|
||||
result = self.run_cli("--srt", duration=5)
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertEqual(result.stdout, "1\n00:00:01,000 --> 00:00:01,400\nHello.\n\n")
|
||||
self.assertEqual(self.requests()[0]["response_format"], "verbose_json")
|
||||
self.assertEqual(self.requests()[0]["timestamp_granularities"], ["segment", "word"])
|
||||
self.assert_diarization(True)
|
||||
|
||||
def test_no_diarization_applies_to_text_srt_and_every_chunk(self):
|
||||
for output in ((), ("--srt",)):
|
||||
for chunked in (False, True):
|
||||
with self.subTest(output=output, chunked=chunked):
|
||||
self.log.unlink(missing_ok=True)
|
||||
options = ("--chunk-minutes", "1") if chunked else ()
|
||||
result = self.run_cli(
|
||||
*output, *options, "--no-diarization", duration=70 if chunked else 5,
|
||||
)
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertTrue(result.stdout)
|
||||
self.assertEqual(len(self.requests()), 2 if chunked else 1)
|
||||
self.assert_diarization(False)
|
||||
for request in self.requests():
|
||||
if output or chunked:
|
||||
self.assertEqual(request["response_format"], "verbose_json")
|
||||
self.assertEqual(request["timestamp_granularities"], ["segment", "word"])
|
||||
else:
|
||||
self.assertIsNone(request["response_format"])
|
||||
self.assertIsNone(request["timestamp_granularities"])
|
||||
self.assertLessEqual(request["upload_duration"], 60)
|
||||
self.assert_cleaned()
|
||||
# The opt-out must also preserve a limit specified after it.
|
||||
self.log.unlink()
|
||||
result = self.run_cli("--no-diarization", "--chunk-minutes", "1")
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertEqual(len(self.requests()), 2)
|
||||
self.assert_diarization(False)
|
||||
self.assert_cleaned()
|
||||
|
||||
def test_default_upload_limits_depend_on_diarization(self):
|
||||
for options, limit in (((), 600), (("--no-diarization",), 1800)):
|
||||
with self.subTest(options=options):
|
||||
self.log.unlink(missing_ok=True)
|
||||
result = self.run_cli(*options, duration=limit + 10)
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
requests = self.requests()
|
||||
self.assertEqual(len(requests), 2)
|
||||
self.assertGreaterEqual(requests[0]["upload_duration"], limit - 0.1)
|
||||
self.assertTrue(all(r["upload_duration"] <= limit for r in requests))
|
||||
self.assert_diarization(not options)
|
||||
self.assert_cleaned()
|
||||
|
||||
def test_diarization_breaks_srt_at_speaker_changes(self):
|
||||
result = self.run_cli("--srt", mode="speakers", duration=5)
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertEqual(result.stdout, (
|
||||
"1\n00:00:01,000 --> 00:00:01,400\nHello\n\n"
|
||||
"2\n00:00:01,500 --> 00:00:01,900\nthere\n\n"
|
||||
))
|
||||
self.assert_diarization(True)
|
||||
self.log.unlink()
|
||||
result = self.run_cli("--no-diarization", "--srt", mode="speakers", duration=5)
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertEqual(result.stdout, "1\n00:00:01,000 --> 00:00:01,900\nHello there\n\n")
|
||||
self.assert_diarization(False)
|
||||
|
||||
def test_failed_later_chunk_has_no_partial_stdout_and_cleans_up(self):
|
||||
for mode in ("http-error", "bad-json", "api-error", "missing-words"):
|
||||
|
||||
Reference in new issue
Block a user