hkblockchaintechnology commited on
Commit
8e4f215
·
verified ·
1 Parent(s): ca62217

Publish showcase.py from marimo

Browse files
Files changed (1) hide show
  1. showcase.py +173 -0
showcase.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Build the capability gallery: one screenshot per thing the harness can do.
2
+
3
+ python showcase.py # every capability
4
+ python showcase.py --list # list the ids without rendering
5
+ python showcase.py --only decisions # render a subset by id substring
6
+
7
+ The shared state - the catalogue, the renderers, the display - lives in
8
+ :mod:`showcase_core`, and the capabilities themselves in :mod:`showcase_catalog`,
9
+ so importing this file never makes a second copy of either.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ import sys
16
+
17
+ import showcase_catalog # noqa: F401 (importing it registers every shot)
18
+ from showcase_core import (
19
+ CATALOG, GALLERY, ROOT, ensure_display, render_desktop, render_terminal, save,
20
+ )
21
+
22
+
23
+ def main(argv: list[str] | None = None) -> int:
24
+ args = list(argv if argv is not None else sys.argv[1:])
25
+ only = args[args.index("--only") + 1] if "--only" in args else None
26
+ if "--card" in args:
27
+ print("card section written:", write_card(_read_index()).name)
28
+ return 0
29
+ display = ensure_display()
30
+ picked = [s for s in CATALOG if not only or only.lower() in s.id.lower()]
31
+ print(f"display: {display} | {len(picked)}/{len(CATALOG)} capabilities")
32
+ if "--list" in args:
33
+ for s in picked:
34
+ print(f" {s.id:36} {s.kind:8} {s.category}: {s.title}")
35
+ return 0
36
+
37
+ GALLERY.mkdir(exist_ok=True)
38
+ if "--reindex" in args or only:
39
+ # an index built from the catalogue, not from what this run happened to draw
40
+ _write_index()
41
+ if "--reindex" in args:
42
+ print(f"reindexed {len(_read_index())} pictures in {GALLERY}")
43
+ return 0
44
+ tmp = ROOT / ".showcase-tmp"
45
+ tmp.mkdir(exist_ok=True)
46
+ made = []
47
+ for s in picked:
48
+ try:
49
+ image = render_desktop(s, tmp) if s.kind == "desktop" else render_terminal(s, tmp)
50
+ path = save(image, s.id)
51
+ made.append(s)
52
+ print(f" ok {s.id:34} {path.name:34} {image.size[0]}x{image.size[1]}")
53
+ except Exception as exc:
54
+ print(f" FAIL {s.id:34} {type(exc).__name__}: {exc}")
55
+
56
+ _write_index()
57
+ print(f"wrote {len(made)} images to {GALLERY}")
58
+ return 0
59
+
60
+
61
+ def _entry(s):
62
+ return {"id": s.id, "category": s.category, "title": s.title, "shows": s.shows,
63
+ "note": s.note, "kind": s.kind}
64
+
65
+
66
+ def _write_index():
67
+ """Index every capability whose picture exists, in catalogue order."""
68
+ entries = [_entry(s) for s in CATALOG if (GALLERY / f"{s.id}.png").exists()]
69
+ (GALLERY / "index.json").write_text(json.dumps(entries, indent=2))
70
+ return entries
71
+
72
+
73
+ def _read_index():
74
+ return json.loads((GALLERY / "index.json").read_text())
75
+
76
+
77
+ def api_surface() -> tuple[list[str], list[str]]:
78
+ """(callables, constants) - the public surface a picture has to cover.
79
+
80
+ Introspected rather than hard-coded, so the gallery's promise is checked
81
+ against the package instead of against a list someone forgot to update.
82
+ """
83
+ import importlib
84
+ import inspect
85
+
86
+ names, constants = [], []
87
+ modules = ["actions", "act", "observe", "perception", "brain", "models", "loop",
88
+ "safety", "desktop", "demo", "trace", "__main__"]
89
+ for module_name in modules:
90
+ module = importlib.import_module(f"tiny_computer_agent.{module_name}")
91
+ for name, obj in vars(module).items():
92
+ if name.startswith("_"):
93
+ continue
94
+ if inspect.isfunction(obj) or inspect.isclass(obj):
95
+ if getattr(obj, "__module__", "") != module.__name__:
96
+ continue # imported, not defined here
97
+ names.append(name)
98
+ if inspect.isclass(obj):
99
+ for member, value in vars(obj).items():
100
+ if member.startswith("_"):
101
+ continue
102
+ if inspect.isfunction(value) or isinstance(value, property):
103
+ names.append(f"{name}.{member}")
104
+ elif name.isupper() and isinstance(obj, (str, int, float, tuple, frozenset)):
105
+ constants.append(name)
106
+ return names, constants
107
+
108
+
109
+ def write_card(entries: list[dict]) -> Path:
110
+ """Write the gallery page, and the section the model card embeds.
111
+
112
+ Every entry carries the callables it demonstrates, so the card can promise -
113
+ and a reader can check - that no part of the public API is left without a
114
+ picture.
115
+ """
116
+ areas: dict[str, list[dict]] = {}
117
+ for entry in entries:
118
+ areas.setdefault(entry["category"], []).append(entry)
119
+ pictured = sorted({name for entry in entries for name in entry["shows"]})
120
+ callables, constants = api_surface()
121
+ missing = sorted(set(callables) - set(pictured))
122
+ if missing:
123
+ print(f" WARNING: {len(missing)} public callables are not pictured: {missing}")
124
+
125
+ lines = [
126
+ "## Capability gallery",
127
+ "",
128
+ f"**{len(entries)} capabilities, one screenshot each - and every one of the "
129
+ f"{len(callables)} public callables in the package (functions, methods, classes and "
130
+ f"protocols) appears in at least one of them**, together with "
131
+ f"{len(set(constants) & set(pictured))} of its public constants.",
132
+ "",
133
+ "Nothing here is a mock-up. Each picture is produced by "
134
+ "[`showcase.py`](showcase.py): a command or a call is run for real, and its actual "
135
+ "output - or the real desktop it acted on - is what you see. The desktop shots are "
136
+ "real screen captures on a real X server (Xvfb, 1280x800), including a real mouse "
137
+ "click verified by the target application's own reaction.",
138
+ "",
139
+ "> **An honest note on the platform.** These were captured on Linux, because the "
140
+ "sandbox that builds this card has no Windows: no KVM, no QEMU and no Windows image. "
141
+ "The harness is OS-agnostic (pyautogui uses `SendInput` on Windows, and `GrabScreen` "
142
+ "falls back to Pillow's `ImageGrab`), so these are the same code paths - but they are "
143
+ "not Windows pixels. The Windows twins are generated by the same script in "
144
+ "[`.github/workflows/live-desktop.yml`](.github/workflows/live-desktop.yml).",
145
+ "",
146
+ "Regenerate it with `python showcase.py` (`--list` to see the ids, `--only <id>` for a "
147
+ "subset, `--card` to rewrite this section). It runs the calls for real, so a broken "
148
+ "capability fails loudly instead of shipping a stale picture.",
149
+ "",
150
+ "| area | capabilities |",
151
+ "|---|---:|",
152
+ ]
153
+ lines += [f"| {area} | {len(items)} |" for area, items in areas.items()]
154
+ lines += ["", "---", ""]
155
+
156
+ for area, items in areas.items():
157
+ lines += [f"### {area}", ""]
158
+ for entry in items:
159
+ lines += [f"**{entry['title']}**", ""]
160
+ if entry["note"]:
161
+ lines += [f"*{entry['note']}*", ""]
162
+ lines += [f'<img src="gallery/{entry["id"]}.png" width="860">', ""]
163
+ lines += ["`shows:` " + ", ".join(f"`{name}`" for name in entry["shows"]), ""]
164
+
165
+ text = "\n".join(lines)
166
+ (GALLERY / "_card_section.md").write_text(text)
167
+ (GALLERY / "README.md").write_text(
168
+ "---\ntitle: Capability gallery\n---\n\n" + text + "\n")
169
+ return GALLERY / "_card_section.md"
170
+
171
+
172
+ if __name__ == "__main__":
173
+ raise SystemExit(main())