/* FinLongDocQA viewer — vanilla JS, two tabs: Corpus (markdown reports) + Eval. */ (function () { "use strict"; var $ = function (id) { return document.getElementById(id); }; function esc(s) { if (s === null || s === undefined) return ""; return String(s) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } var state = { mode: "corpus", corpus: [], corpusView: [], corpusIdx: 0, byDocId: {}, mdCache: {}, // doc_id -> [{num, md}] curPages: [], curPageIdx: 0, pendingPage: null, // page number to jump to once the report loads loadSeq: 0, // guards against out-of-order async renders questions: [], evalView: [], evalIdx: 0, }; /* ---------------- data loading ---------------- */ function parseJSONL(text) { var out = []; text.split("\n").forEach(function (ln) { ln = ln.trim(); if (ln) { try { out.push(JSON.parse(ln)); } catch (e) {} } }); return out; } function loadAll() { return Promise.all([ fetch("corpus_index.json").then(function (r) { return r.json(); }), fetch("eval.json").then(function (r) { return r.json(); }), ]).then(function (res) { state.corpus = res[0] || []; state.questions = res[1] || []; state.corpus.forEach(function (d) { state.byDocId[d.doc_id] = d; }); }); } /* ---------------- corpus tab ---------------- */ function populateCorpusFilters() { var years = {}; state.corpus.forEach(function (d) { if (d.year) years[d.year] = true; }); var yf = $("yearFilter"); Object.keys(years).sort().forEach(function (y) { var o = document.createElement("option"); o.value = y; o.textContent = y; yf.appendChild(o); }); } function filterCorpus() { var q = $("corpusFilter").value.trim().toLowerCase(); var yr = $("yearFilter").value; var hasQ = $("hasQFilter").value; state.corpusView = state.corpus.filter(function (d) { if (yr && d.year !== yr) return false; if (hasQ === "q" && !d.n_questions) return false; if (hasQ === "noq" && d.n_questions) return false; if (q && (d.company || "").toLowerCase().indexOf(q) === -1) return false; return true; }); if (state.corpusIdx >= state.corpusView.length) state.corpusIdx = 0; rebuildDocSelect(); renderCorpus(); } function rebuildDocSelect() { var sel = $("docSelect"); sel.innerHTML = ""; state.corpusView.forEach(function (d, i) { var o = document.createElement("option"); o.value = String(i); o.textContent = d.title + (d.n_questions ? " · " + d.n_questions + "q" : ""); sel.appendChild(o); }); sel.value = String(state.corpusIdx); } function splitPages(md) { var lines = md.split("\n"); var re = /^#\s*Page\s+(\d+)\s*$/; var pages = [], cur = null; for (var i = 0; i < lines.length; i++) { var m = lines[i].match(re); if (m) { cur = { num: parseInt(m[1], 10), lines: [] }; pages.push(cur); } else if (cur) { cur.lines.push(lines[i]); } } if (!pages.length) pages = [{ num: 1, lines: lines }]; return pages.map(function (p) { return { num: p.num, md: p.lines.join("\n") }; }); } function renderCorpus() { var meta = $("docMetaCard"); var render = $("mdRender"); var nav = $("pageNav"); if (!state.corpusView.length) { meta.innerHTML = '
No reports match the filter.
'; render.innerHTML = ""; nav.style.display = "none"; $("corpusCounter").textContent = "0 / 0"; return; } var d = state.corpusView[state.corpusIdx]; $("docSelect").value = String(state.corpusIdx); $("corpusCounter").textContent = (state.corpusIdx + 1) + " / " + state.corpusView.length; var pills = 'Company: ' + esc(d.company) + "" + 'Fiscal year: ' + esc(d.year) + "" + 'Cited by ' + (d.n_questions || 0) + " question(s)"; var link = 'raw .md ↗'; meta.innerHTML = "

" + esc(d.title) + " — Annual Report

" + '
' + pills + link + "
"; var seq = ++state.loadSeq; nav.style.display = "none"; render.className = "md-render loading"; render.textContent = "Loading report…"; var cached = state.mdCache[d.doc_id]; var got = cached ? Promise.resolve(cached) : fetch(d.md_url).then(function (r) { if (!r.ok) throw new Error("HTTP " + r.status); return r.text(); }).then(function (t) { var p = splitPages(t); state.mdCache[d.doc_id] = p; return p; }); got.then(function (pages) { if (seq !== state.loadSeq) return; // a newer selection superseded us state.curPages = pages; var idx = 0; if (state.pendingPage != null) { for (var i = 0; i < pages.length; i++) { if (pages[i].num === state.pendingPage) { idx = i; break; } } state.pendingPage = null; } state.curPageIdx = idx; rebuildPageSelect(); nav.style.display = "flex"; renderPage(); }).catch(function (err) { if (seq !== state.loadSeq) return; render.className = "md-render"; render.innerHTML = '
Failed to load report: ' + esc(err.message) + '
open raw markdown ↗
'; }); } function rebuildPageSelect() { var sel = $("pageSelect"); sel.innerHTML = ""; state.curPages.forEach(function (p, i) { var o = document.createElement("option"); o.value = String(i); o.textContent = "Page " + p.num; sel.appendChild(o); }); } function renderPage() { var render = $("mdRender"); var p = state.curPages[state.curPageIdx]; render.className = "md-render"; render.innerHTML = window.marked ? window.marked.parse(p.md) : esc(p.md); render.scrollTop = 0; $("pageCounter").textContent = "Page " + p.num + " (" + (state.curPageIdx + 1) + " / " + state.curPages.length + ")"; $("pageSelect").value = String(state.curPageIdx); $("pagePrevBtn").disabled = state.curPageIdx <= 0; $("pageNextBtn").disabled = state.curPageIdx >= state.curPages.length - 1; } function selectDocById(docId, pageNum) { $("corpusFilter").value = ""; $("yearFilter").value = ""; $("hasQFilter").value = ""; state.corpusView = state.corpus.slice(); var idx = 0; for (var i = 0; i < state.corpusView.length; i++) { if (state.corpusView[i].doc_id === docId) { idx = i; break; } } state.corpusIdx = idx; state.pendingPage = (pageNum != null) ? pageNum : null; rebuildDocSelect(); renderCorpus(); } /* ---------------- eval tab ---------------- */ function filterEval() { var q = $("evalSearch").value.trim().toLowerCase(); var typ = $("typeFilter").value; state.evalView = state.questions.filter(function (x) { if (typ && x.type !== typ) return false; if (q) { var hay = [x.question, x.company, x.id, x.title].join(" ").toLowerCase(); if (hay.indexOf(q) === -1) return false; } return true; }); if (state.evalIdx >= state.evalView.length) state.evalIdx = 0; rebuildQSelect(); renderEval(); } function rebuildQSelect() { var sel = $("qSelect"); sel.innerHTML = ""; state.evalView.forEach(function (x, i) { var o = document.createElement("option"); o.value = String(i); var q = (x.question || "").replace(/\s+/g, " "); if (q.length > 62) q = q.slice(0, 62) + "…"; o.textContent = "[" + x.title + "] " + q; sel.appendChild(o); }); sel.value = String(state.evalIdx); } function field(lbl, valHtml) { return '
' + esc(lbl) + '
' + valHtml + "
"; } function renderEval() { var card = $("evalCard"); if (!state.evalView.length) { card.innerHTML = '
No questions match the search.
'; $("evalCounter").textContent = "0 / 0"; return; } var x = state.evalView[state.evalIdx]; $("qSelect").value = String(state.evalIdx); $("evalCounter").textContent = (state.evalIdx + 1) + " / " + state.evalView.length; var badges = '#' + esc(x.id) + "" + '' + esc(x.type) + "" + '' + esc(x.title) + " ↗"; var pages = x.page_numbers || []; var pagesHtml = pages.length ? '
' + pages.map(function (n) { return '📄 Page ' + esc(n) + ""; }).join("") + "
" : 'none'; var ansHtml = (x.answer === null || x.answer === undefined) ? "—" : esc(x.answer); card.innerHTML = '
' + badges + "
" + "

" + esc(x.question) + "

" + '
Ground-truth answer
' + ansHtml + "
" + field("Evidence pages", pagesHtml) + field("Reasoning trace (thoughts)", '
' + esc(x.thoughts || "—") + "
") + field("Python code", '
' + esc(x.python_code || "—") + "
"); // company badge -> open report Array.prototype.forEach.call(card.querySelectorAll(".badge.company[data-doc-id]"), function (el) { el.addEventListener("click", function () { setMode("corpus"); selectDocById(this.getAttribute("data-doc-id")); }); }); // evidence page chip -> open report at that page Array.prototype.forEach.call(card.querySelectorAll(".page-chip[data-doc-id]"), function (el) { el.addEventListener("click", function () { setMode("corpus"); selectDocById(this.getAttribute("data-doc-id"), parseInt(this.getAttribute("data-page"), 10)); }); }); } /* ---------------- mode switching ---------------- */ function setMode(mode) { state.mode = mode; $("modeCorpusBtn").classList.toggle("active", mode === "corpus"); $("modeEvalBtn").classList.toggle("active", mode === "eval"); $("corpusControls").style.display = mode === "corpus" ? "" : "none"; $("evalControls").style.display = mode === "eval" ? "" : "none"; $("corpusView").style.display = mode === "corpus" ? "flex" : "none"; $("evalView").style.display = mode === "eval" ? "block" : "none"; } /* ---------------- wiring ---------------- */ function wire() { $("modeCorpusBtn").addEventListener("click", function () { setMode("corpus"); }); $("modeEvalBtn").addEventListener("click", function () { setMode("eval"); }); // corpus $("corpusFilter").addEventListener("input", filterCorpus); $("yearFilter").addEventListener("change", filterCorpus); $("hasQFilter").addEventListener("change", filterCorpus); $("docSelect").addEventListener("change", function () { state.corpusIdx = parseInt(this.value, 10) || 0; renderCorpus(); }); $("corpusPrevBtn").addEventListener("click", function () { if (state.corpusIdx > 0) { state.corpusIdx--; renderCorpus(); } }); $("corpusNextBtn").addEventListener("click", function () { if (state.corpusIdx < state.corpusView.length - 1) { state.corpusIdx++; renderCorpus(); } }); // page nav $("pagePrevBtn").addEventListener("click", function () { if (state.curPageIdx > 0) { state.curPageIdx--; renderPage(); } }); $("pageNextBtn").addEventListener("click", function () { if (state.curPageIdx < state.curPages.length - 1) { state.curPageIdx++; renderPage(); } }); $("pageSelect").addEventListener("change", function () { state.curPageIdx = parseInt(this.value, 10) || 0; renderPage(); }); // eval $("evalSearchBtn").addEventListener("click", filterEval); $("evalSearch").addEventListener("keydown", function (e) { if (e.key === "Enter") filterEval(); }); $("evalClearBtn").addEventListener("click", function () { $("evalSearch").value = ""; $("typeFilter").value = ""; filterEval(); }); $("typeFilter").addEventListener("change", filterEval); $("qSelect").addEventListener("change", function () { state.evalIdx = parseInt(this.value, 10) || 0; renderEval(); }); $("evalPrevBtn").addEventListener("click", function () { if (state.evalIdx > 0) { state.evalIdx--; renderEval(); } }); $("evalNextBtn").addEventListener("click", function () { if (state.evalIdx < state.evalView.length - 1) { state.evalIdx++; renderEval(); } }); // keyboard arrows (report nav in corpus, question nav in eval) document.addEventListener("keydown", function (e) { var tag = (e.target.tagName || "").toLowerCase(); if (tag === "input" || tag === "select" || tag === "textarea") return; if (e.key === "ArrowLeft") { if (state.mode === "corpus") $("corpusPrevBtn").click(); else $("evalPrevBtn").click(); } else if (e.key === "ArrowRight") { if (state.mode === "corpus") $("corpusNextBtn").click(); else $("evalNextBtn").click(); } }); } /* ---------------- boot ---------------- */ loadAll().then(function () { $("loading").style.display = "none"; $("sidebarFooter").innerHTML = state.corpus.length + " reports · " + state.questions.length + " questions
" + 'GitHub · ' + 'HF dataset · ' + 'arXiv'; populateCorpusFilters(); wire(); setMode("corpus"); filterCorpus(); filterEval(); }).catch(function (err) { $("loading").textContent = "Failed to load data: " + err; }); })();