HCAI-Lab/w2-consensus-deepdive-unlearning-artifacts / social-data-attribution-w2 /scripts /validation /classification_viewer.html
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>SocialIQA Classification Audit Viewer</title> | |
| <style> | |
| * { box-sizing: border-box; margin: 0; padding: 0; } | |
| body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace; background: #0d1117; color: #c9d1d9; padding: 16px; } | |
| h1 { font-size: 18px; margin-bottom: 12px; color: #e6edf3; } | |
| .controls { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; align-items: center; } | |
| .controls select, .controls input { background: #161b22; border: 1px solid #30363d; color: #c9d1d9; padding: 6px 10px; border-radius: 4px; font-size: 13px; } | |
| .controls input[type="text"] { width: 220px; } | |
| .controls select { min-width: 140px; } | |
| .drop-zone { border: 2px dashed #30363d; border-radius: 8px; padding: 32px; text-align: center; margin-bottom: 16px; cursor: pointer; transition: border-color 0.2s; } | |
| .drop-zone:hover, .drop-zone.over { border-color: #58a6ff; } | |
| .drop-zone input { display: none; } | |
| .stats { display: flex; gap: 16px; flex-wrap: wrap; margin-bottom: 16px; } | |
| .stat { background: #161b22; border: 1px solid #30363d; border-radius: 6px; padding: 10px 14px; } | |
| .stat .n { font-size: 22px; font-weight: 600; color: #e6edf3; } | |
| .stat .lbl { font-size: 11px; color: #8b949e; text-transform: uppercase; letter-spacing: 0.5px; } | |
| table { width: 100%; border-collapse: collapse; font-size: 12px; table-layout: fixed; } | |
| thead th { background: #161b22; position: sticky; top: 0; padding: 8px 6px; text-align: left; border-bottom: 1px solid #30363d; cursor: pointer; white-space: nowrap; } | |
| thead th:hover { color: #58a6ff; } | |
| tbody td { padding: 6px; border-bottom: 1px solid #21262d; vertical-align: top; word-wrap: break-word; overflow-wrap: break-word; } | |
| tbody tr:hover { background: #161b22; } | |
| tr.agree-yes td:first-child { border-left: 3px solid #3fb950; } | |
| tr.agree-no td:first-child { border-left: 3px solid #f85149; } | |
| tr.agree-nr td:first-child { border-left: 3px solid #30363d; } | |
| .page-controls { margin-top: 12px; display: flex; gap: 8px; align-items: center; justify-content: center; } | |
| .page-controls button { background: #21262d; border: 1px solid #30363d; color: #c9d1d9; padding: 6px 14px; border-radius: 4px; cursor: pointer; } | |
| .page-controls button:hover { background: #30363d; } | |
| .page-controls button:disabled { opacity: 0.4; cursor: default; } | |
| .method-badge { display: inline-block; padding: 2px 6px; border-radius: 3px; font-size: 11px; font-weight: 500; } | |
| .method-badge.o_pattern { background: #1f6feb33; color: #58a6ff; } | |
| .method-badge.x_pattern { background: #23863633; color: #3fb950; } | |
| .method-badge.x_to_o_disambiguation { background: #a371f733; color: #bc8cff; } | |
| .method-badge.manual_override { background: #d2992233; color: #d29922; } | |
| .method-badge.verified_correction { background: #f8514933; color: #f85149; } | |
| .method-badge.verified_correction_by_text { background: #f8514933; color: #f85149; } | |
| .hidden { display: none; } | |
| col.c-id { width: 110px; } col.c-ctx { width: 22%; } col.c-q { width: 20%; } | |
| col.c-label { width: 70px; } col.c-method { width: 150px; } col.c-pattern { width: 14%; } | |
| col.c-actor { width: 60px; } col.c-subj { width: 60px; } col.c-xo { width: 40px; } | |
| col.c-sonnet { width: 70px; } col.c-agree { width: 65px; } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>SocialIQA ATOMIC Reasoning Type — Classification Audit</h1> | |
| <div id="dropZone" class="drop-zone"> | |
| Drop <code>socialiqa_classification_audit.csv</code> here or <label style="color:#58a6ff;cursor:pointer">browse<input type="file" id="fileInput" accept=".csv"></label> | |
| </div> | |
| <div id="app" class="hidden"> | |
| <div class="stats" id="stats"></div> | |
| <div class="controls"> | |
| <select id="fLabel"><option value="">All labels</option></select> | |
| <select id="fMethod"><option value="">All methods</option></select> | |
| <select id="fAgree"><option value="">All agreement</option></select> | |
| <input type="text" id="fSearch" placeholder="Search question text..."> | |
| <span id="countDisplay" style="color:#8b949e;font-size:13px"></span> | |
| </div> | |
| <div style="overflow-x:auto"> | |
| <table> | |
| <colgroup> | |
| <col class="c-id"><col class="c-ctx"><col class="c-q"><col class="c-label"> | |
| <col class="c-method"><col class="c-pattern"><col class="c-actor"><col class="c-subj"> | |
| <col class="c-xo"><col class="c-sonnet"><col class="c-agree"> | |
| </colgroup> | |
| <thead><tr> | |
| <th data-col="query_id">query_id</th> | |
| <th data-col="context">context</th> | |
| <th data-col="question_sentence">question</th> | |
| <th data-col="final_label">label</th> | |
| <th data-col="classification_method">method</th> | |
| <th data-col="pattern_matched">pattern</th> | |
| <th data-col="context_actor">actor</th> | |
| <th data-col="question_subject">subject</th> | |
| <th data-col="x_to_o_applied">x→o</th> | |
| <th data-col="sonnet_label">sonnet</th> | |
| <th data-col="sonnet_agrees">agrees</th> | |
| </tr></thead> | |
| <tbody id="tbody"></tbody> | |
| </table> | |
| </div> | |
| <div class="page-controls"> | |
| <button id="prevBtn" onclick="changePage(-1)">Prev</button> | |
| <span id="pageInfo"></span> | |
| <button id="nextBtn" onclick="changePage(1)">Next</button> | |
| </div> | |
| </div> | |
| <script> | |
| let allRows = [], filtered = [], page = 0; | |
| const PER_PAGE = 100; | |
| function parseCSV(text) { | |
| const lines = text.split('\n').filter(l => l.trim()); | |
| const headers = parseCSVLine(lines[0]); | |
| return lines.slice(1).map(line => { | |
| const vals = parseCSVLine(line); | |
| const obj = {}; | |
| headers.forEach((h, i) => obj[h] = vals[i] || ''); | |
| return obj; | |
| }); | |
| } | |
| function parseCSVLine(line) { | |
| const result = []; let current = '', inQuotes = false; | |
| for (let i = 0; i < line.length; i++) { | |
| const ch = line[i]; | |
| if (inQuotes) { | |
| if (ch === '"' && line[i+1] === '"') { current += '"'; i++; } | |
| else if (ch === '"') { inQuotes = false; } | |
| else { current += ch; } | |
| } else { | |
| if (ch === '"') { inQuotes = true; } | |
| else if (ch === ',') { result.push(current); current = ''; } | |
| else { current += ch; } | |
| } | |
| } | |
| result.push(current); | |
| return result; | |
| } | |
| function loadData(rows) { | |
| allRows = rows; | |
| const labels = [...new Set(rows.map(r => r.final_label))].sort(); | |
| const methods = [...new Set(rows.map(r => r.classification_method))].sort(); | |
| const agrees = [...new Set(rows.map(r => r.sonnet_agrees))].sort(); | |
| populateSelect('fLabel', labels); | |
| populateSelect('fMethod', methods); | |
| populateSelect('fAgree', agrees); | |
| updateStats(); | |
| applyFilters(); | |
| document.getElementById('dropZone').classList.add('hidden'); | |
| document.getElementById('app').classList.remove('hidden'); | |
| } | |
| function populateSelect(id, values) { | |
| const sel = document.getElementById(id); | |
| values.forEach(v => { const o = document.createElement('option'); o.value = v; o.textContent = v || '(empty)'; sel.appendChild(o); }); | |
| } | |
| function updateStats() { | |
| const s = document.getElementById('stats'); | |
| const methodCounts = {}; | |
| allRows.forEach(r => { methodCounts[r.classification_method] = (methodCounts[r.classification_method] || 0) + 1; }); | |
| const agreeCounts = {}; | |
| allRows.forEach(r => { agreeCounts[r.sonnet_agrees] = (agreeCounts[r.sonnet_agrees] || 0) + 1; }); | |
| s.innerHTML = ` | |
| <div class="stat"><div class="n">${allRows.length.toLocaleString()}</div><div class="lbl">Total</div></div> | |
| <div class="stat"><div class="n">${methodCounts['x_pattern'] || 0}</div><div class="lbl">x_pattern</div></div> | |
| <div class="stat"><div class="n">${methodCounts['x_to_o_disambiguation'] || 0}</div><div class="lbl">x→o disambig</div></div> | |
| <div class="stat"><div class="n">${methodCounts['o_pattern'] || 0}</div><div class="lbl">o_pattern</div></div> | |
| <div class="stat"><div class="n">${(methodCounts['verified_correction'] || 0) + (methodCounts['verified_correction_by_text'] || 0) + (methodCounts['manual_override'] || 0)}</div><div class="lbl">Overrides</div></div> | |
| <div class="stat"><div class="n">${agreeCounts['yes'] || 0}</div><div class="lbl">Sonnet agrees</div></div> | |
| <div class="stat"><div class="n">${agreeCounts['no'] || 0}</div><div class="lbl">Sonnet disagrees</div></div> | |
| `; | |
| } | |
| function applyFilters() { | |
| const label = document.getElementById('fLabel').value; | |
| const method = document.getElementById('fMethod').value; | |
| const agree = document.getElementById('fAgree').value; | |
| const search = document.getElementById('fSearch').value.toLowerCase(); | |
| filtered = allRows.filter(r => | |
| (!label || r.final_label === label) && | |
| (!method || r.classification_method === method) && | |
| (!agree || r.sonnet_agrees === agree) && | |
| (!search || r.context.toLowerCase().includes(search) || r.question_sentence.toLowerCase().includes(search)) | |
| ); | |
| page = 0; | |
| document.getElementById('countDisplay').textContent = `${filtered.length.toLocaleString()} rows`; | |
| render(); | |
| } | |
| function render() { | |
| const tbody = document.getElementById('tbody'); | |
| const start = page * PER_PAGE; | |
| const slice = filtered.slice(start, start + PER_PAGE); | |
| tbody.innerHTML = slice.map(r => { | |
| const cls = r.sonnet_agrees === 'yes' ? 'agree-yes' : r.sonnet_agrees === 'no' ? 'agree-no' : 'agree-nr'; | |
| const mCls = r.classification_method.replace(/ /g, '_'); | |
| return `<tr class="${cls}"> | |
| <td>${esc(r.query_id)}</td> | |
| <td>${esc(r.context)}</td> | |
| <td>${esc(r.question_sentence)}</td> | |
| <td><strong>${esc(r.final_label)}</strong></td> | |
| <td><span class="method-badge ${mCls}">${esc(r.classification_method)}</span></td> | |
| <td>${esc(r.pattern_matched)}</td> | |
| <td>${esc(r.context_actor)}</td> | |
| <td>${esc(r.question_subject)}</td> | |
| <td>${r.x_to_o_applied === 'True' ? 'yes' : ''}</td> | |
| <td>${esc(r.sonnet_label)}</td> | |
| <td>${esc(r.sonnet_agrees)}</td> | |
| </tr>`; | |
| }).join(''); | |
| const totalPages = Math.ceil(filtered.length / PER_PAGE); | |
| document.getElementById('pageInfo').textContent = `Page ${page + 1} of ${totalPages}`; | |
| document.getElementById('prevBtn').disabled = page === 0; | |
| document.getElementById('nextBtn').disabled = page >= totalPages - 1; | |
| } | |
| function changePage(delta) { page += delta; render(); } | |
| function esc(s) { const d = document.createElement('div'); d.textContent = s; return d.innerHTML; } | |
| ['fLabel', 'fMethod', 'fAgree'].forEach(id => document.getElementById(id).addEventListener('change', applyFilters)); | |
| document.getElementById('fSearch').addEventListener('input', applyFilters); | |
| const dropZone = document.getElementById('dropZone'); | |
| dropZone.addEventListener('dragover', e => { e.preventDefault(); dropZone.classList.add('over'); }); | |
| dropZone.addEventListener('dragleave', () => dropZone.classList.remove('over')); | |
| dropZone.addEventListener('drop', e => { e.preventDefault(); dropZone.classList.remove('over'); handleFile(e.dataTransfer.files[0]); }); | |
| document.getElementById('fileInput').addEventListener('change', e => handleFile(e.target.files[0])); | |
| function handleFile(file) { | |
| if (!file) return; | |
| const reader = new FileReader(); | |
| reader.onload = e => loadData(parseCSV(e.target.result)); | |
| reader.readAsText(file); | |
| } | |
| document.querySelectorAll('thead th').forEach(th => { | |
| th.addEventListener('click', () => { | |
| const col = th.dataset.col; | |
| filtered.sort((a, b) => a[col].localeCompare(b[col])); | |
| page = 0; render(); | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> | |
Xet Storage Details
- Size:
- 11.2 kB
- Xet hash:
- cca0c1b0dcd0f84fd1b7fe4beb5f42fb011e4b15b8007dbce2928707d87d8124
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.