File size: 7,397 Bytes
25e624c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# -*- coding: utf-8 -*-
"""
Live Stream Test - Test real-time emotion transitions

Tests that emoji changes correctly when user types new text
Simulates live typing with emotion transitions
"""

import time
from typing import Dict, List, Tuple, Any
from dataclasses import dataclass


@dataclass
class TransitionResult:
    """Result of an emotion transition test"""
    from_text: str
    from_emotion: str
    from_emoji: str
    to_text: str
    to_emotion: str
    to_emoji: str
    combined_text: str
    final_detected_emotion: str
    final_emoji: str
    transition_correct: bool
    transition_time_ms: float


class LiveStreamTest:
    """
    Test live streaming emotion detection
    
    Simulates real-time typing with emotion transitions
    """
    
    # Emotion transition test cases
    # Format: [(from_text, from_emotion), (to_text, to_emotion)]
    TRANSITION_TESTS: List[Tuple[Tuple[str, str], Tuple[str, str]]] = [
        # Positive to Negative
        (("I love this!", "positive"), ("But now I'm angry", "negative")),
        (("This is amazing!", "positive"), ("Wait, this is terrible", "negative")),
        (("I'm so happy!", "positive"), ("Now I feel sad", "negative")),
        (("Great work!", "positive"), ("Actually, this is frustrating", "negative")),
        (("I'm excited!", "positive"), ("Now I'm disappointed", "negative")),
        
        # Negative to Positive
        (("I'm sad", "negative"), ("But now I'm happy!", "positive")),
        (("This is terrible", "negative"), ("Actually, it's great!", "positive")),
        (("I'm angry", "negative"), ("Now I feel better", "positive")),
        (("I'm frustrated", "negative"), ("But I'm grateful now", "positive")),
        (("I'm scared", "negative"), ("Now I'm excited!", "positive")),
        
        # Neutral transitions
        (("The weather is okay", "neutral"), ("I love sunny days!", "positive")),
        (("It's just normal", "neutral"), ("This is terrible news", "negative")),
        
        # Complex transitions
        (("I was worried", "negative"), ("But everything worked out great!", "positive")),
        (("Started feeling anxious", "negative"), ("Now I'm relieved and happy", "positive")),
        (("I'm confused", "negative"), ("But this explanation is amazing!", "positive")),
    ]
    
    def __init__(self, analyzer, emoji_mapper):
        """
        Initialize with analyzer and mapper
        
        Args:
            analyzer: SentimentAnalyzer instance
            emoji_mapper: EmojiMapper instance
        """
        self.analyzer = analyzer
        self.emoji_mapper = emoji_mapper
    
    def _get_polarity(self, label: str) -> str:
        """Map label to polarity"""
        positive = ["happiness", "joy", "positive", "love", "excitement"]
        negative = ["sadness", "anger", "negative", "fear", "frustration"]
        
        label_lower = label.lower()
        if label_lower in positive or "happiness" in label_lower:
            return "positive"
        elif label_lower in negative or "sadness" in label_lower:
            return "negative"
        return "neutral"
    
    def run_single_transition(
        self,
        from_text: str,
        from_expected: str,
        to_text: str,
        to_expected: str
    ) -> TransitionResult:
        """Run a single transition test"""
        # Analyze first text
        result1 = self.analyzer.analyze(from_text)
        from_emotion = result1.get("label", "neutral")
        from_emoji = self.emoji_mapper.get_emoji(from_emotion)
        
        # Combine texts (simulating continued typing)
        combined = f"{from_text} {to_text}"
        
        # Analyze combined (should detect LAST sentence emotion)
        start_time = time.perf_counter()
        result2 = self.analyzer.analyze(combined)
        end_time = time.perf_counter()
        
        transition_time_ms = (end_time - start_time) * 1000
        
        final_emotion = result2.get("label", "neutral")
        final_emoji = self.emoji_mapper.get_emoji(final_emotion)
        
        # Check if transition is correct (final emotion matches to_expected polarity)
        final_polarity = self._get_polarity(final_emotion)
        transition_correct = final_polarity == to_expected
        
        return TransitionResult(
            from_text=from_text,
            from_emotion=from_emotion,
            from_emoji=from_emoji,
            to_text=to_text,
            to_emotion=to_expected,
            to_emoji="",  # Expected emoji
            combined_text=combined,
            final_detected_emotion=final_emotion,
            final_emoji=final_emoji,
            transition_correct=transition_correct,
            transition_time_ms=transition_time_ms
        )
    
    def run_all_transitions(self) -> List[TransitionResult]:
        """Run all transition tests"""
        results = []
        
        for (from_text, from_exp), (to_text, to_exp) in self.TRANSITION_TESTS:
            result = self.run_single_transition(from_text, from_exp, to_text, to_exp)
            results.append(result)
        
        return results
    
    def get_transition_report(self, results: List[TransitionResult]) -> str:
        """Generate human-readable transition report"""
        correct = sum(1 for r in results if r.transition_correct)
        total = len(results)
        accuracy = correct / total if total > 0 else 0
        avg_time = sum(r.transition_time_ms for r in results) / total if total > 0 else 0
        
        lines = [
            "=" * 80,
            "LIVE STREAM EMOTION TRANSITION TEST",
            "=" * 80,
            "",
            f"Total Transitions: {total}",
            f"Correct Transitions: {correct}",
            f"Transition Accuracy: {accuracy:.1%}",
            f"Avg Transition Time: {avg_time:.2f} ms",
            "",
            "-" * 80,
            "TRANSITION DETAILS",
            "-" * 80,
        ]
        
        for i, r in enumerate(results, 1):
            status = "✓" if r.transition_correct else "✗"
            lines.extend([
                f"\n{status} Test {i}:",
                f"   From: \"{r.from_text[:40]}...\" → {r.from_emoji} ({r.from_emotion})",
                f"   To:   \"{r.to_text[:40]}...\" → Expected: {r.to_emotion}",
                f"   Combined: \"{r.combined_text[:50]}...\"",
                f"   Detected: {r.final_emoji} ({r.final_detected_emotion})",
                f"   Time: {r.transition_time_ms:.2f} ms",
            ])
        
        # Summary of failures
        failures = [r for r in results if not r.transition_correct]
        if failures:
            lines.extend([
                "",
                "-" * 80,
                f"FAILED TRANSITIONS: {len(failures)}",
                "-" * 80,
            ])
            for r in failures:
                lines.append(
                    f"  ✗ \"{r.combined_text[:60]}...\" "
                    f"→ Expected {r.to_emotion}, got {r.final_detected_emotion}"
                )
        
        lines.append("=" * 80)
        
        return "\n".join(lines)


if __name__ == "__main__":
    from avatar import SentimentAnalyzer, EmojiMapper
    
    analyzer = SentimentAnalyzer()
    mapper = EmojiMapper()
    test = LiveStreamTest(analyzer, mapper)
    
    results = test.run_all_transitions()
    print(test.get_transition_report(results))