| """Public demo (read-only) entry for HF Spaces — Reconciliation Workbench. |
| |
| This is the PUBLIC demo build. It ships ONLY the frontend, two pre-computed sample |
| payloads and the demo video. The deterministic reconciliation engine and the LLM |
| extraction pipeline are deliberately NOT included; live PDF upload and on-the-fly |
| recompute are disabled (see the demo video). The two bundled samples render fully |
| from cached results, so the PDF ↔ live-sheet ↔ finding linkage all works. |
| """ |
| from __future__ import annotations |
|
|
| import json |
| from pathlib import Path |
| from urllib.parse import quote |
|
|
| import gradio as gr |
|
|
| from wbdemo import enrich |
|
|
| _HERE = Path(__file__).resolve().parent |
| _WB = _HERE / "wbdemo" |
| _ASSETS = _WB / "assets" |
| _PDFJS = "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174" |
|
|
| |
| _HEAD = f""" |
| <script src="{_PDFJS}/pdf.min.js"></script> |
| <script> |
| window.__pdfReady = new Promise(function (res) {{ |
| (function t() {{ |
| if (window.pdfjsLib) {{ |
| window.pdfjsLib.GlobalWorkerOptions.workerSrc = "{_PDFJS}/pdf.worker.min.js"; |
| res(window.pdfjsLib); |
| }} else {{ setTimeout(t, 30); }} |
| }})(); |
| }}); |
| </script> |
| """ |
|
|
| _SAMPLES = { |
| "sanmu": { |
| "title": "Sanmu Group 2024 Annual Report (Consolidated)", |
| "payload": "sanmu.json", "pdf": "sanmu.pdf", |
| }, |
| "prospectus": { |
| "title": "A Prospectus (Consolidated)", |
| "payload": "prospectus.json", "pdf": None, |
| }, |
| } |
| _DEFAULT = "sanmu" |
|
|
|
|
| def _read(name: str) -> str: |
| return (_ASSETS / name).read_text(encoding="utf-8") |
|
|
|
|
| def _file_url(abspath: str | None) -> str | None: |
| if not abspath: |
| return None |
| return "/gradio_api/file=" + quote(abspath, safe="/:") |
|
|
|
|
| def _load_payload(fn: str) -> dict: |
| p = json.loads((_WB / "payloads" / fn).read_text(encoding="utf-8")) |
| return enrich.attach_review_cells(p) |
|
|
|
|
| def _focus_table_id(payload: dict) -> str | None: |
| for t in payload.get("tables", []): |
| if t.get("kind") == "BS": |
| return t.get("table_id") |
| return None |
|
|
|
|
| def _initial_value() -> dict: |
| samples: dict = {} |
| for k, s in _SAMPLES.items(): |
| payload = _load_payload(s["payload"]) |
| pdf_abs = str(_WB / s["pdf"]) if s["pdf"] else None |
| samples[k] = { |
| "sample_key": k, "title": s["title"], "payload": payload, |
| "pdf_url": _file_url(pdf_abs), "focus_table_id": _focus_table_id(payload), |
| } |
| return {"samples": samples, "default": _DEFAULT} |
|
|
|
|
| |
| _DISABLED = { |
| "ok": False, |
| "error": ("This public demo is read-only. Live PDF upload, human correction + recompute, " |
| "and Excel export run the deterministic engine, which isn't shipped in this public " |
| "demo — watch the demo video for them. Full interactive version available on request."), |
| } |
|
|
|
|
| def submit_override(req: dict) -> dict: |
| return dict(_DISABLED) |
|
|
|
|
| def process_pdf(req: dict) -> dict: |
| return dict(_DISABLED) |
|
|
|
|
| def export_xlsx(req: dict) -> dict: |
| return dict(_DISABLED) |
|
|
|
|
| def build_demo() -> gr.Blocks: |
| pdf_files = [str(_WB / s["pdf"]) for s in _SAMPLES.values() if s["pdf"]] |
| if pdf_files: |
| gr.set_static_paths(paths=pdf_files) |
| init = _initial_value() |
| with gr.Blocks(title="Reconciliation Workbench") as demo: |
| gr.HTML( |
| value=init, |
| html_template=_read("island.html"), |
| css_template=_read("island.css"), |
| js_on_load=_read("island.js"), |
| head=_HEAD, |
| apply_default_css=False, |
| min_height=640, |
| server_functions=[submit_override, process_pdf, export_xlsx], |
| ) |
| return demo |
|
|
|
|
| demo = build_demo() |
|
|
| if __name__ == "__main__": |
| |
| |
| demo.launch() |
|
|