ui fix
Browse files- app.py +8 -1
- ocr_votes.sql +25 -0
- ui_helpers.py +26 -24
app.py
CHANGED
|
@@ -263,15 +263,20 @@ with gr.Blocks(title="OCR Comparison", css="""
|
|
| 263 |
border-collapse: collapse;
|
| 264 |
width: 100%;
|
| 265 |
margin: 10px 0;
|
|
|
|
| 266 |
}
|
| 267 |
.vote-table th, .vote-table td {
|
| 268 |
border: 1px solid #ddd;
|
| 269 |
-
padding:
|
| 270 |
text-align: left;
|
|
|
|
| 271 |
}
|
| 272 |
.vote-table th {
|
| 273 |
background-color: #f2f2f2;
|
| 274 |
font-weight: bold;
|
|
|
|
|
|
|
|
|
|
| 275 |
}
|
| 276 |
.vote-table tr:nth-child(even) {
|
| 277 |
background-color: #f9f9f9;
|
|
@@ -281,6 +286,8 @@ with gr.Blocks(title="OCR Comparison", css="""
|
|
| 281 |
}
|
| 282 |
.vote-table img {
|
| 283 |
transition: transform 0.2s ease;
|
|
|
|
|
|
|
| 284 |
}
|
| 285 |
.vote-table img:hover {
|
| 286 |
transform: scale(1.1);
|
|
|
|
| 263 |
border-collapse: collapse;
|
| 264 |
width: 100%;
|
| 265 |
margin: 10px 0;
|
| 266 |
+
min-width: 800px;
|
| 267 |
}
|
| 268 |
.vote-table th, .vote-table td {
|
| 269 |
border: 1px solid #ddd;
|
| 270 |
+
padding: 6px;
|
| 271 |
text-align: left;
|
| 272 |
+
vertical-align: top;
|
| 273 |
}
|
| 274 |
.vote-table th {
|
| 275 |
background-color: #f2f2f2;
|
| 276 |
font-weight: bold;
|
| 277 |
+
position: sticky;
|
| 278 |
+
top: 0;
|
| 279 |
+
z-index: 10;
|
| 280 |
}
|
| 281 |
.vote-table tr:nth-child(even) {
|
| 282 |
background-color: #f9f9f9;
|
|
|
|
| 286 |
}
|
| 287 |
.vote-table img {
|
| 288 |
transition: transform 0.2s ease;
|
| 289 |
+
max-width: 100%;
|
| 290 |
+
height: auto;
|
| 291 |
}
|
| 292 |
.vote-table img:hover {
|
| 293 |
transform: scale(1.1);
|
ocr_votes.sql
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
-- New database schema for three-model OCR comparison system
|
| 2 |
+
-- This script creates a new table with model information
|
| 3 |
+
|
| 4 |
+
-- Drop the existing table if it exists
|
| 5 |
+
DROP TABLE IF EXISTS ocr_votes;
|
| 6 |
+
|
| 7 |
+
-- Create the new table with model information
|
| 8 |
+
CREATE TABLE ocr_votes (
|
| 9 |
+
id SERIAL PRIMARY KEY,
|
| 10 |
+
username VARCHAR(255) NOT NULL,
|
| 11 |
+
model_a VARCHAR(50) NOT NULL, -- 'gemini', 'mistral', or 'openai'
|
| 12 |
+
model_b VARCHAR(50) NOT NULL, -- 'gemini', 'mistral', or 'openai'
|
| 13 |
+
model_a_output TEXT NOT NULL,
|
| 14 |
+
model_b_output TEXT NOT NULL,
|
| 15 |
+
vote VARCHAR(50) NOT NULL, -- 'model_a' or 'model_b'
|
| 16 |
+
image_url TEXT,
|
| 17 |
+
timestamp VARCHAR(50) NOT NULL, -- Format: YYYY-MM-DD HH:MM:SS
|
| 18 |
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
| 19 |
+
);
|
| 20 |
+
|
| 21 |
+
-- Create indexes for better performance
|
| 22 |
+
CREATE INDEX idx_ocr_votes_username ON ocr_votes(username);
|
| 23 |
+
CREATE INDEX idx_ocr_votes_timestamp ON ocr_votes(timestamp);
|
| 24 |
+
CREATE INDEX idx_ocr_votes_vote ON ocr_votes(vote);
|
| 25 |
+
CREATE INDEX idx_ocr_votes_models ON ocr_votes(model_a, model_b);
|
ui_helpers.py
CHANGED
|
@@ -35,19 +35,20 @@ def format_votes_table(votes: List[Dict[str, Any]]) -> str:
|
|
| 35 |
sorted_votes = sorted(votes, key=lambda x: x.get('timestamp', ''), reverse=True)
|
| 36 |
|
| 37 |
html = """
|
| 38 |
-
<
|
| 39 |
-
<
|
| 40 |
-
<
|
| 41 |
-
<
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
|
|
|
| 51 |
"""
|
| 52 |
|
| 53 |
for vote in sorted_votes:
|
|
@@ -92,9 +93,9 @@ def format_votes_table(votes: List[Dict[str, Any]]) -> str:
|
|
| 92 |
voted_model_name = model_b_name
|
| 93 |
vote_color = "blue"
|
| 94 |
|
| 95 |
-
# Truncate OCR outputs for table display
|
| 96 |
-
model_a_preview = model_a_output[:
|
| 97 |
-
model_b_preview = model_b_output[:
|
| 98 |
|
| 99 |
# Fix image URL - use the correct Supabase storage URL format
|
| 100 |
if image_url and image_url != 'N/A' and not image_url.startswith('http'):
|
|
@@ -104,25 +105,26 @@ def format_votes_table(votes: List[Dict[str, Any]]) -> str:
|
|
| 104 |
|
| 105 |
# Create image thumbnail or placeholder
|
| 106 |
if image_url and image_url != 'N/A':
|
| 107 |
-
image_html = f'<img src="{image_url}" alt="OCR Image" style="width:
|
| 108 |
else:
|
| 109 |
image_html = '<span style="color: #999; font-style: italic;">No image</span>'
|
| 110 |
|
| 111 |
html += f"""
|
| 112 |
<tr>
|
| 113 |
-
<td>{formatted_time}</td>
|
| 114 |
-
<td><strong>{username}</strong></td>
|
| 115 |
-
<td><small>{models_display}</small></td>
|
| 116 |
-
<td style="color: {vote_color}; font-weight: bold;">{voted_model_name}</td>
|
| 117 |
-
<td title="{model_a_output}">{model_a_preview}</td>
|
| 118 |
-
<td title="{model_b_output}">{model_b_preview}</td>
|
| 119 |
-
<td>{image_html}</td>
|
| 120 |
</tr>
|
| 121 |
"""
|
| 122 |
|
| 123 |
html += """
|
| 124 |
</tbody>
|
| 125 |
</table>
|
|
|
|
| 126 |
"""
|
| 127 |
|
| 128 |
return html
|
|
|
|
| 35 |
sorted_votes = sorted(votes, key=lambda x: x.get('timestamp', ''), reverse=True)
|
| 36 |
|
| 37 |
html = """
|
| 38 |
+
<div style="overflow-x: auto; max-width: 100%;">
|
| 39 |
+
<table class="vote-table" style="width: 100%; table-layout: fixed; font-size: 12px;">
|
| 40 |
+
<thead>
|
| 41 |
+
<tr>
|
| 42 |
+
<th style="width: 12%;">Timestamp</th>
|
| 43 |
+
<th style="width: 8%;">Username</th>
|
| 44 |
+
<th style="width: 10%;">Models</th>
|
| 45 |
+
<th style="width: 8%;">Vote</th>
|
| 46 |
+
<th style="width: 25%;">Model A Output</th>
|
| 47 |
+
<th style="width: 25%;">Model B Output</th>
|
| 48 |
+
<th style="width: 12%;">Image</th>
|
| 49 |
+
</tr>
|
| 50 |
+
</thead>
|
| 51 |
+
<tbody>
|
| 52 |
"""
|
| 53 |
|
| 54 |
for vote in sorted_votes:
|
|
|
|
| 93 |
voted_model_name = model_b_name
|
| 94 |
vote_color = "blue"
|
| 95 |
|
| 96 |
+
# Truncate OCR outputs for table display (shorter for better fit)
|
| 97 |
+
model_a_preview = model_a_output[:80] + "..." if len(model_a_output) > 80 else model_a_output
|
| 98 |
+
model_b_preview = model_b_output[:80] + "..." if len(model_b_output) > 80 else model_b_output
|
| 99 |
|
| 100 |
# Fix image URL - use the correct Supabase storage URL format
|
| 101 |
if image_url and image_url != 'N/A' and not image_url.startswith('http'):
|
|
|
|
| 105 |
|
| 106 |
# Create image thumbnail or placeholder
|
| 107 |
if image_url and image_url != 'N/A':
|
| 108 |
+
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">'
|
| 109 |
else:
|
| 110 |
image_html = '<span style="color: #999; font-style: italic;">No image</span>'
|
| 111 |
|
| 112 |
html += f"""
|
| 113 |
<tr>
|
| 114 |
+
<td style="word-wrap: break-word; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">{formatted_time}</td>
|
| 115 |
+
<td style="word-wrap: break-word; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"><strong>{username}</strong></td>
|
| 116 |
+
<td style="word-wrap: break-word; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"><small>{models_display}</small></td>
|
| 117 |
+
<td style="color: {vote_color}; font-weight: bold; word-wrap: break-word; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">{voted_model_name}</td>
|
| 118 |
+
<td style="word-wrap: break-word; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="{model_a_output}">{model_a_preview}</td>
|
| 119 |
+
<td style="word-wrap: break-word; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="{model_b_output}">{model_b_preview}</td>
|
| 120 |
+
<td style="text-align: center;">{image_html}</td>
|
| 121 |
</tr>
|
| 122 |
"""
|
| 123 |
|
| 124 |
html += """
|
| 125 |
</tbody>
|
| 126 |
</table>
|
| 127 |
+
</div>
|
| 128 |
"""
|
| 129 |
|
| 130 |
return html
|