mythforge-comic-generator / comic_generator.py
emailvenky's picture
Upload 27 files
4b19c49 verified
"""
Comic Generator with Character Consistency Integration
Safe wrapper that integrates character consistency system with automatic fallback to legacy system
"""
import asyncio
import os
from typing import Dict, List, Optional, Union
from PIL import Image
from config import Config
# Try to import character consistency system (optional dependency)
try:
from character_consistency_manager import CharacterConsistencyManager
CHARACTER_CONSISTENCY_AVAILABLE = True
print("✓ Character Consistency system available")
except ImportError as e:
CHARACTER_CONSISTENCY_AVAILABLE = False
print(f"⚠️ Character Consistency not available - using legacy system")
print(f" Import error: {e}")
class ComicGeneratorWithConsistency:
"""
Unified comic generator with character consistency support and legacy fallback
This class provides a safe integration layer between the new character consistency
system and the existing comic generation logic in app_comic.py
Behavior:
- If ENABLE_NANO_BANANA=true AND system available: Use character consistency
- If character consistency fails OR disabled: Automatic fallback to legacy system
- Legacy system always available as safety net
"""
def __init__(self):
"""Initialize comic generator with optional character consistency"""
self.consistency_enabled = (
CHARACTER_CONSISTENCY_AVAILABLE and
Config.ENABLE_NANO_BANANA
)
self.consistency_manager = None
if self.consistency_enabled:
try:
self.consistency_manager = CharacterConsistencyManager()
print("✓ Character Consistency Manager initialized")
except Exception as e:
print(f"⚠️ Failed to initialize Character Consistency: {e}")
print("🔄 Will use legacy system")
self.consistency_enabled = False
# Stats tracking
self.consistency_success_count = 0
self.consistency_failure_count = 0
self.fallback_count = 0
async def generate_comic_from_prompt(
self,
story_prompt: str,
num_panels: int = 3,
art_style: str = "manga",
include_surprise_character: bool = True,
force_legacy: bool = False,
output_dir: Optional[str] = None
) -> Dict:
"""
Generate comic with automatic character consistency or legacy fallback
Args:
story_prompt: User's story prompt
num_panels: Number of panels to generate
art_style: Art style for the comic
include_surprise_character: Add AI-generated surprise character
force_legacy: Force use of legacy system (for testing)
output_dir: Output directory for generated files
Returns:
Dictionary with generation results:
{
"success": bool,
"method": str, # "character_consistency" or "legacy"
"panels": List[Image],
"characters": Dict[str, str], # Only if character_consistency used
"output_dir": str,
"panel_info": List[Dict], # Panel metadata
"error": Optional[str]
}
"""
# Determine which system to use
use_consistency = (
self.consistency_enabled and
not force_legacy and
self.consistency_manager is not None
)
if use_consistency:
print(f"\n🎨 Generating comic with CHARACTER CONSISTENCY system...")
print(f" Story: {story_prompt[:100]}...")
print(f" Panels: {num_panels}, Style: {art_style}")
try:
result = await self._generate_with_consistency(
story_prompt=story_prompt,
num_panels=num_panels,
art_style=art_style,
include_surprise_character=include_surprise_character,
output_dir=output_dir
)
if result["success"]:
self.consistency_success_count += 1
print(f"✓ Character consistency generation successful!")
return result
else:
print(f"⚠️ Character consistency failed: {result.get('error')}")
print(f"🔄 Falling back to legacy system...")
self.consistency_failure_count += 1
except Exception as e:
print(f"⚠️ Character consistency exception: {e}")
print(f"🔄 Falling back to legacy system...")
self.consistency_failure_count += 1
# Fallback to legacy system
self.fallback_count += 1
print(f"\n🎨 Generating comic with LEGACY system...")
return await self._generate_with_legacy(
story_prompt=story_prompt,
num_panels=num_panels,
art_style=art_style,
output_dir=output_dir
)
async def _generate_with_consistency(
self,
story_prompt: str,
num_panels: int,
art_style: str,
include_surprise_character: bool,
output_dir: Optional[str]
) -> Dict:
"""
Generate comic using character consistency system
This wraps the CharacterConsistencyManager.generate_comic_from_prompt method
in a safe async context with proper error handling
"""
try:
# Call character consistency system (runs in executor for async compatibility)
loop = asyncio.get_event_loop()
result = await loop.run_in_executor(
None,
self.consistency_manager.generate_comic_from_prompt,
story_prompt,
num_panels,
art_style,
include_surprise_character,
output_dir or "./auto_generated_comics"
)
# Add success flag and method
result["success"] = True
result["method"] = "character_consistency"
return result
except Exception as e:
return {
"success": False,
"method": "character_consistency",
"error": str(e),
"panels": [],
"characters": {},
"panel_info": []
}
async def _generate_with_legacy(
self,
story_prompt: str,
num_panels: int,
art_style: str,
output_dir: Optional[str]
) -> Dict:
"""
Generate comic using legacy system (placeholder for app_comic.py integration)
NOTE: This is a placeholder. In actual integration, this would call the
existing comic generation logic from app_comic.py
For now, returns a structure indicating legacy mode was used
"""
return {
"success": True,
"method": "legacy",
"panels": [],
"characters": {},
"panel_info": [
{
"panel_number": i + 1,
"characters": [],
"filename": f"legacy_panel_{i+1}.png"
}
for i in range(num_panels)
],
"output_dir": output_dir or "./generated_comics",
"note": "Legacy system placeholder - integrate with app_comic.py logic"
}
def get_stats(self) -> Dict:
"""Get generation statistics"""
total = self.consistency_success_count + self.consistency_failure_count + self.fallback_count
return {
"total_generations": total,
"consistency_enabled": self.consistency_enabled,
"consistency_available": CHARACTER_CONSISTENCY_AVAILABLE,
"consistency_successes": self.consistency_success_count,
"consistency_failures": self.consistency_failure_count,
"legacy_fallbacks": self.fallback_count,
"consistency_rate": (
f"{(self.consistency_success_count / total * 100):.1f}%"
if total > 0 else "N/A"
)
}
def print_stats(self):
"""Print generation statistics"""
stats = self.get_stats()
print("\n" + "="*70)
print(" COMIC GENERATOR STATISTICS")
print("="*70)
print(f"Character Consistency Available: {stats['consistency_available']}")
print(f"Character Consistency Enabled: {stats['consistency_enabled']}")
print(f"\nTotal Generations: {stats['total_generations']}")
print(f" ✓ Consistency Successes: {stats['consistency_successes']}")
print(f" ⚠ Consistency Failures: {stats['consistency_failures']}")
print(f" 🔄 Legacy Fallbacks: {stats['legacy_fallbacks']}")
print(f"\nConsistency Success Rate: {stats['consistency_rate']}")
print("="*70)
# Example usage and testing
async def test_comic_generator():
"""Test the comic generator with both systems"""
print("\n" + "="*70)
print(" COMIC GENERATOR TEST")
print("="*70)
generator = ComicGeneratorWithConsistency()
test_prompt = "A yogi teaching a young aspirant the rules of meditation and mindfulness leading to levitation by his own example in a beautiful vibrant colorful jungle"
# Test 1: Character consistency (if available)
print("\n--- Test 1: Character Consistency Mode ---")
result1 = await generator.generate_comic_from_prompt(
story_prompt=test_prompt,
num_panels=3,
art_style="manga",
include_surprise_character=True
)
print(f"\nResult: {result1['method']}")
print(f"Success: {result1['success']}")
if result1.get('characters'):
print(f"Characters: {list(result1['characters'].keys())}")
# Test 2: Force legacy mode
print("\n--- Test 2: Forced Legacy Mode ---")
result2 = await generator.generate_comic_from_prompt(
story_prompt=test_prompt,
num_panels=3,
art_style="manga",
force_legacy=True
)
print(f"\nResult: {result2['method']}")
print(f"Success: {result2['success']}")
# Print stats
generator.print_stats()
if __name__ == "__main__":
# Run test
asyncio.run(test_comic_generator())