193 lines
7.2 KiB
Python
193 lines
7.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
🦖 COMPLETE DINO VALLEY DLC GENERATOR
|
|
Generates all remaining 136 assets for Dino Valley biome
|
|
"""
|
|
|
|
import json
|
|
import time
|
|
import os
|
|
from pathlib import Path
|
|
from PIL import Image
|
|
import google.generativeai as genai
|
|
|
|
# Configure Gemini
|
|
genai.configure(api_key=os.environ.get("GEMINI_API_KEY"))
|
|
|
|
REPO = Path("/Users/davidkotnik/repos/novafarma")
|
|
MANIFEST = REPO / "DINO_VALLEY_COMPLETE_MANIFEST.json"
|
|
OUTPUT_DIR = REPO / "assets/slike/dinozavri"
|
|
|
|
# Style prompts
|
|
STYLE_A_BASE = "ISOLATED ON PURE WHITE BACKGROUND. Vibrant cartoon vector art with bold black outlines, flat colors, cute and playful style. NO shadows, NO gradients. Clean cel-shaded look."
|
|
STYLE_B_BASE = "ISOLATED ON PURE WHITE BACKGROUND. Dark hand-drawn 2D indie game art. Noir style with high contrast, sketchy linework, dramatic shadows. Gritty and atmospheric."
|
|
|
|
def create_preview(image_path: Path, size=256):
|
|
"""Create preview version"""
|
|
try:
|
|
img = Image.open(image_path)
|
|
preview = img.resize((size, size), Image.Resampling.LANCZOS)
|
|
preview_path = image_path.parent / f"{image_path.stem}_preview_{size}x{size}.png"
|
|
preview.save(preview_path, 'PNG', optimize=True)
|
|
return preview_path
|
|
except Exception as e:
|
|
print(f" ⚠️ Preview failed: {e}")
|
|
return None
|
|
|
|
def generate_image(prompt: str, output_path: Path, log_file):
|
|
"""Generate single image using Gemini"""
|
|
start = time.time()
|
|
|
|
try:
|
|
print(f" 🎨 Generating: {output_path.name}")
|
|
log_file.write(f"{time.strftime('%H:%M:%S')} - Generating {output_path.name}\n")
|
|
log_file.flush()
|
|
|
|
model = genai.GenerativeModel('gemini-2.5-flash')
|
|
response = model.generate_content([prompt])
|
|
|
|
if hasattr(response, '_result') and response._result.candidates:
|
|
image_data = response._result.candidates[0].content.parts[0].inline_data.data
|
|
|
|
# Save original
|
|
with open(output_path, 'wb') as f:
|
|
f.write(image_data)
|
|
|
|
# Create preview
|
|
preview = create_preview(output_path)
|
|
|
|
elapsed = time.time() - start
|
|
print(f" ✅ Saved: {output_path.name} ({elapsed:.1f}s)")
|
|
log_file.write(f"{time.strftime('%H:%M:%S')} - SUCCESS {output_path.name} ({elapsed:.1f}s)\n")
|
|
log_file.flush()
|
|
|
|
return True
|
|
else:
|
|
print(f" ❌ No image data")
|
|
log_file.write(f"{time.strftime('%H:%M:%S')} - FAILED {output_path.name} - No data\n")
|
|
log_file.flush()
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f" ❌ Error: {e}")
|
|
log_file.write(f"{time.strftime('%H:%M:%S')} - ERROR {output_path.name} - {e}\n")
|
|
log_file.flush()
|
|
return False
|
|
|
|
def run_generation():
|
|
"""Run complete Dino Valley generation"""
|
|
|
|
# Load manifest
|
|
with open(MANIFEST, 'r') as f:
|
|
manifest = json.load(f)
|
|
|
|
# Create output directory
|
|
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Create log
|
|
log_dir = REPO / "logs"
|
|
log_dir.mkdir(exist_ok=True)
|
|
log_file = open(log_dir / f"dino_valley_{time.strftime('%Y%m%d_%H%M%S')}.log", 'w')
|
|
|
|
print("="*70)
|
|
print("🦖 COMPLETE DINO VALLEY DLC GENERATION")
|
|
print("="*70)
|
|
print(f"Total needed: {manifest['total_assets_needed']} assets")
|
|
print(f"Completed: {manifest['completed']} assets")
|
|
print(f"Remaining: {manifest['remaining']} assets")
|
|
print("="*70)
|
|
|
|
log_file.write(f"DINO VALLEY GENERATION - {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
|
|
log_file.write(f"Remaining: {manifest['remaining']} assets\n")
|
|
log_file.write("="*70 + "\n\n")
|
|
log_file.flush()
|
|
|
|
stats = {'total': 0, 'success': 0, 'failed': 0}
|
|
|
|
try:
|
|
# Process each category
|
|
for category_name in manifest['generation_order']:
|
|
# Parse category name
|
|
cat_key = category_name.split(' (')[0]
|
|
|
|
category = manifest['categories'][cat_key]
|
|
|
|
if category['status'] == "✅ 100% COMPLETE":
|
|
print(f"\n⏭️ Skipping {cat_key} (already complete)")
|
|
continue
|
|
|
|
print(f"\n{'='*70}")
|
|
print(f"📦 CATEGORY: {cat_key}")
|
|
print(f"{'='*70}")
|
|
|
|
log_file.write(f"\n{'='*70}\n")
|
|
log_file.write(f"CATEGORY: {cat_key}\n")
|
|
log_file.write(f"{'='*70}\n\n")
|
|
log_file.flush()
|
|
|
|
# Process each asset
|
|
for asset in category['assets']:
|
|
if isinstance(asset, str):
|
|
# Simple string asset (skip, already done)
|
|
continue
|
|
|
|
asset_name = asset['name']
|
|
description = asset['description']
|
|
|
|
# Generate styleA
|
|
stats['total'] += 1
|
|
print(f"\n📸 [{stats['total']}/{manifest['remaining']}] {asset_name}_styleA")
|
|
|
|
prompt = f"{STYLE_A_BASE}\n\n{description}\n\nPrehistoric Dino Valley biome theme. Gamedev sprite asset."
|
|
output_path = OUTPUT_DIR / f"{asset_name}_stylea.png"
|
|
|
|
if generate_image(prompt, output_path, log_file):
|
|
stats['success'] += 1
|
|
else:
|
|
stats['failed'] += 1
|
|
|
|
time.sleep(15) # Rate limiting (5 req/min limit)
|
|
|
|
# Generate styleB
|
|
stats['total'] += 1
|
|
print(f"\n📸 [{stats['total']}/{manifest['remaining']}] {asset_name}_styleB")
|
|
|
|
prompt = f"{STYLE_B_BASE}\n\n{description}\n\nPrehistoric Dino Valley biome theme. Gamedev sprite asset."
|
|
output_path = OUTPUT_DIR / f"{asset_name}_styleb.png"
|
|
|
|
if generate_image(prompt, output_path, log_file):
|
|
stats['success'] += 1
|
|
else:
|
|
stats['failed'] += 1
|
|
|
|
# Progress
|
|
progress = (stats['total'] / manifest['remaining']) * 100
|
|
print(f"\n📊 Progress: {progress:.1f}% | Success: {stats['success']} | Failed: {stats['failed']}")
|
|
|
|
time.sleep(15) # Rate limiting (5 req/min limit)
|
|
|
|
# Final summary
|
|
print("\n" + "="*70)
|
|
print("✅ DINO VALLEY GENERATION COMPLETE!")
|
|
print("="*70)
|
|
print(f"Total: {stats['total']}")
|
|
print(f"✅ Success: {stats['success']}")
|
|
print(f"❌ Failed: {stats['failed']}")
|
|
print(f"📈 Success rate: {stats['success']/stats['total']*100:.1f}%")
|
|
|
|
log_file.write(f"\n{'='*70}\n")
|
|
log_file.write(f"GENERATION COMPLETE\n")
|
|
log_file.write(f"Total: {stats['total']}\n")
|
|
log_file.write(f"Success: {stats['success']}\n")
|
|
log_file.write(f"Failed: {stats['failed']}\n")
|
|
|
|
except KeyboardInterrupt:
|
|
print(f"\n\n⚠️ INTERRUPTED at {stats['total']}")
|
|
log_file.write(f"\n\nINTERRUPTED at {stats['total']}\n")
|
|
|
|
finally:
|
|
log_file.close()
|
|
|
|
if __name__ == "__main__":
|
|
run_generation()
|