"""Assign pyannote speaker labels to whisper segments via max-overlap.""" def _overlap(a_start, a_end, b_start, b_end): return max(0.0, min(a_end, b_end) - max(a_start, b_start)) def assign_speakers(whisper_segs, diar_turns): """For each whisper segment, pick the speaker whose pyannote turn overlaps most. Falls back to the nearest-midpoint speaker if no overlap exists. If diar_turns is empty, every segment is labeled SPEAKER_00. """ if not diar_turns: return [{**s, "speaker": "SPEAKER_00"} for s in whisper_segs] result = [] for seg in whisper_segs: best_speaker = None best_overlap = 0.0 nearest_speaker = None best_distance = float("inf") seg_mid = (seg["start"] + seg["end"]) / 2 for turn in diar_turns: ov = _overlap(seg["start"], seg["end"], turn["start"], turn["end"]) if ov > best_overlap: best_overlap = ov best_speaker = turn["speaker"] turn_mid = (turn["start"] + turn["end"]) / 2 d = abs(seg_mid - turn_mid) if d < best_distance: best_distance = d nearest_speaker = turn["speaker"] speaker = best_speaker or nearest_speaker or "SPEAKER_00" result.append({**seg, "speaker": speaker}) return result