Spaces:
Running
Running
review.html: push-all button, no legacy
Browse files- review.html +49 -0
review.html
CHANGED
|
@@ -72,6 +72,7 @@ footer .sp { flex: 1; }
|
|
| 72 |
<span class="sp"></span><span id="count"></span>
|
| 73 |
<input id="hubtok" type="password" placeholder="HF token" title="write token for data-use-annotations; only needed on static hosting without the bundled server"
|
| 74 |
style="font:inherit;color:var(--fg);background:var(--bg);border:1px solid var(--line);border-radius:8px;padding:8px 10px;max-width:130px">
|
|
|
|
| 75 |
<button id="hubBtn" onclick="exp()">export</button>
|
| 76 |
</footer>
|
| 77 |
<script>
|
|
@@ -81,6 +82,7 @@ const DS = { sample: './queue_annotate_sample.json', gold: './queue_review473.js
|
|
| 81 |
const USERS = ['paddy', 'aj', 'aivin', 'rafael'];
|
| 82 |
const LS = 'review_rulings';
|
| 83 |
let R = JSON.parse(localStorage.getItem(LS) || '{}');
|
|
|
|
| 84 |
const $ = id => document.getElementById(id);
|
| 85 |
const esc = s => String(s).replace(/[&<>]/g, c => ({'&':'&','<':'<','>':'>'}[c]));
|
| 86 |
const QD = document.documentElement;
|
|
@@ -242,7 +244,9 @@ async function rule(v) {
|
|
| 242 |
if (needName()) return;
|
| 243 |
const k = span().key;
|
| 244 |
R[k] = v;
|
|
|
|
| 245 |
localStorage.setItem(LS, JSON.stringify(R));
|
|
|
|
| 246 |
paintGate();
|
| 247 |
const entry = {key: k, ruling: v, queue: $('ds').value, annotator: who()};
|
| 248 |
let saved = 'this browser only';
|
|
@@ -287,6 +291,50 @@ async function hubCommit(entry) {
|
|
| 287 |
return 'Hub';
|
| 288 |
} catch (e) { return 'this browser only (Hub sync failed)'; }
|
| 289 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 290 |
document.addEventListener('keydown', e => {
|
| 291 |
if (e.target.tagName === 'INPUT' || e.target.tagName === 'SELECT') return;
|
| 292 |
if (e.key === 'ArrowRight') smove(1);
|
|
@@ -294,6 +342,7 @@ document.addEventListener('keydown', e => {
|
|
| 294 |
else if (e.key === '[') { wc = Math.max(0, (wc ?? 0) - WSIZES[wi] / 2); render(); }
|
| 295 |
else if (e.key === ']') { wc = (wc ?? 0) + WSIZES[wi] / 2; render(); }
|
| 296 |
else if (e.key === '-' || e.key === '_') { wi = Math.max(0, wi - 1); render(); }
|
|
|
|
| 297 |
else if (e.key === 'k' || e.key === 'K') rule('DATA_MENTION');
|
| 298 |
else if (e.key === 'd' || e.key === 'D') rule('NON_MENTION');
|
| 299 |
else if (e.key === ' ') { e.preventDefault(); skip(); }
|
|
|
|
| 72 |
<span class="sp"></span><span id="count"></span>
|
| 73 |
<input id="hubtok" type="password" placeholder="HF token" title="write token for data-use-annotations; only needed on static hosting without the bundled server"
|
| 74 |
style="font:inherit;color:var(--fg);background:var(--bg);border:1px solid var(--line);border-radius:8px;padding:8px 10px;max-width:130px">
|
| 75 |
+
<button id="pushBtn" onclick="pushAll()">push annotations</button>
|
| 76 |
<button id="hubBtn" onclick="exp()">export</button>
|
| 77 |
</footer>
|
| 78 |
<script>
|
|
|
|
| 82 |
const USERS = ['paddy', 'aj', 'aivin', 'rafael'];
|
| 83 |
const LS = 'review_rulings';
|
| 84 |
let R = JSON.parse(localStorage.getItem(LS) || '{}');
|
| 85 |
+
let RQ = JSON.parse(localStorage.getItem('review_queues') || '{}');
|
| 86 |
const $ = id => document.getElementById(id);
|
| 87 |
const esc = s => String(s).replace(/[&<>]/g, c => ({'&':'&','<':'<','>':'>'}[c]));
|
| 88 |
const QD = document.documentElement;
|
|
|
|
| 244 |
if (needName()) return;
|
| 245 |
const k = span().key;
|
| 246 |
R[k] = v;
|
| 247 |
+
RQ[k] = $('ds').value;
|
| 248 |
localStorage.setItem(LS, JSON.stringify(R));
|
| 249 |
+
localStorage.setItem('review_queues', JSON.stringify(RQ));
|
| 250 |
paintGate();
|
| 251 |
const entry = {key: k, ruling: v, queue: $('ds').value, annotator: who()};
|
| 252 |
let saved = 'this browser only';
|
|
|
|
| 291 |
return 'Hub';
|
| 292 |
} catch (e) { return 'this browser only (Hub sync failed)'; }
|
| 293 |
}
|
| 294 |
+
async function pushAll() {
|
| 295 |
+
// one read, merge every local ruling, one commit to your own file.
|
| 296 |
+
// use after pasting your token, or to retry anything saved locally only.
|
| 297 |
+
if (needName()) return;
|
| 298 |
+
const tok = ($('hubtok').value || '').trim();
|
| 299 |
+
if (!tok) { $('mine').textContent = 'paste your HF write token first (footer field)'; $('hubtok').focus(); return; }
|
| 300 |
+
const btn = $('pushBtn');
|
| 301 |
+
btn.disabled = true;
|
| 302 |
+
try {
|
| 303 |
+
const repo = 'rafmacalaba/data-use-annotations';
|
| 304 |
+
const who = who().replace(/[^a-zA-Z0-9-_]/g, '_');
|
| 305 |
+
const path = `rulings/${who}.jsonl`;
|
| 306 |
+
let rows = [];
|
| 307 |
+
try {
|
| 308 |
+
const r = await fetch(`https://huggingface.co/datasets/${repo}/resolve/main/${path}`);
|
| 309 |
+
if (r.ok) rows = (await r.text()).split('\n').filter(Boolean).map(JSON.parse);
|
| 310 |
+
} catch (e) {}
|
| 311 |
+
const seen = new Set(rows.map(x => x.queue + '|' + x.key));
|
| 312 |
+
let added = 0;
|
| 313 |
+
for (const [key, ruling] of Object.entries(R)) {
|
| 314 |
+
const q = RQ[key] || $('ds').value;
|
| 315 |
+
if (seen.has(q + '|' + key)) continue;
|
| 316 |
+
rows.push({key, ruling, queue: q, annotator: who(),
|
| 317 |
+
ts: new Date().toISOString().replace(/\.\d+Z$/, '+00:00')});
|
| 318 |
+
added++;
|
| 319 |
+
}
|
| 320 |
+
if (!added) { lastSaved = 'Hub (already in sync)'; lightMeta(); btn.disabled = false; return; }
|
| 321 |
+
const content = btoa(unescape(encodeURIComponent(rows.map(x => JSON.stringify(x)).join('\n') + '\n')));
|
| 322 |
+
const nd = [{key: 'header', value: {summary: `push ${added} rulings (${who}, web)`, description: ''}},
|
| 323 |
+
{key: 'file', value: {content, path, encoding: 'base64'}}].map(o => JSON.stringify(o)).join('\n');
|
| 324 |
+
const res = await fetch(`https://huggingface.co/api/datasets/${repo}/commit/main`, {
|
| 325 |
+
method: 'POST', headers: {Authorization: `Bearer ${tok}`, 'Content-Type': 'application/x-ndjson'}, body: nd});
|
| 326 |
+
if (!res.ok) throw new Error('hub ' + res.status);
|
| 327 |
+
lastSaved = `Hub (${added} pushed)`;
|
| 328 |
+
} catch (e) { lastSaved = 'push failed — still stored in this browser'; }
|
| 329 |
+
btn.disabled = false;
|
| 330 |
+
lightMeta();
|
| 331 |
+
}
|
| 332 |
+
function exp() {
|
| 333 |
+
const rows = Object.entries(R).map(([key, ruling]) => ({key, ruling, queue: RQ[key] || $('ds').value, annotator: who()}));
|
| 334 |
+
const a = document.createElement('a');
|
| 335 |
+
a.href = URL.createObjectURL(new Blob([rows.map(r => JSON.stringify(r)).join('\n')], {type: 'application/json'}));
|
| 336 |
+
a.download = 'review-rulings.jsonl'; a.click();
|
| 337 |
+
}
|
| 338 |
document.addEventListener('keydown', e => {
|
| 339 |
if (e.target.tagName === 'INPUT' || e.target.tagName === 'SELECT') return;
|
| 340 |
if (e.key === 'ArrowRight') smove(1);
|
|
|
|
| 342 |
else if (e.key === '[') { wc = Math.max(0, (wc ?? 0) - WSIZES[wi] / 2); render(); }
|
| 343 |
else if (e.key === ']') { wc = (wc ?? 0) + WSIZES[wi] / 2; render(); }
|
| 344 |
else if (e.key === '-' || e.key === '_') { wi = Math.max(0, wi - 1); render(); }
|
| 345 |
+
else if (e.key === '=' || e.key === '+') { wi = Math.min(WSIZES.length - 1, wi + 1); render(); }
|
| 346 |
else if (e.key === 'k' || e.key === 'K') rule('DATA_MENTION');
|
| 347 |
else if (e.key === 'd' || e.key === 'D') rule('NON_MENTION');
|
| 348 |
else if (e.key === ' ') { e.preventDefault(); skip(); }
|