""" Generation Request Model ======================== Data model for image generation requests. Provides type-safe structure for all generation parameters. """ from dataclasses import dataclass, field from typing import List, Optional from PIL import Image @dataclass class GenerationRequest: """ Represents a request for image generation. This is the standard interface for all generation requests, regardless of backend or generation type. Attributes: prompt: Text prompt describing desired image backend: Backend to use ("Gemini API (Cloud)" or "OmniGen2 (Local)") aspect_ratio: Aspect ratio (e.g. "16:9", "3:4") temperature: Temperature/creativity parameter (0.0-1.0) input_images: Optional list of input images for image-to-image is_character_sheet: Mark input images as character sheets metadata: Additional metadata for tracking """ # Required fields prompt: str backend: str aspect_ratio: str temperature: float # Optional fields input_images: Optional[List[Image.Image]] = None is_character_sheet: List[bool] = field(default_factory=list) metadata: dict = field(default_factory=dict) negative_prompt: Optional[str] = None seed: Optional[int] = None def __post_init__(self): """Validate and normalize data after initialization.""" # Ensure prompt is string if not isinstance(self.prompt, str): raise TypeError("prompt must be a string") # Strip whitespace from prompt self.prompt = self.prompt.strip() # Ensure temperature is numeric if not isinstance(self.temperature, (int, float)): raise TypeError("temperature must be numeric") # Convert temperature to float self.temperature = float(self.temperature) # Normalize input_images (convert None to empty list) if self.input_images is None: self.input_images = [] # Ensure is_character_sheet matches input_images length if len(self.is_character_sheet) < len(self.input_images): # Pad with False self.is_character_sheet.extend( [False] * (len(self.input_images) - len(self.is_character_sheet)) ) @property def has_input_images(self) -> bool: """Check if request has input images.""" return self.input_images is not None and len(self.input_images) > 0 @property def image_count(self) -> int: """Get number of input images.""" return len(self.input_images) if self.input_images else 0 @property def is_text_to_image(self) -> bool: """Check if this is a text-to-image request (no input images).""" return not self.has_input_images @property def is_image_to_image(self) -> bool: """Check if this is an image-to-image request (has input images).""" return self.has_input_images def to_dict(self) -> dict: """ Convert request to dictionary (for metadata/logging). Note: Images are not included in dict (only count). Returns: Dictionary representation """ return { "prompt": self.prompt, "backend": self.backend, "aspect_ratio": self.aspect_ratio, "temperature": self.temperature, "input_image_count": self.image_count, "is_character_sheet": self.is_character_sheet, "negative_prompt": self.negative_prompt, "seed": self.seed, "metadata": self.metadata } def __repr__(self) -> str: """String representation for debugging.""" return ( f"GenerationRequest(" f"prompt='{self.prompt[:50]}...', " f"backend='{self.backend}', " f"aspect_ratio='{self.aspect_ratio}', " f"temperature={self.temperature}, " f"input_images={self.image_count})" )