ghmk's picture
Initial deployment of Character Forge
5b6e956
"""
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})"