Spaces:
Running
Running
Add per-token logprob sparkline under the legend, gradient-stroked to match colormap
Browse files- index.html +57 -4
index.html
CHANGED
|
@@ -221,6 +221,10 @@
|
|
| 221 |
border-radius: 1px;
|
| 222 |
}
|
| 223 |
.legend-row { display: flex; justify-content: space-between; }
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
|
| 225 |
::-webkit-scrollbar { width: 8px; height: 8px; }
|
| 226 |
::-webkit-scrollbar-thumb { background: #ccc; border-radius: 4px; }
|
|
@@ -299,6 +303,7 @@
|
|
| 299 |
<div>token logprob</div>
|
| 300 |
<div class="legend-bar" id="legend-bar"></div>
|
| 301 |
<div class="legend-row"><span id="lp-min">—</span><span id="lp-mid">—</span><span id="lp-max">—</span></div>
|
|
|
|
| 302 |
</div>
|
| 303 |
</div>
|
| 304 |
</div>
|
|
@@ -380,14 +385,62 @@ function updateLegend() {
|
|
| 380 |
if (!lpRange) {
|
| 381 |
minEl.textContent = midEl.textContent = maxEl.textContent = "—";
|
| 382 |
bar.style.background = "linear-gradient(to right, #d83a2a, #888, #1a1a1a)";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 383 |
return;
|
| 384 |
}
|
|
|
|
| 385 |
const { min, mid, max } = lpRange;
|
| 386 |
-
|
| 387 |
-
|
| 388 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 389 |
const midPct = max > min ? ((mid - min) / (max - min)) * 100 : 50;
|
| 390 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 391 |
}
|
| 392 |
function logprobRgb(lp) {
|
| 393 |
if (lp == null || isNaN(lp) || !lpRange) return DARK_RGB;
|
|
|
|
| 221 |
border-radius: 1px;
|
| 222 |
}
|
| 223 |
.legend-row { display: flex; justify-content: space-between; }
|
| 224 |
+
.lp-chart {
|
| 225 |
+
display: block; width: 100%; height: 40px;
|
| 226 |
+
margin-top: 8px;
|
| 227 |
+
}
|
| 228 |
|
| 229 |
::-webkit-scrollbar { width: 8px; height: 8px; }
|
| 230 |
::-webkit-scrollbar-thumb { background: #ccc; border-radius: 4px; }
|
|
|
|
| 303 |
<div>token logprob</div>
|
| 304 |
<div class="legend-bar" id="legend-bar"></div>
|
| 305 |
<div class="legend-row"><span id="lp-min">—</span><span id="lp-mid">—</span><span id="lp-max">—</span></div>
|
| 306 |
+
<svg id="lp-chart" class="lp-chart" preserveAspectRatio="none"></svg>
|
| 307 |
</div>
|
| 308 |
</div>
|
| 309 |
</div>
|
|
|
|
| 385 |
if (!lpRange) {
|
| 386 |
minEl.textContent = midEl.textContent = maxEl.textContent = "—";
|
| 387 |
bar.style.background = "linear-gradient(to right, #d83a2a, #888, #1a1a1a)";
|
| 388 |
+
} else {
|
| 389 |
+
const { min, mid, max } = lpRange;
|
| 390 |
+
minEl.textContent = min.toFixed(1);
|
| 391 |
+
midEl.textContent = mid.toFixed(1);
|
| 392 |
+
maxEl.textContent = max.toFixed(1);
|
| 393 |
+
const midPct = max > min ? ((mid - min) / (max - min)) * 100 : 50;
|
| 394 |
+
bar.style.background = `linear-gradient(to right, #d83a2a 0%, #888 ${midPct.toFixed(1)}%, #1a1a1a 100%)`;
|
| 395 |
+
}
|
| 396 |
+
updateLpChart();
|
| 397 |
+
}
|
| 398 |
+
|
| 399 |
+
function updateLpChart() {
|
| 400 |
+
const svg = document.getElementById("lp-chart");
|
| 401 |
+
if (!svg) return;
|
| 402 |
+
if (!lpRange || genTokens.length < 2) {
|
| 403 |
+
svg.innerHTML = "";
|
| 404 |
return;
|
| 405 |
}
|
| 406 |
+
const W = 200, H = 40, pad = 2;
|
| 407 |
const { min, mid, max } = lpRange;
|
| 408 |
+
const yTop = pad, yBot = H - pad;
|
| 409 |
+
const yScale = (lp) => yTop + (1 - (lp - min) / Math.max(1e-9, max - min)) * (yBot - yTop);
|
| 410 |
+
|
| 411 |
+
// Subsample to ~W points so the path stays cheap to draw at long sequences.
|
| 412 |
+
const n = genTokens.length;
|
| 413 |
+
const step = Math.max(1, Math.ceil(n / W));
|
| 414 |
+
const xScale = (i) => (n === 1 ? W / 2 : pad + (i / (n - 1)) * (W - 2 * pad));
|
| 415 |
+
|
| 416 |
+
let d = "";
|
| 417 |
+
let started = false;
|
| 418 |
+
for (let i = 0; i < n; i += step) {
|
| 419 |
+
const lp = genTokens[i].logprob;
|
| 420 |
+
if (lp == null || isNaN(lp)) continue;
|
| 421 |
+
d += (started ? "L" : "M") + xScale(i).toFixed(1) + " " + yScale(lp).toFixed(1);
|
| 422 |
+
started = true;
|
| 423 |
+
}
|
| 424 |
+
// Always anchor the very last token, even if subsampling skipped it.
|
| 425 |
+
if ((n - 1) % step !== 0) {
|
| 426 |
+
const lp = genTokens[n - 1].logprob;
|
| 427 |
+
if (lp != null && !isNaN(lp)) {
|
| 428 |
+
d += "L" + xScale(n - 1).toFixed(1) + " " + yScale(lp).toFixed(1);
|
| 429 |
+
}
|
| 430 |
+
}
|
| 431 |
+
|
| 432 |
const midPct = max > min ? ((mid - min) / (max - min)) * 100 : 50;
|
| 433 |
+
svg.setAttribute("viewBox", `0 0 ${W} ${H}`);
|
| 434 |
+
svg.innerHTML = `
|
| 435 |
+
<defs>
|
| 436 |
+
<linearGradient id="lp-grad" gradientUnits="userSpaceOnUse" x1="0" y1="${yBot}" x2="0" y2="${yTop}">
|
| 437 |
+
<stop offset="0%" stop-color="#d83a2a"/>
|
| 438 |
+
<stop offset="${midPct.toFixed(1)}%" stop-color="#888"/>
|
| 439 |
+
<stop offset="100%" stop-color="#1a1a1a"/>
|
| 440 |
+
</linearGradient>
|
| 441 |
+
</defs>
|
| 442 |
+
<path d="${d}" fill="none" stroke="url(#lp-grad)" stroke-width="1.2" stroke-linejoin="round" stroke-linecap="round"/>
|
| 443 |
+
`;
|
| 444 |
}
|
| 445 |
function logprobRgb(lp) {
|
| 446 |
if (lp == null || isNaN(lp) || !lpRange) return DARK_RGB;
|