Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Header - QIMMA Leaderboard</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://unpkg.com/lucide@latest"></script> | |
| <script> | |
| tailwind.config = { darkMode: 'class', theme: { extend: { colors: { darkbg: '#131825', darkcard: '#1c2235' } } } } | |
| </script> | |
| </head> | |
| <body class="bg-slate-50 text-slate-800 dark:bg-darkbg dark:text-slate-100"> | |
| <style> | |
| :root { --card-bg: #ffffff; } | |
| .dark { --card-bg: #161828; } | |
| html[dir="rtl"] #headerSection { | |
| direction: rtl; | |
| text-align: right; | |
| } | |
| html[dir="rtl"] #headerSection .stat-card { | |
| flex-direction: row-reverse; | |
| text-align: right; | |
| } | |
| </style> | |
| <div id="headerSection"> | |
| <div class="text-center mb-10 pt-8"> | |
| <h1 class="text-4xl font-extrabold tracking-tight sm:text-6xl mb-4 inline-flex items-center justify-center gap-4"> | |
| <span class="text-transparent bg-clip-text bg-gradient-to-r from-purple-600 to-violet-400 dark:from-purple-400 dark:to-violet-300"> | |
| QIMMA ⛰ قمة | |
| <span class="block text-center" id="headerHeroLabel">Leaderboard</span> | |
| </span> | |
| </h1> | |
| <p class="text-lg text-slate-600 dark:text-slate-400 max-w-2xl mx-auto" id="headerHeroSubtitle">A quality-first Arabic LLM Leaderboard that evaluates and compares the performance of Arabic Large Language Models.</p> | |
| </div> | |
| <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-12"> | |
| <!-- Podium — NO class changes, inline style preserved for light mode --> | |
| <div id="podium-card" class="rounded-xl p-6 shadow-sm text-white relative overflow-hidden group col-span-1 sm:col-span-2 lg:col-span-1 transition-all duration-300 ease-in-out transform hover:-translate-y-1 cursor-default" | |
| style="background: linear-gradient(to bottom, #2d7d65, #1f604f);"> | |
| <div class="absolute -right-6 -top-6 w-[86px] h-[86px] rounded-full opacity-50 group-hover:scale-[2.5] transition-transform duration-500" | |
| style="background-color: #174d3e;"></div> | |
| <div class="flex justify-between items-start mb-4 relative z-10"> | |
| <p id="podium-label" class="text-sm font-medium text-white/80 uppercase tracking-wider">Podium</p> | |
| <i data-lucide="trophy" class="w-5 h-5 text-yellow-300"></i> | |
| </div> | |
| <div id="top-performers-list" class="space-y-3 relative z-10 overflow-visible"></div> | |
| </div> | |
| <!-- Total Models --> | |
| <div id="stat-card-models" class="stat-card p-4 rounded-2xl border border-slate-300 dark:border-slate-600 shadow-md flex items-center gap-4 transition-all duration-300 ease-in-out transform hover:-translate-y-1 cursor-default" | |
| style="background-color: var(--card-bg);"> | |
| <div id="icon-wrap-models" class="p-3 bg-indigo-50 dark:bg-indigo-900/30 rounded-xl border border-indigo-200 dark:border-indigo-700"> | |
| <i data-lucide="database" class="w-6 h-6 text-indigo-600 dark:text-indigo-400"></i> | |
| </div> | |
| <div> | |
| <p class="text-xs font-bold uppercase text-slate-400 tracking-wider" id="label-total-models">Total Models</p> | |
| <h3 class="text-2xl font-bold text-slate-800 dark:text-white" id="stat-total-models">--</h3> | |
| </div> | |
| </div> | |
| <!-- Eval Status --> | |
| <div id="stat-card-eval" class="stat-card p-4 rounded-2xl border border-slate-300 dark:border-slate-600 shadow-md flex items-center gap-4 transition-all duration-300 ease-in-out transform hover:-translate-y-1 cursor-default" | |
| style="background-color: var(--card-bg);"> | |
| <div id="icon-wrap-eval" class="p-3 bg-emerald-50 dark:bg-emerald-900/30 rounded-xl border border-emerald-200 dark:border-emerald-700 shrink-0"> | |
| <i data-lucide="activity" class="w-6 h-6 text-emerald-600 dark:text-emerald-400"></i> | |
| </div> | |
| <div class="w-full"> | |
| <p class="text-xs font-bold uppercase text-slate-400 tracking-wider mb-2" id="label-eval-status">Eval Status</p> | |
| <div class="grid grid-cols-4 gap-1 text-center mb-2"> | |
| <div> | |
| <div class="text-base font-bold text-emerald-600 dark:text-emerald-400" id="stat-done">--</div> | |
| <div class="text-[10px] text-slate-500 dark:text-slate-400" id="sublabel-done">Done</div> | |
| </div> | |
| <div> | |
| <div class="text-base font-bold text-rose-600 dark:text-rose-400" id="stat-failed">--</div> | |
| <div class="text-[10px] text-slate-500 dark:text-slate-400" id="sublabel-failed">Failed</div> | |
| </div> | |
| <div> | |
| <div class="text-base font-bold text-blue-600 dark:text-blue-400" id="stat-running">--</div> | |
| <div class="text-[10px] text-slate-500 dark:text-slate-400" id="sublabel-running">Running</div> | |
| </div> | |
| <div> | |
| <div class="text-base font-bold text-amber-500 dark:text-amber-400" id="stat-queue">--</div> | |
| <div class="text-[10px] text-slate-500 dark:text-slate-400" id="sublabel-queue">Queue</div> | |
| </div> | |
| </div> | |
| <div id="progress-track" class="flex w-full h-2 rounded-full overflow-hidden bg-slate-100 dark:bg-slate-700"> | |
| <div id="bar-done" class="bg-emerald-500 h-full transition-all duration-500" style="width: 0%"></div> | |
| <div id="bar-failed" class="bg-rose-500 h-full transition-all duration-500" style="width: 0%"></div> | |
| <div id="bar-running" class="bg-blue-500 h-full transition-all duration-500" style="width: 0%"></div> | |
| <div id="bar-queue" class="bg-amber-500 h-full transition-all duration-500" style="width: 0%"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Benchmarks --> | |
| <div id="stat-card-bench" class="stat-card p-4 rounded-2xl border border-slate-300 dark:border-slate-600 shadow-md flex items-center gap-4 transition-all duration-300 ease-in-out transform hover:-translate-y-1 cursor-default" | |
| style="background-color: var(--card-bg);"> | |
| <div id="icon-wrap-bench" class="p-3 bg-purple-50 dark:bg-purple-900/30 rounded-xl border border-purple-200 dark:border-purple-700"> | |
| <i data-lucide="bar-chart-2" class="w-6 h-6 text-purple-600 dark:text-purple-400"></i> | |
| </div> | |
| <div> | |
| <p class="text-xs font-bold uppercase text-slate-400 tracking-wider" id="label-benchmarks">Benchmarks</p> | |
| <h3 class="text-2xl font-bold text-slate-800 dark:text-white" id="stat-metrics">--</h3> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| window.updateHeaderStats = function (safeQ) { | |
| if (!safeQ) return; | |
| const doneCount = allData ? allData.length : safeQ.finished.length; | |
| const failedCount = safeQ.failed ? safeQ.failed.length : 0; | |
| const runningCount = safeQ.running ? safeQ.running.length : 0; | |
| const queueCount = safeQ.pending ? safeQ.pending.length : 0; | |
| const setTxt = (id, val) => { if (document.getElementById(id)) document.getElementById(id).innerText = val; }; | |
| setTxt('stat-done', doneCount); | |
| setTxt('stat-failed', failedCount); | |
| setTxt('stat-running', runningCount); | |
| setTxt('stat-queue', queueCount); | |
| const total = doneCount + failedCount + runningCount + queueCount; | |
| if (total > 0) { | |
| document.getElementById('bar-done').style.width = (doneCount / total * 100) + "%"; | |
| document.getElementById('bar-failed').style.width = (failedCount / total * 100) + "%"; | |
| document.getElementById('bar-running').style.width = (runningCount / total * 100) + "%"; | |
| document.getElementById('bar-queue').style.width = (queueCount / total * 100) + "%"; | |
| } | |
| }; | |
| // All dark mode styling via IDs — no class selectors, no CSS specificity battles | |
| function applyDarkModeCards() { | |
| const isDark = document.documentElement.classList.contains('dark'); | |
| // Podium | |
| const podium = document.getElementById('podium-card'); | |
| if (podium) { | |
| podium.style.background = isDark ? '#1a3028' : 'linear-gradient(to bottom, #2d7d65, #1f604f)'; | |
| podium.style.border = isDark ? '1px solid #2d5a3d' : ''; | |
| } | |
| const podiumLabel = document.getElementById('podium-label'); | |
| if (podiumLabel) podiumLabel.style.color = isDark ? '#5aaf7a' : ''; | |
| // Stat cards | |
| ['stat-card-models', 'stat-card-eval', 'stat-card-bench'].forEach(id => { | |
| const el = document.getElementById(id); | |
| if (!el) return; | |
| el.style.backgroundColor = isDark ? '#161828' : ''; | |
| el.style.border = isDark ? '1px solid #252048' : ''; | |
| }); | |
| // Icon wrappers | |
| ['icon-wrap-models', 'icon-wrap-eval', 'icon-wrap-bench'].forEach(id => { | |
| const el = document.getElementById(id); | |
| if (!el) return; | |
| el.style.background = isDark ? '#1e1a40' : ''; | |
| el.style.borderColor = isDark ? 'transparent' : ''; | |
| const icon = el.querySelector('i'); | |
| if (icon) icon.style.color = isDark ? '#7868c8' : ''; | |
| }); | |
| // Stat labels | |
| ['label-total-models', 'label-eval-status', 'label-benchmarks'].forEach(id => { | |
| const el = document.getElementById(id); | |
| if (el) el.style.color = isDark ? '#7878a8' : ''; | |
| }); | |
| // Stat big values | |
| ['stat-total-models', 'stat-metrics'].forEach(id => { | |
| const el = document.getElementById(id); | |
| if (el) el.style.color = isDark ? '#d0cef0' : ''; | |
| }); | |
| // Eval sublabels | |
| ['sublabel-done', 'sublabel-failed', 'sublabel-running', 'sublabel-queue'].forEach(id => { | |
| const el = document.getElementById(id); | |
| if (el) el.style.color = isDark ? '#585878' : ''; | |
| }); | |
| // Running + Queue numbers muted | |
| ['stat-running', 'stat-queue'].forEach(id => { | |
| const el = document.getElementById(id); | |
| if (el) el.style.color = isDark ? '#7878a8' : ''; | |
| }); | |
| // Progress bar track | |
| const track = document.getElementById('progress-track'); | |
| if (track) track.style.background = isDark ? '#1e1a40' : ''; | |
| // Progress bar segments | |
| const bars = { 'bar-done': '#3a5a8a', 'bar-failed': '#7a3a3a', 'bar-running': '#2e2468', 'bar-queue': '#3a3010' }; | |
| Object.entries(bars).forEach(([id, color]) => { | |
| const el = document.getElementById(id); | |
| if (el) el.style.backgroundColor = isDark ? color : ''; | |
| }); | |
| // Top accent lines via box-shadow trick (no ::before in JS) | |
| const podiumAccent = document.getElementById('podium-card'); | |
| if (podiumAccent) { | |
| podiumAccent.style.boxShadow = isDark ? 'inset 0 2px 0 0 #4a8a5a' : ''; | |
| } | |
| ['stat-card-models', 'stat-card-eval', 'stat-card-bench'].forEach(id => { | |
| const el = document.getElementById(id); | |
| if (el) el.style.boxShadow = isDark ? 'inset 0 2px 0 0 #5040a0' : ''; | |
| }); | |
| } | |
| function renderHeaderTableStats(data) { | |
| const $ = (selector) => document.querySelector(selector); | |
| const esc = (v) => String(v ?? "") | |
| .replace(/&/g, "&") | |
| .replace(/</g, "<") | |
| .replace(/>/g, ">") | |
| .replace(/\"/g, """) | |
| .replace(/'/g, "'"); | |
| if ($('#stat-total-models')) $('#stat-total-models').innerText = data.length; | |
| if ($('#stat-metrics') && window.EVAL_COLUMNS) $('#stat-metrics').innerText = window.EVAL_COLUMNS.filter(c => c !== "Average").length; | |
| const avgK = Object.keys(data[0] || {}).find(k => k.includes("Average")); | |
| if (avgK && $('#top-performers-list')) { | |
| const top3 = [...data].sort((a, b) => parseFloat(b[avgK]) - parseFloat(a[avgK])).slice(0, 3); | |
| const isDark = document.documentElement.classList.contains('dark'); | |
| const rankBadgeStyles = isDark ? [ | |
| 'background:#1a3a22;color:#7ad898;box-shadow:0 0 0 1px #2e5a38', | |
| 'background:#162e1e;color:#5ab878;box-shadow:0 0 0 1px #244830', | |
| 'background:#1a2a1a;color:#4aa858;box-shadow:0 0 0 1px #203820', | |
| ] : [ | |
| 'background:#facc15;color:#064e3b', | |
| 'background:#cbd5e1;color:#064e3b', | |
| 'background:#fdba74;color:#064e3b', | |
| ]; | |
| $('#top-performers-list').innerHTML = top3.map((m, i) => ` | |
| <div class="group/podium relative py-0.5"> | |
| <div class="flex items-center gap-3"> | |
| <div class="w-4 h-5 shrink-0 rounded-full flex items-center justify-center text-xs font-bold" style="${rankBadgeStyles[i] || ''}">${i + 1}</div> | |
| <span class="text-sm font-semibold truncate flex-1 min-w-0 cursor-pointer hover:underline" style="${isDark ? 'color:#b8d8c0' : ''}" onclick="window.openModelDetails && window.openModelDetails(decodeURIComponent('${encodeURIComponent(m["Model Name"])}'))">${esc(m["Model Name"].split('/').pop())}</span> | |
| <span class="ml-auto text-xs font-mono" style="${isDark ? 'color:#6aba82' : 'color:rgb(110 231 183)'}">${parseFloat(m[avgK]).toFixed(1)}</span> | |
| </div> | |
| <div class="absolute left-7 top-full mt-1 z-30 pointer-events-none opacity-0 translate-y-1 group-hover/podium:opacity-100 group-hover/podium:translate-y-0 transition-all duration-200 ease-out"> | |
| <div class="inline-block w-max max-w-[34rem] rounded-md border border-emerald-300/60 bg-emerald-950/90 backdrop-blur px-2 py-1 text-[11px] text-emerald-100 break-words shadow-lg"> | |
| ${esc(m["Model Name"])} | |
| </div> | |
| </div> | |
| </div> | |
| `).join(''); | |
| } | |
| // Re-apply dark mode after DOM update | |
| applyDarkModeCards(); | |
| } | |
| const HEADER_TRANSLATIONS = { | |
| ar: { | |
| hero_label: "لوحة الصدارة", | |
| hero_subtitle: "لوحة صدارة عربية للنماذج اللغوية الكبرى تركّز على الجودة، وتقيّم وتقارن أداء النماذج اللغوية العربية.", | |
| podium: "الصدارة", | |
| total_models: "إجمالي النماذج", | |
| eval_status: "حالة التقييم", | |
| done: "مكتمل", | |
| failed: "فشل", | |
| running: "قيد التنفيذ", | |
| queue: "الانتظار", | |
| benchmarks: "المعايير", | |
| }, | |
| en: { | |
| hero_label: "Leaderboard", | |
| hero_subtitle: "A quality-first Arabic LLM Leaderboard that evaluates and compares the performance of Arabic Large Language Models.", | |
| podium: "Podium", | |
| total_models: "Total Models", | |
| eval_status: "Eval Status", | |
| done: "Done", | |
| failed: "Failed", | |
| running: "Running", | |
| queue: "Queue", | |
| benchmarks: "Benchmarks", | |
| } | |
| }; | |
| function applyHeaderTranslations(lang) { | |
| const t = HEADER_TRANSLATIONS[lang] || HEADER_TRANSLATIONS.en; | |
| const setTxt = (id, val) => { | |
| const el = document.getElementById(id); | |
| if (el) el.innerText = val; | |
| }; | |
| setTxt('headerHeroLabel', t.hero_label); | |
| setTxt('headerHeroSubtitle', t.hero_subtitle); | |
| setTxt('podium-label', t.podium); | |
| setTxt('label-total-models', t.total_models); | |
| setTxt('label-eval-status', t.eval_status); | |
| setTxt('sublabel-done', t.done); | |
| setTxt('sublabel-failed', t.failed); | |
| setTxt('sublabel-running', t.running); | |
| setTxt('sublabel-queue', t.queue); | |
| setTxt('label-benchmarks', t.benchmarks); | |
| } | |
| applyHeaderTranslations(window.getCurrentLanguage ? window.getCurrentLanguage() : 'en'); | |
| if (window.registerLanguageListener) { | |
| window.registerLanguageListener(applyHeaderTranslations); | |
| } | |
| window.initHeader = async function () { renderHeaderTableStats(allData); }; | |
| window.initHeader(); | |
| if (window.lucide) lucide.createIcons(); | |
| // Apply immediately and watch for theme toggles | |
| applyDarkModeCards(); | |
| new MutationObserver(applyDarkModeCards).observe( | |
| document.documentElement, { attributes: true, attributeFilter: ['class'] } | |
| ); | |
| </script> | |
| </body> | |
| </html> | |