"""Browse a recorded CUA dataset: stats, filters, and a step-through player. python scripts/view_cua.py artifacts/cua # writes artifacts/cua/index.html python -m http.server -d artifacts/cua 8097 # then open http://localhost:8097 The page reads `cua.jsonl` (inlined) and the dataset's own image files (by relative path), so what you step through is exactly what a trainer would load. """ from __future__ import annotations import json import sys from collections import Counter from pathlib import Path NAMES = {"figma": "Studio", "canva": "Template", "photoshop": "Pixel", "slides": "Deck", "powerpoint": "Present", "inkscape": "Vector"} def _calls(msg): out = [] for c in msg.get("tool_calls", []): args = json.loads(c["function"]["arguments"]) parts = [f"{k}={json.dumps(v, ensure_ascii=False)}" for k, v in args.items() if v is not None] out.append(f"{c['function']['name']}({', '.join(parts)})") return out def summarise(traj: dict) -> dict: msgs = traj["messages"] user_imgs = [c["image"] for c in msgs[1]["content"] if c["type"] == "image"] steps, frames = [], [user_imgs[-1]] i = 2 while i < len(msgs): a = msgs[i] n = len(a.get("tool_calls", [])) shot, extra = None, [] for r in msgs[i + 1:i + 1 + n]: if isinstance(r["content"], list): ims = [c["image"] for c in r["content"] if c["type"] == "image"] if ims: shot = ims[-1] extra += ims[:-1] steps.append({"t": a.get("content") or "", "c": _calls(a), "m": a.get("train") is False, "f": len(frames) if shot else None, "x": extra}) if shot: frames.append(shot) i += 1 + n sub = next((k for k, s in enumerate(steps) if any(w in s["t"] for w in ("Export", "export", "Submit", "submit"))), len(steps) - 1) done = next((s["f"] for s in reversed(steps[:sub]) if s["f"] is not None), len(frames) - 1) return {"meta": traj["meta"], "target": user_imgs[0] if traj["meta"]["mode"] == "reference" else None, "frames": frames, "steps": steps, "done": done} PAGE = """