From 8073eb5b20bb65bce689ed08311b676d0bc122c2 Mon Sep 17 00:00:00 2001 From: NotYuSheng Date: Mon, 18 May 2026 23:00:01 +0800 Subject: [PATCH 1/4] fix: handle both pyannote 4.x DiarizeOutput and legacy Annotation return types pyannote 4.x returns DiarizeOutput (with .speaker_diarization) when legacy=False, but returns Annotation directly when legacy=True or when using pyannote <4.0. Guard with hasattr check so both paths work correctly. Co-Authored-By: Claude Sonnet 4.6 --- backend/services/diarization_service.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/backend/services/diarization_service.py b/backend/services/diarization_service.py index f01675c..bcea6d4 100644 --- a/backend/services/diarization_service.py +++ b/backend/services/diarization_service.py @@ -83,12 +83,17 @@ async def diarize(self, job_uuid: str, file_path: str) -> dict: logger.info("Diarization complete for job %s", job_uuid) # Convert diarization to serializable format - # pyannote 4.x returns a DiarizeOutput object; itertracks is on the inner Annotation + # pyannote 4.x (legacy=False) returns DiarizeOutput; legacy=True or <4.x returns Annotation directly + annotation = ( + diarization.speaker_diarization + if hasattr(diarization, "speaker_diarization") + else diarization + ) diarization_data = { "segments": [] } - for turn, _, speaker in diarization.speaker_diarization.itertracks(yield_label=True): + for turn, _, speaker in annotation.itertracks(yield_label=True): diarization_data["segments"].append({ "start": turn.start, "end": turn.end, From b1b6a1ab7c33631668970d9c5774bab6af442df3 Mon Sep 17 00:00:00 2001 From: NotYuSheng Date: Mon, 18 May 2026 23:01:28 +0800 Subject: [PATCH 2/4] revert: remove legacy pyannote compatibility guard pyannote>=4.0 is pinned in requirements.txt so legacy=True can never occur in this codebase. The hasattr guard was dead code. Co-Authored-By: Claude Sonnet 4.6 --- backend/services/diarization_service.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/backend/services/diarization_service.py b/backend/services/diarization_service.py index bcea6d4..f97c7ad 100644 --- a/backend/services/diarization_service.py +++ b/backend/services/diarization_service.py @@ -83,17 +83,12 @@ async def diarize(self, job_uuid: str, file_path: str) -> dict: logger.info("Diarization complete for job %s", job_uuid) # Convert diarization to serializable format - # pyannote 4.x (legacy=False) returns DiarizeOutput; legacy=True or <4.x returns Annotation directly - annotation = ( - diarization.speaker_diarization - if hasattr(diarization, "speaker_diarization") - else diarization - ) + # pyannote 4.x returns a DiarizeOutput; itertracks is on the inner Annotation diarization_data = { "segments": [] } - for turn, _, speaker in annotation.itertracks(yield_label=True): + for turn, _, speaker in diarization.speaker_diarization.itertracks(yield_label=True): diarization_data["segments"].append({ "start": turn.start, "end": turn.end, From 5c205751dc076528777bedfea13cfd477e2e4a3d Mon Sep 17 00:00:00 2001 From: NotYuSheng Date: Mon, 18 May 2026 23:04:01 +0800 Subject: [PATCH 3/4] fix: truncate long speaker badge names in sidebar with ellipsis Badges now cap at 160px with text-overflow: ellipsis and a title attribute for full name on hover. Container uses flex-wrap so multiple badges wrap cleanly instead of overflowing the card. Co-Authored-By: Claude Sonnet 4.6 --- .../src/components/Transcript/MeetingInfoSidebar.jsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Transcript/MeetingInfoSidebar.jsx b/frontend/src/components/Transcript/MeetingInfoSidebar.jsx index 870ad42..6fa694b 100644 --- a/frontend/src/components/Transcript/MeetingInfoSidebar.jsx +++ b/frontend/src/components/Transcript/MeetingInfoSidebar.jsx @@ -33,10 +33,15 @@ export default function MeetingInfoSidebar({
Speakers -
+
{transcript?.segments ? ( [...new Set(transcript.segments.map((s) => s.speaker))].map((speaker) => ( - + {speaker} )) From 90b2e6ed7f9e5ec5e316ccfb1a7c663cb0463632 Mon Sep 17 00:00:00 2001 From: NotYuSheng Date: Mon, 18 May 2026 23:10:09 +0800 Subject: [PATCH 4/4] fix: use text-truncate class for speaker badge overflow Replace verbose inline overflow styles with Bootstrap text-truncate utility class, keeping only maxWidth in the style prop. Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/components/Transcript/MeetingInfoSidebar.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/Transcript/MeetingInfoSidebar.jsx b/frontend/src/components/Transcript/MeetingInfoSidebar.jsx index cdd80e0..76a0080 100644 --- a/frontend/src/components/Transcript/MeetingInfoSidebar.jsx +++ b/frontend/src/components/Transcript/MeetingInfoSidebar.jsx @@ -39,7 +39,8 @@ export default function MeetingInfoSidebar({ {speaker}