/ scripts / render_agentic_demo.py
render_agentic_demo.py
 1  #!/usr/bin/env python3
 2  # -*- coding: utf-8 -*-
 3  """Render examples/agentic_demo.html to docs/figs/agentic-demo.png.
 4  
 5  Uses Playwright's headless Chromium to capture a single full-page
 6  screenshot at viewport width 1200px (matching the demo's 1180px max
 7  container width), with the top CAPTURE toolbar hidden via the
 8  ``body.capture`` CSS class.
 9  
10  Re-run this any time ``examples/agentic_demo.html`` changes so the
11  figure at ``docs/figs/agentic-demo.png`` (rendered on readthedocs via
12  ``docs/examples/agentic.rst``) stays in sync with the HTML source.
13  
14  Prerequisites (one-time):
15  
16  .. code-block:: bash
17  
18      pip install playwright
19      playwright install chromium
20  
21  Usage:
22  
23  .. code-block:: bash
24  
25      python scripts/render_agentic_demo.py
26  """
27  from __future__ import annotations
28  
29  import sys
30  from pathlib import Path
31  
32  REPO = Path(__file__).resolve().parents[1]
33  HTML = REPO / "examples" / "agentic_demo.html"
34  PNG = REPO / "docs" / "figs" / "agentic-demo.png"
35  
36  
37  def main() -> int:
38      try:
39          from playwright.sync_api import sync_playwright
40      except ImportError:
41          print(
42              "playwright is not installed. Run:\n"
43              "    pip install playwright\n"
44              "    playwright install chromium",
45              file=sys.stderr,
46          )
47          return 1
48  
49      if not HTML.is_file():
50          print(f"ERROR: {HTML} not found", file=sys.stderr)
51          return 1
52  
53      PNG.parent.mkdir(parents=True, exist_ok=True)
54  
55      with sync_playwright() as pw:
56          browser = pw.chromium.launch()
57          context = browser.new_context(
58              viewport={"width": 1200, "height": 900},
59              device_scale_factor=2,  # retina-sharp for docs
60          )
61          page = context.new_page()
62          page.goto(HTML.as_uri())
63          # Hide the top CAPTURE toolbar so it does not appear in the PNG.
64          # The HTML wires this up via the `body.capture` class selector.
65          page.evaluate("document.body.classList.add('capture')")
66          # Wait for layout and web fonts to settle before capturing.
67          page.wait_for_load_state("networkidle")
68          # `full_page=True` captures the entire scroll height as a single
69          # PNG, so there is no need to stitch multiple screenshots.
70          page.screenshot(path=str(PNG), full_page=True)
71          browser.close()
72  
73      size_kb = PNG.stat().st_size / 1024
74      print(f"Wrote {PNG.relative_to(REPO)} ({size_kb:.0f} KB)")
75      return 0
76  
77  
78  if __name__ == "__main__":
79      sys.exit(main())