File size: 4,003 Bytes
5b6e956
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
"""
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})"
        )