Add canonical audio preparation and meeting context support

This commit is contained in:
2026-08-24 10:22:16 +02:00
parent 8dab928763
commit d94436af43
14 changed files with 713 additions and 23 deletions
+75 -1
View File
@@ -1,11 +1,14 @@
import json
import shutil
import subprocess
import tempfile
import unittest
from dataclasses import replace
from pathlib import Path
from unittest.mock import patch
from scripts import run_mvp_meeting as cli
from src.meeting_lab.audio import PreparedAudio
from src.meeting_lab.models.meeting_context import load_meeting_context
from src.meeting_lab.orchestration import mvp as mvp_api
from src.meeting_lab.orchestration.mvp import MvpMeetingConfig, MvpRunResult
@@ -71,6 +74,12 @@ def fake_transcribe(audio, model, output, language, **kwargs):
return TranscriptionResult(output, raw, transcript, text, metadata, 0.1)
def fake_prepare(source, destination, **kwargs):
destination.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(source, destination)
return PreparedAudio(source, source.suffix.removeprefix("."), destination, "ffmpeg", "ffmpeg")
def fake_protocol(transcript, context, **kwargs):
rendered_context = load_meeting_context(context)
assert rendered_context.meeting_id == "programmatic-test"
@@ -103,6 +112,7 @@ class MvpApiTests(unittest.TestCase):
events = []
with (
patch.object(mvp_api, "transcribe_audio", side_effect=fake_transcribe),
patch.object(mvp_api, "prepare_audio", side_effect=fake_prepare),
patch.object(
mvp_api, "generate_direct_protocol", side_effect=fake_protocol
),
@@ -142,7 +152,7 @@ class MvpApiTests(unittest.TestCase):
mvp_api,
"transcribe_audio",
side_effect=TranscriptionError("stopped"),
):
), patch.object(mvp_api, "prepare_audio", side_effect=fake_prepare):
result = mvp_api.run_mvp_meeting(config, progress_sink=events.append)
self.assertEqual(result.exit_code, 2)
@@ -168,8 +178,72 @@ class MvpApiTests(unittest.TestCase):
self.assertEqual(delegated.diarization, "off")
self.assertEqual(delegated.language, "de")
self.assertEqual(delegated.whisper_executable, "whisper-cli")
self.assertEqual(delegated.ffmpeg_executable, "ffmpeg")
self.assertTrue(delegated.audio_normalization)
self.assertEqual(api.call_args.kwargs["meeting_context"], context_data())
def test_cli_explicit_audio_normalization_values_are_propagated(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
config = self.config(root)
enabled = cli.config_from_args(
cli.parse_args(
[
str(config.audio_file),
"--whisper-model",
str(config.whisper_model),
"--audio-normalization",
]
)
)
disabled = cli.config_from_args(
cli.parse_args(
[
str(config.audio_file),
"--whisper-model",
str(config.whisper_model),
"--no-audio-normalization",
]
)
)
self.assertTrue(enabled.audio_normalization)
self.assertFalse(disabled.audio_normalization)
def test_transcription_receives_prepared_wav_for_encoded_inputs(self):
for suffix in (".flac", ".m4a"):
with self.subTest(suffix=suffix), tempfile.TemporaryDirectory() as directory:
root = Path(directory)
config = self.config(root)
encoded = config.audio_file.with_suffix(suffix)
config.audio_file.rename(encoded)
config = replace(config, audio_file=encoded)
received = []
def capture_transcribe(audio, *args, received_paths=received, **kwargs):
received_paths.append(audio)
return fake_transcribe(audio, *args, **kwargs)
with (
patch.object(mvp_api, "prepare_audio", side_effect=fake_prepare),
patch.object(mvp_api, "transcribe_audio", side_effect=capture_transcribe),
patch.object(mvp_api, "generate_direct_protocol", side_effect=fake_protocol),
):
result = mvp_api.run_mvp_meeting(
config, meeting_context=context_data()
)
self.assertEqual(result.exit_code, 0)
self.assertEqual(received, [result.run_dir / "audio" / "prepared.wav"])
manifest = json.loads(
(result.run_dir / "audio" / "input_manifest.json").read_text()
)
self.assertEqual(manifest["format"], suffix.removeprefix("."))
self.assertEqual(
manifest["prepared_audio"]["prepared_audio_path"],
str((result.run_dir / "audio" / "prepared.wav").resolve()),
)
if __name__ == "__main__":
unittest.main()