diff --git a/internal/coalesce/coalesce.go b/internal/coalesce/coalesce.go index 6b8566e..dad9807 100644 --- a/internal/coalesce/coalesce.go +++ b/internal/coalesce/coalesce.go @@ -160,13 +160,7 @@ func (r run) coalescedSegment(id int) model.Segment { } func segmentRef(segment model.Segment) string { - if segment.SourceSegmentIndex != nil { - return fmt.Sprintf("%s#%d", segment.Source, *segment.SourceSegmentIndex) - } - if segment.SourceRef != "" { - return segment.SourceRef - } - return segment.Source + return model.SegmentReference(segment) } func isSkippableInterjection(segment model.Segment) bool { diff --git a/internal/model/model.go b/internal/model/model.go index b129ec9..1b35939 100644 --- a/internal/model/model.go +++ b/internal/model/model.go @@ -1,5 +1,7 @@ package model +import "fmt" + // RawTranscript is a loaded input document before canonical normalization. type RawTranscript struct { Source string `json:"source"` @@ -61,6 +63,17 @@ type Segment struct { OverlapGroupID int `json:"overlap_group_id,omitempty"` } +// SegmentReference returns the best available external reference for a segment. +func SegmentReference(segment Segment) string { + if segment.Source != "" && segment.SourceSegmentIndex != nil { + return fmt.Sprintf("%s#%d", segment.Source, *segment.SourceSegmentIndex) + } + if segment.SourceRef != "" { + return segment.SourceRef + } + return "" +} + // Word preserves optional word-level timing data. type Word struct { Text string `json:"text"` diff --git a/internal/model/model_test.go b/internal/model/model_test.go new file mode 100644 index 0000000..2550b8d --- /dev/null +++ b/internal/model/model_test.go @@ -0,0 +1,41 @@ +package model + +import "testing" + +func TestSegmentReferenceUsesSourceAndIndexWhenAvailable(t *testing.T) { + index := 3 + segment := Segment{ + Source: "input.json", + SourceSegmentIndex: &index, + SourceRef: "word-run:1:2:3", + } + + got := SegmentReference(segment) + want := "input.json#3" + if got != want { + t.Fatalf("reference = %q, want %q", got, want) + } +} + +func TestSegmentReferenceFallsBackToSourceRef(t *testing.T) { + segment := Segment{ + Source: "input.json", + SourceRef: "coalesce:2", + } + + got := SegmentReference(segment) + want := "coalesce:2" + if got != want { + t.Fatalf("reference = %q, want %q", got, want) + } +} + +func TestSegmentReferenceReturnsEmptyWhenNoReferenceFieldsPresent(t *testing.T) { + segment := Segment{ + Source: "input.json", + } + + if got := SegmentReference(segment); got != "" { + t.Fatalf("reference = %q, want empty", got) + } +} diff --git a/internal/overlap/detect.go b/internal/overlap/detect.go index bd8248b..97a1061 100644 --- a/internal/overlap/detect.go +++ b/internal/overlap/detect.go @@ -1,7 +1,6 @@ package overlap import ( - "fmt" "sort" "gitea.maximumdirect.net/eric/seriatim/internal/model" @@ -121,13 +120,7 @@ func distinctSpeakers(segments []model.Segment, indices []int) []string { // SegmentRef returns the stable overlap reference for a segment. func SegmentRef(segment model.Segment) string { - if segment.SourceSegmentIndex != nil { - return fmt.Sprintf("%s#%d", segment.Source, *segment.SourceSegmentIndex) - } - if segment.SourceRef != "" { - return segment.SourceRef - } - return segment.Source + return model.SegmentReference(segment) } func clearExisting(in *model.MergedTranscript) {