""" Generation Result Model ======================= Data model for image generation results. Provides consistent structure for results from any backend. """ from dataclasses import dataclass, field from typing import Optional from datetime import datetime from pathlib import Path from PIL import Image @dataclass class GenerationResult: """ Represents the result of an image generation request. This is the standard interface for all generation results, regardless of backend or generation type. Attributes: success: Whether generation succeeded image: Generated image (None if failed) message: Status/error message generation_time: Time taken in seconds saved_path: Path where image was saved (if saved) metadata: Additional metadata """ # Required fields success: bool message: str # Optional fields image: Optional[Image.Image] = None generation_time: Optional[float] = None saved_path: Optional[Path] = None metadata: dict = field(default_factory=dict) # Auto-populated fields timestamp: datetime = field(default_factory=datetime.now) def __post_init__(self): """Validate data after initialization.""" # Ensure success is boolean if not isinstance(self.success, bool): raise TypeError("success must be boolean") # Ensure message is string if not isinstance(self.message, str): raise TypeError("message must be a string") # If success, image should be provided if self.success and self.image is None: raise ValueError("Success result must have an image") # If failed, image should be None if not self.success and self.image is not None: raise ValueError("Failed result should not have an image") @property def is_successful(self) -> bool: """Alias for success field.""" return self.success @property def has_image(self) -> bool: """Check if result has an image.""" return self.image is not None @property def is_saved(self) -> bool: """Check if result was saved to disk.""" return self.saved_path is not None and self.saved_path.exists() @classmethod def success_result( cls, image: Image.Image, message: str = "Generation successful", generation_time: Optional[float] = None, **kwargs ) -> 'GenerationResult': """ Create a successful generation result. Args: image: Generated image message: Success message generation_time: Time taken in seconds **kwargs: Additional metadata Returns: GenerationResult instance """ return cls( success=True, image=image, message=message, generation_time=generation_time, metadata=kwargs ) @classmethod def error_result( cls, message: str, **kwargs ) -> 'GenerationResult': """ Create a failed generation result. Args: message: Error message **kwargs: Additional metadata Returns: GenerationResult instance """ return cls( success=False, image=None, message=message, metadata=kwargs ) def to_dict(self) -> dict: """ Convert result to dictionary (for metadata/logging). Note: Image is not included in dict (only status). Returns: Dictionary representation """ result = { "success": self.success, "message": self.message, "timestamp": self.timestamp.isoformat(), "has_image": self.has_image } if self.generation_time is not None: result["generation_time_seconds"] = round(self.generation_time, 2) if self.saved_path: result["saved_path"] = str(self.saved_path) result["metadata"] = self.metadata return result def __repr__(self) -> str: """String representation for debugging.""" status = "SUCCESS" if self.success else "FAILED" time_str = f", {self.generation_time:.2f}s" if self.generation_time else "" return f"GenerationResult({status}: {self.message}{time_str})"