"""Faithful design preview: renders the REAL style.css + render.py output across all UI states into a single static HTML file, so design iteration can be screenshot-verified without launching Gradio or a GPU. Dev tool only — not part of the shipped app. Usage: python scripts/design_preview.py -> writes design_preview_live.html """ from __future__ import annotations import json import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT)) import render # noqa: E402 from schema import HandoffOutput # noqa: E402 CSS = (ROOT / "style.css").read_text(encoding="utf-8") CACHE = ROOT / "data" / "example_cache" def load(name: str) -> HandoffOutput: return HandoffOutput.model_validate(json.loads((CACHE / f"{name}.json").read_text(encoding="utf-8"))) def sec(label: str) -> str: return f'
{label}
' def build() -> str: ahmed = load("ahmed") arabic = load("arabic") root_canal = load("root_canal") # Pick a flagged case to exercise the fired safety panel / interrupt path. flagged = next((c for c in (root_canal, ahmed, arabic) if c.red_flags), root_canal) blocks: list[str] = [ render.header_html(), render.footer_html(), sec("Step rail"), render.rail_html(), sec("Agent dashboard — initial (Ready)"), render.initial_agent_dashboard_html(), sec("Agent dashboard — live auditable run"), render.render_agent_dashboard( "Cached", "Complete", f"{len(flagged.red_flags)} flags found", "Passed", route_note="Cached case · model drafted narrative · sentinel ran between turns", ), sec("Safety panel — clear"), render.initial_safety_html(), sec("Safety panel — fired (rule-based)"), render.render_safety_html(flagged), sec("Handoff card — empty / ghost state"), render.placeholder_handoff_html(), sec("Handoff card — loading skeleton"), render.skeleton_handoff_html(), sec("Handoff card — English (Ahmed, model-authored narrative)"), render.render_handoff_html(ahmed, "English", model_authored=True), sec("Handoff card — Bilingual (English + Arabic)"), render.render_handoff_html(arabic, "Bilingual"), ] # Show the hard-interrupt card if any cached case triggers it. interrupt_case = next((c for c in (root_canal, ahmed, arabic) if render.is_hard_interrupt(c)), None) if interrupt_case is not None: blocks += [sec("Hard interrupt card"), render._interrupt_card(interrupt_case, "Bilingual")] fonts = ( '' '' '' ) shell = ( "body{max-width:1180px;margin:0 auto;padding:28px 20px;background:#F5F4F0;}" ".preview-sec{margin:34px 0 12px;font-family:'IBM Plex Mono',monospace;font-size:11px;" "letter-spacing:.14em;text-transform:uppercase;color:#8C887E;border-top:1px solid #E2DFD6;padding-top:14px;}" ) return ( f"{fonts}" f"" f"{''.join(blocks)}" ) if __name__ == "__main__": out = ROOT / "design_preview_live.html" out.write_text(build(), encoding="utf-8") print(f"wrote {out}")