Skip to content

Commit b7441b6

Browse files
devin-ai-integration[bot]John
andcommitted
fix: speaker assignment not saving when selected from dropdown
Two issues in the Rust transcript rendering pipeline: 1. Auto-generated channel assignments (from participant list) were appended AFTER user assignments, causing HashMap::insert to overwrite user choices with auto-generated ones. Fix: reverse ordering so user assignments are processed last and take priority. 2. Channel-scoped assignments were gated by complete_channels, which only includes RemoteParty for exactly 2-participant meetings. For 3+ participant meetings without speaker diarization, user assignments on RemoteParty were silently ignored. Fix: remove the complete_channels gate from apply_identity_rules and assign_complete_channel_human_id so channel-wide assignments are always applied. Closes #4860 Co-Authored-By: John <john@hyprnote.com>
1 parent a6e50d3 commit b7441b6

3 files changed

Lines changed: 47 additions & 7 deletions

File tree

crates/transcript/src/render.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,11 @@ pub fn render_transcript_segments(
7171
.map(|started_at| started_at - base_started_at)
7272
.unwrap_or(0);
7373

74-
let (words, mut assignments) =
74+
let (words, user_assignments) =
7575
offset_transcript_data(transcript.words, transcript.assignments, offset);
76-
let channel_assignments =
76+
let mut assignments =
7777
channel_assignments_for_participants(&participant_human_ids, self_human_id.as_deref());
78-
assignments.extend(channel_assignments);
78+
assignments.extend(user_assignments);
7979

8080
let segments = build_segments(&words, &[], &assignments, Some(&segment_options));
8181
all_segments.extend(segments);
@@ -464,6 +464,40 @@ mod tests {
464464
assert_eq!(segments[1].text, "remote more");
465465
}
466466

467+
#[test]
468+
fn user_assignment_overrides_auto_channel_assignment() {
469+
let segments = render_transcript_segments(RenderTranscriptRequest {
470+
transcripts: vec![RenderTranscriptInput {
471+
started_at: Some(0),
472+
words: vec![
473+
word("w1", " hello", 0, 100, 0),
474+
word("w2", " remote", 120, 220, 1),
475+
],
476+
assignments: vec![channel_assignment("override", ChannelProfile::RemoteParty)],
477+
}],
478+
participant_human_ids: vec!["self".to_string(), "auto-remote".to_string()],
479+
self_human_id: Some("self".to_string()),
480+
humans: vec![
481+
RenderTranscriptHuman {
482+
human_id: "self".to_string(),
483+
name: "Me".to_string(),
484+
},
485+
RenderTranscriptHuman {
486+
human_id: "auto-remote".to_string(),
487+
name: "Auto".to_string(),
488+
},
489+
RenderTranscriptHuman {
490+
human_id: "override".to_string(),
491+
name: "Override".to_string(),
492+
},
493+
],
494+
});
495+
496+
assert_eq!(segments.len(), 2);
497+
assert_eq!(segments[0].speaker_label, "Me");
498+
assert_eq!(segments[1].speaker_label, "Override");
499+
}
500+
467501
#[test]
468502
fn keeps_missing_started_at_rows_anchored_at_zero() {
469503
let segments = render_transcript_segments(RenderTranscriptRequest {

crates/transcript/src/segments/speakers.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,6 @@ pub(super) fn assign_complete_channel_human_id(segment: &mut ProtoSegment, state
9191
}
9292

9393
let channel = segment.key.channel;
94-
if !state.complete_channels.contains(&channel) {
95-
return;
96-
}
9794

9895
if let Some(human_id) = state.human_id_by_channel.get(&channel) {
9996
segment.key = SegmentKey {
@@ -120,7 +117,6 @@ fn apply_identity_rules(
120117
}
121118

122119
if identity.human_id.is_none()
123-
&& state.complete_channels.contains(&word.channel)
124120
&& let Some(human_id) = state.human_id_by_channel.get(&word.channel)
125121
{
126122
identity.human_id = Some(human_id.clone());

crates/transcript/src/segments/tests.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,16 @@ fn propagates_remote_party_identity_when_channel_marked_complete() {
405405
assert_eq!(result[0].key.speaker_human_id.as_deref(), Some("remote"));
406406
}
407407

408+
#[test]
409+
fn applies_channel_assignment_even_without_complete_channel() {
410+
let finals = vec![fw("0", 0, 100, 1), fw("1", 200, 300, 1)];
411+
let assignments = vec![channel_human("remote", ChannelProfile::RemoteParty)];
412+
// Default options only mark DirectMic as complete, not RemoteParty
413+
let result = build_segments(&finals, &[], &assignments, None);
414+
assert_eq!(result.len(), 1);
415+
assert_eq!(result[0].key.speaker_human_id.as_deref(), Some("remote"));
416+
}
417+
408418
#[test]
409419
fn partial_word_ignores_its_own_runtime_hint_and_keeps_previous_segment_key() {
410420
let finals = vec![fw_si("0", 0, 100, 0, 0)];

0 commit comments

Comments
 (0)