duyet Claude Opus 4.5 commited on
Commit
6a0c4b2
·
unverified ·
1 Parent(s): 3597860

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>

Files changed (2) hide show
  1. app.py +473 -315
  2. 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
- print("Pipeline loaded!")
20
-
21
- @spaces.GPU
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
- def update_dimensions(aspect_ratio):
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
- # Modern dark theme with purple/violet accent
77
- custom_theme = gr.themes.Base(
78
- primary_hue="violet",
79
- secondary_hue="purple",
80
- neutral_hue="slate",
81
- font=gr.themes.GoogleFont("Inter"),
82
- text_size="lg",
83
- spacing_size="md",
84
- radius_size="lg"
85
- ).set(
86
- # Dark mode colors
87
- body_background_fill="*neutral_950",
88
- body_background_fill_dark="*neutral_950",
89
- background_fill_primary="*neutral_900",
90
- background_fill_primary_dark="*neutral_900",
91
- background_fill_secondary="*neutral_800",
92
- background_fill_secondary_dark="*neutral_800",
93
-
94
- # Text colors
95
- body_text_color="*neutral_100",
96
- body_text_color_dark="*neutral_100",
97
- body_text_color_subdued="*neutral_400",
98
- body_text_color_subdued_dark="*neutral_400",
99
-
100
- # Border styling
101
- border_color_primary="*neutral_700",
102
- border_color_primary_dark="*neutral_700",
103
- block_border_width="1px",
104
-
105
- # Button styling
106
- button_primary_background_fill="linear-gradient(135deg, *primary_500 0%, *secondary_600 100%)",
107
- button_primary_background_fill_hover="linear-gradient(135deg, *primary_400 0%, *secondary_500 100%)",
108
- button_primary_text_color="white",
109
- button_primary_border_color="transparent",
110
-
111
- # Input styling
112
- input_background_fill="*neutral_800",
113
- input_background_fill_dark="*neutral_800",
114
- input_border_color="*neutral_600",
115
- input_border_color_dark="*neutral_600",
116
- input_border_color_focus="*primary_500",
117
- input_border_color_focus_dark="*primary_500",
118
-
119
- # Block styling
120
- block_background_fill="*neutral_900",
121
- block_background_fill_dark="*neutral_900",
122
- block_label_background_fill="*neutral_800",
123
- block_label_text_color="*neutral_200",
124
- block_title_text_weight="600",
125
- block_label_text_weight="500",
126
-
127
- # Shadow and depth
128
- shadow_drop="0 4px 20px rgba(0, 0, 0, 0.3)",
129
- shadow_drop_lg="0 8px 40px rgba(0, 0, 0, 0.4)",
130
- )
131
-
132
- # Build the Gradio interface
133
- with gr.Blocks(fill_height=True, title="Z-Image-Turbo | AI Image Generator") as demo:
134
- # Hero Header
135
- gr.HTML(
136
- """
137
- <div class="hero-section">
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">&lt;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">&#9998;</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">&#9634;</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">&#10024;</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">&#128444;</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">&#129303;</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">&#128104;&#8205;&#128187;</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
- generate_btn.click(
333
- fn=generate_image,
334
- inputs=[prompt, height, width, num_inference_steps, seed, randomize_seed],
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
- # Custom CSS for modern UI
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=custom_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">&lt;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">&#129303;</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">&#128104;&#8205;&#128187;</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">&#9998;</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">&#9634;</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">&#10024;</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">&#128444;</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
- kernels
5
- gradio[mcp]
 
1
+ torch
2
  gradio
3
  git+https://github.com/huggingface/diffusers
4
  transformers
5
+ accelerate
6
+ spaces