Download app/frontend/src/components/Ledger.tsx from ml-intern-explorers/primarydraft: direct link, hf CLI and curl.
- Browser
- Download file 9.76 kB
-
https://huggingface.co/spaces/ml-intern-explorers/primarydraft/resolve/main/app/frontend/src/components/Ledger.tsx
- Command line
-
hf download hf://spaces/ml-intern-explorers/primarydraft/app/frontend/src/components/Ledger.tsx
-
curl -L -o Ledger.tsx https://huggingface.co/spaces/ml-intern-explorers/primarydraft/resolve/main/app/frontend/src/components/Ledger.tsx
9.76 kB
| import { useEffect, useRef, useState } from "react"; | |
| import { Stack, ArrowRight, X } from "@phosphor-icons/react"; | |
| import { api, factValue, type Fact, type RunSummary } from "../lib/api"; | |
| import { Empty, Note, ProvenanceList, Spinner, StatusChip } from "./common"; | |
| const FILTERS = [ | |
| { k: "", label: "all" }, | |
| { k: "verified", label: "verified" }, | |
| { k: "derived", label: "derived" }, | |
| { k: "unverified", label: "unverified" }, | |
| { k: "conflicted", label: "conflicted" }, | |
| { k: "attested", label: "attested" }, | |
| { k: "resolved", label: "resolved" }, | |
| ] as const; | |
| export function Ledger({ run, onNext }: { run: RunSummary; onNext: () => void }) { | |
| const [facts, setFacts] = useState<Fact[]>([]); | |
| const [total, setTotal] = useState(run.fact_count); | |
| const [streaming, setStreaming] = useState(true); | |
| const [filter, setFilter] = useState<string>(""); | |
| const [open, setOpen] = useState<Fact | null>(null); | |
| const seen = useRef(new Set<string>()); | |
| useEffect(() => { | |
| // Stream the ledger so the reviewer watches it being assembled from the filing. | |
| const es = new EventSource(`/api/runs/${run.id}/ledger/stream?delay_ms=14`); | |
| es.addEventListener("start", (e) => setTotal(JSON.parse((e as MessageEvent).data).total)); | |
| es.addEventListener("fact", (e) => { | |
| const { fact } = JSON.parse((e as MessageEvent).data); | |
| if (seen.current.has(fact.id)) return; | |
| seen.current.add(fact.id); | |
| setFacts((prev) => [...prev, fact]); | |
| }); | |
| es.addEventListener("done", () => { setStreaming(false); es.close(); }); | |
| es.onerror = () => { setStreaming(false); es.close(); }; | |
| return () => es.close(); | |
| }, [run.id]); | |
| const shown = filter ? facts.filter((f) => f.status === filter) : facts; | |
| const counts = facts.reduce<Record<string, number>>((a, f) => { | |
| a[f.status] = (a[f.status] ?? 0) + 1; | |
| return a; | |
| }, {}); | |
| return ( | |
| <> | |
| <div className="page-head"> | |
| <h1 className="page">Disclosure ledger</h1> | |
| <p className="lede"> | |
| Each row is one atomic disclosure value read from the issuer's own filing, bound to the | |
| page it came from. Status is earned, never assumed: a figure is verified only when two | |
| independent sections agree or an accounting identity supports it. Everything else | |
| abstains and says what to confirm. | |
| </p> | |
| </div> | |
| <div className="stats" style={{ marginBottom: 14 }}> | |
| <div className="stat"> | |
| <div className="stat-v">{facts.length}</div> | |
| <div className="stat-l">facts extracted{streaming ? " so far" : ""}</div> | |
| </div> | |
| <div className="stat"> | |
| <div className="stat-v ok">{counts.verified ?? 0}</div> | |
| <div className="stat-l">verified by corroboration or identity</div> | |
| </div> | |
| <div className="stat"> | |
| <div className="stat-v">{counts.derived ?? 0}</div> | |
| <div className="stat-l">derived, with lineage recorded</div> | |
| </div> | |
| <div className="stat"> | |
| <div className="stat-v warn">{counts.unverified ?? 0}</div> | |
| <div className="stat-l">abstained, awaiting confirmation</div> | |
| </div> | |
| <div className="stat"> | |
| <div className="stat-v stop">{counts.conflicted ?? 0}</div> | |
| <div className="stat-l">sources disagree</div> | |
| </div> | |
| </div> | |
| {streaming && ( | |
| <div className="bar" style={{ marginBottom: 14 }}> | |
| <i style={{ width: `${total ? (facts.length / total) * 100 : 0}%` }} /> | |
| </div> | |
| )} | |
| <section className="panel"> | |
| <div className="panel-h"> | |
| <Stack size={16} /> | |
| <h2>Facts</h2> | |
| <span className="count">{shown.length} shown</span> | |
| <div className="filters" style={{ marginLeft: "auto" }}> | |
| {FILTERS.map((f) => ( | |
| <button | |
| key={f.k} | |
| className="filter" | |
| aria-pressed={filter === f.k} | |
| onClick={() => setFilter(f.k)} | |
| > | |
| {f.label} | |
| {f.k && counts[f.k] ? ` ${counts[f.k]}` : ""} | |
| </button> | |
| ))} | |
| </div> | |
| </div> | |
| <div style={{ maxHeight: "58vh", overflowY: "auto" }}> | |
| {shown.length === 0 && !streaming ? ( | |
| <Empty title={filter ? `No ${filter} facts` : "The ledger is empty"}> | |
| {filter | |
| ? "No figure in this filing earned that status." | |
| : "No disclosure value could be read from the source records."} | |
| </Empty> | |
| ) : ( | |
| <table className="tbl"> | |
| <thead> | |
| <tr> | |
| <th style={{ width: "34%" }}>Disclosure</th> | |
| <th className="r" style={{ width: "16%" }}>Value</th> | |
| <th style={{ width: "12%" }}>Status</th> | |
| <th>Source</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| {shown.map((f, i) => ( | |
| <tr | |
| key={f.id} | |
| className={i >= shown.length - 3 && streaming ? "arrived" : ""} | |
| onClick={() => setOpen(f)} | |
| style={{ cursor: "pointer" }} | |
| > | |
| <td> | |
| <div className="f-label">{f.label}</div> | |
| <div className="f-id">{f.id}</div> | |
| {f.note && <div className="f-note">{f.note}</div>} | |
| </td> | |
| <td className="r num" style={{ fontWeight: 500 }}>{factValue(f)}</td> | |
| <td><StatusChip status={f.status} /></td> | |
| <td> | |
| <div className="f-src">{f.provenance[0]?.locator ?? "n/a"}</div> | |
| {f.provenance.length > 1 && ( | |
| <div className="tag tag-ok" style={{ marginTop: 3, display: "inline-block" }}> | |
| {f.provenance.length} sources agree | |
| </div> | |
| )} | |
| {f.identities.length > 0 && ( | |
| <div className="f-id" style={{ marginTop: 3 }}>{f.identities[0]}</div> | |
| )} | |
| </td> | |
| </tr> | |
| ))} | |
| </tbody> | |
| </table> | |
| )} | |
| </div> | |
| </section> | |
| <div style={{ display: "flex", gap: 10, marginTop: 16, alignItems: "center" }}> | |
| <button className="btn btn-primary" onClick={onNext} disabled={streaming}> | |
| {streaming ? <><Spinner /> Reading filing</> : <>Draft the offer document <ArrowRight size={15} /></>} | |
| </button> | |
| {!streaming && (counts.unverified ?? 0) > 0 && ( | |
| <span style={{ fontSize: 12.5, color: "var(--text-2)" }}> | |
| {counts.unverified} figures abstained. The engine will list each one for attestation. | |
| </span> | |
| )} | |
| </div> | |
| {open && <FactDrawer fact={open} onClose={() => setOpen(null)} />} | |
| </> | |
| ); | |
| } | |
| function FactDrawer({ fact, onClose }: { fact: Fact; onClose: () => void }) { | |
| useEffect(() => { | |
| const onKey = (e: KeyboardEvent) => e.key === "Escape" && onClose(); | |
| window.addEventListener("keydown", onKey); | |
| return () => window.removeEventListener("keydown", onKey); | |
| }, [onClose]); | |
| return ( | |
| <div | |
| style={{ | |
| position: "fixed", inset: 0, background: "rgba(11,27,43,0.4)", | |
| zIndex: 50, display: "grid", placeItems: "center", padding: 20, | |
| }} | |
| onClick={onClose} | |
| > | |
| <div | |
| className="panel" | |
| style={{ maxWidth: 620, width: "100%", maxHeight: "82vh", overflowY: "auto" }} | |
| onClick={(e) => e.stopPropagation()} | |
| role="dialog" | |
| aria-label={fact.label} | |
| > | |
| <div className="panel-h"> | |
| <h2>{fact.label}</h2> | |
| <button className="btn btn-ghost btn-sm" style={{ marginLeft: "auto" }} onClick={onClose}> | |
| <X size={13} /> Close | |
| </button> | |
| </div> | |
| <div className="panel-b" style={{ display: "grid", gap: 14 }}> | |
| <div style={{ display: "flex", gap: 12, alignItems: "baseline" }}> | |
| <span className="num" style={{ fontSize: 22, fontWeight: 600 }}>{factValue(fact)}</span> | |
| <StatusChip status={fact.status} /> | |
| <span className="f-id">{fact.id}</span> | |
| </div> | |
| {fact.note && <Note tone="warn">{fact.note}</Note>} | |
| {fact.identities.length > 0 && ( | |
| <div> | |
| <div className="f-src" style={{ marginBottom: 5 }}>Supported by</div> | |
| {fact.identities.map((i) => ( | |
| <div key={i} className="mono" style={{ fontSize: 11.5, color: "var(--ok)" }}>{i}</div> | |
| ))} | |
| </div> | |
| )} | |
| {fact.derived_from.length > 0 && ( | |
| <div> | |
| <div className="f-src" style={{ marginBottom: 5 }}>Derived from</div> | |
| {fact.derived_from.map((d) => ( | |
| <div key={d} className="f-id">{d}</div> | |
| ))} | |
| </div> | |
| )} | |
| <div> | |
| <div className="f-src" style={{ marginBottom: 6 }}> | |
| Provenance ({fact.provenance.length}) | |
| </div> | |
| <ProvenanceList provenance={fact.provenance} /> | |
| </div> | |
| {fact.section_refs.length > 0 && ( | |
| <div> | |
| <div className="f-src" style={{ marginBottom: 5 }}>Used in sections</div> | |
| <div style={{ display: "flex", gap: 5, flexWrap: "wrap" }}> | |
| {fact.section_refs.map((s) => ( | |
| <span key={s} className="tag">{s.replace(/_/g, " ")}</span> | |
| ))} | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |