Spaces:
Running
Running
Download app.js from Kaleto/LocalLLMBenchmarks: direct link, hf CLI and curl.
- Browser
- Download file 13.2 kB
-
https://huggingface.co/spaces/Kaleto/LocalLLMBenchmarks/resolve/main/app.js
- Command line
-
hf download hf://spaces/Kaleto/LocalLLMBenchmarks/app.js
-
curl -L -o app.js https://huggingface.co/spaces/Kaleto/LocalLLMBenchmarks/resolve/main/app.js
13.2 kB
| (function () { | |
| "use strict"; | |
| // Tabellen sortieren (Klick auf th[data-sort]); leere Werte stehen immer am Ende. | |
| document.querySelectorAll("table.sortable").forEach(function (table) { | |
| table.querySelectorAll("th[data-sort]").forEach(function (th) { | |
| th.addEventListener("click", function () { | |
| var index = Array.prototype.indexOf.call(th.parentNode.children, th); | |
| var numeric = th.dataset.sort === "num"; | |
| var dir = th.getAttribute("aria-sort") === "descending" ? "ascending" : "descending"; | |
| table.querySelectorAll("th[aria-sort]").forEach(function (other) { other.removeAttribute("aria-sort"); }); | |
| th.setAttribute("aria-sort", dir); | |
| var body = table.tBodies[0]; | |
| var rows = Array.prototype.slice.call(body.rows); | |
| function valueOf(row) { | |
| var cell = row.cells[index]; | |
| return cell.dataset.value !== undefined ? cell.dataset.value : cell.textContent.trim(); | |
| } | |
| rows.sort(function (a, b) { | |
| var va = valueOf(a), vb = valueOf(b); | |
| if (numeric) { | |
| var na = va === "" ? null : parseFloat(va); | |
| var nb = vb === "" ? null : parseFloat(vb); | |
| if (na === null && nb === null) return 0; | |
| if (na === null) return 1; | |
| if (nb === null) return -1; | |
| return dir === "ascending" ? na - nb : nb - na; | |
| } | |
| return dir === "ascending" ? va.localeCompare(vb, "de") : vb.localeCompare(va, "de"); | |
| }); | |
| rows.forEach(function (row) { body.appendChild(row); }); | |
| }); | |
| }); | |
| }); | |
| // Zeilen nach Reasoning-Modus filtern. Die Schalter stehen nur im HTML, wenn eine Tabelle mehrere Modi | |
| // zeigt; ohne JavaScript bleiben alle Zeilen sichtbar. | |
| document.querySelectorAll("[data-filter-table]").forEach(function (group) { | |
| var table = document.getElementById(group.dataset.filterTable); | |
| if (!table || !table.tBodies[0]) return; | |
| var buttons = Array.prototype.slice.call(group.querySelectorAll("[data-reasoning-filter]")); | |
| buttons.forEach(function (button) { | |
| button.addEventListener("click", function () { | |
| var wanted = button.dataset.reasoningFilter; | |
| buttons.forEach(function (other) { | |
| var picked = other === button; | |
| other.classList.toggle("active", picked); | |
| other.setAttribute("aria-pressed", picked ? "true" : "false"); | |
| }); | |
| Array.prototype.slice.call(table.tBodies[0].rows).forEach(function (row) { | |
| row.hidden = wanted !== "all" && (row.dataset.reasoning || "default") !== wanted; | |
| }); | |
| }); | |
| }); | |
| }); | |
| // Läufe für den Vergleich auswählen (mindestens 2). | |
| var picks = document.querySelectorAll(".compare-pick"); | |
| var button = document.getElementById("compare-button"); | |
| var hidden = document.getElementById("compare-runs"); | |
| picks.forEach(function (box) { | |
| box.addEventListener("change", function () { | |
| var ids = Array.prototype.filter.call(picks, function (p) { return p.checked; }).map(function (p) { return p.value; }); | |
| hidden.value = ids.join(","); | |
| button.disabled = ids.length < 2; | |
| }); | |
| }); | |
| // Bestätigung vor gefährlichen Aktionen (Formulare mit data-confirm). | |
| document.querySelectorAll("form[data-confirm]").forEach(function (form) { | |
| form.addEventListener("submit", function (event) { | |
| if (!window.confirm(form.dataset.confirm)) event.preventDefault(); | |
| }); | |
| }); | |
| if (typeof Chart === "undefined") return; | |
| var css = getComputedStyle(document.documentElement); | |
| function token(name) { return css.getPropertyValue(name).trim(); } | |
| var ink = token("--ink"), ink2 = token("--ink-2"), muted = token("--muted"); | |
| var grid = token("--grid"), axisColor = token("--axis"), surface = token("--surface"); | |
| var series = [token("--series-1"), token("--series-2"), token("--series-3")]; | |
| var fontFamily = 'system-ui, -apple-system, "Segoe UI", sans-serif'; | |
| Chart.defaults.font.family = fontFamily; | |
| Chart.defaults.color = ink2; | |
| function axis(title, extra) { | |
| var config = { | |
| grid: { color: grid, drawTicks: false }, | |
| border: { color: axisColor }, | |
| ticks: { color: muted, padding: 6 } | |
| }; | |
| if (title) config.title = { display: true, text: title, color: ink2 }; | |
| return Object.assign(config, extra || {}); | |
| } | |
| function readJson(id) { | |
| var el = document.getElementById(id); | |
| return el ? JSON.parse(el.textContent) : null; | |
| } | |
| // Wert direkt am Balkenende (nur für die einreihige Übersicht). | |
| var barValueLabels = { | |
| id: "barValueLabels", | |
| afterDatasetsDraw: function (chart) { | |
| var meta = chart.getDatasetMeta(0); | |
| var ctx = chart.ctx; | |
| ctx.save(); | |
| ctx.fillStyle = ink; | |
| ctx.font = "12px " + fontFamily; | |
| ctx.textBaseline = "middle"; | |
| meta.data.forEach(function (bar, i) { | |
| var value = chart.data.datasets[0].data[i]; | |
| if (value !== null && value !== undefined) ctx.fillText(value.toFixed(1), bar.x + 6, bar.y); | |
| }); | |
| ctx.restore(); | |
| } | |
| }; | |
| // Wunschbereich im Streudiagramm: rechts von min. Tokens/s und über min. Note, leicht grün hinterlegt. | |
| // Fehlt einer der Werte, ist der Bereich zu dieser Seite hin offen. | |
| var zone = token("--zone"); | |
| var zonePlugin = { | |
| id: "zone", | |
| beforeDatasetsDraw: function (chart, args, opts) { | |
| if (!opts || (opts.minX == null && opts.minY == null)) return; | |
| var area = chart.chartArea; | |
| var left = opts.minX == null ? area.left : Math.max(area.left, chart.scales.x.getPixelForValue(opts.minX)); | |
| var bottom = opts.minY == null ? area.bottom : Math.min(area.bottom, chart.scales.y.getPixelForValue(opts.minY)); | |
| if (left >= area.right || bottom <= area.top) return; | |
| var ctx = chart.ctx; | |
| ctx.save(); | |
| ctx.fillStyle = zone; | |
| ctx.fillRect(left, area.top, area.right - left, bottom - area.top); | |
| ctx.restore(); | |
| } | |
| }; | |
| // Gewählte Kategorie je Browser merken – nur Bequemlichkeit, ohne Speicher geht es mit „Gesamt“ los. | |
| var CATEGORY_KEY = "bench.chartCategory"; | |
| function rememberedCategory() { | |
| try { return window.localStorage.getItem(CATEGORY_KEY); } catch (e) { return null; } | |
| } | |
| function rememberCategory(key) { | |
| try { window.localStorage.setItem(CATEGORY_KEY, key); } catch (e) { /* ohne Speicher */ } | |
| } | |
| // Übersicht (Webseite und Space): je .chart-set ein Balken- und ein Streudiagramm, umschaltbar nach Kategorie. | |
| document.querySelectorAll(".chart-set").forEach(function (set) { | |
| var dataEl = set.querySelector("script.chart-data"); | |
| if (!dataEl) return; | |
| var data = JSON.parse(dataEl.textContent); | |
| var texts = data.texts; | |
| var limits = data.thresholds || {}; | |
| var buttons = Array.prototype.slice.call(set.querySelectorAll("[data-chart-category]")); | |
| var barBox = set.querySelector('[data-chart-box="bar"]'); | |
| var barTitle = set.querySelector('[data-chart-title="bar"]'); | |
| var scatterTitle = set.querySelector('[data-chart-title="scatter"]'); | |
| var barChart = null, scatterChart = null; | |
| function titleOf(key) { | |
| if (key === "overall") return texts.overall_title; | |
| var match = data.categories.filter(function (c) { return c.key === key; })[0]; | |
| return match ? match.label : key; | |
| } | |
| function show(key) { | |
| var title = titleOf(key); | |
| buttons.forEach(function (b) { | |
| var picked = b.dataset.chartCategory === key; | |
| b.classList.toggle("active", picked); | |
| b.setAttribute("aria-pressed", picked ? "true" : "false"); | |
| }); | |
| if (barTitle) barTitle.textContent = title; | |
| if (scatterTitle) scatterTitle.textContent = title + texts.vs; | |
| var bars = data.runs.filter(function (r) { return r.scores[key] !== null && r.scores[key] !== undefined; }) | |
| .sort(function (a, b) { return b.scores[key] - a.scores[key]; }); | |
| var points = bars.filter(function (r) { return r.tps !== null; }) | |
| .map(function (r) { return { label: r.label, x: r.tps, y: r.scores[key], source: r.tps_source }; }); | |
| // Hohl: Geschwindigkeit nur aus dem Speed-Test, der Lauf lieferte keine Werte. | |
| var fills = points.map(function (p) { return p.source === "test" ? surface : series[0]; }); | |
| var edges = points.map(function (p) { return p.source === "test" ? series[0] : surface; }); | |
| // Balken der Modelle im Wunschbereich grün – dieselbe Regel wie das Rechteck im Streudiagramm. | |
| var minTps = limits.min_gen_tps == null ? null : limits.min_gen_tps; | |
| var minScore = limits.min_score == null ? null : limits.min_score; | |
| function inZone(r) { | |
| if (minTps === null && minScore === null) return false; | |
| if (minTps !== null && (r.tps === null || r.tps < minTps)) return false; | |
| return minScore === null || r.scores[key] >= minScore; | |
| } | |
| if (barChart) barChart.destroy(); | |
| if (barBox) barBox.style.height = (70 + 30 * Math.max(bars.length, 1)) + "px"; | |
| barChart = new Chart(set.querySelector('[data-chart="bar"]'), { | |
| type: "bar", | |
| data: { | |
| labels: bars.map(function (r) { return r.label; }), | |
| datasets: [{ | |
| label: title, | |
| data: bars.map(function (r) { return r.scores[key]; }), | |
| backgroundColor: bars.map(function (r) { return inZone(r) ? series[2] : series[0]; }), | |
| borderRadius: 4, | |
| borderSkipped: "start", | |
| barPercentage: 0.8, | |
| categoryPercentage: 0.9, | |
| maxBarThickness: 18 | |
| }] | |
| }, | |
| options: { | |
| indexAxis: "y", | |
| maintainAspectRatio: false, | |
| animation: false, | |
| layout: { padding: { right: 40 } }, | |
| scales: { x: axis(texts.score_axis, { min: 0, max: 100 }), y: axis(null, { grid: { display: false } }) }, | |
| plugins: { | |
| legend: { display: false }, | |
| tooltip: { callbacks: { label: function (c) { return title + ": " + c.parsed.x.toFixed(1); } } } | |
| } | |
| }, | |
| plugins: [barValueLabels] | |
| }); | |
| if (scatterChart) scatterChart.destroy(); | |
| var minX = limits.min_gen_tps == null ? null : limits.min_gen_tps; | |
| var minY = limits.min_score == null ? null : limits.min_score; | |
| scatterChart = new Chart(set.querySelector('[data-chart="scatter"]'), { | |
| type: "scatter", | |
| data: { | |
| datasets: [{ | |
| label: title, | |
| data: points, | |
| backgroundColor: fills, | |
| borderColor: edges, | |
| borderWidth: 2, | |
| pointRadius: 5, | |
| pointHoverRadius: 7, | |
| pointHitRadius: 12 | |
| }] | |
| }, | |
| options: { | |
| maintainAspectRatio: false, | |
| animation: false, | |
| scales: { | |
| // Der Wunschbereich bleibt sichtbar, auch wenn alle Modelle langsamer sind. | |
| x: axis(texts.tps_axis, { beginAtZero: true, suggestedMax: minX === null ? undefined : minX * 1.1 }), | |
| y: axis(title, { min: 0, max: 100 }) | |
| }, | |
| plugins: { | |
| legend: { display: false }, | |
| zone: { minX: minX, minY: minY }, | |
| tooltip: { | |
| callbacks: { | |
| label: function (c) { | |
| var source = c.raw.source === "test" ? texts.source_test : texts.source_run; | |
| return c.raw.label + ": " + c.raw.y.toFixed(1) + " " + texts.points + ", " + c.raw.x.toFixed(1) + " t/s (" + source + ")"; | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| plugins: [zonePlugin] | |
| }); | |
| } | |
| buttons.forEach(function (b) { | |
| b.addEventListener("click", function () { | |
| show(b.dataset.chartCategory); | |
| rememberCategory(b.dataset.chartCategory); | |
| }); | |
| }); | |
| var start = rememberedCategory(); | |
| var known = data.categories.some(function (c) { return c.key === start; }); | |
| show(known ? start : "overall"); | |
| }); | |
| var categories = readJson("category-data"); | |
| if (categories && categories.series.length) { | |
| new Chart(document.getElementById("category-chart"), { | |
| type: "bar", | |
| data: { | |
| labels: categories.labels, | |
| datasets: categories.series.map(function (s, i) { | |
| return { | |
| label: s.label, | |
| data: s.values, | |
| backgroundColor: series[i], | |
| borderColor: surface, | |
| borderWidth: { top: 1, bottom: 1, right: 2 }, | |
| borderRadius: 4, | |
| borderSkipped: "start", | |
| barPercentage: 0.9, | |
| categoryPercentage: 0.8, | |
| maxBarThickness: 16 | |
| }; | |
| }) | |
| }, | |
| options: { | |
| indexAxis: "y", | |
| maintainAspectRatio: false, | |
| animation: false, | |
| scales: { x: axis("Score (0–100)", { min: 0, max: 100 }), y: axis(null, { grid: { display: false } }) }, | |
| plugins: { | |
| legend: { display: true, position: "top", align: "start", labels: { usePointStyle: true, pointStyle: "rectRounded", color: ink2 } }, | |
| tooltip: { | |
| callbacks: { | |
| label: function (c) { return c.dataset.label + ": " + (c.parsed.x === null ? "–" : c.parsed.x.toFixed(1)); } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| } | |
| })(); | |