File size: 10,418 Bytes
71a764a
 
 
36d5e94
71a764a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57be184
71a764a
 
57be184
 
 
 
 
 
71a764a
 
 
 
 
 
 
 
 
36d5e94
71a764a
 
 
 
 
 
 
 
 
 
36d5e94
 
 
 
71a764a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57be184
71a764a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
"""Scoring logic and enhanced score display functionality"""

import random
from .achievements import AchievementSystem

class Scorer:
    """Handles scoring calculations and display generation"""
    
    def __init__(self, template_renderer=None):
        self.template_renderer = template_renderer
    
    def calculate_difficulty(self, user_input, partial_response, llm_manager):
        """Calculate difficulty based on user input tokens and partial completion length"""
        if not user_input.strip():
            return "Easy", 0
        
        # Count tokens for user input
        user_token_count = llm_manager.count_tokens(user_input)
        
        # Count tokens for partial response  
        partial_token_count = llm_manager.count_tokens(partial_response)
        
        # Difficulty based on tokens and completion percentage
        completion_percentage = partial_token_count / 100  # Assume 100 is typical full response
        
        if user_token_count <= 2:
            if completion_percentage < 0.3:
                return "Medium", user_token_count
            else:
                return "Easy", user_token_count
        elif user_token_count <= 4:
            return "Medium", user_token_count
        else:
            return "Hard", user_token_count
    
    def calculate_rank_and_percentile(self, user_score, prompt_results, user_tokens, separate_by_token_count=False):
        """Calculate user's rank and percentile among users with same prompt and token count."""
        # Filter to only same prompt and same token count
        if separate_by_token_count:
            comparable_scores = [r["cosine_distance"] for r in prompt_results 
                            if r["num_user_tokens"] == user_tokens]
        else:
            comparable_scores = [r["cosine_distance"] for r in prompt_results]

        if not comparable_scores:
            return None, None
        
        # Sort scores in descending order (higher cosine distance = better creativity)
        sorted_scores = sorted(comparable_scores, reverse=True)
        
        # Find rank (1-based)
        rank = None
        for i, score in enumerate(sorted_scores):
            if user_score >= score:
                rank = i + 1
                break
        
        if rank is None:
            rank = len(sorted_scores) + 1
        
        # Calculate percentile (0-100)
        if len(sorted_scores) <= 1:
            percentile = 50.0
        else:
            # Compute raw percentile: proportion of users the current user is better than.
            raw_percentile = (len(sorted_scores) - rank) / len(sorted_scores) * 100.0
            # Ensure percentile is always within 0-100 even if rank is out of expected bounds
            percentile = max(0.0, min(100.0, raw_percentile))
        
        return rank, percentile
    
    def create_enhanced_score_display(self, cosine_distance, rank, percentile, user_tokens, same_category_attempts):
        """Create an enhanced score display with progress bars and metrics"""
        # Calculate progress bar width (cosine distance is 0-1, so multiply by 100 for percentage)
        score_percentage = min(100, cosine_distance * 100)
        
        # Determine score level and message
        if cosine_distance >= 0.7:
            score_level = "๐ŸŒŸ LEGENDARY CREATIVITY!"
            bar_color = "linear-gradient(45deg, #ff6b6b, #ffa726)"
        elif cosine_distance >= 0.5:
            score_level = "๐Ÿ”ฅ EXCEPTIONAL CREATIVITY!"
            bar_color = "linear-gradient(45deg, #4CAF50, #8bc34a)"
        elif cosine_distance >= 0.3:
            score_level = "โœจ GREAT CREATIVITY!"
            bar_color = "linear-gradient(45deg, #2196F3, #03DAC6)"
        elif cosine_distance >= 0.15:
            score_level = "๐Ÿ’ก GOOD CREATIVITY!"
            bar_color = "linear-gradient(45deg, #FF9800, #FFC107)"
        else:
            score_level = "๐Ÿค” ROOM FOR IMPROVEMENT"
            bar_color = "linear-gradient(45deg, #9E9E9E, #607D8B)"
        
        html_content = f"""
        <div class="score-container">
            <div class="score-header">{score_level}</div>
            <div class="progress-bar-container">
                <div class="progress-bar" style="width: {score_percentage}%; background: {bar_color};"></div>
            </div>
            <div style="text-align: center; margin: 10px 0;">
                <span style="font-size: 24px; font-weight: bold;">
                    Creativity Score: {cosine_distance:.3f}
                    <span class="help-tooltip">โ„น๏ธ
                        <span class="tooltip-text">
                            <strong>Creativity Score (0-1):</strong><br/>
                            Measures how different your influenced response is from the AI's original response. 
                            Higher scores = more creative divergence!<br/><br/>
                            โ€ข 0.7+: Legendary creativity<br/>
                            โ€ข 0.5+: Exceptional creativity<br/>
                            โ€ข 0.3+: Great creativity<br/>
                            โ€ข 0.15+: Good creativity
                        </span>
                    </span>
                </span>
            </div>
            <div class="score-details">
        """
        
        if rank is not None and percentile is not None:
            html_content += f"""
                <div class="score-metric">
                    <div class="metric-value">#{rank}</div>
                    <div class="metric-label">Rank out of {same_category_attempts}</div>
                </div>
                <div class="score-metric">
                    <div class="metric-value">{percentile:.1f}%</div>
                    <div class="metric-label">Better than others</div>
                </div>
            """
        
        html_content += f"""
                <div class="score-metric">
                    <div class="metric-value">{user_tokens}</div>
                    <div class="metric-label">Token{'s' if user_tokens != 1 else ''} used
                        <span class="help-tooltip">โ„น๏ธ
                            <span class="tooltip-text">
                                <strong>More tokens = Higher potential score!</strong><br/>
                                Using more tokens gives you more ways to steer me in creative directions, 
                                but the real challenge is making any number of tokens count!
                            </span>
                        </span>
                    </div>
                </div>
            </div>
        """
        
        # Add achievement titles
        achievement_system = AchievementSystem()
        achievements = achievement_system.determine_achievement_titles(cosine_distance, user_tokens)
        
        if achievements:
            html_content += """
            <div class="achievements-container">
                <div class="achievements-title">
                    ๐Ÿ† Achievements Earned
                    <span class="help-tooltip">โ„น๏ธ
                        <span class="tooltip-text">
                            <strong>Achievements:</strong><br/>
                            Earned based on your performance this session:<br/><br/>
                            โ€ข Creativity level (Genius, Master, Spark, etc.)<br/>
                            โ€ข Token efficiency (Word Wizard, Phrase Magician)<br/>
                            โ€ข Difficulty tackled (Challenge Conqueror)<br/>
                            โ€ข Special combos (One-Word Wonder, Elite Performer)
                        </span>
                    </span>
                </div>
                <div class="achievement-badges">
            """
            for title in achievements:
                html_content += f'<div class="achievement-badge">{title}</div>'
            html_content += """
                </div>
            </div>
            """
        
        # Add smart contextual tip
        smart_tip = self.generate_smart_tip(cosine_distance, user_tokens, rank, percentile)
        html_content += f"""
            <div class="smart-tip-container">
                <span class="smart-tip-icon">๐Ÿ’ก</span>
                <span class="smart-tip-text">{smart_tip}</span>
            </div>
            <div style="text-align: center; margin-top: 15px; opacity: 0.9; font-size: 14px;">
                Higher scores indicate more creative divergence from the original response!
            </div>
        </div>
        """
        
        return html_content
    
    def generate_smart_tip(self, cosine_distance, user_tokens, rank, percentile):
        """Generate personalized tips based on user performance"""
        tips = []
        
        # Performance-based tips
        if cosine_distance < 0.1:
            tips.append("๐Ÿ’ก Try using more unexpected or creative words to steer me in a completely new direction!")
        elif cosine_distance < 0.2:
            tips.append("โœจ Good start! Try thinking more out-of-the-box to maximize your creativity score.")
        elif cosine_distance >= 0.5:
            tips.append("๐ŸŒŸ Excellent creativity! You're successfully making me generate very different responses.")
        
        # Token efficiency tips
        if user_tokens >= 4:
            tips.append("โšก Challenge yourself: try achieving the same creative impact with fewer tokens!")
        elif user_tokens == 1 and cosine_distance >= 0.2:
            tips.append("๐ŸŽฏ Outstanding! You're a master of single-token creativity.")
        elif user_tokens <= 2 and cosine_distance >= 0.3:
            tips.append("๐Ÿ† Incredible efficiency - maximum creativity with minimal tokens!")
        
        # Ranking tips
        if rank and percentile:
            if percentile >= 80:
                tips.append("๐Ÿ‘‘ You're in the top performers - keep up the amazing work!")
            elif percentile >= 50:
                tips.append("๐Ÿ“ˆ You're above average! Push a bit further to join the top tier.")
            else:
                tips.append("๐ŸŽฏ Room to grow - try more unexpected word combinations!")
        
        # Return a random tip if multiple apply, or a default encouragement
        if tips:
            return random.choice(tips)
        else:
            return "๐ŸŽฎ Great job playing! Try a new prompt to test different creative strategies."