- Created overnight generation system
- Added master character references (Gronk, Kai)
- Implemented auto-commit for all generated assets
- Created comprehensive documentation and changelogs
- Setup FULL generator (850+ assets without NPCs)
- Added progress tracking and status check scripts
Ready for overnight mass generation 🌙
176 lines
6.4 KiB
Python
176 lines
6.4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
🎨 REGENERATE - Z Master Reference
|
|
Uporablja točne specifikacije iz MASTER_GRONK.png in MASTER_KAI.png
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import json
|
|
import time
|
|
import uuid
|
|
import requests
|
|
import subprocess
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
|
|
try:
|
|
from rembg import remove
|
|
from PIL import Image
|
|
except ImportError:
|
|
os.system("pip3 install --user rembg pillow onnxruntime")
|
|
from rembg import remove
|
|
from PIL import Image
|
|
|
|
COMFYUI_URL = "http://127.0.0.1:8000"
|
|
OUTPUT_DIR = Path("/Users/davidkotnik/repos/novafarma/assets/images")
|
|
REPO_DIR = Path("/Users/davidkotnik/repos/novafarma")
|
|
|
|
STYLE = "2D indie game cartoon character sprite, clean vector style, smooth bold outlines, full body visible head to feet, isolated on pure white background"
|
|
NEGATIVE = "pixel art, pixelated, 3d render, realistic photo, anime, manga, blurry, watermark, text, green background, cut off"
|
|
|
|
# 🎯 CORRECT PROMPTS based on MASTER references
|
|
CORRECT_ASSETS = [
|
|
("npcs", "gronk_front_walk1",
|
|
"Gronk the troll character, green-grey skin with visible round belly, "
|
|
"BRIGHT PINK dreadlocks, large ear gauges, nose ring and facial piercings, "
|
|
"wearing black baggy t-shirt with purple TROLL SABBATH text, "
|
|
"black loose baggy pants, bright pink sneakers, "
|
|
"holding colorful rainbow vape device with pink smoke, "
|
|
"peaceful relaxed expression, full body, front view, walking pose left leg forward"),
|
|
|
|
("npcs", "kai_front_walk1",
|
|
"Kai teenage survivor character, dark forest green thick dreadlocks, "
|
|
"medium skin tone, large ear gauges, nose piercing and lip piercing, "
|
|
"serious determined expression, "
|
|
"wearing weathered blue-grey denim jacket with dirt stains, "
|
|
"beige t-shirt underneath, "
|
|
"torn blue jeans ripped at knees, "
|
|
"brown leather combat boots, "
|
|
"brown survival backpack with straps and pockets, "
|
|
"athletic lean build, full body, front view, walking pose left leg forward"),
|
|
]
|
|
|
|
|
|
def log(msg):
|
|
ts = datetime.now().strftime("%H:%M:%S")
|
|
print(f"[{ts}] {msg}")
|
|
sys.stdout.flush()
|
|
|
|
|
|
def git_commit(file_path, category, name):
|
|
try:
|
|
rel_path = file_path.relative_to(REPO_DIR)
|
|
subprocess.run(["git", "add", str(rel_path)], cwd=REPO_DIR, check=True, capture_output=True)
|
|
subprocess.run(["git", "commit", "-m", f"🎨 CORRECT: {category}/{name} (master ref)"], cwd=REPO_DIR, check=True, capture_output=True)
|
|
log(f" 📝 Git committed with master ref tag")
|
|
return True
|
|
except:
|
|
return False
|
|
|
|
|
|
def create_workflow(prompt_text, output_name, size=512):
|
|
seed = int(time.time() * 1000) % 2147483647
|
|
full_prompt = f"{STYLE}, {prompt_text}"
|
|
|
|
return {
|
|
"1": {"class_type": "CheckpointLoaderSimple", "inputs": {"ckpt_name": "dreamshaper_8.safetensors"}},
|
|
"2": {"class_type": "EmptyLatentImage", "inputs": {"width": size, "height": size, "batch_size": 1}},
|
|
"3": {"class_type": "CLIPTextEncode", "inputs": {"text": full_prompt, "clip": ["1", 1]}},
|
|
"4": {"class_type": "CLIPTextEncode", "inputs": {"text": NEGATIVE, "clip": ["1", 1]}},
|
|
"5": {
|
|
"class_type": "KSampler",
|
|
"inputs": {
|
|
"seed": seed, "steps": 35, "cfg": 8.0,
|
|
"sampler_name": "euler_ancestral", "scheduler": "karras",
|
|
"denoise": 1.0, "model": ["1", 0],
|
|
"positive": ["3", 0], "negative": ["4", 0], "latent_image": ["2", 0]
|
|
}
|
|
},
|
|
"6": {"class_type": "VAEDecode", "inputs": {"samples": ["5", 0], "vae": ["1", 2]}},
|
|
"7": {"class_type": "SaveImage", "inputs": {"filename_prefix": output_name, "images": ["6", 0]}}
|
|
}
|
|
|
|
|
|
def queue_prompt(workflow):
|
|
try:
|
|
r = requests.post(f"{COMFYUI_URL}/prompt", json={"prompt": workflow, "client_id": f"regen_{uuid.uuid4().hex[:8]}"}, timeout=10)
|
|
return r.json().get("prompt_id")
|
|
except Exception as e:
|
|
log(f"❌ Queue error: {e}")
|
|
return None
|
|
|
|
|
|
def wait_completion(prompt_id, timeout=120):
|
|
start = time.time()
|
|
while time.time() - start < timeout:
|
|
try:
|
|
r = requests.get(f"{COMFYUI_URL}/history/{prompt_id}", timeout=5)
|
|
if prompt_id in r.json() and r.json()[prompt_id].get("outputs"):
|
|
return True
|
|
except:
|
|
pass
|
|
time.sleep(2)
|
|
return False
|
|
|
|
|
|
def download_and_process(prompt_id, output_path):
|
|
try:
|
|
h = requests.get(f"{COMFYUI_URL}/history/{prompt_id}").json()
|
|
for out in h.get(prompt_id, {}).get("outputs", {}).values():
|
|
for img in out.get("images", []):
|
|
r = requests.get(f"{COMFYUI_URL}/view", params={"filename": img["filename"], "subfolder": img.get("subfolder", ""), "type": "output"})
|
|
if r.status_code == 200:
|
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
from io import BytesIO
|
|
transparent_img = remove(Image.open(BytesIO(r.content)))
|
|
transparent_img.save(str(output_path), "PNG")
|
|
return True
|
|
return False
|
|
except Exception as e:
|
|
log(f"❌ Download error: {e}")
|
|
return False
|
|
|
|
|
|
def main():
|
|
log("="*70)
|
|
log("🎨 REGENERATE - Z Master Reference Slikami")
|
|
log(" Točne specifikacije iz MASTER_GRONK.png & MASTER_KAI.png")
|
|
log("="*70)
|
|
|
|
try:
|
|
r = requests.get(f"{COMFYUI_URL}/system_stats", timeout=5)
|
|
log(f"✅ ComfyUI v{r.json()['system']['comfyui_version']} running")
|
|
except:
|
|
log("❌ ComfyUI not running!")
|
|
return
|
|
|
|
log(f"\n🎯 Regenerating {len(CORRECT_ASSETS)} characters with CORRECT style...\n")
|
|
|
|
for i, (cat, name, prompt) in enumerate(CORRECT_ASSETS, 1):
|
|
path = OUTPUT_DIR / cat / f"{name}.png"
|
|
|
|
log(f"[{i}/{len(CORRECT_ASSETS)}] 🎨 {name}...")
|
|
log(f" 📋 Using master reference prompt")
|
|
|
|
wf = create_workflow(prompt, name, 512)
|
|
pid = queue_prompt(wf)
|
|
|
|
if pid and wait_completion(pid) and download_and_process(pid, path):
|
|
log(f" ✅ Generated with CORRECT style!")
|
|
git_commit(path, cat, name)
|
|
|
|
# Auto-open to verify
|
|
os.system(f"open {path}")
|
|
else:
|
|
log(f" ❌ FAILED")
|
|
|
|
log("\n" + "="*70)
|
|
log("🎨 REGENERATION COMPLETE!")
|
|
log(" Slike so odprte - preverite ali sedaj ustrezajo!")
|
|
log("="*70)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|