Forward glossary provenance without transcript substitution

This commit is contained in:
2026-09-12 11:51:38 +02:00
parent 77be2b39ff
commit 500d2c4c67
6 changed files with 39 additions and 1 deletions
+2
View File
@@ -20,6 +20,8 @@
### Changed ### Changed
- Record active glossary configuration without rewriting protocol transcript input.
- Reconciled the documented MVP with the validated Meeting Lab backend. - Reconciled the documented MVP with the validated Meeting Lab backend.
- Selected `whisper.cpp` for transcription and made diarization optional. - Selected `whisper.cpp` for transcription and made diarization optional.
- Defined the Python API, progress-event and Meeting Context integration - Defined the Python API, progress-event and Meeting Context integration
+5
View File
@@ -164,3 +164,8 @@ product work, not a current MVP requirement.
- no automatic identity claims - no automatic identity claims
- human review of generated protocols - human review of generated protocols
- small modules and simple interfaces - small modules and simple interfaces
Active glossary aliases are forwarded to Meeting Lab as provenance metadata.
Canonical terminology remains Meeting Context guidance; the exact protocol
transcript input and the raw Whisper/diarization artifacts are not rewritten.
`glossary_replacements` remains empty.
+5
View File
@@ -229,3 +229,8 @@ transcription; Meeting Assistant does not duplicate audio conversion.
See [Architecture](docs/architecture.md), [Project Knowledge](PROJECT_KNOWLEDGE.md), See [Architecture](docs/architecture.md), [Project Knowledge](PROJECT_KNOWLEDGE.md),
[Roadmap](ROADMAP.md) and [ADR 0011](docs/adr/0011-use-meeting-lab-mvp-backend.md). [Roadmap](ROADMAP.md) and [ADR 0011](docs/adr/0011-use-meeting-lab-mvp-backend.md).
Active glossary aliases are forwarded to Meeting Lab as provenance metadata.
Canonical terminology remains Meeting Context guidance; the exact protocol
transcript input and the raw Whisper/diarization artifacts are not rewritten.
`glossary_replacements` remains empty.
+5
View File
@@ -355,6 +355,11 @@ def render_glossary_terms(entries: Iterable[GlossaryEntry]) -> list[str]:
return rendered return rendered
def glossary_alias_mapping(entries: Iterable[GlossaryEntry]) -> dict[str, str]:
"""Return explicit alias configuration for provenance, not substitution."""
return {alias: entry.canonical_term for entry in entries for alias in entry.aliases}
def _timestamp() -> str: def _timestamp() -> str:
return datetime.now(UTC).isoformat(timespec="seconds") return datetime.now(UTC).isoformat(timespec="seconds")
+7 -1
View File
@@ -15,7 +15,11 @@ from uuid import uuid4
import yaml import yaml
from mka.application.config import AppSettings from mka.application.config import AppSettings
from mka.application.glossary import GlossaryRepository, render_glossary_terms from mka.application.glossary import (
GlossaryRepository,
glossary_alias_mapping,
render_glossary_terms,
)
from mka.application.performance import DEFAULT_PERFORMANCE_PROFILE, resolve_ollama_num_thread from mka.application.performance import DEFAULT_PERFORMANCE_PROFILE, resolve_ollama_num_thread
STAGES = ("preparing", "transcription", "diarization", "protocol_generation") STAGES = ("preparing", "transcription", "diarization", "protocol_generation")
@@ -231,6 +235,7 @@ class MeetingProcessingService:
"model": self.settings.protocol_model, "model": self.settings.protocol_model,
"ollama_endpoint": self.settings.ollama_endpoint, "ollama_endpoint": self.settings.ollama_endpoint,
"protocol_num_ctx": self.settings.protocol_num_ctx, "protocol_num_ctx": self.settings.protocol_num_ctx,
"glossary_aliases": glossary_alias_mapping(self.glossary.list(active_only=True)),
"protocol_num_thread": resolve_ollama_num_thread(options.performance_profile), "protocol_num_thread": resolve_ollama_num_thread(options.performance_profile),
"protocol_safe_input_token_budget": ( "protocol_safe_input_token_budget": (
self.settings.protocol_safe_input_token_budget self.settings.protocol_safe_input_token_budget
@@ -405,6 +410,7 @@ class MeetingProcessingService:
model=self.settings.protocol_model, model=self.settings.protocol_model,
ollama_endpoint=self.settings.ollama_endpoint, ollama_endpoint=self.settings.ollama_endpoint,
protocol_num_ctx=self.settings.protocol_num_ctx, protocol_num_ctx=self.settings.protocol_num_ctx,
glossary_aliases=glossary_alias_mapping(self.glossary.list(active_only=True)),
protocol_num_thread=resolve_ollama_num_thread(performance_profile), protocol_num_thread=resolve_ollama_num_thread(performance_profile),
protocol_safe_input_token_budget=(self.settings.protocol_safe_input_token_budget), protocol_safe_input_token_budget=(self.settings.protocol_safe_input_token_budget),
) )
+15
View File
@@ -512,6 +512,7 @@ def test_protocol_only_regeneration_persists_mappings_without_rewriting_transcri
"SPEAKER_00": "martin" "SPEAKER_00": "martin"
} }
assert gateway.regeneration["options"]["protocol_num_ctx"] == 32_768 assert gateway.regeneration["options"]["protocol_num_ctx"] == 32_768
assert gateway.regeneration["options"]["glossary_aliases"] == {"Enlyse": "ENLYZE"}
assert events[0].stage == "protocol_generation" assert events[0].stage == "protocol_generation"
assert source.read_bytes() == original_source assert source.read_bytes() == original_source
@@ -608,3 +609,17 @@ def test_protocol_regeneration_propagates_explicit_profile(tmp_path: Path) -> No
assert gateway.regeneration is not None assert gateway.regeneration is not None
assert gateway.regeneration["options"]["protocol_num_thread"] == 16 assert gateway.regeneration["options"]["protocol_num_thread"] == 16
def test_process_passes_only_active_explicit_glossary_aliases(tmp_path: Path) -> None:
service, gateway = make_service(tmp_path)
service.glossary.create("Luminy", "product", aliases=("Lumini",))
inactive = service.glossary.create("PBAT", "acronym", aliases=("PBRT",))
service.glossary.set_active(inactive.id, False)
audio = tmp_path / "meeting.wav"
audio.write_bytes(b"audio")
service.process(audio, meeting(), participants(), ProcessingOptions())
assert gateway.config_values is not None
assert gateway.config_values["glossary_aliases"] == {"Lumini": "Luminy"}