diff --git a/CHANGELOG_29_12_2025.md b/CHANGELOG_29_12_2025.md new file mode 100644 index 000000000..4e7df7760 --- /dev/null +++ b/CHANGELOG_29_12_2025.md @@ -0,0 +1,145 @@ +# ๐Ÿ“ Changelog - 29.12.2025 + +## ๐ŸŒ™ Noฤna Session (03:00 - 09:00) + +### **Glavna Aktivnost:** +Avtomatska generacija FULL asset set-a za DolinaSmrti + +--- + +## โœ… Opravljeno: + +### **1. Character Reference System** +- โœ… Upload master reference slik (Gronk, Kai) +- โœ… Kreiran `reference_images/` directory +- โœ… Dokumentacija v `CHARACTER_REFERENCES.md` +- โœ… NPCs izkljuฤeni iz avtomatske generacije + +### **2. Test Generacije** +- โœ… Regeneriran Gronk walking frame (z master ref) +- โœ… Regeneriran Kai walking frame (z master ref) +- โœ… Test samples iz vsake kategorije +- โœ… Kvalitetni check - APPROVED + +### **3. Generator Setup** +- โœ… Posodobljen `generate_local_final.py` z auto-commit +- โœ… Kreiran `test_category_samples.py` +- โœ… Kreiran `regenerate_with_master_ref.py` +- โœ… Kreiran `generate_full_auto.py` za FULL set + +### **4. Automation Scripts** +- โœ… `run_auto_generation.sh` - background runner +- โœ… `check_generation_status.sh` - napredek checker +- โœ… Auto-commit functionality (Git) +- โœ… Auto-open images za review + +### **5. Dokumentacija** +- โœ… `AUTO_GENERATION_README.md` +- โœ… `CHARACTER_REFERENCES.md` +- โœ… `NOCNA_GENERACIJA_LOG.md` (ta datoteka) +- โœ… Session changelog + +--- + +## ๐ŸŽฏ V Teku: + +### **FULL Asset Generation** +- **Start:** ~03:45 +- **Target:** ~850 slik +- **Categories:** Buildings, Workstations, Items, Animals, Environment, Mutants, Bosses, UI +- **Excluded:** NPCs, Main Characters +- **ETA:** ~09:00 (5-6 ur) + +--- + +## ๐Ÿ“Š Statistika: + +### **Pred Generacijo:** +- PNG slik: 150 +- Git commits: ~50 + +### **Po Generaciji (target):** +- PNG slik: ~1,000 +- Git commits: ~900 +- Kategorij: 8 +- Total MB: ~150-300 MB + +--- + +## ๐Ÿ”ง Tehniฤni Detajli: + +### **ComfyUI Setup:** +- Lokalni server: `127.0.0.1:8000` +- Model: Dreamshaper 8 +- Version: 0.6.0 +- Status: Running โœ… + +### **Processing:** +- Generation: ComfyUI workflow +- Background removal: rembg (u2net model) +- Format: PNG (transparent) +- Size: 512x512 (bosses 768x768) + +--- + +## ๐Ÿ› Issues Fixed: + +1. โœ… NPCs excluded iz automation (user request) +2. โœ… Master reference integration +3. โœ… Git auto-commit dodano +4. โœ… Progress tracking izboljลกano + +--- + +## ๐Ÿ“… Naslednji Koraki (Za Jutri): + +### **Prioriteta 1: Review** +- [ ] Pregled vseh generiranih slik +- [ ] Kvalitetni check po kategorijah +- [ ] Identifikacija slab generiranih + +### **Prioriteta 2: NPCs (Manual)** +- [ ] Pregled NPC lista +- [ ] Generacija z master reference style +- [ ] Review vsake slike posebej + +### **Prioriteta 3: Assets Integration** +- [ ] Import v game +- [ ] Test v Tiled +- [ ] Animation sequences + +--- + +## ๐Ÿ’พ Backup Info: + +**Git Status:** +- Branch: master +- Auto-commits: Enabled +- Remote: Ready for push + +**Files Modified:** +- `scripts/generate_*.py` (multiple) +- `reference_images/*` +- `assets/images/*` (mass update) + +--- + +## ๐ŸŽจ Asset Breakdown: + +| Category | Target | Status | +|:---|---:|:---| +| Buildings | 57 | Generira se | +| Workstations | 25 | Generira se | +| Items | 505 | Generira se | +| Animals | 147 | Generira se | +| Environment | 103 | Generira se | +| Mutants | 98 | Generira se | +| Bosses | 25 | Generira se | +| UI | 41 | Generira se | +| **TOTAL** | **1,001** | **V teku** | + +--- + +**Last Updated:** 29.12.2025 03:43 +**Next Review:** 29.12.2025 09:00 (zjutraj) +**Status:** ๐ŸŸข RUNNING diff --git a/NOCNA_GENERACIJA_LOG.md b/NOCNA_GENERACIJA_LOG.md new file mode 100644 index 000000000..3972b00b6 --- /dev/null +++ b/NOCNA_GENERACIJA_LOG.md @@ -0,0 +1,154 @@ +# ๐ŸŒ™ NOฤŒNA GENERACIJA - Session Log +**Datum:** 29. December 2025, 03:42 +**Status:** AVTOMATSKA GENERACIJA V TEKU + +--- + +## ๐Ÿ“‹ ฤŒE BERETE TO ZJUTRAJ: + +Pozdravljen! Tukaj je kratek pregled kaj je bilo narejeno med spanjem. + +--- + +## ๐ŸŽฏ CILJ NOฤŒNE GENERACIJE: + +**FULL Asset Set** - ~850 slik (BREZ NPCs in glavnih karakterjev) + +### **Vkljuฤeno:** +- โœ… **Buildings** (57) - Farm, Production, Town buildings +- โœ… **Workstations** (25) - Crafting stations +- โœ… **Items** (505) - Tools, weapons, potions, food +- โœ… **Animals** (147) - Farm, wildlife, legendary +- โœ… **Environment** (103) - Trees, objects, terrain +- โœ… **Mutanti** (98) - Zombies, slimes +- โœ… **Bosses** (25) - Epic encounters +- โœ… **UI** (41) - Interface elements + +### **IZKLJUฤŒENO:** +- โŒ NPCs (~85) +- โŒ Main Characters (Gronk, Kai, Ana) + +--- + +## ๐Ÿ“Š PRED GENERACIJO: + +**ลฝe generirano:** 150 PNG slik +**Cilj:** ~1,000 PNG slik (FULL set brez NPCs) +**Manjka:** ~850 slik + +--- + +## โฑ๏ธ ฤŒASOVNI OKVIR: + +**Ocena:** 5-6 ur +**Start:** 29.12.2025 ~03:45 +**Predviden konec:** 29.12.2025 ~09:00 + +--- + +## ๐Ÿ”ง TEHNIฤŒNI DETAJLI: + +### **Generator:** +- Script: `generate_full_auto.py` +- ComfyUI: Local port 8000 +- Model: Dreamshaper 8 +- Background removal: rembg (u2net) +- Auto-commit: DA (vsaka slika) + +### **Konfiguratcija:** +- Size: 512x512 (bosses 768x768) +- Steps: 30 +- CFG: 7.5 +- Sampler: euler_ancestral +- Scheduler: karras + +--- + +## ๐Ÿ“ OUTPUT: + +Vse slike v: +``` +/Users/davidkotnik/repos/novafarma/assets/images/ +โ”œโ”€โ”€ items/ +โ”œโ”€โ”€ buildings/ +โ”œโ”€โ”€ workstations/ +โ”œโ”€โ”€ environment/ +โ”œโ”€โ”€ zivali/ +โ”œโ”€โ”€ mutanti/ +โ”œโ”€โ”€ bosses/ +โ””โ”€โ”€ ui/ +``` + +--- + +## ๐Ÿ“ GIT COMMITS: + +Vsaka slika se avtomatsko committa: +``` +๐ŸŽจ Auto-generated: [category]/[filename] +``` + +--- + +## ๐Ÿ” KAKO PREVERITI NAPREDEK: + +### **1. Pregled logov:** +```bash +cat /Users/davidkotnik/repos/novafarma/generation_progress.log +``` + +### **2. Status check:** +```bash +cd /Users/davidkotnik/repos/novafarma/scripts +./check_generation_status.sh +``` + +### **3. ล tetje slik:** +```bash +find /Users/davidkotnik/repos/novafarma/assets/images -name "*.png" | wc -l +``` + +--- + +## โœ… ฤŒE JE VSE OK: + +Priฤakujete: +- **~1,000 PNG slik** v `/assets/images/` +- **~850 Git commits** +- **Vse transparentne** (rembg processed) +- **Organizirano po kategorijah** + +--- + +## โŒ ฤŒE NEKAJ NI V REDU: + +Preverite: +1. `generation_progress.log` - za errore +2. ComfyUI je ลกe vedno running +3. Disk space (vsaka slika ~100-300 KB) + +--- + +## ๐ŸŽจ MASTER REFERENCES: + +**Vaลพno:** NPCs ostanejo roฤno, ker uporabljamo master reference: +- `reference_images/MASTER_GRONK.png` +- `reference_images/MASTER_KAI.png` + +--- + +## ๐Ÿ“ˆ NASLEDNJI KORAKI (za zjutraj): + +1. โœ… Pregled kvalitete slik +2. โœ… ฤŒe je OK โ†’ lahko zaฤnemo z NPCs (roฤno) +3. โœ… ฤŒe ni OK โ†’ debug in ponovna generacija + +--- + +**Generated:** 29.12.2025 03:42 +**By:** Antigravity AI Assistant +**Purpose:** Overnight mass asset generation for DolinaSmrti game + +--- + +**Lep poฤitek in pohvale za jutro!** ๐ŸŒŸ diff --git a/reference_images/CHARACTER_REFERENCES.md b/reference_images/CHARACTER_REFERENCES.md new file mode 100644 index 000000000..75ce4e70e --- /dev/null +++ b/reference_images/CHARACTER_REFERENCES.md @@ -0,0 +1,80 @@ +# ๐ŸŽจ MASTER CHARACTER REFERENCES + +These are the **DEFINITIVE** character designs. ALL generated assets MUST match these exact styles. + +## ๐ŸงŒ GRONK - Master Reference +![Gronk Master](MASTER_GRONK.png) + +**Key Features:** +- **Skin**: Green-grey, visible belly +- **Hair**: BRIGHT PINK dreadlocks with ear gauges +- **Face**: Piercings (nose ring, ear piercings), peaceful zen expression +- **Clothing**: + - Black t-shirt with "TROLL SABBATH" purple text + - Black baggy pants (loose fit) + - PINK sneakers (bright magenta) +- **Props**: Colorful vape device with pink/purple smoke +- **Body**: Large, overweight, relaxed posture + +**Exact Prompt Template:** +``` +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 +``` + +--- + +## ๐Ÿ‘ค KAI - Master Reference +![Kai Master](MASTER_KAI.png) + +**Key Features:** +- **Skin**: Medium tone, clean +- **Hair**: DARK GREEN thick dreadlocks (forest green, not lime) +- **Face**: Ear gauges (stretched lobes), nose piercing, lip piercing, serious expression +- **Clothing**: + - Blue-grey weathered denim jacket (dirt stains, wear marks) + - Beige/tan undershirt + - Ripped blue jeans (torn at knees) + - Brown leather combat boots (laced up) + - Brown survival backpack with pockets and straps +- **Build**: Teenage, athletic, lean +- **Posture**: Determined, survivor stance + +**Exact Prompt Template:** +``` +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 +``` + +--- + +## ๐ŸŽฏ USAGE INSTRUCTIONS + +1. **All Gronk animations** must use the Gronk template +2. **All Kai animations** must use the Kai template +3. **Color accuracy is critical**: + - Gronk's pink = `#FF1493` (bright magenta) + - Kai's green = `#2D5016` (dark forest green) +4. **Include ALL details** - piercings, clothing text, wear/dirt +5. **Match proportions** - Gronk is wide/heavy, Kai is lean/athletic + +--- + +## ๐Ÿ“ REGENERATION NEEDED + +The following files were generated BEFORE these references and need regeneration: +- `npcs/gronk_front_walk1.png` โŒ +- `npcs/kai_front_walk1.png` โŒ + +Delete and regenerate with correct prompts. diff --git a/reference_images/MASTER_GRONK.png b/reference_images/MASTER_GRONK.png new file mode 100644 index 000000000..345236022 Binary files /dev/null and b/reference_images/MASTER_GRONK.png differ diff --git a/reference_images/MASTER_KAI.png b/reference_images/MASTER_KAI.png new file mode 100644 index 000000000..65d104d34 Binary files /dev/null and b/reference_images/MASTER_KAI.png differ diff --git a/scripts/AUTO_GENERATION_README.md b/scripts/AUTO_GENERATION_README.md new file mode 100644 index 000000000..7f1b6b718 --- /dev/null +++ b/scripts/AUTO_GENERATION_README.md @@ -0,0 +1,124 @@ +# ๐ŸŽฎ DOLINA SMRTI - Avtomatska Generacija Assetsov + +## ๐Ÿš€ NAฤŒIN 1: Popolnoma Avtomatsko (PRIPOROฤŒENO) + +### Zagon: +```bash +cd /Users/davidkotnik/repos/novafarma/scripts +./run_auto_generation.sh +``` + +**To bo:** +- โœ… Zagnalo generacijo v ozadju +- โœ… Kreiral log datoteko z timestampom +- โœ… Omogoฤil da zaprete terminal ALI greste spat +- โœ… ComfyUI ลพe teฤe, zato bo zaฤel takoj + +**Po zagonu lahko:** +- Zaprete terminal - proces bo tekel naprej +- Ugasnete zaslon - proces bo tekel naprej +- Greste spat - proces bo tekel naprej + +--- + +## ๐Ÿ“Š Spremljanje Napredka + +### Preveri status: +```bash +./check_generation_status.sh +``` + +### Live spremljanje (real-time): +```bash +tail -f /Users/davidkotnik/repos/novafarma/generation_*.log +``` + +Za izhod iz live pogleda: **Ctrl+C** + +--- + +## โน๏ธ Ustavitev Generacije + +ฤŒe ลพelite ustaviti: +```bash +kill $(cat /tmp/dolina_generation.pid) +``` + +--- + +## ๐Ÿš€ NAฤŒIN 2: Terminal Session (za debugging) + +ฤŒe ลพelite videti output v realnem ฤasu: +```bash +cd /Users/davidkotnik/repos/novafarma/scripts +python3 generate_local_final.py +``` + +--- + +## โฑ๏ธ ฤŒasovni Okvir + +**Na podlagi testov:** +- โฑ๏ธ ~15-30 sekund na asset +- ๐Ÿ“Š **110 remaining assets** = ~45-90 minut +- ๐Ÿ“Š **422 total V7 assets** = ~3-5 ur +- ๐Ÿ“Š **1,418 full assets** = ~10-18 ur + +**Ker ComfyUI teฤe lokalno:** +- โŒ BREZ API rate limitov +- โŒ BREZ pavz +- โŒ BREZ potrebe po vaลกi prisotnosti +- โœ… Lahko teฤe ฤŒEZNOJI + +--- + +## ๐Ÿ“ Rezultati + +Vsi generirani PNG-ji so avtomatsko: +- โœ… Odstranjeno ozadje (transparentni) +- โœ… Shranjeni v `/Users/davidkotnik/repos/novafarma/assets/images/` +- โœ… Razvrลกฤeni po kategorijah + +--- + +## ๐Ÿ”ง Moลพne Teลพave + +### ComfyUI se ne odziva: +1. Odprite ComfyUI app +2. Poฤakajte da se zaลพene (zeleni indikator) +3. Poskusite znova + +### Generacija se ne zaฤne: +```bash +# Preverite error log: +cat /Users/davidkotnik/repos/novafarma/generation_*.log +``` + +--- + +## ๐Ÿ’ก Nasveti + +**ZA ฤŒEZ NOฤŒ:** +1. Zaลพenite: `./run_auto_generation.sh` +2. Greste spat ๐Ÿ˜ด +3. Zjutraj: `./check_generation_status.sh` +4. Profit! ๐ŸŽ‰ + +**ZA PREMIUM REZULTATE:** +- ComfyUI uporablja **Dreamshaper 8** model +- Vsaka slika je **512x512** (bosses 768x768) +- Background removal z **rembg (u2net model)** +- **30 generation steps** za kakovost + +--- + +## ๐Ÿ“ˆ Trenutni Status + +Po zadnjem preverjanju: +- โœ… ComfyUI: **v teku** (port 8000) +- ๐Ÿ“Š Generirano: **148/422** (V7) ali **148/1,418** (FULL) +- โณ Manjka: **~274 slik** za V7 set + +--- + +**๐ŸŽฏ Glavna Prednost: Lahko vse teฤe AVTOMATSKO ฤez noฤ!** ๐ŸŒ™ diff --git a/scripts/check_generation_status.sh b/scripts/check_generation_status.sh new file mode 100755 index 000000000..fcca931ca --- /dev/null +++ b/scripts/check_generation_status.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# ๐Ÿ” Preveri status generacije + +echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" +echo "๐ŸŽฎ DOLINA SMRTI - Asset Generation Status" +echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" +echo "" + +# Preveri ฤe proces teฤe +if [ -f /tmp/dolina_generation.pid ]; then + PID=$(cat /tmp/dolina_generation.pid) + if ps -p $PID > /dev/null 2>&1; then + echo "โœ… Generacija TEฤŒE (PID: $PID)" + + # Pokaลพi zadnje loge + LATEST_LOG=$(ls -t /Users/davidkotnik/repos/novafarma/generation_*.log 2>/dev/null | head -1) + if [ -n "$LATEST_LOG" ]; then + echo "๐Ÿ“‚ Log file: $LATEST_LOG" + echo "" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + echo "๐Ÿ“Š Zadnjih 15 vrstic:" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + tail -15 "$LATEST_LOG" + fi + else + echo "โŒ Proces NE teฤe veฤ (PID $PID ni aktiven)" + rm /tmp/dolina_generation.pid + fi +else + echo "โญ• Generacija NI zagnana" +fi + +echo "" +echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" +echo "๐Ÿ“ Trenutno generirane slike:" +echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + +cd /Users/davidkotnik/repos/novafarma/assets/images +for dir in */; do + count=$(find "$dir" -name "*.png" 2>/dev/null | wc -l) + printf " %-20s: %3d slik\n" "${dir%/}" "$count" +done + +total=$(find . -name "*.png" 2>/dev/null | wc -l) +echo " โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" +printf " %-20s: %3d slik\n" "SKUPAJ" "$total" + +echo "" +echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" diff --git a/scripts/fresh_test.py b/scripts/fresh_test.py new file mode 100644 index 000000000..deb2809df --- /dev/null +++ b/scripts/fresh_test.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 +""" +๐Ÿš€ FRESH TEST - Generira 3 nove slike ki jih ลกe ni +""" + +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: + print("๐Ÿ“ฆ Installing rembg...") + 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") + +STYLE = "2D indie game sprite, cartoon vector style, clean smooth lines, full body visible, isolated on pure white background" +NEGATIVE = "pixel art, pixelated, 3d, realistic, photo, blurry, watermark, text, green background" + +# ๐Ÿ†• NOVE SLIKE - ล e ne generirane +NEW_ASSETS = [ + ("npcs", "gronk_front_walk1", "Gronk massive troll, PINK dreadlocks, black baggy t-shirt and pants, pink sneakers, holding vape, front view walking left leg forward"), + ("npcs", "kai_front_walk1", "Kai teenage survivor, GREEN dreadlocks, blue jacket, torn jeans, boots, front view walking left leg forward"), + ("zivali", "fox_red", "red fox wildlife animal, bushy tail, clever expression, side view"), +] + + +def log(msg): + ts = datetime.now().strftime("%H:%M:%S") + print(f"[{ts}] {msg}") + sys.stdout.flush() + + +def git_commit(file_path, category, name): + """Auto-commit generated asset""" + 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, check=True, capture_output=True) + log(f" ๐Ÿ“ Git committed: {rel_path}") + 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": 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"โŒ 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("="*60) + log("๐Ÿš€ FRESH TEST - Generiranje Novih Slik") + log(" Z avtomatskim Git commitom") + log("="*60) + + 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๐ŸŽฏ Generating {len(NEW_ASSETS)} new assets...\n") + + for i, (cat, name, prompt) in enumerate(NEW_ASSETS, 1): + path = OUTPUT_DIR / cat / f"{name}.png" + + if path.exists(): + log(f"[{i}/{len(NEW_ASSETS)}] โญ๏ธ {name} - skipping (exists)") + continue + + log(f"[{i}/{len(NEW_ASSETS)}] ๐ŸŽจ {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" โœ… Generated & transparent!") + git_commit(path, cat, name) + else: + log(f" โŒ FAILED") + + log("\n" + "="*60) + log("๐Ÿš€ FRESH TEST COMPLETE!") + log("="*60) + + +if __name__ == "__main__": + main() diff --git a/scripts/generate_local_final.py b/scripts/generate_local_final.py index c99efd00a..13f1342e5 100644 --- a/scripts/generate_local_final.py +++ b/scripts/generate_local_final.py @@ -11,6 +11,7 @@ import json import time import uuid import requests +import subprocess from pathlib import Path from datetime import datetime @@ -116,6 +117,40 @@ def log(msg): sys.stdout.flush() +def git_commit(file_path, category, name): + """Auto-commit generated asset to Git""" + try: + repo_dir = Path("/Users/davidkotnik/repos/novafarma") + rel_path = file_path.relative_to(repo_dir) + + # Git add + subprocess.run( + ["git", "add", str(rel_path)], + cwd=repo_dir, + check=True, + capture_output=True + ) + + # Git commit + commit_msg = f"๐ŸŽจ Auto-generated asset: {category}/{name}" + result = subprocess.run( + ["git", "commit", "-m", commit_msg], + cwd=repo_dir, + capture_output=True, + text=True + ) + + if result.returncode == 0: + log(f" ๐Ÿ“ Git committed") + return True + else: + # Moลพno da je ลพe committed ali ni sprememb + return False + except Exception as e: + log(f" โš ๏ธ Git: {str(e)[:50]}") + return False + + def create_workflow(prompt_text, output_name, size=512): """Create ComfyUI workflow""" seed = int(time.time() * 1000) % 2147483647 @@ -271,6 +306,8 @@ def main(): if pid and wait_completion(pid) and download_and_process(pid, path): log(f" โœ… DONE (transparent)") + # Auto-commit to Git + git_commit(path, cat, name) success += 1 else: log(f" โŒ FAILED") diff --git a/scripts/regenerate_with_master_ref.py b/scripts/regenerate_with_master_ref.py new file mode 100644 index 000000000..3e2b02371 --- /dev/null +++ b/scripts/regenerate_with_master_ref.py @@ -0,0 +1,175 @@ +#!/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() diff --git a/scripts/run_auto_generation.sh b/scripts/run_auto_generation.sh new file mode 100755 index 000000000..996990b38 --- /dev/null +++ b/scripts/run_auto_generation.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# ๐ŸŽฎ DOLINA SMRTI - Avtomatski generator +# Teฤe v ozadju, logs v datoteko + +cd /Users/davidkotnik/repos/novafarma/scripts + +# Kreiraj log file z timestampom +LOG_FILE="/Users/davidkotnik/repos/novafarma/generation_$(date +%Y%m%d_%H%M%S).log" + +echo "๐ŸŽฎ Starting DOLINA SMRTI Asset Generation..." +echo "๐Ÿ“‚ Logs: $LOG_FILE" +echo "โฑ๏ธ Start time: $(date)" +echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" +echo "" +echo "๐Ÿ”ฅ Generation je v teku... lahko zaprete terminal ali pustite raฤun vklopljen." +echo " Za preverjanje statusa: tail -f $LOG_FILE" +echo "" + +# Zaลพeni generacijo v ozadju z logs +nohup python3 generate_local_final.py > "$LOG_FILE" 2>&1 & + +# Shrani PID +PID=$! +echo "โœ… Process ID: $PID" +echo "$PID" > /tmp/dolina_generation.pid + +echo "" +echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" +echo "๐Ÿ“Š Za spremljanje napredka (live):" +echo " tail -f $LOG_FILE" +echo "" +echo "โน๏ธ Za ustavitev generacije:" +echo " kill $PID" +echo "" +echo "๐ŸŽฏ Ko je konฤano, rezultat bo v:" +echo " /Users/davidkotnik/repos/novafarma/assets/images/" +echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" diff --git a/scripts/test_category_samples.py b/scripts/test_category_samples.py new file mode 100644 index 000000000..0ce8dc1d3 --- /dev/null +++ b/scripts/test_category_samples.py @@ -0,0 +1,201 @@ +#!/usr/bin/env python3 +""" +๐Ÿงช CATEGORY TEST SAMPLES +Po 1 stvar iz vsake kategorije - kvalitetni check pred mnoลพiฤno generacijo +""" + +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 sprite, cartoon vector style, clean smooth outlines, full body visible, isolated on pure white background" +NEGATIVE = "pixel art, pixelated, 3d render, realistic photo, anime, blurry, watermark, text, green background" + +# ๐Ÿงช TEST SAMPLES - Po 1 iz vsake kategorije (BREZ NPCs!) +TEST_SAMPLES = [ + # ลฝivali + ("zivali", "rabbit_white", "white rabbit animal, long ears, fluffy tail, cute, side view"), + + # Bosses + ("bosses", "boss_dragon_ice", "Ice Dragon boss, massive blue dragon, frost breath, ice scales, menacing, full body"), + + # Items - Tool + ("items", "tool_pickaxe_iron", "iron pickaxe tool, metal head, wooden handle, mining equipment"), + + # Items - Weapon + ("items", "weapon_bow_wood", "wooden bow with arrow, hunting weapon, medieval style"), + + # Items - Magic + ("items", "wand_lightning", "lightning magic wand, yellow crystal tip, electric sparks, glowing"), + + # Items - Potion + ("items", "potion_mana", "mana potion, blue liquid in glass bottle, magical glow"), + + # Items - Food + ("items", "food_bread", "bread loaf, fresh baked, brown crust, artisan style"), + + # Environment - Tree + ("environment", "tree_pine", "pine tree, evergreen, cone shaped, forest tree, full tree"), + + # Environment - Object + ("environment", "barrel_wood", "wooden storage barrel, medieval style, brown wood"), + + # Mutanti + ("mutanti", "slime_purple", "purple poison slime monster, bouncing blob, toxic bubbles"), +] + + +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"๐Ÿงช Test sample: {category}/{name}"], cwd=REPO_DIR, check=True, capture_output=True) + log(f" ๐Ÿ“ Committed") + 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": 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("๐Ÿงช CATEGORY TEST SAMPLES") + log(" Po 1 iz vsake kategorije - kvalitetni check") + log(" NPCs IZKLJUฤŒENI iz avtomatike!") + 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_SAMPLES)} test samples...\n") + + success = 0 + + for i, (cat, name, prompt) in enumerate(TEST_SAMPLES, 1): + path = OUTPUT_DIR / cat / f"{name}.png" + + if path.exists(): + log(f"[{i}/{len(TEST_SAMPLES)}] โญ๏ธ {name} - exists") + continue + + log(f"[{i}/{len(TEST_SAMPLES)}] ๐ŸŽจ {cat}/{name}") + + size = 768 if cat == "bosses" else 512 + wf = create_workflow(prompt, name, size) + pid = queue_prompt(wf) + + if pid and wait_completion(pid) and download_and_process(pid, path): + log(f" โœ… Done!") + git_commit(path, cat, name) + success += 1 + + # Open image immediately for review + os.system(f"open {path}") + else: + log(f" โŒ Failed") + + # Brief pause between generations + if i < len(TEST_SAMPLES): + time.sleep(2) + + log("\n" + "="*70) + log(f"๐Ÿงช TEST SAMPLES COMPLETE! ({success}/{len(TEST_SAMPLES)})") + log(" Slike so odprte - preverite kakovost!") + log("="*70) + log("\n๐Ÿ’ก ฤŒe je kakovost OK โ†’ lahko zaลพenem VSE ostale") + log(" (items, environment, animals, bosses, mutants)") + log(" NPCs ostanejo ROฤŒNO!") + + +if __name__ == "__main__": + main() diff --git a/scripts/test_generation.py b/scripts/test_generation.py new file mode 100755 index 000000000..da5bd0c0e --- /dev/null +++ b/scripts/test_generation.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python3 +""" +๐Ÿงช TEST GENERATION - Generira 5 testnih slik +Z avtomatskim Git commitom +""" + +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: + print("๐Ÿ“ฆ Installing rembg...") + 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") + +STYLE = "2D indie game sprite, cartoon vector style, clean smooth lines, full body visible, isolated on pure white background #FFFFFF" +NEGATIVE = "pixel art, pixelated, 3d, realistic, photo, blurry, watermark, text, green background" + +# ๐Ÿงช TEST ASSETS - Par hitrih testnih slik +TEST_ASSETS = [ + ("npcs", "npc_elder", "wise tribal elder NPC, walking stick, long white beard, robes"), + ("npcs", "npc_child", "survivor orphan child NPC, oversized clothes, teddy bear"), + ("zivali", "goat_brown", "brown goat farm animal, small horns, playful"), + ("items", "tool_hammer", "hammer building tool, wooden handle"), + ("environment", "flower_red", "red flowers patch, blooming"), +] + + +def log(msg): + ts = datetime.now().strftime("%H:%M:%S") + print(f"[{ts}] {msg}") + sys.stdout.flush() + + +def git_commit(file_path, category, name): + """Auto-commit generated asset""" + try: + rel_path = file_path.relative_to(REPO_DIR) + + # Git add + subprocess.run( + ["git", "add", str(rel_path)], + cwd=REPO_DIR, + check=True, + capture_output=True + ) + + # Git commit + commit_msg = f"๐ŸŽจ Generated asset: {category}/{name}" + subprocess.run( + ["git", "commit", "-m", commit_msg], + cwd=REPO_DIR, + check=True, + capture_output=True + ) + + log(f" โœ… Git committed: {rel_path}") + return True + except subprocess.CalledProcessError as e: + log(f" โš ๏ธ Git commit failed (moลพno ลพe committed): {e}") + 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": 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"โŒ 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) + data = r.json() + if prompt_id in data and data[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) + + # Remove background + from io import BytesIO + src_img = Image.open(BytesIO(r.content)) + transparent_img = remove(src_img) + 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("=" * 60) + log("๐Ÿงช TEST GENERATION - 5 Testnih Slik") + log(" Z avtomatskim Git commitom") + log("=" * 60) + + # Check ComfyUI + try: + r = requests.get(f"{COMFYUI_URL}/system_stats", timeout=5) + v = r.json()["system"]["comfyui_version"] + log(f"โœ… ComfyUI v{v} running") + except: + log("โŒ ComfyUI not running!") + return + + log(f"\n๐ŸŽฏ Generating {len(TEST_ASSETS)} test assets...\n") + + success, fail = 0, 0 + start_time = time.time() + + for i, (cat, name, prompt) in enumerate(TEST_ASSETS, 1): + path = OUTPUT_DIR / cat / f"{name}.png" + + # Skip if exists + if path.exists(): + log(f"[{i}/{len(TEST_ASSETS)}] โญ๏ธ {name} - already exists") + continue + + log(f"[{i}/{len(TEST_ASSETS)}] ๐ŸŽจ Generating {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" โœ… Image saved (transparent)") + + # Auto-commit + git_commit(path, cat, name) + + success += 1 + else: + log(f" โŒ FAILED") + fail += 1 + + elapsed = time.time() - start_time + log("\n" + "=" * 60) + log("๐Ÿงช TEST COMPLETE!") + log(f" โœ… Success: {success}") + log(f" โŒ Failed: {fail}") + log(f" โฑ๏ธ Time: {elapsed:.1f}s ({elapsed/60:.1f} min)") + log(f" ๐Ÿ“ Output: {OUTPUT_DIR}") + log("=" * 60) + + +if __name__ == "__main__": + main()