magicciv/tools/sprite-generation/grok_poc.py
Natalie 7eb2897854 feat(@projects/@magic-civilization): 🎨 Grok sprite-generation pipeline + starter orchestration
Adds a Grok image backend (grok_generator.py) behind a generator factory, a
starter-set orchestrator (starter.py, orchestrate_starter.py, starter_manifest.json)
and a Grok PoC harness with proof renders. Updates the ranker/processor/composition
prompts and sprite-config; refreshes the sprite-gallery design preview.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 17:57:01 -05:00

121 lines
No EOL
4.2 KiB
Python

#!/usr/bin/env python3
"""One-shot Grok Build proof — additive to model-boss, not a replacement.
Uses grok-build-batch-sdk (grok CLI + GenerateImage), same auth pattern as
claude-code-batch-sdk for scoring.
Usage:
python3 grok_poc.py --sprite units/spearmen_dwarves_m
python3 grok_poc.py --prompt "game sprite dwarf warrior, top-down view"
"""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
TOOL_DIR = Path(__file__).resolve().parent
sys.path.insert(0, str(TOOL_DIR))
CONFIG_PATH = TOOL_DIR / "sprite-config.json"
DB_PATH = TOOL_DIR / "spritegen.db"
RAW_DIR = TOOL_DIR / "raw"
EXPERIMENTS = TOOL_DIR / "experiments"
def main() -> None:
parser = argparse.ArgumentParser(description="Generate one Grok Build sprite proof")
parser.add_argument("--sprite", help="Sprite id from spritegen.db (e.g. units/spearmen_dwarves_m)")
parser.add_argument("--prompt", help="Raw prompt override (skips registry)")
parser.add_argument("--negative", default="", help="Negative prompt for adaptation")
parser.add_argument("--out", help="Output path (default: experiments/grok_poc_<name>.png)")
args = parser.parse_args()
import asyncio
from engine.factory import create_generator
from engine.grok_generator import GrokSpriteGenerator, _adapt_prompt_for_grok
from engine.registry import SpriteRegistry
config = json.loads(CONFIG_PATH.read_text())
config["backend"] = "grok"
if args.prompt:
from engine.grok_generator import _ensure_grok_sdk
_ensure_grok_sdk()
from grok_build_batch_sdk import GrokBuildClient
grok_cfg = config.get("grok", {})
grok_prompt = _adapt_prompt_for_grok(args.prompt, args.negative)
client = GrokBuildClient(
model=grok_cfg.get("model", "grok-build"),
grok_bin=grok_cfg.get("cli_bin"),
image_tool=grok_cfg.get("image_tool", "GenerateImage"),
)
print("Adapted prompt:\n", grok_prompt, "\n")
async def _run():
return await client.generate_image(
grok_prompt,
aspect_ratio=grok_cfg.get("aspect_ratio", "1:1"),
cwd=str(TOOL_DIR),
)
result = asyncio.run(_run())
if result is None:
print("Generation failed.")
sys.exit(1)
from engine.grok_generator import _image_to_png_bytes
out = Path(args.out) if args.out else EXPERIMENTS / "grok_poc_custom.png"
out.parent.mkdir(parents=True, exist_ok=True)
out.write_bytes(_image_to_png_bytes(result.path))
print(f"Wrote {out} ({result.duration_ms} ms) from {result.path}")
return
if not args.sprite:
parser.error("Provide --sprite or --prompt")
reg = SpriteRegistry(DB_PATH)
sprite = reg.get_sprite(args.sprite)
if not sprite:
print(f"Sprite not found: {args.sprite}")
sys.exit(1)
category = sprite["category"]
entity_id = sprite.get("entity_id", "")
prompt, negative = GrokSpriteGenerator._compose_fresh(category, entity_id)
if not prompt:
prompt = sprite["prompt"] or ""
negative = sprite.get("negative_prompt") or ""
print("SDXL prompt (first 200 chars):", prompt[:200], "...")
print("Adapted prompt:\n", _adapt_prompt_for_grok(prompt, negative), "\n")
gen = create_generator(config=config, registry=reg, raw_dir=RAW_DIR)
result = asyncio.run(gen.submit_one(
sprite_id=args.sprite,
prompt=prompt,
negative=negative,
width=sprite.get("gen_width") or 1024,
height=sprite.get("gen_height") or 1024,
seed=42,
))
if not result:
print("Generation failed.")
sys.exit(1)
variant_id, _ = result
variant = reg.conn.execute(
"SELECT raw_path FROM variants WHERE id=?", (variant_id,),
).fetchone()
raw_path = Path(variant["raw_path"])
out = Path(args.out) if args.out else EXPERIMENTS / f"grok_poc_{args.sprite.replace('/', '_')}.png"
out.parent.mkdir(parents=True, exist_ok=True)
out.write_bytes(raw_path.read_bytes())
print(f"Variant {variant_id}{raw_path}")
print(f"Copied proof to {out}")
if __name__ == "__main__":
main()