Spaces:
Running
Running
| {% extends "base.html" %} | |
| {% block title %}Leaderboard — OCR Bench{% endblock %} | |
| {% block content %} | |
| <h2 style="font-size: 1.1rem; font-weight: 600; margin-bottom: 0.25rem;">Leaderboard</h2> | |
| <p style="font-size: 0.8rem; color: #888; margin-top: 0;"><a href="https://huggingface.co/datasets/{{ repo_id }}" style="color: #888; text-decoration: underline;" target="_blank">{{ repo_id }}</a></p> | |
| <p style="font-size: 0.82rem; color: #999; line-height: 1.5; max-width: 48rem; margin: 0.75rem 0 1rem;"> | |
| Rankings are computed using <strong style="color: #bbb;">Bradley-Terry MLE</strong> from pairwise comparisons judged by a vision-language model. | |
| The judge sees the original document image alongside two anonymised OCR outputs and picks the more faithful transcription. | |
| Browse the <a href="/comparisons" style="color: #aaa;">comparisons</a> to see the evidence — and vote yourself to build a Human ELO column. | |
| Human votes are stored locally for this session only and will reset when the server restarts. | |
| </p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>#</th> | |
| <th>Model</th> | |
| <th class="num">Params</th> | |
| <th class="num">Judge ELO</th> | |
| {% if has_ci %}<th class="num">95% CI</th>{% endif %} | |
| <th class="num">Wins</th> | |
| <th class="num">Losses</th> | |
| <th class="num">Ties</th> | |
| <th class="num">Win%</th> | |
| {% if has_human_elo %} | |
| <th class="num">Human ELO</th> | |
| <th class="num">H-Win%</th> | |
| {% endif %} | |
| </tr> | |
| </thead> | |
| <tbody> | |
| {% for row in rows %} | |
| <tr> | |
| <td>{{ loop.index }}</td> | |
| <td class="model">{{ row.model_short }}</td> | |
| <td class="num">{{ row.params if row.params else "—" }}</td> | |
| <td class="num">{{ row.elo }}</td> | |
| {% if has_ci %}<td class="num">{{ row.elo_low }}–{{ row.elo_high }}</td>{% endif %} | |
| <td class="num">{{ row.wins }}</td> | |
| <td class="num">{{ row.losses }}</td> | |
| <td class="num">{{ row.ties }}</td> | |
| <td class="num">{{ row.win_pct }}%</td> | |
| {% if has_human_elo %} | |
| <td class="num">{{ row.human_elo if row.human_elo is not none else "—" }}</td> | |
| <td class="num">{{ row.human_win_pct if row.human_win_pct is not none else "—" }}</td> | |
| {% endif %} | |
| </tr> | |
| {% endfor %} | |
| </tbody> | |
| </table> | |
| {% if chart_points|length >= 2 %} | |
| <h3 style="font-size: 0.95rem; font-weight: 600; margin-top: 2rem; margin-bottom: 0.5rem;"> | |
| ELO vs Parameter Count | |
| </h3> | |
| <p style="font-size: 0.78rem; color: #888; margin-top: 0; margin-bottom: 0.75rem;"> | |
| Smaller models can win on the right documents. Error bars show 95% confidence intervals. | |
| </p> | |
| <div style="max-width: 560px; position: relative;"> | |
| <canvas id="paramsChart"></canvas> | |
| </div> | |
| <script src="https://cdn.jsdelivr.net/npm/chart.js@4"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2"></script> | |
| <script> | |
| (function() { | |
| const points = {{ chart_points | tojson }}; | |
| const colors = ['#6fa8dc', '#93c47d', '#e06666', '#f6b26b', '#8e7cc3']; | |
| const gridColor = 'rgba(255,255,255,0.1)'; | |
| const textColor = '#aaa'; | |
| const datasets = points.map((p, i) => ({ | |
| label: p.name, | |
| data: [{ | |
| x: p.params, | |
| y: p.elo, | |
| elo_low: p.elo_low, | |
| elo_high: p.elo_high, | |
| win_pct: p.win_pct, | |
| }], | |
| backgroundColor: colors[i % colors.length], | |
| borderColor: colors[i % colors.length], | |
| pointRadius: 10, | |
| pointHoverRadius: 13, | |
| })); | |
| // Custom plugin to draw error bars | |
| const errorBarPlugin = { | |
| id: 'errorBars', | |
| afterDatasetsDraw(chart) { | |
| const { ctx } = chart; | |
| chart.data.datasets.forEach((ds, i) => { | |
| const meta = chart.getDatasetMeta(i); | |
| meta.data.forEach((point, j) => { | |
| const d = ds.data[j]; | |
| if (d.elo_low == null || d.elo_high == null) return; | |
| const xPx = point.x; | |
| const yLo = chart.scales.y.getPixelForValue(d.elo_low); | |
| const yHi = chart.scales.y.getPixelForValue(d.elo_high); | |
| const capW = 5; | |
| ctx.save(); | |
| ctx.strokeStyle = ds.borderColor; | |
| ctx.lineWidth = 1.5; | |
| ctx.globalAlpha = 0.6; | |
| // Vertical line | |
| ctx.beginPath(); | |
| ctx.moveTo(xPx, yLo); | |
| ctx.lineTo(xPx, yHi); | |
| ctx.stroke(); | |
| // Top cap | |
| ctx.beginPath(); | |
| ctx.moveTo(xPx - capW, yHi); | |
| ctx.lineTo(xPx + capW, yHi); | |
| ctx.stroke(); | |
| // Bottom cap | |
| ctx.beginPath(); | |
| ctx.moveTo(xPx - capW, yLo); | |
| ctx.lineTo(xPx + capW, yLo); | |
| ctx.stroke(); | |
| ctx.restore(); | |
| }); | |
| }); | |
| }, | |
| }; | |
| Chart.register(ChartDataLabels, errorBarPlugin); | |
| new Chart(document.getElementById('paramsChart'), { | |
| type: 'scatter', | |
| data: { datasets }, | |
| options: { | |
| responsive: true, | |
| animation: { duration: 400 }, | |
| scales: { | |
| x: { | |
| title: { display: true, text: 'Parameters (B)', color: textColor }, | |
| grid: { color: gridColor }, | |
| ticks: { color: textColor, callback: v => v + 'B' }, | |
| }, | |
| y: { | |
| title: { display: true, text: 'ELO', color: textColor }, | |
| grid: { color: gridColor }, | |
| ticks: { color: textColor }, | |
| }, | |
| }, | |
| plugins: { | |
| legend: { display: false }, | |
| tooltip: { | |
| callbacks: { | |
| label: ctx => { | |
| const d = ctx.raw; | |
| let s = `${ctx.dataset.label}: ${d.x}B, ELO ${d.y}`; | |
| if (d.elo_low != null) s += ` (${d.elo_low}\u2013${d.elo_high})`; | |
| s += `, ${d.win_pct}% wins`; | |
| return s; | |
| }, | |
| }, | |
| }, | |
| datalabels: { | |
| align: function(ctx) { | |
| const d = ctx.dataset.data[0]; | |
| const maxX = Math.max(...points.map(p => p.params)); | |
| // Rightmost point: label left. Otherwise label right. | |
| if (d.x >= maxX) return 'left'; | |
| return 'right'; | |
| }, | |
| anchor: 'center', | |
| offset: 12, | |
| color: textColor, | |
| font: { size: 11 }, | |
| formatter: (val, ctx) => ctx.dataset.label, | |
| }, | |
| }, | |
| }, | |
| }); | |
| })(); | |
| </script> | |
| {% endif %} | |
| {% endblock %} | |