| """Phase 0 (SPEC §12) — prove mapping quality before any art or UI. |
| |
| Runs Agent 1 (the Deck Designer) against the open ≤32B model for several varied |
| themes and prints each deck as a readable archetype→concept table plus the full |
| JSON. Inspect by hand: do the mappings read as clever-but-right across all |
| themes? If not, fix the prompt/few-shots before building anything else. |
| |
| Usage: |
| set -a; source ~/tokens; set +a |
| python -m scripts.phase0_mapping # default 5 themes |
| python -m scripts.phase0_mapping "free jazz" "tax law" |
| """ |
| from __future__ import annotations |
|
|
| import json |
| import os |
| import sys |
| import time |
|
|
| from arcana.archetypes import MAJOR_ARCANA |
| from arcana.designer import DeckError, design_deck |
| from arcana.llm import get_llm |
|
|
| DEFAULT_THEMES = [ |
| "thermodynamics", |
| "Lord of the Rings", |
| "the French Revolution", |
| "breakfast foods", |
| "professional wrestling", |
| ] |
|
|
| OUT_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), |
| "phase0_out") |
|
|
|
|
| def print_table(deck: dict) -> None: |
| print(f"\n style: {deck['style_suffix']}") |
| for a in MAJOR_ARCANA: |
| c = deck["cards"][a.number] |
| print(f" {a.roman:<5} {a.name:<18} → {c['concept']}") |
| print(f" ↳ {c['justification']}") |
|
|
|
|
| def main(themes: list[str]) -> int: |
| os.makedirs(OUT_DIR, exist_ok=True) |
| llm = get_llm() |
| print(f"Model: {getattr(llm, 'model', '?')} via {getattr(llm, 'base_url', '?')}") |
|
|
| failures = 0 |
| for theme in themes: |
| print("\n" + "=" * 72) |
| print(f"THEME: {theme}") |
| print("=" * 72) |
| t0 = time.time() |
| try: |
| deck = design_deck(theme, llm=llm) |
| except DeckError as e: |
| failures += 1 |
| print(f" ✗ FAILED: {e} ({time.time() - t0:.1f}s)") |
| continue |
| dt = time.time() - t0 |
| print_table(deck) |
| slug = "".join(ch if ch.isalnum() else "_" for ch in theme.lower())[:40] |
| path = os.path.join(OUT_DIR, f"{slug}.json") |
| with open(path, "w") as f: |
| json.dump(deck, f, indent=2, ensure_ascii=False) |
| print(f"\n ✓ 22 cards in {dt:.1f}s → {path}") |
|
|
| print("\n" + "=" * 72) |
| print(f"DONE — {len(themes) - failures}/{len(themes)} decks generated.") |
| print("Inspect the tables above: do the mappings feel clever-but-right?") |
| return 1 if failures else 0 |
|
|
|
|
| if __name__ == "__main__": |
| args = sys.argv[1:] or DEFAULT_THEMES |
| raise SystemExit(main(args)) |
|
|