Make protocol language follow meeting language

This commit is contained in:
2026-09-11 10:25:45 +02:00
parent 8a0f38fce4
commit 6fc07690d9
6 changed files with 204 additions and 4 deletions
+164
View File
@@ -0,0 +1,164 @@
"""Meeting-language regression tests without media or model execution."""
import json
import tempfile
import unittest
from functools import partial
from pathlib import Path
from unittest.mock import Mock, patch
from src.meeting_lab.llm.ollama import OllamaGeneration
from src.meeting_lab.models.meeting_context import load_meeting_context
from src.meeting_lab.orchestration.mvp import regenerate_mvp_protocol
from src.meeting_lab.protocol.direct_protocol_prompt import build_direct_protocol_prompt
from src.meeting_lab.protocol.generate_direct_protocol import (
estimate_input_tokens,
generate_direct_protocol,
select_transcript_input,
)
class MeetingLanguageTests(unittest.TestCase):
def test_diarized_plain_fallback_retains_english_instruction(self) -> None:
segments = [
{
"start": index,
"end": index + 1,
"text": "Word.",
"speaker_id": f"SPEAKER_{index % 2:02d}",
}
for index in range(200)
]
plain = " ".join(segment["text"] for segment in segments)
budget = estimate_input_tokens(
build_direct_protocol_prompt(plain, meeting_language="en")
)
selected = select_transcript_input(
{"text": plain, "segments": segments, "speaker_labels_anonymous": True},
None,
meeting_language="en",
safe_input_token_budget=budget,
)
self.assertEqual(selected.representation, "plain_transcript_fallback")
self.assertIn("Write the meeting protocol in English.", selected.prompt)
self.assertEqual(selected.text, plain)
def test_generation_and_regeneration_preserve_language_and_inputs(self) -> None:
for language, expected in (
("de", "German"),
("en", "English"),
(None, "German"),
):
for diarized in (False, True):
with (
self.subTest(language=language, diarized=diarized),
tempfile.TemporaryDirectory() as directory,
):
run = Path(directory)
context_path = run / "context" / "meeting_context.yaml"
context_path.parent.mkdir()
context_text = (
'schema_version: "1"\nmeeting:\n'
" meeting_id: test\n title: Mixed terminology\n"
+ (f" language: {language}\n" if language else "")
+ ' notes: "Freigabe für Product X"\n'
"participants:\n - participant_id: person\n"
' display_name: "Jörg Müller"\n'
"speaker_mappings:\n SPEAKER_00: person\n"
)
context_path.write_text(context_text, encoding="utf-8")
transcript = run / ("diarization" if diarized else "transcript")
transcript.mkdir()
transcript /= (
"transcript_diarized.json" if diarized else "transcript.json"
)
transcript.write_text(
json.dumps(
{
"text": "I will check Product X.",
"speaker_labels_anonymous": diarized,
"segments": [
{
"id": 0,
"start": 0,
"end": 1,
"speaker_id": "SPEAKER_00",
"text": "I will check Product X.",
}
],
}
),
encoding="utf-8",
)
original = transcript.read_bytes()
call = Mock(
return_value=OllamaGeneration(
text="# Meeting Protocol",
raw_response={},
client_wall_time_seconds=0.1,
)
)
generate = partial(
generate_direct_protocol,
model_check=Mock(return_value={}),
generation_call=call,
)
result = generate(transcript, context_path)
self.assertIn(
f"Write the meeting protocol in {expected}.",
result.exact_prompt,
)
self.assertNotIn("in deutscher Sprache", result.exact_prompt)
self.assertNotIn("auf Deutsch", result.exact_prompt)
self.assertIn("Jörg Müller", result.exact_prompt)
self.assertIn("Mixed terminology", result.exact_prompt)
self.assertIn("I will check Product X.", result.transcript_input)
self.assertEqual(
result.runtime_metadata["output_language"], language or "de"
)
self.assertEqual(
context_path.read_text(encoding="utf-8"), context_text
)
context = load_meeting_context(context_path)
with (
patch(
"src.meeting_lab.orchestration.mvp.generate_direct_protocol",
side_effect=generate,
),
patch(
"src.meeting_lab.orchestration.mvp.transcribe_audio",
side_effect=AssertionError("Retranscription is forbidden"),
),
):
regenerate_mvp_protocol(run, meeting_context=context)
metadata = json.loads(
(run / "protocol" / "runtime_metadata.json").read_text()
)
self.assertEqual(metadata["output_language"], language or "de")
self.assertIn(
f"Write the meeting protocol in {expected}.",
call.call_args.args[2],
)
self.assertEqual(transcript.read_bytes(), original)
self.assertEqual(
load_meeting_context(context_path).data, context.data
)
self.assertEqual(context.speaker_mappings, {"SPEAKER_00": "person"})
def test_no_context_defaults_to_german(self) -> None:
with tempfile.TemporaryDirectory() as directory:
transcript = Path(directory) / "transcript.json"
transcript.write_text('{"text": "English source text."}')
result = generate_direct_protocol(
transcript,
model_check=Mock(return_value={}),
generation_call=Mock(
return_value=OllamaGeneration(
text="Protocol",
raw_response={},
client_wall_time_seconds=0.1,
)
),
)
self.assertIn("Write the meeting protocol in German.", result.exact_prompt)
self.assertEqual(result.runtime_metadata["output_language"], "de")