Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
@@ -1,13 +1,16 @@
|
|
1 |
import gradio as gr
|
2 |
import torch
|
3 |
from diffusers import StableDiffusionXLPipeline, StableDiffusionXLImg2ImgPipeline
|
4 |
-
from PIL import Image
|
|
|
5 |
import os
|
6 |
import gc
|
7 |
import time
|
8 |
import spaces
|
9 |
from typing import Optional, Tuple
|
10 |
from huggingface_hub import hf_hub_download
|
|
|
|
|
11 |
|
12 |
# Global pipeline variables
|
13 |
txt2img_pipe = None
|
@@ -17,6 +20,14 @@ device = "cuda" if torch.cuda.is_available() else "cpu"
|
|
17 |
# Hugging Face model configuration
|
18 |
MODEL_REPO = "ajsbsd/CyberRealistic-Pony"
|
19 |
MODEL_FILENAME = "cyberrealisticPony_v110.safetensors"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
|
21 |
def clear_memory():
|
22 |
"""Clear GPU memory"""
|
@@ -24,6 +35,24 @@ def clear_memory():
|
|
24 |
torch.cuda.empty_cache()
|
25 |
gc.collect()
|
26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
def load_models():
|
28 |
"""Load both text2img and img2img pipelines optimized for Spaces"""
|
29 |
global txt2img_pipe, img2img_pipe
|
@@ -108,6 +137,22 @@ def validate_dimensions(width: int, height: int) -> Tuple[int, int]:
|
|
108 |
|
109 |
return width, height
|
110 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
@spaces.GPU(duration=60) # GPU decorator for Spaces
|
112 |
def generate_txt2img(prompt, negative_prompt, num_steps, guidance_scale, width, height, seed, add_quality_tags):
|
113 |
"""Generate image from text prompt with Spaces GPU support"""
|
@@ -127,10 +172,12 @@ def generate_txt2img(prompt, negative_prompt, num_steps, guidance_scale, width,
|
|
127 |
# Validate dimensions
|
128 |
width, height = validate_dimensions(width, height)
|
129 |
|
|
|
|
|
|
|
|
|
130 |
# Set seed
|
131 |
-
generator =
|
132 |
-
if seed != -1:
|
133 |
-
generator = torch.Generator(device=device).manual_seed(int(seed))
|
134 |
|
135 |
# Enhance prompt
|
136 |
enhanced_prompt = enhance_prompt(prompt, add_quality_tags)
|
@@ -151,7 +198,19 @@ def generate_txt2img(prompt, negative_prompt, num_steps, guidance_scale, width,
|
|
151 |
)
|
152 |
|
153 |
generation_time = time.time() - start_time
|
154 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
155 |
|
156 |
return result.images[0], status
|
157 |
|
@@ -179,10 +238,12 @@ def generate_img2img(input_image, prompt, negative_prompt, num_steps, guidance_s
|
|
179 |
try:
|
180 |
clear_memory()
|
181 |
|
|
|
|
|
|
|
|
|
182 |
# Set seed
|
183 |
-
generator =
|
184 |
-
if seed != -1:
|
185 |
-
generator = torch.Generator(device=device).manual_seed(int(seed))
|
186 |
|
187 |
# Enhance prompt
|
188 |
enhanced_prompt = enhance_prompt(prompt, add_quality_tags)
|
@@ -215,7 +276,19 @@ def generate_img2img(input_image, prompt, negative_prompt, num_steps, guidance_s
|
|
215 |
)
|
216 |
|
217 |
generation_time = time.time() - start_time
|
218 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
219 |
|
220 |
return result.images[0], status
|
221 |
|
@@ -224,10 +297,26 @@ def generate_img2img(input_image, prompt, negative_prompt, num_steps, guidance_s
|
|
224 |
finally:
|
225 |
clear_memory()
|
226 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
227 |
# Simplified negative prompt for better performance
|
228 |
DEFAULT_NEGATIVE = """
|
229 |
-
(low quality:1.3), (worst quality:1.3), (bad quality:1.2),
|
230 |
-
|
231 |
"""
|
232 |
|
233 |
# Gradio interface optimized for Spaces
|
@@ -241,17 +330,21 @@ with gr.Blocks(
|
|
241 |
Generate high-quality images using the CyberRealistic Pony SDXL model.
|
242 |
|
243 |
β οΈ **Note**: First generation may take longer as the model loads. GPU time is limited on Spaces.
|
|
|
244 |
""")
|
245 |
|
246 |
with gr.Tabs():
|
247 |
with gr.TabItem("π¨ Text to Image"):
|
248 |
with gr.Row():
|
249 |
with gr.Column():
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
|
|
|
|
|
|
255 |
|
256 |
with gr.Accordion("Advanced Settings", open=False):
|
257 |
txt2img_negative = gr.Textbox(
|
@@ -273,24 +366,30 @@ with gr.Blocks(
|
|
273 |
txt2img_width = gr.Slider(512, 1024, 768, step=64, label="Width")
|
274 |
txt2img_height = gr.Slider(512, 1024, 768, step=64, label="Height")
|
275 |
|
276 |
-
txt2img_seed = gr.
|
|
|
|
|
|
|
277 |
|
278 |
txt2img_btn = gr.Button("π¨ Generate", variant="primary", size="lg")
|
279 |
|
280 |
with gr.Column():
|
281 |
txt2img_output = gr.Image(label="Generated Image", height=400)
|
282 |
-
txt2img_status = gr.Textbox(label="
|
283 |
|
284 |
with gr.TabItem("πΌοΈ Image to Image"):
|
285 |
with gr.Row():
|
286 |
with gr.Column():
|
287 |
img2img_input = gr.Image(label="Input Image", type="pil", height=250)
|
288 |
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
|
|
|
|
|
|
294 |
|
295 |
with gr.Accordion("Advanced Settings", open=False):
|
296 |
img2img_negative = gr.Textbox(
|
@@ -313,13 +412,16 @@ with gr.Blocks(
|
|
313 |
label="Strength (Higher = more creative)"
|
314 |
)
|
315 |
|
316 |
-
img2img_seed = gr.
|
|
|
|
|
|
|
317 |
|
318 |
img2img_btn = gr.Button("πΌοΈ Transform", variant="primary", size="lg")
|
319 |
|
320 |
with gr.Column():
|
321 |
img2img_output = gr.Image(label="Generated Image", height=400)
|
322 |
-
img2img_status = gr.Textbox(label="
|
323 |
|
324 |
# Event handlers
|
325 |
txt2img_btn.click(
|
@@ -335,6 +437,17 @@ with gr.Blocks(
|
|
335 |
img2img_strength, img2img_seed, img2img_quality_tags],
|
336 |
outputs=[img2img_output, img2img_status]
|
337 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
338 |
|
339 |
print(f"π CyberRealistic Pony Generator initialized on {device}")
|
340 |
|
|
|
1 |
import gradio as gr
|
2 |
import torch
|
3 |
from diffusers import StableDiffusionXLPipeline, StableDiffusionXLImg2ImgPipeline
|
4 |
+
from PIL import Image, PngImagePlugin
|
5 |
+
from datetime import datetime
|
6 |
import os
|
7 |
import gc
|
8 |
import time
|
9 |
import spaces
|
10 |
from typing import Optional, Tuple
|
11 |
from huggingface_hub import hf_hub_download
|
12 |
+
import tempfile
|
13 |
+
import random
|
14 |
|
15 |
# Global pipeline variables
|
16 |
txt2img_pipe = None
|
|
|
20 |
# Hugging Face model configuration
|
21 |
MODEL_REPO = "ajsbsd/CyberRealistic-Pony"
|
22 |
MODEL_FILENAME = "cyberrealisticPony_v110.safetensors"
|
23 |
+
model_id = f"{MODEL_REPO}/{MODEL_FILENAME}"
|
24 |
+
|
25 |
+
# Generation configuration for metadata
|
26 |
+
generation_config = {
|
27 |
+
"vae": "SDXL VAE",
|
28 |
+
"sampler": "DPM++ 2M Karras",
|
29 |
+
"steps": 20
|
30 |
+
}
|
31 |
|
32 |
def clear_memory():
|
33 |
"""Clear GPU memory"""
|
|
|
35 |
torch.cuda.empty_cache()
|
36 |
gc.collect()
|
37 |
|
38 |
+
def add_metadata_and_save(image: Image.Image, filepath: str, prompt: str, negative_prompt: str, seed: int, steps: int, guidance: float, strength: Optional[float] = None):
|
39 |
+
"""Embed generation metadata into a PNG and save it."""
|
40 |
+
meta = PngImagePlugin.PngInfo()
|
41 |
+
meta.add_text("Prompt", prompt)
|
42 |
+
meta.add_text("NegativePrompt", negative_prompt)
|
43 |
+
meta.add_text("Model", model_id)
|
44 |
+
meta.add_text("VAE", generation_config["vae"])
|
45 |
+
meta.add_text("Sampler", generation_config["sampler"])
|
46 |
+
meta.add_text("Steps", str(steps))
|
47 |
+
meta.add_text("CFG_Scale", str(guidance))
|
48 |
+
if strength is not None:
|
49 |
+
meta.add_text("Strength", str(strength))
|
50 |
+
meta.add_text("Seed", str(seed))
|
51 |
+
meta.add_text("Date", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
52 |
+
|
53 |
+
image.save(filepath, "PNG", pnginfo=meta)
|
54 |
+
return filepath
|
55 |
+
|
56 |
def load_models():
|
57 |
"""Load both text2img and img2img pipelines optimized for Spaces"""
|
58 |
global txt2img_pipe, img2img_pipe
|
|
|
137 |
|
138 |
return width, height
|
139 |
|
140 |
+
def format_status_with_metadata(generation_time: float, width: int, height: int, prompt: str, negative_prompt: str, seed: int, steps: int, guidance: float, strength: Optional[float] = None):
|
141 |
+
"""Format status message with generation metadata"""
|
142 |
+
status_parts = [
|
143 |
+
f"β
Generated in {generation_time:.1f}s ({width}Γ{height})",
|
144 |
+
f"π― Prompt: {prompt[:50]}..." if len(prompt) > 50 else f"π― Prompt: {prompt}",
|
145 |
+
f"π« Negative: {negative_prompt[:30]}..." if negative_prompt and len(negative_prompt) > 30 else f"π« Negative: {negative_prompt or 'None'}",
|
146 |
+
f"π² Seed: {seed}",
|
147 |
+
f"π Steps: {steps}",
|
148 |
+
f"ποΈ CFG: {guidance}"
|
149 |
+
]
|
150 |
+
|
151 |
+
if strength is not None:
|
152 |
+
status_parts.append(f"πͺ Strength: {strength}")
|
153 |
+
|
154 |
+
return "\n".join(status_parts)
|
155 |
+
|
156 |
@spaces.GPU(duration=60) # GPU decorator for Spaces
|
157 |
def generate_txt2img(prompt, negative_prompt, num_steps, guidance_scale, width, height, seed, add_quality_tags):
|
158 |
"""Generate image from text prompt with Spaces GPU support"""
|
|
|
172 |
# Validate dimensions
|
173 |
width, height = validate_dimensions(width, height)
|
174 |
|
175 |
+
# Handle seed
|
176 |
+
if seed == -1:
|
177 |
+
seed = random.randint(0, 2147483647)
|
178 |
+
|
179 |
# Set seed
|
180 |
+
generator = torch.Generator(device=device).manual_seed(int(seed))
|
|
|
|
|
181 |
|
182 |
# Enhance prompt
|
183 |
enhanced_prompt = enhance_prompt(prompt, add_quality_tags)
|
|
|
198 |
)
|
199 |
|
200 |
generation_time = time.time() - start_time
|
201 |
+
|
202 |
+
# Save with metadata
|
203 |
+
temp_path = tempfile.mktemp(suffix=".png")
|
204 |
+
add_metadata_and_save(
|
205 |
+
result.images[0], temp_path, enhanced_prompt, negative_prompt or "",
|
206 |
+
seed, num_steps, guidance_scale
|
207 |
+
)
|
208 |
+
|
209 |
+
# Format status with metadata
|
210 |
+
status = format_status_with_metadata(
|
211 |
+
generation_time, width, height, enhanced_prompt,
|
212 |
+
negative_prompt or "", seed, num_steps, guidance_scale
|
213 |
+
)
|
214 |
|
215 |
return result.images[0], status
|
216 |
|
|
|
238 |
try:
|
239 |
clear_memory()
|
240 |
|
241 |
+
# Handle seed
|
242 |
+
if seed == -1:
|
243 |
+
seed = random.randint(0, 2147483647)
|
244 |
+
|
245 |
# Set seed
|
246 |
+
generator = torch.Generator(device=device).manual_seed(int(seed))
|
|
|
|
|
247 |
|
248 |
# Enhance prompt
|
249 |
enhanced_prompt = enhance_prompt(prompt, add_quality_tags)
|
|
|
276 |
)
|
277 |
|
278 |
generation_time = time.time() - start_time
|
279 |
+
|
280 |
+
# Save with metadata
|
281 |
+
temp_path = tempfile.mktemp(suffix=".png")
|
282 |
+
add_metadata_and_save(
|
283 |
+
result.images[0], temp_path, enhanced_prompt, negative_prompt or "",
|
284 |
+
seed, num_steps, guidance_scale, strength
|
285 |
+
)
|
286 |
+
|
287 |
+
# Format status with metadata
|
288 |
+
status = format_status_with_metadata(
|
289 |
+
generation_time, w, h, enhanced_prompt,
|
290 |
+
negative_prompt or "", seed, num_steps, guidance_scale, strength
|
291 |
+
)
|
292 |
|
293 |
return result.images[0], status
|
294 |
|
|
|
297 |
finally:
|
298 |
clear_memory()
|
299 |
|
300 |
+
# Example prompts for inspiration
|
301 |
+
EXAMPLE_PROMPTS = [
|
302 |
+
"beautiful anime girl with long flowing hair, cherry blossoms, soft lighting",
|
303 |
+
"cyberpunk cityscape at night, neon lights, rain reflections, detailed architecture",
|
304 |
+
"majestic dragon flying over mountains, fantasy landscape, dramatic clouds",
|
305 |
+
"cute anthropomorphic fox character, forest background, magical atmosphere",
|
306 |
+
"elegant woman in Victorian dress, portrait, ornate background, vintage style",
|
307 |
+
"futuristic robot with glowing eyes, metallic surface, sci-fi environment",
|
308 |
+
"mystical unicorn in enchanted forest, rainbow mane, sparkles, ethereal lighting",
|
309 |
+
"steampunk airship floating in sky, gears and brass, adventure scene"
|
310 |
+
]
|
311 |
+
|
312 |
+
def set_example_prompt():
|
313 |
+
"""Return a random example prompt"""
|
314 |
+
return random.choice(EXAMPLE_PROMPTS)
|
315 |
+
|
316 |
# Simplified negative prompt for better performance
|
317 |
DEFAULT_NEGATIVE = """
|
318 |
+
(low quality:1.3), (worst quality:1.3), (bad quality:1.2), (nsfw:1.5), (easynegative:1.3) (bad_prompt:1.3) badhandv4 bad-hands-5 (negative_hand-neg) (bad-picture-chill-75v), (worst quality:1.3), (low quality:1.3), (bad quality:1.3), (a shadow on skin:1.3), (a shaded skin:1.3), (a dark skin:1.3), (blush:1.3), (signature, watermark, username, letter, copyright name,
|
319 |
+
copyright, chinese text, artist name, name tag, company name, name tag, text, error:1.5), (bad anatomy:1.5), (low quality hand:1.5), (worst quality hand:1.5)
|
320 |
"""
|
321 |
|
322 |
# Gradio interface optimized for Spaces
|
|
|
330 |
Generate high-quality images using the CyberRealistic Pony SDXL model.
|
331 |
|
332 |
β οΈ **Note**: First generation may take longer as the model loads. GPU time is limited on Spaces.
|
333 |
+
π **Metadata**: All generated images include embedded metadata (prompt, settings, seed, etc.)
|
334 |
""")
|
335 |
|
336 |
with gr.Tabs():
|
337 |
with gr.TabItem("π¨ Text to Image"):
|
338 |
with gr.Row():
|
339 |
with gr.Column():
|
340 |
+
with gr.Row():
|
341 |
+
txt2img_prompt = gr.Textbox(
|
342 |
+
label="Prompt",
|
343 |
+
placeholder="beautiful landscape, mountains, sunset",
|
344 |
+
lines=2,
|
345 |
+
scale=4
|
346 |
+
)
|
347 |
+
txt2img_example_btn = gr.Button("π² Random Example", scale=1)
|
348 |
|
349 |
with gr.Accordion("Advanced Settings", open=False):
|
350 |
txt2img_negative = gr.Textbox(
|
|
|
366 |
txt2img_width = gr.Slider(512, 1024, 768, step=64, label="Width")
|
367 |
txt2img_height = gr.Slider(512, 1024, 768, step=64, label="Height")
|
368 |
|
369 |
+
txt2img_seed = gr.Slider(
|
370 |
+
minimum=-1, maximum=2147483647, value=-1, step=1,
|
371 |
+
label="Seed (-1 for random)"
|
372 |
+
)
|
373 |
|
374 |
txt2img_btn = gr.Button("π¨ Generate", variant="primary", size="lg")
|
375 |
|
376 |
with gr.Column():
|
377 |
txt2img_output = gr.Image(label="Generated Image", height=400)
|
378 |
+
txt2img_status = gr.Textbox(label="Generation Info", interactive=False, lines=6)
|
379 |
|
380 |
with gr.TabItem("πΌοΈ Image to Image"):
|
381 |
with gr.Row():
|
382 |
with gr.Column():
|
383 |
img2img_input = gr.Image(label="Input Image", type="pil", height=250)
|
384 |
|
385 |
+
with gr.Row():
|
386 |
+
img2img_prompt = gr.Textbox(
|
387 |
+
label="Prompt",
|
388 |
+
placeholder="digital painting style, vibrant colors",
|
389 |
+
lines=2,
|
390 |
+
scale=4
|
391 |
+
)
|
392 |
+
img2img_example_btn = gr.Button("π² Random Example", scale=1)
|
393 |
|
394 |
with gr.Accordion("Advanced Settings", open=False):
|
395 |
img2img_negative = gr.Textbox(
|
|
|
412 |
label="Strength (Higher = more creative)"
|
413 |
)
|
414 |
|
415 |
+
img2img_seed = gr.Slider(
|
416 |
+
minimum=-1, maximum=2147483647, value=-1, step=1,
|
417 |
+
label="Seed (-1 for random)"
|
418 |
+
)
|
419 |
|
420 |
img2img_btn = gr.Button("πΌοΈ Transform", variant="primary", size="lg")
|
421 |
|
422 |
with gr.Column():
|
423 |
img2img_output = gr.Image(label="Generated Image", height=400)
|
424 |
+
img2img_status = gr.Textbox(label="Generation Info", interactive=False, lines=6)
|
425 |
|
426 |
# Event handlers
|
427 |
txt2img_btn.click(
|
|
|
437 |
img2img_strength, img2img_seed, img2img_quality_tags],
|
438 |
outputs=[img2img_output, img2img_status]
|
439 |
)
|
440 |
+
|
441 |
+
# Example prompt buttons
|
442 |
+
txt2img_example_btn.click(
|
443 |
+
fn=set_example_prompt,
|
444 |
+
outputs=[txt2img_prompt]
|
445 |
+
)
|
446 |
+
|
447 |
+
img2img_example_btn.click(
|
448 |
+
fn=set_example_prompt,
|
449 |
+
outputs=[img2img_prompt]
|
450 |
+
)
|
451 |
|
452 |
print(f"π CyberRealistic Pony Generator initialized on {device}")
|
453 |
|