| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <title>Trace Viewer</title> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <style> | |
| :root { --fg:#111; --muted:#888; --new:#0a7f2e; --mask:#aaa; --border:#ddd; } | |
| body { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; margin:16px; color:var(--fg); } | |
| h1 { font-size:18px; margin:0 0 12px 0; } | |
| .controls { display:flex; flex-wrap:wrap; gap:8px; align-items:center; margin-bottom:12px; } | |
| .controls > * { font-size:14px; } | |
| #viewer { border:1px solid var(--border); padding:12px; height:60vh; overflow:auto; | |
| white-space:pre-wrap; overflow-wrap:anywhere; word-break:normal; } | |
| .masked { color:transparent; text-shadow:0 0 0 var(--mask); } | |
| .unmasked { color:inherit; } | |
| .new { background:#e9f7ee; outline:1px dashed #b7e1c3; } | |
| .special { color:var(--muted); } | |
| .meta { color:var(--muted); font-size:12px; margin-bottom:6px; } | |
| .row { display:flex; gap:8px; align-items:center; } | |
| input[type="range"] { width:300px; } | |
| button { padding:4px 10px; } | |
| select { padding:2px 6px; } | |
| label { user-select:none; } | |
| .maskToken { display:inline-block; width:7ch; text-align:center; white-space:nowrap; word-break:keep-all; } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>Unmask Viewer</h1> | |
| <div class="meta" id="meta"></div> | |
| <div class="controls"> | |
| <div class="row"> | |
| <button id="play">Play</button> | |
| <button id="prev">-1</button> | |
| <input id="step" type="range" min="0" max="0" value="0"> | |
| <button id="next">+1</button> | |
| </div> | |
| <div class="row"> | |
| <label>Step: <span id="stepNum">0</span>/<span id="stepMax">0</span></label> | |
| <label style="margin-left:12px;">Speed: | |
| <select id="speed"> | |
| <option value="1200">0.8×</option> | |
| <option value="800" selected>1×</option> | |
| <option value="500">1.6×</option> | |
| <option value="300">2.6×</option> | |
| </select> | |
| </label> | |
| <label style="margin-left:12px;"> | |
| <input id="hideSpecial" type="checkbox"> Hide special tokens | |
| </label> | |
| <label style="margin-left:12px;"> | |
| <input id="showMaskedShapes" type="checkbox" checked> Show masked placeholders | |
| </label> | |
| </div> | |
| </div> | |
| <div id="viewer"></div> | |
| <script id="data" type="application/json">{"pieces": ["Re", "in", "forcement", " learning", " is", " a", " type", " of", " machine", " learning", " where", " an", " agent", " learns", " to", " make", " decisions", " by", " interacting", " with", " an", " environment", ".", " The", " agent", " receives", " feedback", " in", " the", " form", " of", " rewards", " or", " punishments", " for", " its", " actions", ",", " and", " uses", " this", " feedback", " to", " adjust", " its", " behavior", " in", " order", " to", " maximize", " its", " total", " reward", " over", " time", ".", " This", " process", " is", " achieved", " through", " trial", " and", " error", ",", " and", " the", " agent", " gradually", " learns", " to", " make", " decisions", " that", " lead", " to", " the", " highest", " possible", " reward", ".", "<|im_end|>", "\n", "<|endoftext|>"], "step_map": [2, 1, 3, 3, 3, 3, 4, 4, 4, 5, 6, 7, 8, 8, 9, 11, 10, 12, 13, 14, 15, 14, 17, 17, 16, 18, 21, 20, 20, 19, 22, 22, 23, 24, 25, 27, 26, 28, 29, 30, 32, 31, 33, 36, 34, 35, 37, 38, 39, 39, 40, 43, 41, 42, 44, 44, 45, 46, 49, 50, 48, 47, 51, 51, 52, 53, 55, 54, 56, 57, 58, 60, 59, 60, 61, 62, 63, 64, 67, 68, 66, 65, 69, 69], "is_special": [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, true]}</script> | |
| <script> | |
| const DATA = JSON.parse(document.getElementById('data').textContent); | |
| const pieces = DATA.pieces; | |
| const steps = DATA.step_map; | |
| const isSpec = DATA.is_special; | |
| const maxStep = Math.max(...steps); | |
| const viewer = document.getElementById('viewer'); | |
| const stepInput = document.getElementById('step'); | |
| const stepNum = document.getElementById('stepNum'); | |
| const stepMax = document.getElementById('stepMax'); | |
| const playBtn = document.getElementById('play'); | |
| const prevBtn = document.getElementById('prev'); | |
| const nextBtn = document.getElementById('next'); | |
| const speedSel = document.getElementById('speed'); | |
| const hideSpecial = document.getElementById('hideSpecial'); | |
| const showMaskedShapes = document.getElementById('showMaskedShapes'); | |
| const meta = document.getElementById('meta'); | |
| stepInput.max = String(maxStep); | |
| stepMax.textContent = String(maxStep); | |
| function render(t) { | |
| stepNum.textContent = String(t); | |
| const frag = document.createDocumentFragment(); | |
| let revealed = 0, newly = 0; | |
| for (let i = 0; i < pieces.length; i++) { | |
| if (hideSpecial.checked && isSpec[i]) continue; | |
| const span = document.createElement('span'); | |
| const piece = pieces[i]; | |
| if (steps[i] <= t) { | |
| span.className = 'unmasked' + (steps[i] === t ? ' new' : ''); | |
| span.textContent = piece; | |
| if (steps[i] === t) newly++; | |
| revealed++; | |
| } else { | |
| span.className = 'masked maskToken' + (isSpec[i] ? ' special' : ''); | |
| span.textContent = showMaskedShapes.checked ? '|<MASK>|' : ''; | |
| } | |
| if (isSpec[i]) span.classList.add('special'); | |
| frag.appendChild(span); | |
| } | |
| viewer.innerHTML = ''; | |
| viewer.appendChild(frag); | |
| meta.textContent = `Tokens revealed: ${revealed} / ${pieces.length} | Newly at step ${t}: ${newly}`; | |
| } | |
| let timer = null; | |
| function play() { | |
| if (timer) return; | |
| playBtn.textContent = 'Pause'; | |
| timer = setInterval(() => { | |
| let v = Number(stepInput.value); | |
| if (v >= maxStep) { | |
| pause(); | |
| return; | |
| } | |
| stepInput.value = String(v + 1); | |
| render(v + 1); | |
| }, Number(speedSel.value)); | |
| } | |
| function pause() { | |
| if (timer) { | |
| clearInterval(timer); | |
| timer = null; | |
| } | |
| playBtn.textContent = 'Play'; | |
| } | |
| stepInput.addEventListener('input', () => render(Number(stepInput.value))); | |
| playBtn.addEventListener('click', () => (timer ? pause() : play())); | |
| prevBtn.addEventListener('click', () => { | |
| const v = Math.max(0, Number(stepInput.value) - 1); | |
| stepInput.value = String(v); | |
| render(v); | |
| }); | |
| nextBtn.addEventListener('click', () => { | |
| const v = Math.min(maxStep, Number(stepInput.value) + 1); | |
| stepInput.value = String(v); | |
| render(v); | |
| }); | |
| speedSel.addEventListener('change', () => { | |
| if (timer) { pause(); play(); } | |
| }); | |
| hideSpecial.addEventListener('change', () => render(Number(stepInput.value))); | |
| showMaskedShapes.addEventListener('change', () => render(Number(stepInput.value))); | |
| render(0); | |
| </script> | |
| </body> | |
| </html> |