Revamp EasyCom floor event review pipeline

This commit is contained in:
Xin Wang
2026-09-14 18:43:58 +08:00
parent 7d9db4af58
commit 4f88806d56
11 changed files with 1081 additions and 965 deletions

View File

@@ -50,17 +50,17 @@ class EOTINTReviewCandidateTests(unittest.TestCase):
def derive(self, rows: list[Utterance]):
return derive_protocol_candidates(rows, [clip()], session="Session_4")
def test_eot_response_is_anchored_by_wearer_onset(self) -> None:
def test_every_wearer_onset_is_an_unresolved_entry_candidate(self) -> None:
rows = [
utterance("other", 4, 0.0, 1.0, "Your turn."),
utterance("wearer", 2, 1.2, 2.0, "My response."),
]
event = next(row for row in self.derive(rows) if row.task == "eot_response")
self.assertEqual(event.automatic_protocol_label, "positive")
self.assertEqual(event.anchor_type, "other_offset")
self.assertEqual(event.behavior_anchor_type, "wearer_onset")
self.assertAlmostEqual(event.anchor_dense_seconds, 1.0)
self.assertAlmostEqual(event.behavior_seconds or -1, 1.2)
event = next(row for row in self.derive(rows) if row.candidate_source == "WEARER_ONSET")
self.assertEqual(event.automatic_protocol_label, "unsure")
self.assertEqual(event.rule_candidate_type, "ENTRY_CANDIDATE")
self.assertEqual(event.anchor_type, "wearer_onset")
self.assertAlmostEqual(event.event_time, 1.2)
self.assertAlmostEqual(event.temporal_evidence["wearer_speech_duration_after_onset_seconds"], 0.8)
def test_same_other_resume_is_eot_midturn_hard_negative(self) -> None:
rows = [
@@ -70,11 +70,11 @@ class EOTINTReviewCandidateTests(unittest.TestCase):
event = next(
row
for row in self.derive(rows)
if row.task == "eot_response" and row.anchor_dense_seconds == 1.0
if row.candidate_source == "SAME_SPEAKER_PAUSE" and row.anchor_dense_seconds == 1.0
)
self.assertEqual(event.automatic_protocol_label, "hard_negative")
self.assertEqual(event.automatic_hard_negative_type, "eot_midturn_pause")
self.assertEqual(event.region_end_reason, "competing_other_onset")
self.assertEqual(event.automatic_hard_negative_type, "EOT_MIDTURN_PAUSE")
self.assertAlmostEqual(event.temporal_evidence["resume_delay_seconds"], 0.3)
def test_other_to_other_transfer_is_eot_hard_negative(self) -> None:
rows = [
@@ -84,31 +84,44 @@ class EOTINTReviewCandidateTests(unittest.TestCase):
event = next(
row
for row in self.derive(rows)
if row.task == "eot_response" and row.anchor_dense_seconds == 1.0
if row.candidate_source == "OTHER_TO_OTHER" and row.anchor_dense_seconds == 1.0
)
self.assertEqual(event.automatic_protocol_label, "hard_negative")
self.assertEqual(event.automatic_hard_negative_type, "eot_other_to_other")
self.assertEqual(event.automatic_hard_negative_type, "EOT_OTHER_TO_OTHER")
self.assertNotEqual(
event.temporal_evidence["previous_speaker_id"],
event.temporal_evidence["incoming_speaker_id"],
)
def test_int_yield_is_anchored_by_wearer_offset(self) -> None:
def test_every_wearer_offset_is_an_unresolved_yield_candidate(self) -> None:
rows = [
utterance("wearer", 2, 0.0, 2.0, "Wearer is speaking."),
utterance("other", 4, 1.0, 3.0, "I will take over now."),
]
event = next(row for row in self.derive(rows) if row.task == "int_yield")
self.assertEqual(event.automatic_protocol_label, "positive")
self.assertEqual(event.anchor_type, "other_onset")
self.assertEqual(event.behavior_anchor_type, "wearer_offset")
self.assertAlmostEqual(event.behavior_seconds or -1, 2.0)
event = next(row for row in self.derive(rows) if row.candidate_source == "WEARER_OFFSET")
self.assertEqual(event.automatic_protocol_label, "unsure")
self.assertEqual(event.rule_candidate_type, "YIELD_CANDIDATE")
self.assertEqual(event.anchor_type, "wearer_offset")
self.assertAlmostEqual(event.event_time, 2.0)
def test_brief_feedback_is_int_backchannel_hard_negative(self) -> None:
rows = [
utterance("wearer", 2, 0.0, 3.0, "Wearer keeps the floor."),
utterance("other", 4, 1.0, 1.4, "Yeah."),
]
event = next(row for row in self.derive(rows) if row.task == "int_yield")
event = next(row for row in self.derive(rows) if row.candidate_source == "OTHER_BACKCHANNEL")
self.assertEqual(event.automatic_protocol_label, "hard_negative")
self.assertEqual(event.automatic_hard_negative_type, "int_backchannel")
self.assertEqual(event.region_end_reason, "competing_other_offset")
self.assertEqual(event.automatic_hard_negative_type, "INT_OTHER_BACKCHANNEL")
self.assertTrue(event.temporal_evidence["wearer_active_through_region"])
def test_non_takeover_overlap_is_scanned_without_wearer_transition(self) -> None:
rows = [
utterance("wearer", 2, 0.0, 4.0, "Long wearer turn."),
utterance("other", 4, 1.0, 2.0, "Long overlapping contribution."),
]
event = next(row for row in self.derive(rows) if row.candidate_source == "NON_TAKEOVER_OVERLAP")
self.assertEqual(event.automatic_hard_negative_type, "INT_NON_TAKEOVER_OVERLAP")
self.assertAlmostEqual(event.region_start_seconds, 1.0)
if __name__ == "__main__":