andreiski's picture
Upload ui.js with huggingface_hub
ce50880 verified
Raw
History Blame Contribute Delete
7.81 kB
() => {
let PAPERS = [];
let cur = null;
let pile = []; // indices into items, top of pile first
let held = []; // indices, newest first
let items = []; // [{text, kind}]
let busy = false;
let jid = null;
let epoch = 0;
let animLock = false;
const $ = (id) => document.getElementById(id);
function esc(t) { const d = document.createElement('div'); d.textContent = t; return d.innerHTML; }
function shuffle(a) {
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
}
function counter() {
$('ivx-counter').textContent = pile.length + ' in the pile \u00b7 ' + held.length + ' held';
$('ivx-gen').disabled = busy || held.length === 0;
$('ivx-heldhead').hidden = held.length === 0;
}
function showTop() {
const card = $('ivx-card');
card.classList.remove('fly-left', 'fly-right');
if (!pile.length) {
card.querySelector('.kind').textContent = '';
card.querySelector('.txt').textContent = held.length
? 'Pile empty. Write, or remove a held card to reconsider it.'
: 'Pile empty.';
counter();
return;
}
const it = items[pile[0]];
card.querySelector('.kind').textContent = it.kind;
card.querySelector('.txt').textContent = it.text;
counter();
}
function renderHeld() {
const box = $('ivx-held');
box.innerHTML = '';
held.forEach((idx) => {
const el = document.createElement('div');
el.className = 'hcard';
el.innerHTML = '<div class="txt">' + esc(items[idx].text) +
'</div><button class="rm" title="remove, back into the pile">&#10005;</button>';
el.querySelector('.rm').addEventListener('click', () => {
held = held.filter(h => h !== idx);
pile.push(idx);
renderHeld(); showTop();
});
box.appendChild(el);
});
counter();
}
function verdict(dir) {
if (animLock || !pile.length) return;
animLock = true;
const card = $('ivx-card');
card.classList.add(dir === 'hold' ? 'fly-right' : 'fly-left');
setTimeout(() => {
const idx = pile.shift();
if (dir === 'hold') { held.unshift(idx); renderHeld(); }
else { pile.push(idx); }
showTop();
animLock = false;
}, 240);
}
function pickPaper(pid) {
cur = PAPERS.find(p => p.id === pid);
epoch += 1;
items = cur.rhetorical.map(t => ({ text: t, kind: 'rhetorical' }))
.concat(cur.content.map(t => ({ text: t, kind: 'content' })));
pile = shuffle(items.map((_, i) => i));
held = [];
document.querySelectorAll('#ivx-tabs button').forEach(b =>
b.classList.toggle('on', b.dataset.pid === pid));
$('ivx-ptitle').textContent = cur.title;
$('ivx-out').hidden = true;
$('ivx-empty').hidden = false;
$('ivx-think').textContent = '';
$('ivx-abs').textContent = '';
$('ivx-bars').innerHTML = '';
renderHeld(); showTop();
}
function setStatus(t) {
const s = $('ivx-status');
if (!t) { s.hidden = true; s.textContent = ''; return; }
s.hidden = false; s.textContent = t;
}
function bars(sel, scores) {
return sel.map((t, i) => {
const s = scores[String(i + 1)] || scores[i + 1];
const pct = s ? s / 5 * 100 : 0;
const color = (s || 0) >= 4 ? 'var(--hold)' : (s || 0) === 3 ? '#d9a514' : '#cc4b4b';
return '<div class="barrow"><div class="bartext" title="' + esc(t) + '">' + esc(t) +
'</div><div class="bartrack"><div class="barfill" style="width:' + pct +
'%;background:' + color + '"></div></div><div class="barnum">' + (s ? s + '/5' : '?') +
'</div></div>';
}).join('');
}
function bridgeCall(inputId, btnId, value) {
const inp = document.querySelector('#' + inputId + ' textarea, #' + inputId + ' input');
const setter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value') ||
Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value');
setter.set.call(inp, value);
inp.dispatchEvent(new Event('input', { bubbles: true }));
setTimeout(() => document.querySelector('#' + btnId + ' button, button#' + btnId).click(), 30);
}
function outValue() {
const el = document.querySelector('#ivx-bridge-out textarea, #ivx-bridge-out input');
return el ? el.value : '';
}
async function restCall(name, args) {
const r = await fetch('gradio_api/call/' + name, {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ data: args }) });
const j = await r.json();
const r2 = await fetch('gradio_api/call/' + name + '/' + j.event_id);
const t = await r2.text();
const lines = t.split('\n').filter(x => x.startsWith('data:'));
if (!lines.length) throw new Error('no data from ' + name);
return JSON.parse(lines[lines.length - 1].slice(5))[0];
}
function run() {
if (busy || !cur || !held.length) return;
busy = true;
const myEpoch = epoch;
const sel = held.map(i => items[i].text);
jid = 'j' + Math.random().toString(36).slice(2);
$('ivx-empty').hidden = true;
$('ivx-out').hidden = false;
$('ivx-thinkbox').open = true;
$('ivx-think').textContent = '';
$('ivx-abs').textContent = '';
$('ivx-bars').innerHTML = '';
setStatus('waking the model\u2026');
counter();
const lastRaw = outValue();
bridgeCall('ivx-bridge-in', 'ivx-bridge-btn',
JSON.stringify({ jid: jid, paper_id: cur.id, intuitions: sel }));
const poll = setInterval(async () => {
if (epoch !== myEpoch) { clearInterval(poll); finish(); return; }
let raw = outValue();
if (!raw || raw === lastRaw) {
try { raw = await restCall('peek', [jid]); } catch (e) { /* keep polling */ }
}
if (!raw || raw === lastRaw) return;
let ob;
try { ob = JSON.parse(raw); } catch (e) { return; }
if (ob.jid !== jid) return;
if (ob.phase === 'error') { setStatus(ob.msg); clearInterval(poll); finish(); return; }
if (ob.thinking) $('ivx-think').textContent = ob.thinking;
if (ob.abstract) $('ivx-abs').textContent = ob.abstract;
setStatus(ob.abstract ? 'writing the abstract\u2026' : 'thinking\u2026');
const tb = $('ivx-think');
tb.scrollTop = tb.scrollHeight;
if (ob.phase === 'done') {
$('ivx-bars').innerHTML = bars(sel, ob.scores || {});
$('ivx-thinkbox').open = false;
setStatus('done');
clearInterval(poll); finish();
}
}, 800);
function finish() { busy = false; counter(); }
}
async function init() {
try {
PAPERS = JSON.parse(await restCall('papers', []));
const tabs = $('ivx-tabs');
PAPERS.forEach(p => {
const b = document.createElement('button');
b.textContent = p.title.length > 42 ? p.title.slice(0, 40) + '\u2026' : p.title;
b.dataset.pid = p.id;
b.addEventListener('click', () => pickPaper(p.id));
tabs.appendChild(b);
});
$('ivx-gen').addEventListener('click', run);
$('ivx-pass').addEventListener('click', () => verdict('pass'));
$('ivx-hold').addEventListener('click', () => verdict('hold'));
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowLeft') verdict('pass');
if (e.key === 'ArrowRight') verdict('hold');
});
$('ivx-ver').textContent = 'VERSION';
pickPaper(PAPERS[0].id);
} catch (e) {
const pt = $('ivx-ptitle');
if (pt) pt.textContent = 'The page failed to load its data. Refresh to retry. (' + e.message + ')';
}
}
const waiter = setInterval(() => {
if (document.getElementById('ivx-app')) { clearInterval(waiter); init(); }
}, 200);
}