Kaleto's picture
Ergebnisse aktualisiert (12 Läufe)
6052894 verified
Raw History Blame Contribute Delete
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)); }
}
}
}
}
});
}
})();