Spaces:
Paused
Paused
refactor(app): reorganize code into modular sections
Browse files- Add docstrings and type hints to all functions
- Extract constants to top-level (ASPECT_RATIOS, EXAMPLE_PROMPTS, DEFAULT_SETTINGS)
- Move CSS and HTML templates to dedicated sections
- Create builder functions for UI components (build_controls_column, build_output_column)
- Add create_app() factory function for better testability
- Wrap pipeline loading in load_pipeline() function
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- app.py +473 -315
- requirements.txt +3 -2
app.py
CHANGED
|
@@ -1,46 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import torch
|
| 2 |
import spaces
|
| 3 |
import gradio as gr
|
| 4 |
from diffusers import DiffusionPipeline
|
| 5 |
|
| 6 |
-
# Load the pipeline once at startup
|
| 7 |
-
print("Loading Z-Image-Turbo pipeline...")
|
| 8 |
-
pipe = DiffusionPipeline.from_pretrained(
|
| 9 |
-
"Tongyi-MAI/Z-Image-Turbo",
|
| 10 |
-
torch_dtype=torch.bfloat16,
|
| 11 |
-
low_cpu_mem_usage=False,
|
| 12 |
-
)
|
| 13 |
-
pipe.to("cuda")
|
| 14 |
-
|
| 15 |
-
# ======== AoTI compilation + FA3 ========
|
| 16 |
-
# pipe.transformer.layers._repeated_blocks = ["ZImageTransformerBlock"]
|
| 17 |
-
# spaces.aoti_blocks_load(pipe.transformer.layers, "zerogpu-aoti/Z-Image", variant="fa3")
|
| 18 |
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
def generate_image(prompt, height, width, num_inference_steps, seed, randomize_seed, progress=gr.Progress(track_tqdm=True)):
|
| 23 |
-
"""Generate an image from the given prompt."""
|
| 24 |
-
if not prompt or prompt.strip() == "":
|
| 25 |
-
gr.Warning("Please enter a prompt first!")
|
| 26 |
-
return None, None
|
| 27 |
|
| 28 |
-
if randomize_seed:
|
| 29 |
-
seed = torch.randint(0, 2**32 - 1, (1,)).item()
|
| 30 |
-
|
| 31 |
-
generator = torch.Generator("cuda").manual_seed(int(seed))
|
| 32 |
-
image = pipe(
|
| 33 |
-
prompt=prompt,
|
| 34 |
-
height=int(height),
|
| 35 |
-
width=int(width),
|
| 36 |
-
num_inference_steps=int(num_inference_steps),
|
| 37 |
-
guidance_scale=0.0,
|
| 38 |
-
generator=generator,
|
| 39 |
-
).images[0]
|
| 40 |
-
|
| 41 |
-
return image, seed
|
| 42 |
-
|
| 43 |
-
# Aspect ratio presets
|
| 44 |
ASPECT_RATIOS = {
|
| 45 |
"1:1 Square": (1024, 1024),
|
| 46 |
"16:9 Landscape": (1344, 768),
|
|
@@ -51,18 +25,7 @@ ASPECT_RATIOS = {
|
|
| 51 |
"Custom": None,
|
| 52 |
}
|
| 53 |
|
| 54 |
-
|
| 55 |
-
"""Update height and width based on selected aspect ratio."""
|
| 56 |
-
if aspect_ratio == "Custom":
|
| 57 |
-
return gr.Slider(interactive=True), gr.Slider(interactive=True)
|
| 58 |
-
|
| 59 |
-
dims = ASPECT_RATIOS.get(aspect_ratio)
|
| 60 |
-
if dims:
|
| 61 |
-
return gr.Slider(value=dims[1], interactive=False), gr.Slider(value=dims[0], interactive=False)
|
| 62 |
-
return gr.Slider(interactive=True), gr.Slider(interactive=True)
|
| 63 |
-
|
| 64 |
-
# Example prompts - curated for quality
|
| 65 |
-
examples = [
|
| 66 |
["Young Chinese woman in red Hanfu, intricate embroidery. Impeccable makeup, red floral forehead pattern. Elaborate high bun, golden phoenix headdress, red flowers, beads. Holds round folding fan with lady, trees, bird. Neon lightning-bolt lamp, bright yellow glow, above extended left palm. Soft-lit outdoor night background, silhouetted tiered pagoda, blurred colorful distant lights."],
|
| 67 |
["A majestic dragon soaring through clouds at sunset, scales shimmering with iridescent colors, detailed fantasy art style"],
|
| 68 |
["Cozy coffee shop interior, warm lighting, rain on windows, plants on shelves, vintage aesthetic, photorealistic"],
|
|
@@ -73,276 +36,76 @@ examples = [
|
|
| 73 |
["Steampunk mechanical owl with brass gears and glowing amber eyes, perched on old leather-bound books, warm candlelight"],
|
| 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 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
""
|
| 137 |
-
|
| 138 |
-
<div class="hero-background"></div>
|
| 139 |
-
<div class="hero-content">
|
| 140 |
-
<div class="logo-badge">
|
| 141 |
-
<span class="logo-icon">Z</span>
|
| 142 |
-
</div>
|
| 143 |
-
<h1 class="hero-title">Z-Image-Turbo</h1>
|
| 144 |
-
<p class="hero-subtitle">Ultra-fast AI image generation powered by state-of-the-art diffusion</p>
|
| 145 |
-
<div class="hero-stats">
|
| 146 |
-
<div class="stat-item">
|
| 147 |
-
<span class="stat-value">8</span>
|
| 148 |
-
<span class="stat-label">DiT Steps</span>
|
| 149 |
-
</div>
|
| 150 |
-
<div class="stat-divider"></div>
|
| 151 |
-
<div class="stat-item">
|
| 152 |
-
<span class="stat-value">2K</span>
|
| 153 |
-
<span class="stat-label">Max Resolution</span>
|
| 154 |
-
</div>
|
| 155 |
-
<div class="stat-divider"></div>
|
| 156 |
-
<div class="stat-item">
|
| 157 |
-
<span class="stat-value"><3s</span>
|
| 158 |
-
<span class="stat-label">Generation</span>
|
| 159 |
-
</div>
|
| 160 |
-
</div>
|
| 161 |
-
</div>
|
| 162 |
-
</div>
|
| 163 |
-
"""
|
| 164 |
-
)
|
| 165 |
-
|
| 166 |
-
with gr.Row(equal_height=False, elem_classes="main-container"):
|
| 167 |
-
# Left column - Controls
|
| 168 |
-
with gr.Column(scale=4, min_width=340, elem_classes="controls-column"):
|
| 169 |
-
# Prompt Section
|
| 170 |
-
gr.HTML('<div class="section-header"><span class="section-icon">✎</span> Describe Your Vision</div>')
|
| 171 |
-
|
| 172 |
-
prompt = gr.Textbox(
|
| 173 |
-
label="",
|
| 174 |
-
placeholder="A mystical forest at twilight, bioluminescent mushrooms glowing softly, ethereal fog weaving between ancient trees...",
|
| 175 |
-
lines=4,
|
| 176 |
-
max_lines=8,
|
| 177 |
-
autofocus=True,
|
| 178 |
-
elem_classes="prompt-input",
|
| 179 |
-
show_label=False,
|
| 180 |
-
)
|
| 181 |
-
|
| 182 |
-
# Quick Actions Row
|
| 183 |
-
with gr.Row(elem_classes="quick-actions"):
|
| 184 |
-
clear_btn = gr.Button("Clear", size="sm", variant="secondary", elem_classes="action-btn")
|
| 185 |
-
enhance_btn = gr.Button("Enhance Prompt", size="sm", variant="secondary", elem_classes="action-btn")
|
| 186 |
-
|
| 187 |
-
# Aspect Ratio Selection
|
| 188 |
-
gr.HTML('<div class="section-header"><span class="section-icon">▢</span> Aspect Ratio</div>')
|
| 189 |
-
|
| 190 |
-
with gr.Row(elem_classes="aspect-ratio-grid"):
|
| 191 |
-
aspect_ratio = gr.Radio(
|
| 192 |
-
choices=list(ASPECT_RATIOS.keys()),
|
| 193 |
-
value="1:1 Square",
|
| 194 |
-
label="",
|
| 195 |
-
show_label=False,
|
| 196 |
-
elem_classes="aspect-radio",
|
| 197 |
-
)
|
| 198 |
-
|
| 199 |
-
# Dimension Controls (shown for Custom)
|
| 200 |
-
with gr.Row(visible=True, elem_classes="dimension-row") as dim_row:
|
| 201 |
-
height = gr.Slider(
|
| 202 |
-
minimum=512,
|
| 203 |
-
maximum=2048,
|
| 204 |
-
value=1024,
|
| 205 |
-
step=64,
|
| 206 |
-
label="Height",
|
| 207 |
-
interactive=False,
|
| 208 |
-
elem_classes="dimension-slider"
|
| 209 |
-
)
|
| 210 |
-
width = gr.Slider(
|
| 211 |
-
minimum=512,
|
| 212 |
-
maximum=2048,
|
| 213 |
-
value=1024,
|
| 214 |
-
step=64,
|
| 215 |
-
label="Width",
|
| 216 |
-
interactive=False,
|
| 217 |
-
elem_classes="dimension-slider"
|
| 218 |
-
)
|
| 219 |
-
|
| 220 |
-
# Advanced Settings
|
| 221 |
-
with gr.Accordion("Advanced Settings", open=False, elem_classes="advanced-accordion"):
|
| 222 |
-
num_inference_steps = gr.Slider(
|
| 223 |
-
minimum=1,
|
| 224 |
-
maximum=20,
|
| 225 |
-
value=9,
|
| 226 |
-
step=1,
|
| 227 |
-
label="Quality Steps",
|
| 228 |
-
info="Higher = better quality, slower generation (9 recommended)"
|
| 229 |
-
)
|
| 230 |
-
|
| 231 |
-
with gr.Row():
|
| 232 |
-
randomize_seed = gr.Checkbox(
|
| 233 |
-
label="Random Seed",
|
| 234 |
-
value=True,
|
| 235 |
-
elem_classes="seed-checkbox"
|
| 236 |
-
)
|
| 237 |
-
seed = gr.Number(
|
| 238 |
-
label="Seed Value",
|
| 239 |
-
value=42,
|
| 240 |
-
precision=0,
|
| 241 |
-
visible=False,
|
| 242 |
-
elem_classes="seed-input"
|
| 243 |
-
)
|
| 244 |
-
|
| 245 |
-
# Generate Button
|
| 246 |
-
generate_btn = gr.Button(
|
| 247 |
-
"Generate Image",
|
| 248 |
-
variant="primary",
|
| 249 |
-
size="lg",
|
| 250 |
-
elem_classes="generate-btn",
|
| 251 |
-
)
|
| 252 |
-
|
| 253 |
-
# Examples Section
|
| 254 |
-
gr.HTML('<div class="section-header"><span class="section-icon">✨</span> Inspiration Gallery</div>')
|
| 255 |
-
|
| 256 |
-
gr.Examples(
|
| 257 |
-
examples=examples,
|
| 258 |
-
inputs=[prompt],
|
| 259 |
-
label="",
|
| 260 |
-
examples_per_page=4,
|
| 261 |
-
elem_id="examples-gallery",
|
| 262 |
-
)
|
| 263 |
-
|
| 264 |
-
# Right column - Output
|
| 265 |
-
with gr.Column(scale=5, min_width=400, elem_classes="output-column"):
|
| 266 |
-
gr.HTML('<div class="section-header"><span class="section-icon">🖼</span> Generated Artwork</div>')
|
| 267 |
-
|
| 268 |
-
output_image = gr.Image(
|
| 269 |
-
label="",
|
| 270 |
-
type="pil",
|
| 271 |
-
show_label=False,
|
| 272 |
-
height=580,
|
| 273 |
-
elem_classes="output-image",
|
| 274 |
-
show_download_button=True,
|
| 275 |
-
show_share_button=True,
|
| 276 |
-
)
|
| 277 |
-
|
| 278 |
-
# Image Info Bar
|
| 279 |
-
with gr.Row(elem_classes="image-info-bar"):
|
| 280 |
-
used_seed = gr.Number(
|
| 281 |
-
label="Seed",
|
| 282 |
-
interactive=False,
|
| 283 |
-
elem_classes="seed-display",
|
| 284 |
-
scale=1,
|
| 285 |
-
)
|
| 286 |
-
|
| 287 |
-
# Footer
|
| 288 |
-
gr.HTML(
|
| 289 |
-
"""
|
| 290 |
-
<footer class="app-footer">
|
| 291 |
-
<div class="footer-content">
|
| 292 |
-
<div class="footer-links">
|
| 293 |
-
<a href="https://huggingface.co/Tongyi-MAI/Z-Image-Turbo" target="_blank" class="footer-link">
|
| 294 |
-
<span class="link-icon">🤗</span> Model
|
| 295 |
-
</a>
|
| 296 |
-
<span class="footer-divider">|</span>
|
| 297 |
-
<a href="https://x.com/realmrfakename" target="_blank" class="footer-link">
|
| 298 |
-
<span class="link-icon">👨‍💻</span> @mrfakename
|
| 299 |
-
</a>
|
| 300 |
-
<span class="footer-divider">|</span>
|
| 301 |
-
<span class="footer-text">Redesigned with care</span>
|
| 302 |
-
</div>
|
| 303 |
-
<div class="footer-badge">
|
| 304 |
-
Apache 2.0 License
|
| 305 |
-
</div>
|
| 306 |
-
</div>
|
| 307 |
-
</footer>
|
| 308 |
-
"""
|
| 309 |
)
|
| 310 |
|
| 311 |
-
# Event handlers
|
| 312 |
-
def toggle_seed(randomize):
|
| 313 |
-
return gr.Number(visible=not randomize)
|
| 314 |
-
|
| 315 |
-
def clear_prompt():
|
| 316 |
-
return ""
|
| 317 |
-
|
| 318 |
-
def enhance_prompt(prompt_text):
|
| 319 |
-
if not prompt_text:
|
| 320 |
-
return prompt_text
|
| 321 |
-
enhancements = ", highly detailed, professional photography, 8k resolution, cinematic lighting, masterpiece"
|
| 322 |
-
if not any(e in prompt_text.lower() for e in ["detailed", "8k", "cinematic", "masterpiece"]):
|
| 323 |
-
return prompt_text + enhancements
|
| 324 |
-
return prompt_text
|
| 325 |
-
|
| 326 |
-
# Connect event handlers
|
| 327 |
-
randomize_seed.change(toggle_seed, inputs=[randomize_seed], outputs=[seed])
|
| 328 |
-
aspect_ratio.change(update_dimensions, inputs=[aspect_ratio], outputs=[height, width])
|
| 329 |
-
clear_btn.click(clear_prompt, outputs=[prompt])
|
| 330 |
-
enhance_btn.click(enhance_prompt, inputs=[prompt], outputs=[prompt])
|
| 331 |
|
| 332 |
-
|
| 333 |
-
|
| 334 |
-
|
| 335 |
-
outputs=[output_image, used_seed],
|
| 336 |
-
)
|
| 337 |
-
|
| 338 |
-
prompt.submit(
|
| 339 |
-
fn=generate_image,
|
| 340 |
-
inputs=[prompt, height, width, num_inference_steps, seed, randomize_seed],
|
| 341 |
-
outputs=[output_image, used_seed],
|
| 342 |
-
)
|
| 343 |
|
| 344 |
-
|
| 345 |
-
custom_css = """
|
| 346 |
/* ===== ROOT VARIABLES ===== */
|
| 347 |
:root {
|
| 348 |
--accent-primary: #8b5cf6;
|
|
@@ -905,8 +668,403 @@ custom_css = """
|
|
| 905 |
}
|
| 906 |
"""
|
| 907 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 908 |
if __name__ == "__main__":
|
| 909 |
demo.launch(
|
| 910 |
theme=custom_theme,
|
| 911 |
-
css=
|
| 912 |
)
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Z-Image-Turbo: Ultra-fast AI image generation powered by diffusion models.
|
| 3 |
+
|
| 4 |
+
A Gradio-based web application for generating images using the Tongyi-MAI/Z-Image-Turbo
|
| 5 |
+
model. Features a modern dark UI with purple/violet accent theme.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
import torch
|
| 9 |
import spaces
|
| 10 |
import gradio as gr
|
| 11 |
from diffusers import DiffusionPipeline
|
| 12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
+
# =============================================================================
|
| 15 |
+
# CONFIGURATION CONSTANTS
|
| 16 |
+
# =============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
ASPECT_RATIOS = {
|
| 19 |
"1:1 Square": (1024, 1024),
|
| 20 |
"16:9 Landscape": (1344, 768),
|
|
|
|
| 25 |
"Custom": None,
|
| 26 |
}
|
| 27 |
|
| 28 |
+
EXAMPLE_PROMPTS = [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
["Young Chinese woman in red Hanfu, intricate embroidery. Impeccable makeup, red floral forehead pattern. Elaborate high bun, golden phoenix headdress, red flowers, beads. Holds round folding fan with lady, trees, bird. Neon lightning-bolt lamp, bright yellow glow, above extended left palm. Soft-lit outdoor night background, silhouetted tiered pagoda, blurred colorful distant lights."],
|
| 30 |
["A majestic dragon soaring through clouds at sunset, scales shimmering with iridescent colors, detailed fantasy art style"],
|
| 31 |
["Cozy coffee shop interior, warm lighting, rain on windows, plants on shelves, vintage aesthetic, photorealistic"],
|
|
|
|
| 36 |
["Steampunk mechanical owl with brass gears and glowing amber eyes, perched on old leather-bound books, warm candlelight"],
|
| 37 |
]
|
| 38 |
|
| 39 |
+
DEFAULT_SETTINGS = {
|
| 40 |
+
"height": 1024,
|
| 41 |
+
"width": 1024,
|
| 42 |
+
"inference_steps": 9,
|
| 43 |
+
"guidance_scale": 0.0,
|
| 44 |
+
"seed": 42,
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
# =============================================================================
|
| 49 |
+
# THEME CONFIGURATION
|
| 50 |
+
# =============================================================================
|
| 51 |
+
|
| 52 |
+
def create_theme():
|
| 53 |
+
"""Create the modern dark theme with purple/violet accents."""
|
| 54 |
+
return gr.themes.Base(
|
| 55 |
+
primary_hue="violet",
|
| 56 |
+
secondary_hue="purple",
|
| 57 |
+
neutral_hue="slate",
|
| 58 |
+
font=gr.themes.GoogleFont("Inter"),
|
| 59 |
+
text_size="lg",
|
| 60 |
+
spacing_size="md",
|
| 61 |
+
radius_size="lg"
|
| 62 |
+
).set(
|
| 63 |
+
# Dark mode colors
|
| 64 |
+
body_background_fill="*neutral_950",
|
| 65 |
+
body_background_fill_dark="*neutral_950",
|
| 66 |
+
background_fill_primary="*neutral_900",
|
| 67 |
+
background_fill_primary_dark="*neutral_900",
|
| 68 |
+
background_fill_secondary="*neutral_800",
|
| 69 |
+
background_fill_secondary_dark="*neutral_800",
|
| 70 |
+
# Text colors
|
| 71 |
+
body_text_color="*neutral_100",
|
| 72 |
+
body_text_color_dark="*neutral_100",
|
| 73 |
+
body_text_color_subdued="*neutral_400",
|
| 74 |
+
body_text_color_subdued_dark="*neutral_400",
|
| 75 |
+
# Border styling
|
| 76 |
+
border_color_primary="*neutral_700",
|
| 77 |
+
border_color_primary_dark="*neutral_700",
|
| 78 |
+
block_border_width="1px",
|
| 79 |
+
# Button styling
|
| 80 |
+
button_primary_background_fill="linear-gradient(135deg, *primary_500 0%, *secondary_600 100%)",
|
| 81 |
+
button_primary_background_fill_hover="linear-gradient(135deg, *primary_400 0%, *secondary_500 100%)",
|
| 82 |
+
button_primary_text_color="white",
|
| 83 |
+
button_primary_border_color="transparent",
|
| 84 |
+
# Input styling
|
| 85 |
+
input_background_fill="*neutral_800",
|
| 86 |
+
input_background_fill_dark="*neutral_800",
|
| 87 |
+
input_border_color="*neutral_600",
|
| 88 |
+
input_border_color_dark="*neutral_600",
|
| 89 |
+
input_border_color_focus="*primary_500",
|
| 90 |
+
input_border_color_focus_dark="*primary_500",
|
| 91 |
+
# Block styling
|
| 92 |
+
block_background_fill="*neutral_900",
|
| 93 |
+
block_background_fill_dark="*neutral_900",
|
| 94 |
+
block_label_background_fill="*neutral_800",
|
| 95 |
+
block_label_text_color="*neutral_200",
|
| 96 |
+
block_title_text_weight="600",
|
| 97 |
+
block_label_text_weight="500",
|
| 98 |
+
# Shadow and depth
|
| 99 |
+
shadow_drop="0 4px 20px rgba(0, 0, 0, 0.3)",
|
| 100 |
+
shadow_drop_lg="0 8px 40px rgba(0, 0, 0, 0.4)",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
)
|
| 102 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
|
| 104 |
+
# =============================================================================
|
| 105 |
+
# CUSTOM CSS
|
| 106 |
+
# =============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
|
| 108 |
+
CUSTOM_CSS = """
|
|
|
|
| 109 |
/* ===== ROOT VARIABLES ===== */
|
| 110 |
:root {
|
| 111 |
--accent-primary: #8b5cf6;
|
|
|
|
| 668 |
}
|
| 669 |
"""
|
| 670 |
|
| 671 |
+
|
| 672 |
+
# =============================================================================
|
| 673 |
+
# HTML TEMPLATES
|
| 674 |
+
# =============================================================================
|
| 675 |
+
|
| 676 |
+
HERO_HTML = """
|
| 677 |
+
<div class="hero-section">
|
| 678 |
+
<div class="hero-background"></div>
|
| 679 |
+
<div class="hero-content">
|
| 680 |
+
<div class="logo-badge">
|
| 681 |
+
<span class="logo-icon">Z</span>
|
| 682 |
+
</div>
|
| 683 |
+
<h1 class="hero-title">Z-Image-Turbo</h1>
|
| 684 |
+
<p class="hero-subtitle">Ultra-fast AI image generation powered by state-of-the-art diffusion</p>
|
| 685 |
+
<div class="hero-stats">
|
| 686 |
+
<div class="stat-item">
|
| 687 |
+
<span class="stat-value">8</span>
|
| 688 |
+
<span class="stat-label">DiT Steps</span>
|
| 689 |
+
</div>
|
| 690 |
+
<div class="stat-divider"></div>
|
| 691 |
+
<div class="stat-item">
|
| 692 |
+
<span class="stat-value">2K</span>
|
| 693 |
+
<span class="stat-label">Max Resolution</span>
|
| 694 |
+
</div>
|
| 695 |
+
<div class="stat-divider"></div>
|
| 696 |
+
<div class="stat-item">
|
| 697 |
+
<span class="stat-value"><3s</span>
|
| 698 |
+
<span class="stat-label">Generation</span>
|
| 699 |
+
</div>
|
| 700 |
+
</div>
|
| 701 |
+
</div>
|
| 702 |
+
</div>
|
| 703 |
+
"""
|
| 704 |
+
|
| 705 |
+
FOOTER_HTML = """
|
| 706 |
+
<footer class="app-footer">
|
| 707 |
+
<div class="footer-content">
|
| 708 |
+
<div class="footer-links">
|
| 709 |
+
<a href="https://huggingface.co/Tongyi-MAI/Z-Image-Turbo" target="_blank" class="footer-link">
|
| 710 |
+
<span class="link-icon">🤗</span> Model
|
| 711 |
+
</a>
|
| 712 |
+
<span class="footer-divider">|</span>
|
| 713 |
+
<a href="https://x.com/realmrfakename" target="_blank" class="footer-link">
|
| 714 |
+
<span class="link-icon">👨‍💻</span> @mrfakename
|
| 715 |
+
</a>
|
| 716 |
+
<span class="footer-divider">|</span>
|
| 717 |
+
<span class="footer-text">Redesigned with care</span>
|
| 718 |
+
</div>
|
| 719 |
+
<div class="footer-badge">
|
| 720 |
+
Apache 2.0 License
|
| 721 |
+
</div>
|
| 722 |
+
</div>
|
| 723 |
+
</footer>
|
| 724 |
+
"""
|
| 725 |
+
|
| 726 |
+
|
| 727 |
+
# =============================================================================
|
| 728 |
+
# MODEL INITIALIZATION
|
| 729 |
+
# =============================================================================
|
| 730 |
+
|
| 731 |
+
def load_pipeline():
|
| 732 |
+
"""Load and configure the diffusion pipeline."""
|
| 733 |
+
print("Loading Z-Image-Turbo pipeline...")
|
| 734 |
+
pipeline = DiffusionPipeline.from_pretrained(
|
| 735 |
+
"Tongyi-MAI/Z-Image-Turbo",
|
| 736 |
+
torch_dtype=torch.bfloat16,
|
| 737 |
+
low_cpu_mem_usage=False,
|
| 738 |
+
)
|
| 739 |
+
pipeline.to("cuda")
|
| 740 |
+
print("Pipeline loaded!")
|
| 741 |
+
return pipeline
|
| 742 |
+
|
| 743 |
+
|
| 744 |
+
# Initialize pipeline at module level
|
| 745 |
+
pipe = load_pipeline()
|
| 746 |
+
|
| 747 |
+
|
| 748 |
+
# =============================================================================
|
| 749 |
+
# CORE FUNCTIONS
|
| 750 |
+
# =============================================================================
|
| 751 |
+
|
| 752 |
+
@spaces.GPU
|
| 753 |
+
def generate_image(
|
| 754 |
+
prompt: str,
|
| 755 |
+
height: int,
|
| 756 |
+
width: int,
|
| 757 |
+
num_inference_steps: int,
|
| 758 |
+
seed: int,
|
| 759 |
+
randomize_seed: bool,
|
| 760 |
+
progress=gr.Progress(track_tqdm=True)
|
| 761 |
+
):
|
| 762 |
+
"""Generate an image from the given prompt.
|
| 763 |
+
|
| 764 |
+
Args:
|
| 765 |
+
prompt: Text description of the image to generate
|
| 766 |
+
height: Output image height in pixels
|
| 767 |
+
width: Output image width in pixels
|
| 768 |
+
num_inference_steps: Number of denoising steps
|
| 769 |
+
seed: Random seed for reproducibility
|
| 770 |
+
randomize_seed: Whether to use a random seed
|
| 771 |
+
progress: Gradio progress tracker
|
| 772 |
+
|
| 773 |
+
Returns:
|
| 774 |
+
Tuple of (generated image, seed used)
|
| 775 |
+
"""
|
| 776 |
+
if not prompt or prompt.strip() == "":
|
| 777 |
+
gr.Warning("Please enter a prompt first!")
|
| 778 |
+
return None, None
|
| 779 |
+
|
| 780 |
+
if randomize_seed:
|
| 781 |
+
seed = torch.randint(0, 2**32 - 1, (1,)).item()
|
| 782 |
+
|
| 783 |
+
generator = torch.Generator("cuda").manual_seed(int(seed))
|
| 784 |
+
image = pipe(
|
| 785 |
+
prompt=prompt,
|
| 786 |
+
height=int(height),
|
| 787 |
+
width=int(width),
|
| 788 |
+
num_inference_steps=int(num_inference_steps),
|
| 789 |
+
guidance_scale=DEFAULT_SETTINGS["guidance_scale"],
|
| 790 |
+
generator=generator,
|
| 791 |
+
).images[0]
|
| 792 |
+
|
| 793 |
+
return image, seed
|
| 794 |
+
|
| 795 |
+
|
| 796 |
+
def update_dimensions(aspect_ratio: str):
|
| 797 |
+
"""Update height and width sliders based on selected aspect ratio.
|
| 798 |
+
|
| 799 |
+
Args:
|
| 800 |
+
aspect_ratio: Selected aspect ratio key from ASPECT_RATIOS
|
| 801 |
+
|
| 802 |
+
Returns:
|
| 803 |
+
Tuple of (height slider, width slider) with updated values
|
| 804 |
+
"""
|
| 805 |
+
if aspect_ratio == "Custom":
|
| 806 |
+
return gr.Slider(interactive=True), gr.Slider(interactive=True)
|
| 807 |
+
|
| 808 |
+
dims = ASPECT_RATIOS.get(aspect_ratio)
|
| 809 |
+
if dims:
|
| 810 |
+
return (
|
| 811 |
+
gr.Slider(value=dims[1], interactive=False),
|
| 812 |
+
gr.Slider(value=dims[0], interactive=False)
|
| 813 |
+
)
|
| 814 |
+
return gr.Slider(interactive=True), gr.Slider(interactive=True)
|
| 815 |
+
|
| 816 |
+
|
| 817 |
+
def toggle_seed_visibility(randomize: bool):
|
| 818 |
+
"""Toggle seed input visibility based on randomize checkbox."""
|
| 819 |
+
return gr.Number(visible=not randomize)
|
| 820 |
+
|
| 821 |
+
|
| 822 |
+
def clear_prompt():
|
| 823 |
+
"""Clear the prompt textbox."""
|
| 824 |
+
return ""
|
| 825 |
+
|
| 826 |
+
|
| 827 |
+
def enhance_prompt(prompt_text: str) -> str:
|
| 828 |
+
"""Add quality enhancement keywords to a prompt.
|
| 829 |
+
|
| 830 |
+
Args:
|
| 831 |
+
prompt_text: Original prompt text
|
| 832 |
+
|
| 833 |
+
Returns:
|
| 834 |
+
Enhanced prompt with quality keywords added
|
| 835 |
+
"""
|
| 836 |
+
if not prompt_text:
|
| 837 |
+
return prompt_text
|
| 838 |
+
|
| 839 |
+
enhancements = ", highly detailed, professional photography, 8k resolution, cinematic lighting, masterpiece"
|
| 840 |
+
enhancement_keywords = ["detailed", "8k", "cinematic", "masterpiece"]
|
| 841 |
+
|
| 842 |
+
if not any(keyword in prompt_text.lower() for keyword in enhancement_keywords):
|
| 843 |
+
return prompt_text + enhancements
|
| 844 |
+
return prompt_text
|
| 845 |
+
|
| 846 |
+
|
| 847 |
+
# =============================================================================
|
| 848 |
+
# UI BUILDER
|
| 849 |
+
# =============================================================================
|
| 850 |
+
|
| 851 |
+
def build_controls_column():
|
| 852 |
+
"""Build the left controls column with prompt input and settings."""
|
| 853 |
+
with gr.Column(scale=4, min_width=340, elem_classes="controls-column"):
|
| 854 |
+
# Prompt Section
|
| 855 |
+
gr.HTML('<div class="section-header"><span class="section-icon">✎</span> Describe Your Vision</div>')
|
| 856 |
+
|
| 857 |
+
prompt = gr.Textbox(
|
| 858 |
+
label="",
|
| 859 |
+
placeholder="A mystical forest at twilight, bioluminescent mushrooms glowing softly, ethereal fog weaving between ancient trees...",
|
| 860 |
+
lines=4,
|
| 861 |
+
max_lines=8,
|
| 862 |
+
autofocus=True,
|
| 863 |
+
elem_classes="prompt-input",
|
| 864 |
+
show_label=False,
|
| 865 |
+
)
|
| 866 |
+
|
| 867 |
+
# Quick Actions Row
|
| 868 |
+
with gr.Row(elem_classes="quick-actions"):
|
| 869 |
+
clear_btn = gr.Button("Clear", size="sm", variant="secondary", elem_classes="action-btn")
|
| 870 |
+
enhance_btn = gr.Button("Enhance Prompt", size="sm", variant="secondary", elem_classes="action-btn")
|
| 871 |
+
|
| 872 |
+
# Aspect Ratio Selection
|
| 873 |
+
gr.HTML('<div class="section-header"><span class="section-icon">▢</span> Aspect Ratio</div>')
|
| 874 |
+
|
| 875 |
+
with gr.Row(elem_classes="aspect-ratio-grid"):
|
| 876 |
+
aspect_ratio = gr.Radio(
|
| 877 |
+
choices=list(ASPECT_RATIOS.keys()),
|
| 878 |
+
value="1:1 Square",
|
| 879 |
+
label="",
|
| 880 |
+
show_label=False,
|
| 881 |
+
elem_classes="aspect-radio",
|
| 882 |
+
)
|
| 883 |
+
|
| 884 |
+
# Dimension Controls
|
| 885 |
+
with gr.Row(visible=True, elem_classes="dimension-row"):
|
| 886 |
+
height = gr.Slider(
|
| 887 |
+
minimum=512,
|
| 888 |
+
maximum=2048,
|
| 889 |
+
value=DEFAULT_SETTINGS["height"],
|
| 890 |
+
step=64,
|
| 891 |
+
label="Height",
|
| 892 |
+
interactive=False,
|
| 893 |
+
elem_classes="dimension-slider"
|
| 894 |
+
)
|
| 895 |
+
width = gr.Slider(
|
| 896 |
+
minimum=512,
|
| 897 |
+
maximum=2048,
|
| 898 |
+
value=DEFAULT_SETTINGS["width"],
|
| 899 |
+
step=64,
|
| 900 |
+
label="Width",
|
| 901 |
+
interactive=False,
|
| 902 |
+
elem_classes="dimension-slider"
|
| 903 |
+
)
|
| 904 |
+
|
| 905 |
+
# Advanced Settings
|
| 906 |
+
with gr.Accordion("Advanced Settings", open=False, elem_classes="advanced-accordion"):
|
| 907 |
+
num_inference_steps = gr.Slider(
|
| 908 |
+
minimum=1,
|
| 909 |
+
maximum=20,
|
| 910 |
+
value=DEFAULT_SETTINGS["inference_steps"],
|
| 911 |
+
step=1,
|
| 912 |
+
label="Quality Steps",
|
| 913 |
+
info="Higher = better quality, slower generation (9 recommended)"
|
| 914 |
+
)
|
| 915 |
+
|
| 916 |
+
with gr.Row():
|
| 917 |
+
randomize_seed = gr.Checkbox(
|
| 918 |
+
label="Random Seed",
|
| 919 |
+
value=True,
|
| 920 |
+
elem_classes="seed-checkbox"
|
| 921 |
+
)
|
| 922 |
+
seed = gr.Number(
|
| 923 |
+
label="Seed Value",
|
| 924 |
+
value=DEFAULT_SETTINGS["seed"],
|
| 925 |
+
precision=0,
|
| 926 |
+
visible=False,
|
| 927 |
+
elem_classes="seed-input"
|
| 928 |
+
)
|
| 929 |
+
|
| 930 |
+
# Generate Button
|
| 931 |
+
generate_btn = gr.Button(
|
| 932 |
+
"Generate Image",
|
| 933 |
+
variant="primary",
|
| 934 |
+
size="lg",
|
| 935 |
+
elem_classes="generate-btn",
|
| 936 |
+
)
|
| 937 |
+
|
| 938 |
+
# Examples Section
|
| 939 |
+
gr.HTML('<div class="section-header"><span class="section-icon">✨</span> Inspiration Gallery</div>')
|
| 940 |
+
|
| 941 |
+
gr.Examples(
|
| 942 |
+
examples=EXAMPLE_PROMPTS,
|
| 943 |
+
inputs=[prompt],
|
| 944 |
+
label="",
|
| 945 |
+
examples_per_page=4,
|
| 946 |
+
elem_id="examples-gallery",
|
| 947 |
+
)
|
| 948 |
+
|
| 949 |
+
return {
|
| 950 |
+
"prompt": prompt,
|
| 951 |
+
"clear_btn": clear_btn,
|
| 952 |
+
"enhance_btn": enhance_btn,
|
| 953 |
+
"aspect_ratio": aspect_ratio,
|
| 954 |
+
"height": height,
|
| 955 |
+
"width": width,
|
| 956 |
+
"num_inference_steps": num_inference_steps,
|
| 957 |
+
"randomize_seed": randomize_seed,
|
| 958 |
+
"seed": seed,
|
| 959 |
+
"generate_btn": generate_btn,
|
| 960 |
+
}
|
| 961 |
+
|
| 962 |
+
|
| 963 |
+
def build_output_column():
|
| 964 |
+
"""Build the right output column with generated image display."""
|
| 965 |
+
with gr.Column(scale=5, min_width=400, elem_classes="output-column"):
|
| 966 |
+
gr.HTML('<div class="section-header"><span class="section-icon">🖼</span> Generated Artwork</div>')
|
| 967 |
+
|
| 968 |
+
output_image = gr.Image(
|
| 969 |
+
label="",
|
| 970 |
+
type="pil",
|
| 971 |
+
show_label=False,
|
| 972 |
+
height=580,
|
| 973 |
+
elem_classes="output-image",
|
| 974 |
+
show_download_button=True,
|
| 975 |
+
show_share_button=True,
|
| 976 |
+
)
|
| 977 |
+
|
| 978 |
+
# Image Info Bar
|
| 979 |
+
with gr.Row(elem_classes="image-info-bar"):
|
| 980 |
+
used_seed = gr.Number(
|
| 981 |
+
label="Seed",
|
| 982 |
+
interactive=False,
|
| 983 |
+
elem_classes="seed-display",
|
| 984 |
+
scale=1,
|
| 985 |
+
)
|
| 986 |
+
|
| 987 |
+
return {
|
| 988 |
+
"output_image": output_image,
|
| 989 |
+
"used_seed": used_seed,
|
| 990 |
+
}
|
| 991 |
+
|
| 992 |
+
|
| 993 |
+
def create_app():
|
| 994 |
+
"""Create and configure the Gradio application."""
|
| 995 |
+
theme = create_theme()
|
| 996 |
+
|
| 997 |
+
with gr.Blocks(fill_height=True, title="Z-Image-Turbo | AI Image Generator") as demo:
|
| 998 |
+
# Hero Header
|
| 999 |
+
gr.HTML(HERO_HTML)
|
| 1000 |
+
|
| 1001 |
+
with gr.Row(equal_height=False, elem_classes="main-container"):
|
| 1002 |
+
# Build UI sections
|
| 1003 |
+
controls = build_controls_column()
|
| 1004 |
+
outputs = build_output_column()
|
| 1005 |
+
|
| 1006 |
+
# Footer
|
| 1007 |
+
gr.HTML(FOOTER_HTML)
|
| 1008 |
+
|
| 1009 |
+
# Wire up event handlers
|
| 1010 |
+
controls["randomize_seed"].change(
|
| 1011 |
+
toggle_seed_visibility,
|
| 1012 |
+
inputs=[controls["randomize_seed"]],
|
| 1013 |
+
outputs=[controls["seed"]]
|
| 1014 |
+
)
|
| 1015 |
+
|
| 1016 |
+
controls["aspect_ratio"].change(
|
| 1017 |
+
update_dimensions,
|
| 1018 |
+
inputs=[controls["aspect_ratio"]],
|
| 1019 |
+
outputs=[controls["height"], controls["width"]]
|
| 1020 |
+
)
|
| 1021 |
+
|
| 1022 |
+
controls["clear_btn"].click(
|
| 1023 |
+
clear_prompt,
|
| 1024 |
+
outputs=[controls["prompt"]]
|
| 1025 |
+
)
|
| 1026 |
+
|
| 1027 |
+
controls["enhance_btn"].click(
|
| 1028 |
+
enhance_prompt,
|
| 1029 |
+
inputs=[controls["prompt"]],
|
| 1030 |
+
outputs=[controls["prompt"]]
|
| 1031 |
+
)
|
| 1032 |
+
|
| 1033 |
+
# Generation triggers
|
| 1034 |
+
generation_inputs = [
|
| 1035 |
+
controls["prompt"],
|
| 1036 |
+
controls["height"],
|
| 1037 |
+
controls["width"],
|
| 1038 |
+
controls["num_inference_steps"],
|
| 1039 |
+
controls["seed"],
|
| 1040 |
+
controls["randomize_seed"],
|
| 1041 |
+
]
|
| 1042 |
+
generation_outputs = [outputs["output_image"], outputs["used_seed"]]
|
| 1043 |
+
|
| 1044 |
+
controls["generate_btn"].click(
|
| 1045 |
+
fn=generate_image,
|
| 1046 |
+
inputs=generation_inputs,
|
| 1047 |
+
outputs=generation_outputs,
|
| 1048 |
+
)
|
| 1049 |
+
|
| 1050 |
+
controls["prompt"].submit(
|
| 1051 |
+
fn=generate_image,
|
| 1052 |
+
inputs=generation_inputs,
|
| 1053 |
+
outputs=generation_outputs,
|
| 1054 |
+
)
|
| 1055 |
+
|
| 1056 |
+
return demo, theme
|
| 1057 |
+
|
| 1058 |
+
|
| 1059 |
+
# =============================================================================
|
| 1060 |
+
# MAIN ENTRY POINT
|
| 1061 |
+
# =============================================================================
|
| 1062 |
+
|
| 1063 |
+
# Create the application
|
| 1064 |
+
demo, custom_theme = create_app()
|
| 1065 |
+
|
| 1066 |
if __name__ == "__main__":
|
| 1067 |
demo.launch(
|
| 1068 |
theme=custom_theme,
|
| 1069 |
+
css=CUSTOM_CSS,
|
| 1070 |
)
|
requirements.txt
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
|
|
| 1 |
gradio
|
| 2 |
git+https://github.com/huggingface/diffusers
|
| 3 |
transformers
|
| 4 |
-
|
| 5 |
-
|
|
|
|
| 1 |
+
torch
|
| 2 |
gradio
|
| 3 |
git+https://github.com/huggingface/diffusers
|
| 4 |
transformers
|
| 5 |
+
accelerate
|
| 6 |
+
spaces
|