Text-to-Image
English
numpy
machine-learning
deep-learning
generative-ai
text-2-image
image-generation
open-weights
model-weights
ai-art
pixel-art
game-development
gamedev
game-assets
asset-generator
sprite-generator
offline
tiny-model
numpy-runtime
int8-quantization
self-supervised
procedural-data
gpt
english-prompts
awesome-ai
Upload cli.py with huggingface_hub
Browse files
cli.py
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""PXG-Tiny CLI (offline, NumPy-only).
|
| 3 |
+
|
| 4 |
+
python3 cli.py "a golden sword" -o sword.png
|
| 5 |
+
python3 cli.py "a golden sword" --variations 4 --sheet row.png
|
| 6 |
+
python3 cli.py --ask "can you draw a photo of a cat"
|
| 7 |
+
python3 cli.py --sheet-from-prompts prompts.txt --outdir sprites/
|
| 8 |
+
"""
|
| 9 |
+
import argparse
|
| 10 |
+
import json
|
| 11 |
+
import sys
|
| 12 |
+
from pathlib import Path
|
| 13 |
+
|
| 14 |
+
ROOT = Path(__file__).resolve().parents[0]
|
| 15 |
+
sys.path.insert(0, str(ROOT / "src"))
|
| 16 |
+
|
| 17 |
+
from PIL import Image # noqa: E402
|
| 18 |
+
|
| 19 |
+
from pxg_tiny import config as C # noqa: E402
|
| 20 |
+
from pxg_tiny.pipeline import PXGPipeline # noqa: E402
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def sheet(grids, path, scale=8):
|
| 24 |
+
n = len(grids)
|
| 25 |
+
im = Image.new("RGBA", (n * (16 * scale + 4) + 4, 16 * scale + 8),
|
| 26 |
+
(24, 24, 30, 255))
|
| 27 |
+
from pxg_tiny.render import grid_to_rgba
|
| 28 |
+
for i, g in enumerate(grids):
|
| 29 |
+
tile = Image.fromarray(grid_to_rgba(g), "RGBA").resize(
|
| 30 |
+
(16 * scale, 16 * scale), Image.NEAREST)
|
| 31 |
+
im.paste(tile, (4 + i * (16 * scale + 4), 4), tile)
|
| 32 |
+
im.save(path)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def main():
|
| 36 |
+
ap = argparse.ArgumentParser(prog="pxg-tiny")
|
| 37 |
+
ap.add_argument("prompt", nargs="?")
|
| 38 |
+
ap.add_argument("-o", "--out", default=None)
|
| 39 |
+
ap.add_argument("--seed", type=int, default=0)
|
| 40 |
+
ap.add_argument("--temperature", type=float, default=None)
|
| 41 |
+
ap.add_argument("--top-k", type=int, default=None)
|
| 42 |
+
ap.add_argument("--variations", type=int, default=1)
|
| 43 |
+
ap.add_argument("--sheet", action="store_true",
|
| 44 |
+
help="save a variations sheet next to the png")
|
| 45 |
+
ap.add_argument("--sheet-from-prompts", default=None,
|
| 46 |
+
help="path to a text file with one prompt per line; "
|
| 47 |
+
"renders every prompt into --outdir")
|
| 48 |
+
ap.add_argument("--outdir", default=None,
|
| 49 |
+
help="output directory for --sheet-from-prompts")
|
| 50 |
+
ap.add_argument("--ask", action="store_true",
|
| 51 |
+
help="ask-first mode: clarify/refuse instead of drawing")
|
| 52 |
+
ap.add_argument("--bundle", default=str(ROOT / "weights"))
|
| 53 |
+
ap.add_argument("--no-quality", action="store_true",
|
| 54 |
+
help="disable the grounding auto-retry gate")
|
| 55 |
+
args = ap.parse_args()
|
| 56 |
+
|
| 57 |
+
if args.sheet_from_prompts:
|
| 58 |
+
outdir = Path(args.outdir or "pxg_batch_out")
|
| 59 |
+
outdir.mkdir(parents=True, exist_ok=True)
|
| 60 |
+
lines = [l.strip() for l in Path(args.sheet_from_prompts)
|
| 61 |
+
.read_text().splitlines() if l.strip()]
|
| 62 |
+
pipe = PXGPipeline(args.bundle)
|
| 63 |
+
grids = []
|
| 64 |
+
results = []
|
| 65 |
+
for i, p in enumerate(lines):
|
| 66 |
+
g, m = pipe.generate_pixels(p, seed=args.seed,
|
| 67 |
+
enforce_quality=not args.no_quality,
|
| 68 |
+
temperature=args.temperature,
|
| 69 |
+
top_k=args.top_k)
|
| 70 |
+
results.append({"prompt": p, "gate": m.get("gate")})
|
| 71 |
+
if g is None:
|
| 72 |
+
print(json.dumps({"i": i, "prompt": p, **m}, indent=2))
|
| 73 |
+
continue
|
| 74 |
+
from pxg_tiny.render import save_png
|
| 75 |
+
f = outdir / f"{i+1:02d}_{p.replace(' ', '_')[:24]}.png"
|
| 76 |
+
save_png(g, f, scale=8)
|
| 77 |
+
grids.append(g)
|
| 78 |
+
results[-1]["file"] = str(f)
|
| 79 |
+
if grids:
|
| 80 |
+
sheet(grids, outdir / "sheet.png")
|
| 81 |
+
print(json.dumps({"n_prompts": len(lines), "n_rendered": len(grids),
|
| 82 |
+
"outdir": str(outdir), "results": results}, indent=2))
|
| 83 |
+
return
|
| 84 |
+
|
| 85 |
+
if not args.prompt:
|
| 86 |
+
ap.error("give me a prompt, e.g. pxg-tiny \"a gold sword\"")
|
| 87 |
+
|
| 88 |
+
pipe = PXGPipeline(args.bundle)
|
| 89 |
+
|
| 90 |
+
if args.ask:
|
| 91 |
+
label, msg = pipe.should_ask(args.prompt)
|
| 92 |
+
print(json.dumps({"label": label, "message": msg}, indent=2))
|
| 93 |
+
return
|
| 94 |
+
|
| 95 |
+
out = Path(args.out) if args.out else Path(
|
| 96 |
+
args.prompt.replace(" ", "_")[:24].replace("/", "_") + ".png")
|
| 97 |
+
out.parent.mkdir(parents=True, exist_ok=True)
|
| 98 |
+
|
| 99 |
+
grids, metas = [], []
|
| 100 |
+
if args.variations > 1:
|
| 101 |
+
res = pipe.variations(args.prompt, k=args.variations,
|
| 102 |
+
start_seed=args.seed,
|
| 103 |
+
enforce_quality=not args.no_quality,
|
| 104 |
+
temperature=args.temperature, top_k=args.top_k)
|
| 105 |
+
grids = [g for g, _ in res if g is not None]
|
| 106 |
+
metas = [m for _, m in res]
|
| 107 |
+
else:
|
| 108 |
+
g, m = pipe.generate_pixels(args.prompt, seed=args.seed,
|
| 109 |
+
temperature=args.temperature,
|
| 110 |
+
top_k=args.top_k,
|
| 111 |
+
enforce_quality=not args.no_quality)
|
| 112 |
+
if g is None:
|
| 113 |
+
print(json.dumps(m, indent=2))
|
| 114 |
+
return
|
| 115 |
+
grids, metas = [g], [m]
|
| 116 |
+
|
| 117 |
+
sheet(grids, out)
|
| 118 |
+
print(json.dumps({"prompt": args.prompt, "out": str(out),
|
| 119 |
+
"n": len(grids), "meta": metas[0]}, indent=2))
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
if __name__ == "__main__":
|
| 123 |
+
main()
|