"""Focused tests for transcript-derived EasyCom interaction proxies.""" from __future__ import annotations import unittest from derive_easycom_interaction_events import Rules, Utterance, classify_utterance def utterance( uid: str, participant: int, start: float, end: float, text: str, *, target: tuple[int | str, ...] = ("Group",), ) -> Utterance: return Utterance( uid=uid, session="Session_7", clip_stem="00-00-000", clip_index=0, segment_id=0, participant_id=participant, target_of_speech=target, transcription=text, source_start_frame=round(start * 20) + 1, source_end_frame=round(end * 20), dense_start_frame=round(start * 20), dense_end_frame_exclusive=round(end * 20), dense_start_seconds=start, dense_end_seconds=end, duration_seconds=end - start, starts_at_clip_boundary=False, ends_at_clip_boundary=False, annotation_end_frame_clamped_by=0, is_cross_clip_continuation=False, ) class InteractionProxyTests(unittest.TestCase): def setUp(self) -> None: self.rules = Rules() def classify(self, target: Utterance, rows: list[Utterance]): return classify_utterance( target, rows, camera_wearer_id=2, rules=self.rules, ) def test_short_feedback_inside_retained_floor_is_backchannel_proxy(self) -> None: floor = utterance("floor", 4, 0.0, 4.0, "Long explanation") feedback = utterance("feedback", 2, 1.0, 1.4, "Yeah.", target=(4,)) event = self.classify(feedback, [floor, feedback]) self.assertEqual(event.event_type, "backchannel_proxy_high") self.assertTrue(event.trainable_auxiliary) self.assertEqual(event.retained_floor_participant_id, 4) def test_short_answer_without_floor_return_is_not_backchannel(self) -> None: question = utterance("question", 4, 0.0, 1.0, "Ready?") answer = utterance("answer", 2, 1.1, 2.3, "Yeah, let us start.", target=(4,)) event = self.classify(answer, [question, answer]) self.assertEqual(event.event_type, "ordinary_switch") def test_overlap_takeover_after_cutoff_is_interruption_proxy(self) -> None: old = utterance("old", 4, 0.0, 2.0, "I was going to-") incoming = utterance("incoming", 2, 1.7, 3.2, "Wait, that is wrong.", target=(4,)) event = self.classify(incoming, [old, incoming]) self.assertEqual(event.event_type, "interruption_proxy_high") self.assertTrue(event.trainable_auxiliary) def test_overlap_takeover_without_cutoff_is_not_called_interruption(self) -> None: old = utterance("old", 4, 0.0, 2.0, "I finished my point.") incoming = utterance("incoming", 2, 1.7, 3.2, "Here is my response.", target=(4,)) event = self.classify(incoming, [old, incoming]) self.assertEqual(event.event_type, "overlap_takeover") self.assertTrue(event.trainable_auxiliary) def test_short_nonlexical_floor_return_is_masked_candidate(self) -> None: before = utterance("before", 4, 0.0, 1.2, "First part") brief = utterance("brief", 2, 1.25, 1.8, "Possibly.", target=(4,)) after = utterance("after", 4, 1.9, 3.0, "Second part") event = self.classify(brief, [before, brief, after]) self.assertEqual(event.event_type, "backchannel_candidate") self.assertFalse(event.trainable_auxiliary) def test_hesitation_marker_is_not_nonverbal_feedback(self) -> None: floor = utterance("floor", 4, 0.0, 4.0, "Long explanation") hesitation = utterance("hesitation", 2, 1.0, 1.2, "[H]", target=(4,)) event = self.classify(hesitation, [floor, hesitation]) self.assertEqual(event.event_type, "nonverbal_candidate") self.assertFalse(event.trainable_auxiliary) def test_cross_clip_continuation_never_creates_switch(self) -> None: row = utterance("continued", 2, 60.0, 61.0, "[X] continued") row = Utterance( **{**row.__dict__, "is_cross_clip_continuation": True} ) event = self.classify(row, [row]) self.assertEqual(event.event_type, "cross_clip_continuation") self.assertFalse(event.trainable_auxiliary) if __name__ == "__main__": unittest.main()