ghmk's picture
Initial deployment of Character Forge
5b6e956
"""
Application Settings and Configuration
=======================================
Centralized configuration management for Nano Banana Streamlit.
All environment variables, paths, and constants defined here.
"""
import os
from pathlib import Path
from typing import Optional
class Settings:
"""
Application-wide settings and configuration.
This class uses class methods and properties to provide
a simple interface for accessing configuration values.
"""
# =========================================================================
# PROJECT PATHS
# =========================================================================
# Root directory of the project
PROJECT_ROOT = Path(__file__).parent.parent
# Output directory for generated images
OUTPUT_DIR = PROJECT_ROOT / "outputs"
# Ensure output directory exists
OUTPUT_DIR.mkdir(exist_ok=True)
# Subdirectories for different generation types
CHARACTER_SHEETS_DIR = OUTPUT_DIR / "character_sheets"
WARDROBE_CHANGES_DIR = OUTPUT_DIR / "wardrobe_changes"
COMPOSITIONS_DIR = OUTPUT_DIR / "compositions"
STANDARD_DIR = OUTPUT_DIR / "standard"
# Create all subdirectories
for directory in [CHARACTER_SHEETS_DIR, WARDROBE_CHANGES_DIR,
COMPOSITIONS_DIR, STANDARD_DIR]:
directory.mkdir(exist_ok=True)
# Log file
LOG_FILE = OUTPUT_DIR / "generation.log"
# =========================================================================
# API KEYS AND CREDENTIALS
# =========================================================================
@classmethod
def get_gemini_api_key(cls) -> Optional[str]:
"""
Get Gemini API key from environment variable.
Returns:
API key string if set, None otherwise
"""
return os.environ.get("GEMINI_API_KEY")
# =========================================================================
# BACKEND CONFIGURATION
# =========================================================================
# OmniGen2 server URL
OMNIGEN2_BASE_URL = "http://127.0.0.1:9002"
# ComfyUI server URL
COMFYUI_BASE_URL = "http://127.0.0.1:8188"
# Backend timeout (seconds)
# Set to None for local backends (ComfyUI) - no timeout needed, monitor logs instead
# For network/API backends (Gemini), keep a reasonable timeout
BACKEND_TIMEOUT = None # No timeout for local models (was 600s / 10 min)
# =========================================================================
# GENERATION PARAMETERS
# =========================================================================
# Available aspect ratios
ASPECT_RATIOS = {
"1:1 (1024x1024)": "1:1",
"16:9 (1344x768)": "16:9",
"9:16 (768x1344)": "9:16",
"3:2 (1248x832)": "3:2",
"2:3 (832x1248)": "2:3",
"3:4 (864x1184)": "3:4", # Character portraits (Gemini actual output)
"4:3 (1344x1008)": "4:3",
"4:5 (1024x1280)": "4:5",
"5:4 (1280x1024)": "5:4",
"21:9 (1536x640)": "21:9",
}
# Default generation parameters
DEFAULT_ASPECT_RATIO = "16:9 (1344x768)"
DEFAULT_TEMPERATURE = 0.4
MIN_TEMPERATURE = 0.0
MAX_TEMPERATURE = 1.0
TEMPERATURE_STEP = 0.05
# =========================================================================
# CHARACTER FORGE SETTINGS
# =========================================================================
# Aspect ratios for character sheet views
PORTRAIT_ASPECT_RATIO = "3:4" # For face portraits (864x1184)
BODY_ASPECT_RATIO = "9:16" # For full body shots (768x1344)
# Generation temperatures for each stage
PORTRAIT_TEMPERATURE = 0.35 # Lower for consistency
BODY_TEMPERATURE = 0.5 # Slightly higher for variety
# Default negative prompts for ComfyUI qwen workflow
# These help steer generation away from common errors
DEFAULT_NEGATIVE_PROMPTS = {
"stage_0a": "blurry, low quality, distorted, deformed, disfigured, bad anatomy, extra limbs, missing limbs, multiple people",
"stage_0b": "different person, wrong face, altered features, different hair color, different eye color, low quality, blurry",
"stage_1": "side view, profile, back view, different person, different face, altered facial features, different clothing, wrong outfit, blurry, low quality",
"stage_2": "front view, facing camera, back view, three-quarter view, different person, different face, altered features, different clothing, wrong outfit, blurry, low quality",
"stage_3": "front view, facing camera, back view, rear view, different person, different face, different body, altered proportions, different clothing, costume change, nude, undressed, blurry, low quality, cut off, cropped, incomplete body",
"stage_4": "front view, facing camera, side view, profile view, face visible, different person, different body, different clothing, costume change, nude, undressed, blurry, low quality, cut off, cropped, incomplete body"
}
# Composition settings
CHARACTER_SHEET_SPACING = 20 # Pixels between rows
CHARACTER_SHEET_BACKGROUND = "#2C2C2C" # Dark gray
# Retry logic
MAX_RETRIES = 3
RETRY_BASE_DELAY = 2 # Seconds (exponential backoff)
RATE_LIMIT_DELAY_MIN = 2.0 # Seconds
RATE_LIMIT_DELAY_MAX = 3.0 # Seconds
# =========================================================================
# LOGGING CONFIGURATION
# =========================================================================
LOG_LEVEL = "INFO"
LOG_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
# Rotating file handler settings
LOG_MAX_BYTES = 10 * 1024 * 1024 # 10 MB
LOG_BACKUP_COUNT = 5 # Keep 5 backup files
# =========================================================================
# UI CONFIGURATION
# =========================================================================
# Maximum image upload size (MB)
MAX_IMAGE_UPLOAD_SIZE = 20 # MB
# Image display size
PREVIEW_IMAGE_WIDTH = 512 # Pixels
# History display
MAX_HISTORY_ITEMS = 20
# =========================================================================
# COMPOSITION ASSISTANT SETTINGS
# =========================================================================
# Image type options
IMAGE_TYPES = [
"Subject/Character",
"Background/Environment",
"Style Reference",
"Product",
"Texture",
"Not Used"
]
# Shot type options
SHOT_TYPES = [
"close-up shot",
"medium shot",
"full body shot",
"wide shot",
"extreme close-up",
"establishing shot"
]
# Camera angle options
CAMERA_ANGLES = [
"eye-level perspective",
"low-angle perspective",
"high-angle perspective",
"bird's-eye view",
"Dutch angle (tilted)",
"over-the-shoulder"
]
# Lighting options
LIGHTING_OPTIONS = [
"Auto (match images)",
"natural daylight",
"soft studio lighting",
"dramatic side lighting",
"golden hour",
"blue hour",
"moody low-key",
"high-key bright",
"rim lighting"
]
# =========================================================================
# BACKEND TYPE ENUMERATION
# =========================================================================
BACKEND_GEMINI = "Gemini API (Cloud)"
BACKEND_OMNIGEN2 = "OmniGen2 (Local)"
BACKEND_COMFYUI = "ComfyUI (Local)"
BACKEND_FLUX_KREA = "FLUX Krea (Local)" # For initial portrait generation
BACKEND_FLUX_KONTEXT = "FLUX Kontext (Local)" # For perspective transformations
AVAILABLE_BACKENDS = [
BACKEND_GEMINI,
BACKEND_OMNIGEN2,
BACKEND_COMFYUI,
BACKEND_FLUX_KREA,
BACKEND_FLUX_KONTEXT
]
# =========================================================================
# HELPER METHODS
# =========================================================================
@classmethod
def get_aspect_ratio_value(cls, display_name: str) -> str:
"""
Convert display name to aspect ratio value.
Args:
display_name: Display name like "16:9 (1344x768)"
Returns:
Aspect ratio value like "16:9"
"""
return cls.ASPECT_RATIOS.get(display_name, "1:1")
@classmethod
def is_gemini_configured(cls) -> bool:
"""Check if Gemini API is configured (API key set)."""
return cls.get_gemini_api_key() is not None
@classmethod
def validate_temperature(cls, temperature: float) -> float:
"""
Validate and clamp temperature to valid range.
Args:
temperature: Temperature value to validate
Returns:
Validated temperature within [MIN_TEMPERATURE, MAX_TEMPERATURE]
"""
return max(cls.MIN_TEMPERATURE, min(cls.MAX_TEMPERATURE, temperature))
# Make settings instance available for import
settings = Settings()