🔊(summary) improve logging of speaker assign

Structure logging of speaker assignment in json format to help
assess its performance.
This commit is contained in:
leo
2026-05-13 18:38:06 +02:00
committed by aleb_the_flash
parent dcaa45ccfe
commit 79400188d8
+46 -12
View File
@@ -8,9 +8,10 @@ Multiple speakers can map to the same participant (e.g. two people sharing
one microphone). A participant with no matching speaker gets no assignment. one microphone). A participant with no matching speaker gets no assignment.
""" """
import json
import logging import logging
from collections import defaultdict from collections import defaultdict
from dataclasses import dataclass, field from dataclasses import asdict, dataclass, field, is_dataclass
from datetime import datetime from datetime import datetime
from typing import Any from typing import Any
@@ -318,6 +319,24 @@ def _build_speaker_timelines(transcription: Any) -> dict[str, list[Interval]]:
return intervals return intervals
def _json_default(obj: Any) -> Any:
"""Encode datetimes, dataclasses, and pydantic models for `json.dumps`.
Intended to be used for logging of `resolve_speaker_identities` (input
and computed variables)
"""
if isinstance(obj, datetime):
return obj.isoformat()
if is_dataclass(obj) and not isinstance(obj, type):
return asdict(obj)
if hasattr(obj, "segments") and hasattr(obj, "word_segments"):
return {"segments": obj.segments, "word_segments": obj.word_segments}
if hasattr(obj, "model_dump"):
return obj.model_dump(mode="json")
raise TypeError(f"Object of type {type(obj).__name__} is not JSON serializable")
def resolve_speaker_identities( def resolve_speaker_identities(
metadata: dict[str, Any], metadata: dict[str, Any],
transcription: Any, transcription: Any,
@@ -344,17 +363,6 @@ def resolve_speaker_identities(
) )
speaker_timelines = _build_speaker_timelines(transcription) speaker_timelines = _build_speaker_timelines(transcription)
logger.debug(
"Assignment inputs: %d participants, %d speakers\n%s\n%s\n%s",
len(participant_timelines),
len(speaker_timelines),
participant_timelines,
speaker_timelines,
_format_timelines_debug(
participant_timelines, participant_names, speaker_timelines
),
)
result = AssignmentResult() result = AssignmentResult()
for speaker, speaker_intervals in speaker_timelines.items(): for speaker, speaker_intervals in speaker_timelines.items():
@@ -397,4 +405,30 @@ def resolve_speaker_identities(
overlap_threshold, overlap_threshold,
) )
logger.debug(
json.dumps(
{
"input": {
"recording_start_datetime": recording_start_datetime.isoformat(),
"recording_end_datetime": recording_end_datetime.isoformat(),
"metadata": metadata,
"transcription": transcription,
},
"computed": {
"speaker_timelines": speaker_timelines,
"participant_timelines": participant_timelines,
"result": result,
},
},
default=_json_default,
indent=2,
ensure_ascii=False,
),
)
logger.debug(
_format_timelines_debug(
participant_timelines, participant_names, speaker_timelines
),
)
return result return result