updated
Browse files
app.py
CHANGED
@@ -20,6 +20,44 @@ def load_environment():
|
|
20 |
|
21 |
return os.getenv("HF_TOKEN")
|
22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
def craft_realistic_prompt(base_prompt: str) -> str:
|
24 |
"""
|
25 |
Enhance prompts for more photorealistic results
|
@@ -49,16 +87,6 @@ def query_hf_api(
|
|
49 |
model_url: str = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0",
|
50 |
max_retries: int = 3
|
51 |
) -> Optional[bytes]:
|
52 |
-
|
53 |
-
# Enhanced configuration for realism
|
54 |
-
payload = {
|
55 |
-
"inputs": craft_realistic_prompt(prompt),
|
56 |
-
"parameters": {
|
57 |
-
"negative_prompt": "cartoon, anime, low quality, bad anatomy, blurry, unrealistic, painting, drawing, sketch",
|
58 |
-
"num_inference_steps": 75, # Increased steps
|
59 |
-
"guidance_scale": 8.5, # Higher guidance
|
60 |
-
}
|
61 |
-
}
|
62 |
"""
|
63 |
Query the Hugging Face Inference API with robust error handling and retry mechanism.
|
64 |
|
@@ -85,12 +113,13 @@ def query_hf_api(
|
|
85 |
"Content-Type": "application/json"
|
86 |
}
|
87 |
|
88 |
-
# Payload with
|
89 |
payload = {
|
90 |
-
"inputs": prompt,
|
91 |
"parameters": {
|
92 |
-
"negative_prompt": "low quality, bad anatomy, blurry",
|
93 |
-
"num_inference_steps":
|
|
|
94 |
}
|
95 |
}
|
96 |
|
@@ -116,20 +145,22 @@ def query_hf_api(
|
|
116 |
|
117 |
raise RuntimeError("Unexpected error in image generation")
|
118 |
|
119 |
-
def generate_image(prompt: str) -> Tuple[Optional[Image.Image], str]:
|
120 |
"""
|
121 |
Generate an image from a text prompt.
|
122 |
|
123 |
Args:
|
124 |
prompt (str): Text description for image generation
|
|
|
125 |
|
126 |
Returns:
|
127 |
-
Tuple[Optional[Image.Image], str]:
|
|
|
128 |
"""
|
129 |
try:
|
130 |
# Validate prompt
|
131 |
if not prompt or not prompt.strip():
|
132 |
-
return None, "Error: Prompt cannot be empty"
|
133 |
|
134 |
# Generate image bytes
|
135 |
image_bytes = query_hf_api(prompt)
|
@@ -137,11 +168,14 @@ def generate_image(prompt: str) -> Tuple[Optional[Image.Image], str]:
|
|
137 |
# Convert to PIL Image
|
138 |
image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
|
139 |
|
140 |
-
|
|
|
|
|
|
|
141 |
|
142 |
except Exception as e:
|
143 |
print(f"Image generation error: {e}")
|
144 |
-
return None, f"Error: {str(e)}"
|
145 |
|
146 |
def create_gradio_interface():
|
147 |
"""
|
@@ -164,10 +198,17 @@ def create_gradio_interface():
|
|
164 |
# Prompt Input
|
165 |
text_input = gr.Textbox(
|
166 |
label="Enter your image prompt",
|
167 |
-
placeholder="e.g., '
|
168 |
lines=3
|
169 |
)
|
170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
171 |
# Generate Button
|
172 |
generate_button = gr.Button("✨ Generate Image", variant="primary")
|
173 |
|
@@ -182,12 +223,18 @@ def create_gradio_interface():
|
|
182 |
# Status Output
|
183 |
status_output = gr.Textbox(label="Status")
|
184 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
# Event Handlers
|
186 |
-
generate_button.click(
|
187 |
fn=generate_image,
|
188 |
-
inputs=[text_input],
|
189 |
-
outputs=[output_image, status_output]
|
190 |
-
api_name="generate"
|
191 |
)
|
192 |
|
193 |
return demo
|
|
|
20 |
|
21 |
return os.getenv("HF_TOKEN")
|
22 |
|
23 |
+
def convert_image(image: Image.Image, format: str = 'png') -> bytes:
|
24 |
+
"""
|
25 |
+
Convert PIL Image to specified format in memory.
|
26 |
+
|
27 |
+
Args:
|
28 |
+
image (Image.Image): Input PIL Image
|
29 |
+
format (str): Desired output format (png, jpg, webp)
|
30 |
+
|
31 |
+
Returns:
|
32 |
+
bytes: Image converted to specified format
|
33 |
+
"""
|
34 |
+
# Supported formats with their MIME types
|
35 |
+
supported_formats = {
|
36 |
+
'png': 'image/png',
|
37 |
+
'jpg': 'image/jpeg',
|
38 |
+
'jpeg': 'image/jpeg',
|
39 |
+
'webp': 'image/webp'
|
40 |
+
}
|
41 |
+
|
42 |
+
# Normalize format
|
43 |
+
format = format.lower()
|
44 |
+
|
45 |
+
# Validate format
|
46 |
+
if format not in supported_formats:
|
47 |
+
raise ValueError(f"Unsupported format. Choose from: {', '.join(supported_formats.keys())}")
|
48 |
+
|
49 |
+
# Convert image
|
50 |
+
byte_array = io.BytesIO()
|
51 |
+
|
52 |
+
# Special handling for JPEG to ensure no alpha channel
|
53 |
+
if format in ['jpg', 'jpeg']:
|
54 |
+
image = image.convert('RGB')
|
55 |
+
|
56 |
+
# Save image to byte array
|
57 |
+
image.save(byte_array, format=format)
|
58 |
+
|
59 |
+
return byte_array.getvalue()
|
60 |
+
|
61 |
def craft_realistic_prompt(base_prompt: str) -> str:
|
62 |
"""
|
63 |
Enhance prompts for more photorealistic results
|
|
|
87 |
model_url: str = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0",
|
88 |
max_retries: int = 3
|
89 |
) -> Optional[bytes]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
"""
|
91 |
Query the Hugging Face Inference API with robust error handling and retry mechanism.
|
92 |
|
|
|
113 |
"Content-Type": "application/json"
|
114 |
}
|
115 |
|
116 |
+
# Payload with enhanced configuration for realism
|
117 |
payload = {
|
118 |
+
"inputs": craft_realistic_prompt(prompt),
|
119 |
"parameters": {
|
120 |
+
"negative_prompt": "cartoon, anime, low quality, bad anatomy, blurry, unrealistic, painting, drawing, sketch",
|
121 |
+
"num_inference_steps": 75, # Increased steps
|
122 |
+
"guidance_scale": 8.5, # Higher guidance
|
123 |
}
|
124 |
}
|
125 |
|
|
|
145 |
|
146 |
raise RuntimeError("Unexpected error in image generation")
|
147 |
|
148 |
+
def generate_image(prompt: str, output_format: str = 'png') -> Tuple[Optional[Image.Image], str, Optional[bytes]]:
|
149 |
"""
|
150 |
Generate an image from a text prompt.
|
151 |
|
152 |
Args:
|
153 |
prompt (str): Text description for image generation
|
154 |
+
output_format (str): Desired output format
|
155 |
|
156 |
Returns:
|
157 |
+
Tuple[Optional[Image.Image], str, Optional[bytes]]:
|
158 |
+
Generated PIL Image, status message, and downloadable image bytes
|
159 |
"""
|
160 |
try:
|
161 |
# Validate prompt
|
162 |
if not prompt or not prompt.strip():
|
163 |
+
return None, "Error: Prompt cannot be empty", None
|
164 |
|
165 |
# Generate image bytes
|
166 |
image_bytes = query_hf_api(prompt)
|
|
|
168 |
# Convert to PIL Image
|
169 |
image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
|
170 |
|
171 |
+
# Convert image to specified format
|
172 |
+
downloadable_image = convert_image(image, output_format)
|
173 |
+
|
174 |
+
return image, "Image generated successfully!", downloadable_image
|
175 |
|
176 |
except Exception as e:
|
177 |
print(f"Image generation error: {e}")
|
178 |
+
return None, f"Error: {str(e)}", None
|
179 |
|
180 |
def create_gradio_interface():
|
181 |
"""
|
|
|
198 |
# Prompt Input
|
199 |
text_input = gr.Textbox(
|
200 |
label="Enter your image prompt",
|
201 |
+
placeholder="e.g., 'Photorealistic portrait of a woman in natural light'",
|
202 |
lines=3
|
203 |
)
|
204 |
|
205 |
+
# Format Selection Dropdown
|
206 |
+
format_dropdown = gr.Dropdown(
|
207 |
+
choices=['PNG', 'JPEG', 'WebP'],
|
208 |
+
value='PNG',
|
209 |
+
label="Output Image Format"
|
210 |
+
)
|
211 |
+
|
212 |
# Generate Button
|
213 |
generate_button = gr.Button("✨ Generate Image", variant="primary")
|
214 |
|
|
|
223 |
# Status Output
|
224 |
status_output = gr.Textbox(label="Status")
|
225 |
|
226 |
+
# Download Button
|
227 |
+
download_button = gr.File(
|
228 |
+
label="Download Image",
|
229 |
+
file_count="single",
|
230 |
+
type="file"
|
231 |
+
)
|
232 |
+
|
233 |
# Event Handlers
|
234 |
+
generate_result = generate_button.click(
|
235 |
fn=generate_image,
|
236 |
+
inputs=[text_input, format_dropdown],
|
237 |
+
outputs=[output_image, status_output, download_button]
|
|
|
238 |
)
|
239 |
|
240 |
return demo
|