diff --git a/scripts/test_cartoon_style.py b/scripts/test_cartoon_style.py new file mode 100644 index 000000000..87ba4a3e8 --- /dev/null +++ b/scripts/test_cartoon_style.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3 +""" +๐Ÿงช STYLE TEST - Generate test animals with NEW cartoon style +""" + +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 + +COMFYUI_URL = "http://127.0.0.1:8000" +OUTPUT_DIR = Path("/Users/davidkotnik/repos/novafarma/assets/images") +REPO_DIR = Path("/Users/davidkotnik/repos/novafarma") + +# NEW CARTOON STYLE (matches Gronk/Kai) +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""" + +# Test animals +TEST_ANIMALS = [ + ("zivali", "cow_normal", "dairy cow, black and white Holstein pattern, friendly cute"), + ("zivali", "pig_normal", "farm pig, pink, curly tail, happy"), + ("zivali", "chicken_white", "white chicken, red comb, pecking"), +] + +def log(msg): + ts = datetime.now().strftime("%H:%M:%S") + print(f"[{ts}] {msg}") + sys.stdout.flush() + +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"test_{uuid.uuid4().hex[:8]}"}, timeout=10) + return r.json().get("prompt_id") + except Exception as e: + log(f"โŒ {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"โŒ {e}") + return False + +def main(): + log("="*70) + log("๐Ÿงช STYLE TEST - NEW Cartoon Vector Style") + log(" Bold outlines, flat colors, cute aesthetic") + 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๐ŸŽจ Generating {len(TEST_ANIMALS)} test animals with CARTOON style...\n") + + for i, (cat, name, prompt) in enumerate(TEST_ANIMALS, 1): + path = OUTPUT_DIR / cat / f"{name}.png" + + log(f"[{i}/{len(TEST_ANIMALS)}] ๐Ÿ„ {name}") + + wf = create_workflow(prompt, name, 512) + pid = queue_prompt(wf) + + if pid and wait_completion(pid) and download_and_process(pid, path): + log(f" โœ… Done!") + # Auto-open for review + os.system(f"open {path}") + else: + log(f" โŒ Failed") + + time.sleep(2) + + log("\n" + "="*70) + log("๐Ÿงช TEST COMPLETE! Slike odprte za pregled.") + log(" Primerjajte z Gronk/Kai reference!") + log("="*70) + +if __name__ == "__main__": + main()