phantom-wiki-viewer / e2e-structures.js
timchen0618's picture
Add E2E v3 + rawtext views
12ea280 verified
Raw
History Blame Contribute Delete
12.7 kB
(function () {
"use strict";
var MODE = "e2e_structures_v3";
var RAWTEXT_MODE = "e2e_rawtext_structures";
var STRUCTURE_MODES = [MODE, RAWTEXT_MODE];
var ROOT = "e2e_structures_v3";
var active = false;
var activeMode = MODE;
var index = null;
var rows = [];
var filtered = [];
var current = 0;
var cache = {};
var loadSequence = 0;
var shapeIcons = {
tabular_records: "Table",
chronology_and_timeline_indexes: "Timeline",
claim_and_theme_summaries: "Claims",
qa_shortcuts_and_templates: "QA",
relation_graphs_and_mappings: "Graph",
};
function $(id) { return document.getElementById(id); }
function esc(value) {
return String(value === null || value === undefined ? "" : value)
.replace(/&/g, "&amp;").replace(/</g, "&lt;")
.replace(/>/g, "&gt;").replace(/"/g, "&quot;");
}
function short(value, limit) {
value = String(value || "").replace(/\s+/g, " ").trim();
return value.length > limit ? value.slice(0, limit - 1) + "..." : value;
}
function hide(id) { if ($(id)) $(id).style.display = "none"; }
function show(id) { if ($(id)) $(id).style.display = ""; }
function installDom() {
if (!$("e2eStructuresControls")) {
var controls = document.createElement("div");
controls.id = "e2eStructuresControls";
controls.style.display = "none";
controls.innerHTML =
'<div class="search-box">' +
'<div class="sidebar-label">Constructed structures</div>' +
'<input id="e2eStructuresSearch" type="text" placeholder="Question / qid / document...">' +
'<select id="e2eStructuresSelect"></select></div>' +
'<div><div class="sidebar-label">Navigate</div><div class="nav-controls">' +
'<button id="e2eStructuresPrev" type="button">← Prev</button>' +
'<span id="e2eStructuresCounter">0 / 0</span>' +
'<button id="e2eStructuresNext" type="button">Next →</button>' +
"</div></div>";
var footer = $("sidebarFooter");
footer.parentNode.insertBefore(controls, footer);
$("e2eStructuresSearch").addEventListener("input", filterRows);
$("e2eStructuresSelect").addEventListener("change", function () {
current = parseInt(this.value, 10) || 0;
renderCurrent();
});
$("e2eStructuresPrev").addEventListener("click", function () {
if (current > 0) { current--; renderCurrent(); }
});
$("e2eStructuresNext").addEventListener("click", function () {
if (current < filtered.length - 1) { current++; renderCurrent(); }
});
}
if (!$("e2eStructuresView")) {
var section = document.createElement("section");
section.id = "e2eStructuresView";
section.style.display = "none";
section.innerHTML =
'<div class="e2estruct-summary" id="e2eStructuresSummary"></div>' +
'<div class="e2estruct-main" id="e2eStructuresMain"></div>';
document.querySelector(".app-main").appendChild(section);
}
}
function ensureButton() {
var toggle = $("viewToggle");
if (!toggle) return;
var compare = toggle.querySelector('[data-mode="compare"]');
[
["modeE2eStructuresV3Btn", MODE, "E2E Structures v3"],
["modeE2eRawtextStructuresBtn", RAWTEXT_MODE, "E2E+Rawtext Structures"],
].forEach(function (definition) {
if ($(definition[0])) return;
var button = document.createElement("button");
button.id = definition[0];
button.type = "button";
button.dataset.mode = definition[1];
button.className = definition[1] === RAWTEXT_MODE
? "e2e-rawtext-structures-tab"
: "e2e-structures-tab";
button.textContent = definition[2];
button.addEventListener("click", activate);
if (compare && compare.parentNode === toggle) toggle.insertBefore(button, compare);
else toggle.appendChild(button);
});
}
function deactivate() {
var wasActive = active;
active = false;
window.__e2eStructuresActive = false;
if (wasActive) window.__e2eStructuresJustClosed = true;
hide("e2eStructuresControls");
hide("e2eStructuresView");
var button = $("modeE2eStructuresV3Btn");
var rawtextButton = $("modeE2eRawtextStructuresBtn");
if (button) button.classList.remove("active");
if (rawtextButton) rawtextButton.classList.remove("active");
}
function activate(event) {
if (event) event.stopImmediatePropagation();
activeMode = event && event.currentTarget.dataset.mode || activeMode;
active = true;
if (index) renderSummary();
window.__e2eStructuresActive = true;
window.__e2eStructuresJustClosed = false;
if ($("setSelect") && $("setSelect").value !== "size5000_seed1") {
$("setSelect").value = "size5000_seed1";
$("setSelect").dispatchEvent(new Event("change"));
}
if ($("setSelect")) $("setSelect").disabled = true;
if ($("scopeNote")) $("scopeNote").style.display = "";
document.querySelectorAll("#viewToggle button").forEach(function (button) {
button.classList.toggle("active", button.dataset.mode === activeMode);
});
["corpusControls", "evalControls", "runControls", "compareControls"].forEach(hide);
["corpusView", "evalView", "runView", "compareView"].forEach(hide);
hide("loading");
show("e2eStructuresControls");
show("e2eStructuresView");
loadIndex().then(function () {
if (!active) return;
filterRows();
}).catch(function (error) {
$("e2eStructuresMain").innerHTML =
'<div class="e2estruct-empty">Failed to load structures: ' + esc(error) + "</div>";
});
}
function loadIndex() {
if (index) return Promise.resolve(index);
$("e2eStructuresMain").innerHTML =
'<div class="e2estruct-empty">Loading E2E v3 structure index...</div>';
return fetch(ROOT + "/index.json").then(function (response) {
if (!response.ok) throw new Error("index HTTP " + response.status);
return response.json();
}).then(function (value) {
index = value;
rows = value.rows || [];
renderSummary();
return value;
});
}
function renderSummary() {
var meta = index.meta || {};
$("e2eStructuresSummary").innerHTML =
'<div><b>' + esc(activeMode === RAWTEXT_MODE
? "E2E+Rawtext Structures"
: (meta.label || "E2E Structures v3")) + "</b></div>" +
(activeMode === RAWTEXT_MODE
? "<div>The five generated shapes were reused exactly; raw universe documents were mounted as a sixth fallback overlay.</div>"
: "") +
'<div class="e2estruct-pills">' +
'<span>' + esc(meta.n_qids) + " questions</span>" +
'<span>' + esc(meta.n_source_docs) + " supporting docs</span>" +
'<span>' + esc(meta.n_structures_total) + " structures</span>" +
"</div>";
}
function filterRows() {
var query = $("e2eStructuresSearch").value.trim().toLowerCase();
var selected = filtered[current] && filtered[current].qid;
var sharedQid = window.TrajectoryUI && window.TrajectoryUI.getQid();
filtered = rows.filter(function (row) {
if (!query) return true;
return [
row.qid, row.question, (row.doc_ids || []).join(" "),
(row.source_doc_ids || []).join(" "),
].join(" ").toLowerCase().indexOf(query) !== -1;
});
current = 0;
if (sharedQid) {
filtered.some(function (row, position) {
if (row.qid !== sharedQid) return false;
current = position;
return true;
});
} else if (selected) {
filtered.some(function (row, position) {
if (row.qid !== selected) return false;
current = position;
return true;
});
}
var select = $("e2eStructuresSelect");
select.innerHTML = "";
filtered.forEach(function (row, position) {
var option = document.createElement("option");
option.value = String(position);
option.textContent = row.qid + " · " + short(row.question, 72);
select.appendChild(option);
});
renderCurrent();
}
function decodeRecord(item) {
if (cache[item.qid]) return Promise.resolve(cache[item.qid]);
return fetch(ROOT + "/" + item.path).then(function (response) {
if (!response.ok) throw new Error(item.path + ": HTTP " + response.status);
return response.text();
}).then(function (encoded) {
var binary = atob(encoded.trim());
var bytes = new Uint8Array(binary.length);
for (var i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
if (typeof DecompressionStream === "undefined") {
throw new Error("This browser does not support gzip structure shards.");
}
var stream = new Blob([bytes]).stream().pipeThrough(new DecompressionStream("gzip"));
return new Response(stream).text();
}).then(function (text) {
cache[item.qid] = JSON.parse(text);
return cache[item.qid];
});
}
function renderCurrent() {
var host = $("e2eStructuresMain");
if (!filtered.length) {
$("e2eStructuresCounter").textContent = "0 / 0";
$("e2eStructuresSelect").innerHTML = "";
host.innerHTML = '<div class="e2estruct-empty">No questions match the filter.</div>';
return;
}
var item = filtered[current];
$("e2eStructuresCounter").textContent = (current + 1) + " / " + filtered.length;
$("e2eStructuresSelect").value = String(current);
host.innerHTML = '<div class="e2estruct-empty">Loading ' + esc(item.qid) + "...</div>";
var sequence = ++loadSequence;
decodeRecord(item).then(function (record) {
if (!active || sequence !== loadSequence) return;
renderRecord(record);
}).catch(function (error) {
host.innerHTML = '<div class="e2estruct-empty">Failed to load record: ' +
esc(error) + "</div>";
});
}
function renderGold(value) {
if (typeof value === "string") return value;
return JSON.stringify(value, null, 2);
}
function renderStructure(structure) {
var label = shapeIcons[structure.shape_id] || structure.shape_id;
var unit = structure.unit_name ? " · " + structure.unit_name : "";
return '<details class="e2estruct-shape">' +
'<summary><span>' + esc(label) + "</span><code>" +
esc(structure.shape_id) + esc(unit) + "</code></summary>" +
(structure.unit_description
? '<div class="e2estruct-description">' + esc(structure.unit_description) + "</div>"
: "") +
'<pre>' + esc(structure.content || "(empty artifact)") + "</pre></details>";
}
function renderDocument(doc, position) {
var sources = (doc.source_doc_ids || []).map(function (id) {
return "<code>" + esc(id) + "</code>";
}).join(" ");
var structures = (doc.structures || []).map(renderStructure).join("");
return '<details class="e2estruct-doc"' + (position === 0 ? " open" : "") + ">" +
'<summary><span>' + esc(doc.doc_id) + "</span><b>" +
esc(doc.n_structures) + " structures</b></summary>" +
'<div class="e2estruct-source-ids"><b>Supporting source artifacts:</b> ' +
(sources || "none") + "</div>" +
'<details class="e2estruct-source"><summary>Supporting text</summary><pre>' +
esc(doc.contents || "") + "</pre></details>" +
(structures || '<div class="e2estruct-empty">No structures for this extraction unit.</div>') +
"</details>";
}
function renderRecord(record) {
if (window.TrajectoryUI) window.TrajectoryUI.setQid(record.qid);
$("e2eStructuresMain").innerHTML =
'<div class="e2estruct-question">' +
'<div class="e2estruct-pills"><span>' + esc(record.qid) + "</span>" +
'<span>' + esc(record.n_source_docs) + " source docs</span>" +
'<span>' + esc(record.n_structures) + " structures</span></div>" +
"<h2>" + esc(record.question) + "</h2>" +
window.TrajectoryUI.gold(record.gold_answers, "Gold") + "</div>" +
(record.docs || []).map(renderDocument).join("");
}
installDom();
ensureButton();
new MutationObserver(ensureButton).observe($("viewToggle"), { childList: true, subtree: true });
document.addEventListener("click", function (event) {
var button = event.target.closest && event.target.closest("#viewToggle button");
if (button && STRUCTURE_MODES.indexOf(button.dataset.mode) === -1) deactivate();
}, true);
document.addEventListener("keydown", function (event) {
if (!active || (event.key !== "ArrowLeft" && event.key !== "ArrowRight")) return;
var tag = (event.target.tagName || "").toLowerCase();
if (tag === "input" || tag === "select" || tag === "textarea") return;
event.stopImmediatePropagation();
(event.key === "ArrowLeft" ? $("e2eStructuresPrev") : $("e2eStructuresNext")).click();
}, true);
})();