File size: 7,270 Bytes
28673b1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e6e2e79
 
 
 
 
 
 
 
 
 
 
 
 
 
28673b1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e6e2e79
 
 
28673b1
 
 
 
 
 
 
 
 
e6e2e79
28673b1
 
 
 
 
e6e2e79
 
 
 
 
 
 
28673b1
 
 
 
 
 
e6e2e79
28673b1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
UI Helpers Module
Contains UI formatting and helper functions for the Gradio interface.
"""

import logging
import random
import math
from typing import Dict, Any, List

# Configure logging
logger = logging.getLogger(__name__)

def get_model_display_name(model_name: str) -> str:
    """Get the display name for a model."""
    model_names = {
        "gemini": "Gemini 2.0 Flash",
        "mistral": "Mistral OCR",
        "openai": "OpenAI GPT-4o"
    }
    return model_names.get(model_name, model_name)

def select_random_models() -> tuple[str, str]:
    """Randomly select two models from the three available: gemini, mistral, openai."""
    models = ["gemini", "mistral", "openai"]
    selected_models = random.sample(models, 2)
    return selected_models[0], selected_models[1]

def format_votes_table(votes: List[Dict[str, Any]]) -> str:
    """Format votes data into an HTML table with OCR outputs and image thumbnails."""
    if not votes:
        return "<p>No votes found in the database.</p>"

    # Sort votes by timestamp (latest first)
    sorted_votes = sorted(votes, key=lambda x: x.get('timestamp', ''), reverse=True)

    html = """
    <div style="overflow-x: auto; max-width: 100%;">
        <table class="vote-table" style="width: 100%; table-layout: fixed; font-size: 12px;">
            <thead>
                <tr>
                    <th style="width: 12%;">Timestamp</th>
                    <th style="width: 8%;">Username</th>
                    <th style="width: 10%;">Models</th>
                    <th style="width: 8%;">Vote</th>
                    <th style="width: 25%;">Model A Output</th>
                    <th style="width: 25%;">Model B Output</th>
                    <th style="width: 12%;">Image</th>
                </tr>
            </thead>
            <tbody>
    """

    for vote in sorted_votes:
        timestamp = vote.get('timestamp', 'N/A')
        username = vote.get('username', 'N/A')
        model_a = vote.get('model_a', 'N/A')
        model_b = vote.get('model_b', 'N/A')
        vote_choice = vote.get('vote', 'N/A')
        model_a_output = vote.get('model_a_output', 'N/A')
        model_b_output = vote.get('model_b_output', 'N/A')
        image_url = vote.get('image_url', 'N/A')

        # Format timestamp - handle both ISO format and our custom format
        if timestamp != 'N/A':
            try:
                from datetime import datetime
                # Check if it's already in our desired format
                if len(timestamp) == 19 and timestamp[10] == ' ':
                    # Already in YYYY-MM-DD HH:MM:SS format
                    formatted_time = timestamp
                else:
                    # Convert from ISO format to our format
                    dt = datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
                    formatted_time = dt.strftime('%Y-%m-%d %H:%M:%S')
            except:
                formatted_time = timestamp
        else:
            formatted_time = 'N/A'

        # Get model display names
        model_a_name = get_model_display_name(model_a)
        model_b_name = get_model_display_name(model_b)
        models_display = f"{model_a_name} vs {model_b_name}"

        # Determine which model was voted for and get its display name
        voted_model_name = ""
        vote_color = "gray"
        if vote_choice == "model_a":
            voted_model_name = model_a_name
            vote_color = "green"
        elif vote_choice == "model_b":
            voted_model_name = model_b_name
            vote_color = "blue"

        # Truncate OCR outputs for table display (shorter for better fit)
        model_a_preview = model_a_output[:80] + "..." if len(model_a_output) > 80 else model_a_output
        model_b_preview = model_b_output[:80] + "..." if len(model_b_output) > 80 else model_b_output

        # Fix image URL - use the correct Supabase storage URL format
        if image_url and image_url != 'N/A' and not image_url.startswith('http'):
            # If it's just a path, construct the full URL
            import os
            image_url = f"{os.getenv('SUPABASE_URL')}/storage/v1/object/public/images/{image_url}"

        # Create image thumbnail or placeholder
        if image_url and image_url != 'N/A':
            image_html = f'<img src="{image_url}" alt="OCR Image" style="width: 60px; height: 45px; object-fit: cover; border-radius: 4px; cursor: pointer;" onclick="window.open(\'{image_url}\', \'_blank\')" title="Click to view full image">'
        else:
            image_html = '<span style="color: #999; font-style: italic;">No image</span>'

        html += f"""
        <tr>
            <td style="word-wrap: break-word; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">{formatted_time}</td>
            <td style="word-wrap: break-word; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"><strong>{username}</strong></td>
            <td style="word-wrap: break-word; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"><small>{models_display}</small></td>
            <td style="color: {vote_color}; font-weight: bold; word-wrap: break-word; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">{voted_model_name}</td>
            <td style="word-wrap: break-word; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="{model_a_output}">{model_a_preview}</td>
            <td style="word-wrap: break-word; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="{model_b_output}">{model_b_preview}</td>
            <td style="text-align: center;">{image_html}</td>
        </tr>
        """

    html += """
        </tbody>
    </table>
    </div>
    """

    return html



def format_elo_leaderboard(elo_ratings: Dict[str, float], vote_counts: Dict[str, int] = None) -> str:
    """Format ELO ratings into a leaderboard HTML table."""
    # Sort models by ELO rating (highest first)
    sorted_models = sorted(elo_ratings.items(), key=lambda x: x[1], reverse=True)

    html = """
    <div style="padding: 15px; background-color: #f8f9fa; border-radius: 8px;">
        <h3>ELO Leaderboard</h3>
        <p><em>Models are ranked by their ELO rating. Higher ratings indicate better performance.</em></p>
        
        <table class="vote-table" style="margin-top: 15px;">
            <thead>
                <tr>
                    <th>Rank</th>
                    <th>Model</th>
                    <th>ELO Rating</th>
                    <th>Total Votes</th>
                </tr>
            </thead>
            <tbody>
    """

    for rank, (model, rating) in enumerate(sorted_models, 1):
        # Get model display name
        display_name = get_model_display_name(model)

        # Get vote count for this model
        vote_count = vote_counts.get(model, 0) if vote_counts else 0

        html += f"""
        <tr>
            <td style="font-weight: bold; text-align: center;">{rank}</td>
            <td><strong>{display_name}</strong></td>
            <td style="font-weight: bold;">{rating:.0f}</td>
            <td style="text-align: center;">{vote_count}</td>
        </tr>
        """

    html += """
            </tbody>
        </table>
    </div>
    """

    return html