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
|