#!/usr/bin/env python3 """ πŸŒ™ NOČNA GENERACIJA - FULL Asset Set BREZ NPCs in glavnih karakterjev Z avtomatskim Git commitom in progress trackingom """ import os import sys 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 # Configuration COMFYUI_URL = "http://127.0.0.1:8000" OUTPUT_DIR = Path("/Users/davidkotnik/repos/novafarma/assets/images") REPO_DIR = Path("/Users/davidkotnik/repos/novafarma") PROGRESS_LOG = REPO_DIR / "generation_progress.log" STYLE = """Clean cartoon vector game sprite, bold smooth outlines, flat vibrant colors, minimal shading, cute playful aesthetic, full body visible head-to-toe, isolated on pure white background, 2D game art similar to Don't Starve or Zelda Link's Awakening style""" NEGATIVE = """pixel art, pixelated, voxel, 3d render, realistic, photorealistic, detailed shading, gradient heavy, anime style, manga, blurry, low quality, watermark, text, green background, Stardew Valley style, farm sim generic style""" def log(msg): ts = datetime.now().strftime("%H:%M:%S") line = f"[{ts}] {msg}" print(line) sys.stdout.flush() with open(PROGRESS_LOG, 'a') as f: f.write(line + "\n") 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"🎨 Generated: {category}/{name}"], cwd=REPO_DIR, capture_output=True) return True except: return False # Load FULL registry safely sys.path.insert(0, str(REPO_DIR / "scripts")) import generate_assets_full ALL_ASSETS = generate_assets_full.generate_registry() FILTERED_ASSETS = [a for a in ALL_ASSETS if a['cat'] != 'npcs'] 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": 30, "cfg": 7.5, "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"full_{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("πŸŒ™ DAYTIME GENERATION - FULL Asset Set") log(" BREZ NPCs in glavnih karakterjev") log("="*70) try: r = requests.get(f"{COMFYUI_URL}/system_stats", timeout=5) log(f"βœ… ComfyUI v{r.json()['system']['comfyui_version']}") except: log("❌ ComfyUI not running!") return log(f"\nπŸ“Š Registry Statistics:") log(f" Total assets: {len(ALL_ASSETS)}") log(f" NPCs (excluded): {len([a for a in ALL_ASSETS if a['cat'] == 'npcs'])}") log(f" FILTERED (to generate): {len(FILTERED_ASSETS)}") existing = sum(1 for a in FILTERED_ASSETS if (OUTPUT_DIR / a['cat'] / a['file']).exists()) to_generate = len(FILTERED_ASSETS) - existing log(f"\nπŸ“ File Status:") log(f" Already exist: {existing}") log(f" To generate: {to_generate}") log(f"\nπŸ“¦ By Category:") cats = {} for a in FILTERED_ASSETS: cats[a['cat']] = cats.get(a['cat'], 0) + 1 for cat, count in sorted(cats.items(), key=lambda x: -x[1]): existing_cat = sum(1 for a in FILTERED_ASSETS if a['cat'] == cat and (OUTPUT_DIR / a['cat'] / a['file']).exists()) log(f" {cat:20s}: {count:4d} total ({existing_cat} exist, {count-existing_cat} to gen)") if to_generate == 0: log("\nβœ… All assets already generated!") return log(f"\nπŸš€ Starting generation of {to_generate} assets...") log(f" ETA: ~{to_generate * 20 / 3600:.1f} hours\n") success, skip, fail = 0, 0, 0 start_time = time.time() for i, asset in enumerate(FILTERED_ASSETS, 1): path = OUTPUT_DIR / asset['cat'] / asset['file'] if path.exists(): skip += 1 if i % 50 == 0: log(f"[{i}/{len(FILTERED_ASSETS)}] Progress: βœ…{success} ⏭️ {skip} ❌{fail}") continue log(f"[{i}/{len(FILTERED_ASSETS)}] 🎨 {asset['cat']}/{asset['file'][:40]}") size = 768 if asset['cat'] == 'bosses' else 512 wf = create_workflow(asset['prompt'], asset['file'].replace('.png', ''), size) pid = queue_prompt(wf) if pid and wait_completion(pid) and download_and_process(pid, path): log(f" βœ… Done") git_commit(path, asset['cat'], asset['file']) success += 1 else: log(f" ❌ FAILED") fail += 1 if i % 10 == 0: elapsed = time.time() - start_time per_asset = elapsed / (success + fail) if (success + fail) > 0 else 20 remaining = per_asset * (to_generate - success - fail) log(f"\nπŸ“Š [{i}/{len(FILTERED_ASSETS)}] βœ…{success} ⏭️ {skip} ❌{fail}") log(f" ⏱️ Elapsed: {elapsed/60:.1f}m | ETA: {remaining/60:.1f}m\n") elapsed = time.time() - start_time log("\n" + "="*70) log("🎨 GENERATION COMPLETE!") log(f" βœ… Success: {success}") log(f" ⏭️ Skipped: {skip}") log(f" ❌ Failed: {fail}") log(f" ⏱️ Total time: {elapsed/3600:.1f} hours") log(f" πŸ“ Output: {OUTPUT_DIR}") log("="*70) if __name__ == "__main__": main()