YiYiXu commited on
Commit
9adb943
·
verified ·
1 Parent(s): 73413bc

Create ideogram_block.py

Browse files
Files changed (1) hide show
  1. ideogram_block.py +150 -0
ideogram_block.py ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
+ from typing import Optional
4
+ from PIL import Image
5
+ from io import BytesIO
6
+ from diffusers.utils import load_image
7
+ from diffusers.modular_pipelines import (
8
+ PipelineState,
9
+ ModularPipelineBlocks,
10
+ InputParam,
11
+ OutputParam,
12
+ )
13
+
14
+ IDEOGRAM_GENERATE_URL = "https://api.ideogram.ai/v1/ideogram-v3/generate"
15
+
16
+ class CreateCharacterImageBlock(ModularPipelineBlocks):
17
+
18
+ @property
19
+ def inputs(self) -> list[InputParam]:
20
+ return [
21
+ InputParam(
22
+ name="prompt",
23
+ type_hint=str,
24
+ description="Text prompt describing the desired image."
25
+ ),
26
+ InputParam(
27
+ name="character_image",
28
+ type_hint=Image.Image,
29
+ description="A single PIL Image to use as the character reference."
30
+ ),
31
+ ]
32
+
33
+ @property
34
+ def intermediate_outputs(self) -> list[OutputParam]:
35
+ return [
36
+ OutputParam(
37
+ name="image",
38
+ type_hint=Image.Image,
39
+ description="Generated image."
40
+ ),
41
+ OutputParam(
42
+ name="image_url",
43
+ type_hint=str,
44
+ description="URL to the generated image."
45
+ )
46
+ ]
47
+
48
+ @staticmethod
49
+ def generate_image_with_character_reference(
50
+ prompt: str,
51
+ character_image: Image.Image, *,
52
+ style_type: str = "AUTO", # "GENERAL", "REALISTIC", "DESIGN", "FICTION"
53
+ seed: Optional[int] = None,
54
+ resolution: Optional[str] = "1024x1024",
55
+ request_timeout: int = 60,
56
+ ) -> str:
57
+ """
58
+ Generate an image using Ideogram's character reference feature.
59
+
60
+ Args:
61
+ api_key: Your Ideogram API key.
62
+ prompt: Text prompt describing the desired image.
63
+ character_image: A single PIL Image to use as the character reference.
64
+ style_type: Ideogram style selection. "AUTO" lets the API decide.
65
+ seed: Random seed for reproducibility.
66
+ resolution: Image resolution.
67
+ request_timeout: Timeout for HTTP requests (seconds).
68
+
69
+ Returns:
70
+ str: URL to the generated image (default)
71
+
72
+ Raises:
73
+ RuntimeError on API errors or missing results.
74
+ """
75
+ # Resolve API key from environment
76
+ api_key = os.getenv("IDEOGRAM_API_KEY")
77
+
78
+ if not api_key:
79
+ raise RuntimeError(
80
+ "IDEOGRAM_API_KEY is not set. Provide api_key param or set env var IDEOGRAM_API_KEY."
81
+ )
82
+
83
+ headers = {"Api-Key": api_key}
84
+
85
+ # Validate image type
86
+ if not isinstance(character_image, Image.Image):
87
+ raise TypeError("character_image must be a PIL.Image.Image")
88
+
89
+ # Validate seed and mutually exclusive resolution/aspect_ratio
90
+ if seed is not None:
91
+ if not (0 <= int(seed) <= 2147483647):
92
+ raise ValueError("seed must be between 0 and 2147483647 inclusive")
93
+
94
+ # Build multipart with a single character reference image
95
+ with BytesIO() as buf:
96
+ character_image.save(buf, format="PNG")
97
+ buf.seek(0)
98
+ files = [
99
+ (
100
+ "character_reference_images",
101
+ ("character.png", buf, "image/png"),
102
+ )
103
+ ]
104
+
105
+ data: dict = {
106
+ "prompt": prompt,
107
+ "style_type": style_type,
108
+ }
109
+ if seed is not None:
110
+ data["seed"] = str(int(seed))
111
+ if resolution is not None:
112
+ data["resolution"] = resolution
113
+
114
+ resp = requests.post(
115
+ IDEOGRAM_GENERATE_URL,
116
+ headers=headers,
117
+ data=data,
118
+ files=files,
119
+ timeout=request_timeout,
120
+ )
121
+ if not resp.ok:
122
+ raise RuntimeError(f"Ideogram API error {resp.status_code}: {resp.text}")
123
+
124
+ payload = resp.json()
125
+ # Expected: payload['data'][0]['url']
126
+ try:
127
+ image_url = payload["data"][0]["url"]
128
+ except Exception as e:
129
+ raise RuntimeError(f"Unexpected Ideogram response format: {payload}") from e
130
+
131
+ return image_url
132
+
133
+ def __call__(self, components: dict, state: PipelineState):
134
+
135
+ block_state = self.get_block_state(state)
136
+
137
+ if isinstance(block_state.character_image, str):
138
+ character_image = load_image(block_state.character_image)
139
+ elif isinstance(block_state.character_image, Image.Image):
140
+ character_image = block_state.character_image
141
+ else:
142
+ raise ValueError(f"Invalid character image type: {type(block_state.character_image)}")
143
+
144
+ block_state.image_url = self.generate_image_with_character_reference(
145
+ prompt=block_state.prompt,
146
+ character_image=character_image,
147
+ )
148
+ block_state.image = load_image(block_state.image_url)
149
+ self.set_block_state(state, block_state)
150
+ return components, state