Skip to content

meeting-minutes: speaker diarization via siren's new endpoints - #11

Merged
Kabilan108 merged 4 commits into
nixosfrom
meeting-minutes-diarization
Jul 27, 2026
Merged

meeting-minutes: speaker diarization via siren's new endpoints#11
Kabilan108 merged 4 commits into
nixosfrom
meeting-minutes-diarization

Conversation

@Kabilan108

@Kabilan108 Kabilan108 commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Client half of the siren diarization rollout (M4/M5 + review hardening). Three commits touching only bin/meeting-minutes.

  • Requests per-word timestamps on every chunk; preserves words in cached transcript parts.
  • Diarizes the whole recording once (/v1/audio/diarize), aligns words to turns server-side (/v1/audio/align), and writes speakers + per-segment speaker into transcript.json additively.
  • Prompt renders grouped [m:ss] SPEAKER_NN: turns (timestamps retained for the screenshot-candidate pass) plus an instruction to map labels to attendee names from content and turn-taking.
  • Best-effort like the calendar pass: any diarize/align failure (including empty-turn responses) degrades to today's flat transcript; MEETING_MINUTES_DIARIZE=0 disables.
  • Trailing sub-second ffmpeg segment slivers are dropped via decode-based duration (segment-muxer FLAC headers report cumulative end timestamps, not chunk length).

Verified end-to-end on a real recorded meeting against the siren branch: 211/211 segments speaker-tagged, prompt renders 102 timestamped speaker turns, flat fallback exercised. Requires the siren diarization-rollout branch server-side; degrades cleanly against older servers.

🤖 Generated with Claude Code


Open in Devin Review

Kabilan108 and others added 3 commits July 26, 2026 08:12
Requests word timestamps from siren, diarizes the whole recording once,
and aligns words to speaker turns server-side, producing speaker-tagged
transcript segments and a grouped "SPEAKER_NN:" prompt rendering in
place of the raw transcript JSON wall. Diarization is best-effort like
the calendar pass: any failure records itself in job status and falls
back to the flat transcript; MEETING_MINUTES_DIARIZE=0 disables it.
Trailing sub-second ffmpeg segment slivers are dropped via a decoding
duration check, since segment-muxer FLAC headers report the cumulative
end timestamp rather than the chunk length.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diarization yields anonymous SPEAKER_NN labels; the minutes model
already receives the attendee roster and calendar evidence, so let it
resolve labels from content and turn-taking. Mapping sharpens
attribution of decisions and follow-up ownership without surfacing
per-line bylines, and the prompt warns about split/mislabeled speakers
so content outweighs labels on conflict.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Restore timestamps to the speaker-tagged prompt rendering as
[m:ss] SPEAKER_NN turn prefixes - the plain speaker rendering had
silently removed every timestamp, breaking the screenshot-candidate
selection that depends on them. Reject empty-turn diarization responses
so a silent diarizer produces the flat-transcript fallback instead of
one fabricated speaker, and drop curl retries from the diarize call so
a slow whole-file pass is not re-run on the GPU after a client timeout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Jul 27, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds the client-side speaker diarization pipeline to meeting-minutes, calling two new Siren endpoints (/v1/audio/diarize, /v1/audio/align) and rendering the result as grouped [m:ss] SPEAKER_NN: turns in the Codex prompt. All diarization steps are best-effort: any failure degrades cleanly to the existing flat JSON transcript, and a MEETING_MINUTES_DIARIZE=0 env var disables the feature entirely.

  • Per-word timestamps are now requested on every transcription chunk via timestamp_granularities[]=word; collect_transcript_words stitches them across chunks with index * CHUNK_SECONDS offsets and feeds them to the align endpoint.
  • A new filter_degenerate_tail_chunks function decodes the last chunk with ffmpeg -f null to drop sub-second slivers created by the segment muxer before transcription; decode_duration (always decode-based) is correctly used here rather than probe_duration (header-based).
  • probe_duration gains a second ffprobe strategy (stream=duration) and an ffmpeg decode fallback, though a structural gap means the fallback is unreachable if ffprobe exits non-zero rather than outputting N/A.

Confidence Score: 5/5

Safe to merge; diarization runs entirely in best-effort mode and every failure path degrades cleanly to the pre-existing flat transcript.

All three new pipeline stages (diarize, align, render) are wrapped in their own isolated try/except blocks that catch subprocess, OS, and application errors and set a failed status before continuing. The transcript.json is only overwritten after valid_alignment passes, and atomic_write_json ensures no partial writes reach the prompt. The one structural gap noted (probe_duration loop not catching a non-zero ffprobe exit before reaching the ffmpeg fallback) affects an uncommon code path and has no impact on the new diarization logic, which correctly uses decode_duration for the sub-second sliver check.

Files Needing Attention: bin/meeting-minutes — specifically probe_duration, which gained new fallback strategies but has an incomplete try/except structure in the loop.

Important Files Changed

Filename Overview
bin/meeting-minutes Adds end-to-end speaker diarization (diarize → align → speaker-tagged prompt rendering) with graceful fallback; one structural gap in the probe_duration loop prevents the ffmpeg decode fallback from being reached when ffprobe exits non-zero.

Sequence Diagram

sequenceDiagram
    participant J as process_job
    participant FC as filter_degenerate_tail_chunks
    participant DR as diarize_recording
    participant TC as transcribe_chunks
    participant AT as align_transcript
    participant S as Siren API

    J->>FC: chunks (sorted FLACs)
    FC->>FC: decode_duration(last chunk)
    alt "duration < 1s"
        FC-->>J: chunks minus trailing sliver
    else
        FC-->>J: chunks unchanged
    end

    J->>DR: diarize_recording(job)
    DR->>S: POST /v1/audio/diarize (whole-recording FLAC)
    S-->>DR: "{turns, speakers, duration}"
    DR-->>J: diarization payload

    J->>TC: transcribe_chunks(job, chunks)
    TC->>S: "POST /v1/audio/transcriptions (per chunk, +timestamp_granularities[]=word)"
    S-->>TC: verbose_json with word timestamps
    TC-->>J: transcript.json

    J->>AT: align_transcript(job, transcript_path, diarization)
    AT->>AT: collect_transcript_words(job, chunks)
    AT->>S: "POST /v1/audio/align ({words, turns})"
    S-->>AT: "{speakers, segments with speaker labels}"
    AT->>AT: overwrite transcript.json with speaker-tagged segments
    AT-->>J: transcript_path

    J->>J: "render_transcript_for_prompt -> [m:ss] SPEAKER_NN: ..."
    J->>J: generate_minutes (Codex prompt)
Loading

Reviews (2): Last reviewed commit: "Address Greptile review findings" | Re-trigger Greptile

Comment thread bin/meeting-minutes
Comment thread bin/meeting-minutes
Comment thread bin/meeting-minutes
Reject empty alignment responses so a degenerate align result triggers
the flat-transcript fallback instead of silently emptying the
transcript, stop catching AssertionError in the job handler (the assert
it covered was removed with the decode-based sliver check), and add the
PEP 8 blank line before the nested timestamp helper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

@Kabilan108
Kabilan108 merged commit 801bb2c into nixos Jul 27, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant