Spaces:
Running
Running
Download app.js from Deep-Fake/T4_Three_Ways: direct link, hf CLI and curl.
- Browser
- Download file 6.42 kB
-
https://huggingface.co/spaces/Deep-Fake/T4_Three_Ways/resolve/main/app.js
- Command line
-
hf download hf://spaces/Deep-Fake/T4_Three_Ways/app.js
-
curl -L -o app.js https://huggingface.co/spaces/Deep-Fake/T4_Three_Ways/resolve/main/app.js
6.42 kB
| // The three annotators, side by side: one card per clip, read from data.js (window.TRIAL). View only. | |
| const rows = window.TRIAL || []; | |
| const esc = (s) => String(s ?? "").replace(/[&<>"]/g, (c) => ({"&": "&", "<": "<", ">": ">", '"': """}[c])); | |
| const store = { | |
| get(k) { try { return localStorage.getItem(k); } catch { return null; } }, | |
| set(k, v) { try { localStorage.setItem(k, v); } catch {} }, | |
| }; | |
| const GROUPS = [ | |
| ["all", "All", () => true], | |
| ["tell", "Known tells", (r) => r.why.startsWith("tell")], | |
| ["looks", "Looks real", (r) => r.why.startsWith("looks real")], | |
| ["signs", "With signs", (r) => r.why.startsWith("signs")], | |
| ["cell", "One per cell", (r) => r.why.startsWith("cell")], | |
| ]; | |
| const GENERATOR = {facefusion: "FaceFusion", animate: "Animate", s2v: "S2V", real: "Real recording"}; | |
| const WHY = {tell: "Known tell (a reviewer's note)", "looks real": "Looks real (a reviewer's note)", signs: "Picked for its signs", | |
| cell: "One per label and generator", sham: "Sham: a real clip, Gemini told it is fake"}; | |
| function text(list, isReal) { | |
| if (!list || !list.length) return '<p class="real">—</p>'; | |
| const body = list.map((s) => `<span class="sent" data-claims="${(s.claims || []).join(",")}">${esc(s.text)}</span>`).join(" "); | |
| return `<p class="${isReal ? "real" : ""}">${body}</p>`; | |
| } | |
| function arm(cls, title, note, r, sentences, claims, ok, extra = "") { | |
| const body = ok === false ? '<p class="failed">Did not pass the checks after 3 tries.</p>' : | |
| ["video", "audio"].map((p) => `<div class="part"><div class="tag">${p}</div>${text(sentences[p], !r.fake_parts.includes(p))}</div>`).join(""); | |
| const facts = (claims || []).length ? `<div class="sub detail"><div class="label">Written from</div><ul>${claims.map((c) => | |
| `<li data-id="${c.id}"><b>${c.id}</b>${esc(c.text)}</li>`).join("")}</ul></div>` : ""; | |
| return `<section class="arm"><h3><span class="dot ${cls}"></span>${title}<small>${note}</small></h3>${body}${facts}${extra}</section>`; | |
| } | |
| function observed(o) { | |
| if (!o || !o.agreed.length) return ""; | |
| const items = o.agreed.map((x) => `<li class="${x.kept ? "kept" : "dropped"}">${esc(x.when)} · ${esc(x.where)} · ${esc(x.what)}</li>`).join(""); | |
| return `<div class="sub detail"><div class="label">What Gemini saw</div> | |
| <p style="margin:0 0 4px">Seen in at least 2 of 3 looks. ✓ confirmed twice on the clip alone; ✕ not confirmed.</p><ul>${items}</ul></div>`; | |
| } | |
| function header(r) { | |
| const parts = ["video", "audio"].map((p) => { | |
| const fake = !r.sham && r.fake_parts.includes(p); | |
| return `<span class="${fake ? "fake" : "real"}">${p[0].toUpperCase() + p.slice(1)} ${fake ? "fake" : "real"}</span>`; | |
| }).join(" · "); | |
| const kind = Object.keys(WHY).find((k) => r.why.startsWith(k)); | |
| const note = kind === "tell" ? r.why.split(": ").slice(1).join(": ") : ""; // the reviewer's words | |
| const rowsDl = [["Picked", WHY[kind] || r.why]]; | |
| if (note) rowsDl.push(["Note", note]); | |
| if (r.signs.length) rowsDl.push(["Signs", r.signs.map((s) => `${esc(s.artifact)} <span style="color:var(--faint)">(${s.score} ${s.value})</span>`).join("<br>")]); | |
| const ref = r.reference ? `<button class="link" data-ref>Show the real clip</button> | |
| <div class="ref" hidden><video controls preload="none" src="${esc(r.reference)}"></video></div>` : ""; | |
| return `<div class="top"><div class="media"><video controls preload="metadata" src="${esc(r.clip)}"></video></div> | |
| <div class="info"><h2>Clip ${r.n}</h2><div class="meta">${GENERATOR[r.generator] || r.generator} · ${parts}</div> | |
| <dl class="facts">${rowsDl.map(([k, v]) => `<dt>${k}</dt><dd>${k === "Signs" ? v : esc(v)}</dd>`).join("")}</dl>${ref}</div></div>`; | |
| } | |
| function card(r) { | |
| if (r.sham) { | |
| const kept = (r.observed?.agreed || []).filter((x) => x.kept) | |
| .map((x) => `<li>${esc(x.when)} · ${esc(x.where)} · ${esc(x.what)}</li>`).join(""); | |
| return `<article class="clip">${header(r)}<div class="cols" style="grid-template-columns:1fr"><section class="arm sham"> | |
| <h3><span class="dot G"></span>Gemini<small>what it kept on a real clip</small></h3> | |
| <ul class="found">${kept || '<li class="none">Nothing kept.</li>'}</ul> | |
| <p class="note">This clip is a real recording, so anything kept here is a hallucination.</p></section></div></article>`; | |
| } | |
| return `<article class="clip">${header(r)}<div class="cols"> | |
| ${arm("S", "Systematic", "metadata", r, r.S, [], true)} | |
| ${arm("P", "Claude", "text only", r, r.P, r.P_claims, r.P_ok)} | |
| ${arm("G", "Gemini", "sees and hears the clip", r, r.G, r.G_claims, r.G_ok, observed(r.observed))} | |
| </div></article>`; | |
| } | |
| function show(key) { | |
| const test = GROUPS.find((g) => g[0] === key)[2]; | |
| document.getElementById("clips").innerHTML = rows.filter(test).map(card).join(""); | |
| for (const b of document.querySelectorAll("#filters button")) b.classList.toggle("on", b.dataset.key === key); | |
| store.set("t4three:filter", key); | |
| } | |
| document.getElementById("filters").innerHTML = GROUPS.map(([k, label, test]) => | |
| `<button data-key="${k}">${label}<span class="count">${rows.filter(test).length}</span></button>`).join(""); | |
| document.getElementById("filters").onclick = (e) => { const b = e.target.closest("button"); if (b) show(b.dataset.key); }; | |
| const details = document.getElementById("details"); | |
| details.checked = store.get("t4three:details") === "1"; | |
| document.body.classList.toggle("details", details.checked); | |
| details.onchange = () => { document.body.classList.toggle("details", details.checked); store.set("t4three:details", details.checked ? "1" : "0"); }; | |
| document.addEventListener("click", (e) => { | |
| const b = e.target.closest("[data-ref]"); | |
| if (!b) return; | |
| const ref = b.nextElementSibling; | |
| ref.hidden = !ref.hidden; | |
| b.textContent = ref.hidden ? "Show the real clip" : "Hide the real clip"; | |
| }); | |
| // hovering a sentence highlights it and, with Details on, the facts it is written from | |
| document.addEventListener("mouseover", (e) => { | |
| const s = e.target.closest(".sent"); | |
| document.querySelectorAll(".hl").forEach((x) => x.classList.remove("hl")); | |
| if (!s || !s.dataset.claims) return; | |
| s.classList.add("hl"); | |
| const col = s.closest(".arm"); | |
| for (const id of s.dataset.claims.split(",")) col.querySelector(`.sub li[data-id="${id}"]`)?.classList.add("hl"); | |
| }); | |
| const start = store.get("t4three:filter"); | |
| show(GROUPS.some((g) => g[0] === start) ? start : "all"); | |