Collapse adjacent same-speaker segments after reconciliation
Fragments reabsorbed by smoothFragments (e.g. "I" then "need to switch it back") were left as separate transcript lines. Add SpeakerReconciler.mergeAdjacent to join consecutive same-speaker segments within 2s, concatenating their text. Wire it into SessionController.finishBackend AFTER reconcile/LLM naming. The collapse needs no LLM, so finishBackend no longer early-returns when the gateway has no chat model — it runs the collapse and re-persists speakers.json unconditionally, gating only the reconcile and recap passes on the model.
This commit is contained in:
@@ -73,6 +73,38 @@ final class SpeakerReconcilerTests: XCTestCase {
|
||||
XCTAssertTrue(out.speakers.contains { $0.name == "Me" }) // self never dissolved
|
||||
}
|
||||
|
||||
func testMergeAdjacentCollapsesSameSpeakerAndJoinsText() {
|
||||
let f = file([sp("A", "content"), sp("B", "content")], [
|
||||
SpeakersFile.Segment(start: 0, end: 1, speaker: "A", text: "I"),
|
||||
SpeakersFile.Segment(start: 1.5, end: 4, speaker: "A", text: "need to switch it back"),
|
||||
SpeakersFile.Segment(start: 4.2, end: 6, speaker: "B", text: "Sure"),
|
||||
])
|
||||
let out = SpeakerReconciler.mergeAdjacent(f, maxGap: 2.0)
|
||||
XCTAssertEqual(out.segments.count, 2) // two A's collapsed
|
||||
XCTAssertEqual(out.segments[0].speaker, "A")
|
||||
XCTAssertEqual(out.segments[0].start, 0, accuracy: 0.001)
|
||||
XCTAssertEqual(out.segments[0].end, 4, accuracy: 0.001)
|
||||
XCTAssertEqual(out.segments[0].text, "I need to switch it back")
|
||||
XCTAssertEqual(out.segments[1].speaker, "B") // different speaker untouched
|
||||
}
|
||||
|
||||
func testMergeAdjacentRespectsMaxGapAndSpeakerBoundaries() {
|
||||
let f = file([sp("A", "content")], [
|
||||
SpeakersFile.Segment(start: 0, end: 1, speaker: "A", text: "one"),
|
||||
SpeakersFile.Segment(start: 5, end: 6, speaker: "A", text: "two"), // gap 4s > maxGap
|
||||
])
|
||||
let out = SpeakerReconciler.mergeAdjacent(f, maxGap: 2.0)
|
||||
XCTAssertEqual(out.segments.count, 2) // large gap → not merged
|
||||
|
||||
// A B A must stay three segments (intervening speaker breaks the run).
|
||||
let g = file([sp("A", "content"), sp("B", "content")], [
|
||||
SpeakersFile.Segment(start: 0, end: 1, speaker: "A", text: "a1"),
|
||||
SpeakersFile.Segment(start: 1.2, end: 2, speaker: "B", text: "b"),
|
||||
SpeakersFile.Segment(start: 2.2, end: 3, speaker: "A", text: "a2"),
|
||||
])
|
||||
XCTAssertEqual(SpeakerReconciler.mergeAdjacent(g, maxGap: 2.0).segments.count, 3)
|
||||
}
|
||||
|
||||
func testParseNamingDropsNullAndKeepsConfidence() {
|
||||
let json = #"{"speakers":[{"current":"MH","name":"Jonathan Kirkwood","confidence":"high"},{"current":"Unknown_0","name":null,"confidence":"low"}]}"#
|
||||
let m = SpeakerReconciler.parseNaming(json)
|
||||
|
||||
Reference in New Issue
Block a user