lenML commited on
Commit
205b0fd
·
verified ·
1 Parent(s): 5b05f62

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +160 -510
app.py CHANGED
@@ -3,10 +3,11 @@ import spaces
3
  import gradio as gr
4
  import time
5
  import re
6
- from diffusers import DiffusionPipeline
 
7
  import warnings
8
 
9
- # 忽略一些警告
10
  warnings.filterwarnings("ignore")
11
 
12
  # ==================== 分辨率配置 ====================
@@ -58,609 +59,258 @@ def get_resolution(resolution_str):
58
  if match:
59
  width = int(match.group(1))
60
  height = int(match.group(2))
61
- # 确保是8的倍数
62
- width = width - width % 8
63
- height = height - height % 8
64
- return width, height
65
  return 1024, 1024
66
 
67
- # ==================== 模型加载优化 ====================
68
- print("🚀 Loading Z-Image-Turbo pipeline...")
69
  start_time = time.time()
70
 
71
- # 注意:Z-Image-Turbo 没有 fp16 变体,移除 variant 参数
 
 
72
  pipe = DiffusionPipeline.from_pretrained(
73
- "Tongyi-MAI/Z-Image-Turbo",
74
  torch_dtype=torch.bfloat16,
75
  low_cpu_mem_usage=True,
76
  use_safetensors=True,
77
  )
78
 
79
- # 快速移动到GPU
 
 
 
 
 
 
 
80
  pipe.to("cuda")
81
 
82
- # 尝试启用内存优化
83
  try:
84
- if hasattr(pipe, "enable_xformers_memory_efficient_attention"):
85
- pipe.enable_xformers_memory_efficient_attention()
86
- print("✅ XFormers enabled")
87
  except Exception as e:
88
  print(f"⚠️ XFormers not available: {e}")
89
 
90
- # 启用VAE切片减少内存
91
  try:
92
- if hasattr(pipe.vae, "enable_slicing"):
93
- pipe.vae.enable_slicing()
94
- print("✅ VAE slicing enabled")
95
  except:
96
  pass
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  load_time = time.time() - start_time
99
- print(f"✅ Pipeline loaded in {load_time:.2f} seconds!")
100
 
101
  # ==================== 生成函数 ====================
102
  @spaces.GPU
103
  def generate_image(
104
  prompt,
105
  resolution_choice,
106
- custom_height=None,
107
- custom_width=None,
108
- use_custom_res=False,
109
- num_inference_steps=8,
110
- seed=42,
111
- randomize_seed=True,
112
- negative_prompt_text="",
 
113
  progress=gr.Progress(track_tqdm=True)
114
  ):
115
- """优化后的图像生成函数"""
 
 
 
116
  try:
117
- # 输入验证
118
  if not prompt or len(prompt.strip()) < 2:
119
- return None, 0, "❌ Please enter a meaningful prompt"
120
 
121
  prompt = prompt.strip()
122
  negative_prompt = negative_prompt_text.strip() if negative_prompt_text else None
123
 
124
  # 确定分辨率
125
  if use_custom_res and custom_height and custom_width:
126
- # 使用自定义分辨率
127
  height = max(512, int(custom_height) - int(custom_height) % 8)
128
  width = max(512, int(custom_width) - int(custom_width) % 8)
129
  else:
130
- # 使用预设分辨率
131
  width, height = get_resolution(resolution_choice)
132
 
133
- # 限制最大尺寸防止OOM(T4 GPU限制)
134
- MAX_SIZE = 1536
135
- if height > MAX_SIZE or width > MAX_SIZE:
136
- height = min(height, MAX_SIZE)
137
- width = min(width, MAX_SIZE)
138
-
139
- # 检查宽高积是否过大
140
  if height * width > 2048 * 2048:
141
- return None, 0, "❌ Resolution too large! Maximum total pixels: 2048x2048"
142
 
143
- # 生成随机种子
144
  if randomize_seed:
145
- seed = torch.randint(0, 2**32 - 1, (1,)).item()
146
-
147
  seed = int(seed)
148
 
149
- # 记录开始时间
150
  gen_start = time.time()
151
 
152
- # 创建生成器
153
  generator = torch.Generator("cuda").manual_seed(seed)
154
 
155
- # 清除CUDA缓存
156
- torch.cuda.empty_cache()
157
-
158
- # 生成图像
159
  with torch.cuda.amp.autocast(dtype=torch.bfloat16):
160
  image = pipe(
161
  prompt=prompt,
162
  height=height,
163
  width=width,
164
  num_inference_steps=int(num_inference_steps),
165
- guidance_scale=0.0,
166
  generator=generator,
167
  negative_prompt=negative_prompt,
168
- output_type="pil",
169
  ).images[0]
170
-
171
- # 再次清除缓存
172
- torch.cuda.empty_cache()
173
-
174
- # 计算生成时间
175
  gen_time = time.time() - gen_start
 
176
 
177
- # 生成信息
178
- info = f"✅ Generated {width}x{height} in {gen_time:.1f}s ({num_inference_steps} steps)"
 
179
 
180
- return image, seed, info
181
 
182
- except torch.cuda.OutOfMemoryError:
183
- return None, seed, "💥 Out of memory! Try smaller image size"
184
  except Exception as e:
185
- error_msg = str(e)[:100]
186
- return None, seed, f"❌ Error: {error_msg}"
187
-
188
- # ==================== 主题配置 ====================
189
- custom_theme = gr.themes.Soft(
190
- primary_hue="yellow",
191
- secondary_hue="amber",
192
- neutral_hue="slate",
193
- font=gr.themes.GoogleFont("Inter"),
194
- text_size="lg",
195
- spacing_size="md",
196
- radius_size="lg"
197
- ).set(
198
- button_primary_background_fill="*primary_500",
199
- button_primary_background_fill_hover="*primary_600",
200
- button_primary_border_color="*primary_500",
201
- button_primary_text_color="white",
202
- block_title_text_weight="600",
203
- block_label_text_weight="500",
204
- checkbox_label_background_fill_selected="*primary_500",
205
- slider_color="*primary_500",
206
- )
207
-
208
- # ==================== 全局样式 ====================
209
- global_styles = """
210
- /* 全局样式 */
211
- body {
212
- font-family: 'Inter', sans-serif !important;
213
- }
214
-
215
- .gradio-container {
216
- max-width: 1200px !important;
217
- margin: 0 auto !important;
218
- padding: 1rem !important;
219
- }
220
-
221
- /* 头部样式 */
222
- #header h1 {
223
- margin-bottom: 0.5rem !important;
224
- }
225
-
226
- /* 输入框 */
227
- #prompt-box, #negative-prompt-box {
228
- border-radius: 10px !important;
229
- border: 2px solid #e2e8f0 !important;
230
- transition: all 0.2s ease !important;
231
- }
232
-
233
- #prompt-box:focus, #negative-prompt-box:focus {
234
- border-color: #f59e0b !important;
235
- box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.1) !important;
236
- }
237
-
238
- /* 按钮 */
239
- button.primary {
240
- background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%) !important;
241
- border: none !important;
242
- font-weight: 600 !important;
243
- transition: all 0.2s ease !important;
244
- }
245
-
246
- button.primary:hover {
247
- transform: translateY(-2px) !important;
248
- box-shadow: 0 4px 12px rgba(245, 158, 11, 0.3) !important;
249
- }
250
-
251
- button.secondary {
252
- transition: all 0.2s ease !important;
253
- }
254
-
255
- button.secondary:hover {
256
- transform: translateY(-1px) !important;
257
- }
258
-
259
- /* 输出图片 */
260
- #output-image {
261
- border-radius: 12px !important;
262
- overflow: hidden !important;
263
- border: 1px solid #e2e8f0 !important;
264
- }
265
-
266
- #output-image img {
267
- border-radius: 10px !important;
268
- transition: transform 0.3s ease !important;
269
- }
270
-
271
- #output-image img:hover {
272
- transform: scale(1.01) !important;
273
- }
274
-
275
- /* 信息显示 */
276
- #info-display {
277
- background: rgba(71,85,105) !important;
278
- border: 1px solid #e2e8f0 !important;
279
- border-radius: 8px !important;
280
- font-size: 0.9rem !important;
281
- padding: 0.75rem !important;
282
- }
283
-
284
- /* 进度条 */
285
- .progress-bar {
286
- background: linear-gradient(90deg, #fbbf24 0%, #f59e0b 100%) !important;
287
- }
288
-
289
- /* 分辨率选择器 */
290
- .resolution-option {
291
- border: 1px solid #e2e8f0 !important;
292
- border-radius: 8px !important;
293
- padding: 0.5rem !important;
294
- margin: 0.25rem !important;
295
- cursor: pointer !important;
296
- transition: all 0.2s ease !important;
297
- }
298
-
299
- .resolution-option:hover {
300
- background: #fefce8 !important;
301
- border-color: #fbbf24 !important;
302
- }
303
-
304
- .resolution-option.selected {
305
- background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%) !important;
306
- border-color: #f59e0b !important;
307
- font-weight: 600 !important;
308
- }
309
-
310
- /* 移动端适配 */
311
- @media (max-width: 768px) {
312
- .gradio-container {
313
- padding: 0.5rem !important;
314
- }
315
-
316
- .gr-row {
317
- flex-direction: column !important;
318
- }
319
-
320
- .gr-column {
321
- min-width: 100% !important;
322
- }
323
-
324
- #header h1 {
325
- font-size: 2rem !important;
326
- }
327
-
328
- #output-image {
329
- height: 350px !important;
330
- }
331
-
332
- button {
333
- width: 100% !important;
334
- margin-bottom: 0.5rem !important;
335
- }
336
- }
337
-
338
- /* 示例样式 */
339
- .example {
340
- cursor: pointer !important;
341
- transition: all 0.2s ease !important;
342
- border: 1px solid #e2e8f0 !important;
343
- border-radius: 8px !important;
344
- padding: 0.75rem !important;
345
- margin-bottom: 0.5rem !important;
346
- }
347
-
348
- .example:hover {
349
- background: #fefce8 !important;
350
- border-color: #fbbf24 !important;
351
- transform: translateY(-1px) !important;
352
- }
353
-
354
- /* 加载动画 */
355
- .spinner {
356
- display: inline-block;
357
- width: 16px;
358
- height: 16px;
359
- border: 2px solid rgba(245, 158, 11, 0.3);
360
- border-radius: 50%;
361
- border-top-color: #f59e0b;
362
- animation: spin 1s ease-in-out infinite;
363
- margin-right: 8px;
364
- }
365
-
366
- @keyframes spin {
367
- to { transform: rotate(360deg); }
368
- }
369
-
370
- /* 成功/错误消息 */
371
- .success {
372
- color: #059669 !important;
373
- }
374
-
375
- .error {
376
- color: #dc2626 !important;
377
  }
378
  """
379
 
380
- # ==================== 示例提示词 ====================
381
- examples = [
382
- ["A beautiful Chinese woman in traditional red Hanfu, intricate embroidery, cinematic lighting, photorealistic"],
383
- ["Cyberpunk city at night, neon lights, rainy streets, futuristic architecture, Blade Runner style"],
384
- ["Majestic dragon flying over ancient Chinese palace, sunset, epic fantasy art"],
385
- ["Cute anime girl with pink hair, cyberpunk street background, vibrant colors"],
386
- ["Fantasy landscape with floating islands, waterfalls, magical creatures, digital painting"],
387
- ["Portrait of a wise old samurai, detailed armor, cherry blossoms, studio lighting"],
388
- ["Steampunk airship flying over Victorian London, gears and cogs, detailed"],
389
- ]
390
-
391
- # ==================== Gradio界面 ====================
392
- with gr.Blocks(
393
- theme=custom_theme,
394
- title="Z-Image-Turbo • Ultra-Fast AI Image Generator",
395
- fill_height=True,
396
- css=global_styles
397
- ) as demo:
398
 
399
- # 头部
400
  gr.Markdown(
401
  """
402
- <div style="text-align: center;">
403
- <h1 style="font-size: 2.5rem; font-weight: 800; margin-bottom: 0.5rem; background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 50%, #d97706 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;">
404
- 🎨 Z-Image-Turbo</h1>
405
- <p style="font-size: 1.1rem; color: #64748b; margin-bottom: 1.5rem;">
406
- Generate stunning images in <strong>8 steps</strong> • Optimized for speed • Multiple resolutions</p>
407
  </div>
408
- """,
409
- elem_id="header"
410
  )
411
 
412
- with gr.Row(equal_height=False, variant="panel"):
413
- # 左侧控制面板
414
- with gr.Column(scale=1, min_width=350):
 
 
 
 
 
 
 
 
 
 
 
 
415
  with gr.Group():
416
- prompt = gr.Textbox(
417
- label="✨ Your Prompt",
418
- placeholder="Describe the image you want to create...",
419
- lines=4,
420
- max_lines=6,
421
- autofocus=True,
422
- elem_id="prompt-box"
423
- )
424
-
425
- negative_prompt = gr.Textbox(
426
- label="🚫 Negative Prompt (Optional)",
427
- placeholder="What you don't want in the image...",
428
- lines=2,
429
- max_lines=4,
430
- elem_id="negative-prompt-box"
431
- )
432
-
433
  with gr.Row():
434
- generate_btn = gr.Button(
435
- "🚀 Generate Image",
436
- variant="primary",
437
- scale=2,
438
- size="lg"
439
- )
440
- clear_btn = gr.Button(
441
- "🗑️ Clear",
442
- variant="secondary",
443
  scale=1
444
  )
445
-
446
- # 分辨率设置
447
- with gr.Accordion("🖼️ Resolution Settings", open=True):
448
- # 分辨率预设选择
449
- resolution_preset = gr.Radio(
450
- label="Preset Resolutions",
451
- choices=["1024", "1280", "1536"],
452
- value="1024",
453
- type="value",
454
- elem_classes="resolution-preset"
455
- )
456
-
457
- # 分辨率选项动态更新
458
- resolution_choices = gr.Dropdown(
459
- label="Select Resolution",
460
- choices=RES_CHOICES["1024"],
461
- value="720x1280 (9:16)",
462
- elem_classes="resolution-choices"
463
- )
464
-
465
- # 自定义分辨率选项
466
- use_custom_res = gr.Checkbox(
467
- label="Use Custom Resolution",
468
- value=False,
469
- info="Manually set width and height"
470
- )
471
-
472
- with gr.Row(visible=False) as custom_res_row:
473
- custom_width = gr.Slider(
474
- label="Width",
475
- minimum=512,
476
- maximum=1536,
477
- value=1024,
478
- step=64,
479
- info="512-1536 pixels"
480
- )
481
- custom_height = gr.Slider(
482
- label="Height",
483
- minimum=512,
484
- maximum=1536,
485
- value=1024,
486
- step=64,
487
- info="512-1536 pixels"
488
  )
489
 
490
- # 高级设置
491
- with gr.Accordion("⚙️ Advanced Settings", open=False):
492
- num_inference_steps = gr.Slider(
493
- label="Inference Steps",
494
- minimum=4,
495
- maximum=20,
496
- value=8,
497
- step=1,
498
- info="8 steps recommended (fastest)"
499
- )
500
-
501
  with gr.Row():
502
- randomize_seed = gr.Checkbox(
503
- label="🎲 Random Seed",
504
- value=True,
505
- scale=1
506
- )
507
- seed = gr.Number(
508
- label="Custom Seed",
509
- value=42,
510
- precision=0,
511
- visible=False,
512
- scale=2
513
- )
514
 
515
- # 示例提示词
516
- gr.Examples(
517
- examples=examples,
518
- inputs=[prompt],
519
- label="💡 Try These Prompts",
520
- examples_per_page=7
521
- )
522
-
523
- # 右侧输出面板
524
- with gr.Column(scale=1, min_width=350):
525
- output_image = gr.Image(
526
- label="Generated Image",
527
- type="pil",
528
- show_label=False,
529
- height=450,
530
- show_download_button=True,
531
  show_share_button=True,
532
- elem_id="output-image"
533
- )
534
-
535
- # 生成信息
536
- info_display = gr.Textbox(
537
- label="ℹ️ Generation Info",
538
- interactive=False,
539
- value="Ready to generate! Enter a prompt above.",
540
- elem_id="info-display"
541
- )
542
-
543
- with gr.Row():
544
- used_seed = gr.Number(
545
- label="🎲 Seed Used",
546
- value=0,
547
- interactive=False,
548
- scale=2
549
- )
550
- copy_seed_btn = gr.Button(
551
- "📋 Copy",
552
- size="sm",
553
- variant="secondary",
554
- scale=1
555
- )
556
-
557
- # 建议提示
558
- gr.Markdown(
559
- """
560
- <div style="background: rgba(71,85,105); border-left: 4px solid #fbbf24; padding: 0.75rem; border-radius: 0.5rem; margin-top: 1rem;">
561
- <strong>💡 Tips for best results:</strong>
562
- <ul style="margin: 0.5rem 0 0 1rem; padding-left: 0.5rem;">
563
- <li>Use descriptive prompts</li>
564
- <li>Start with 8 steps for speed</li>
565
- <li>1024x1024 is optimal for most cases</li>
566
- <li>Higher resolutions require more VRAM</li>
567
- <li>Use negative prompts to exclude unwanted elements</li>
568
- </ul>
569
- </div>
570
- """,
571
- elem_id="tips-box"
572
  )
 
 
 
573
 
574
- # 页脚
575
- gr.Markdown(
576
- """
577
- <div style="text-align: center; margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid #e2e8f0; color: #64748b; font-size: 0.9rem;">
578
- <p style="margin-bottom: 0.5rem;">
579
- <strong>Model:</strong> <a href="https://huggingface.co/Tongyi-MAI/Z-Image-Turbo" target="_blank" style="color: #f59e0b; text-decoration: none;">Z-Image-Turbo</a> •
580
- <strong>Demo:</strong> Optimized for Hugging Face Spaces
581
- </p>
582
- </div>
583
- """,
584
- elem_id="footer"
585
- )
586
-
587
- # ==================== 事件处理 ====================
588
-
589
- # 更新分辨率选项
590
- def update_resolution_choices(preset):
591
  return gr.Dropdown(choices=RES_CHOICES[preset], value=RES_CHOICES[preset][0])
592
 
593
- resolution_preset.change(
594
- update_resolution_choices,
595
- inputs=[resolution_preset],
596
- outputs=[resolution_choices]
597
- )
598
-
599
- # 显示/隐藏自定义分辨率
600
- def toggle_custom_resolution(use_custom):
601
- return gr.Row(visible=use_custom), gr.Dropdown(visible=not use_custom)
602
 
603
- use_custom_res.change(
604
- toggle_custom_resolution,
605
- inputs=[use_custom_res],
606
- outputs=[custom_res_row, resolution_choices]
 
607
  )
608
 
609
- # 显示/隐藏种子输入
610
- def toggle_seed_visibility(randomize):
611
- return gr.Number(visible=not randomize)
612
-
613
- randomize_seed.change(
614
- toggle_seed_visibility,
615
- inputs=[randomize_seed],
616
- outputs=[seed]
617
  )
618
 
619
- # 复制种子按钮
620
- def copy_seed_to_clipboard(s):
621
- if s != 0:
622
- gr.Info(f"Seed {s} copied to clipboard!")
623
- return s
624
-
625
- copy_seed_btn.click(
626
- copy_seed_to_clipboard,
627
- inputs=[used_seed],
628
- outputs=[]
629
- )
630
-
631
- # 生成按钮点击
632
  generate_btn.click(
633
  fn=generate_image,
634
- inputs=[prompt, resolution_choices, custom_height, custom_width, use_custom_res,
635
- num_inference_steps, seed, randomize_seed, negative_prompt],
636
- outputs=[output_image, used_seed, info_display],
637
- api_name="generate"
638
- )
639
-
640
- # Enter键提交
641
- prompt.submit(
642
- fn=generate_image,
643
- inputs=[prompt, resolution_choices, custom_height, custom_width, use_custom_res,
644
- num_inference_steps, seed, randomize_seed, negative_prompt],
645
- outputs=[output_image, used_seed, info_display]
646
  )
647
 
648
- # 清除按钮
649
- def clear_all():
650
- return None, 0, "Cleared! Enter a new prompt..."
651
-
652
- clear_btn.click(
653
- fn=clear_all,
654
- outputs=[output_image, used_seed, info_display]
655
- )
656
 
657
- # ==================== 启动应用 ====================
658
  if __name__ == "__main__":
659
- demo.launch(
660
- debug=False,
661
- show_error=True,
662
- share=False,
663
- server_name="0.0.0.0",
664
- server_port=7860,
665
- quiet=True
666
- )
 
3
  import gradio as gr
4
  import time
5
  import re
6
+ import random
7
+ from diffusers import DiffusionPipeline, FlowMatchEulerDiscreteScheduler
8
  import warnings
9
 
10
+ # 忽略警告
11
  warnings.filterwarnings("ignore")
12
 
13
  # ==================== 分辨率配置 ====================
 
59
  if match:
60
  width = int(match.group(1))
61
  height = int(match.group(2))
62
+ return width - width % 8, height - height % 8
 
 
 
63
  return 1024, 1024
64
 
65
+ # ==================== 模型加载与优化 ====================
66
+ print("🚀 Loading Z-Image-Turbo pipeline with optimizations...")
67
  start_time = time.time()
68
 
69
+ model_id = "Tongyi-MAI/Z-Image-Turbo"
70
+
71
+ # 1. 加载管道
72
  pipe = DiffusionPipeline.from_pretrained(
73
+ model_id,
74
  torch_dtype=torch.bfloat16,
75
  low_cpu_mem_usage=True,
76
  use_safetensors=True,
77
  )
78
 
79
+ # 2. 调度器优化
80
+ # 参考官方代码 logic
81
+ pipe.scheduler = FlowMatchEulerDiscreteScheduler.from_config(
82
+ pipe.scheduler.config,
83
+ shift=3.0
84
+ )
85
+
86
+ # 3. 移动到 GPU
87
  pipe.to("cuda")
88
 
89
+ # 4. 显存优化 (xFormers)
90
  try:
91
+ pipe.enable_xformers_memory_efficient_attention()
92
+ print("✅ XFormers enabled")
 
93
  except Exception as e:
94
  print(f"⚠️ XFormers not available: {e}")
95
 
96
+ # 5. VAE 优化
97
  try:
98
+ pipe.vae.enable_slicing()
99
+ # pipe.vae.enable_tiling() # 如果显存非常紧张可开启此项,但会轻微降低速度
 
100
  except:
101
  pass
102
 
103
+ # 6. 编译优化
104
+ # 注意:第一次生成时会进行编译,耗时较长,之后速度会大幅提升
105
+ print("⚡ Compiling transformer model (this may take a moment during first run)...")
106
+ try:
107
+ pipe.transformer = torch.compile(
108
+ pipe.transformer,
109
+ mode="max-autotune-no-cudagraphs",
110
+ fullgraph=False
111
+ )
112
+ print("✅ Torch Compile enabled")
113
+ except Exception as e:
114
+ print(f"⚠️ Torch compile skipped: {e}")
115
+
116
  load_time = time.time() - start_time
117
+ print(f"✅ Pipeline ready in {load_time:.2f} seconds!")
118
 
119
  # ==================== 生成函数 ====================
120
  @spaces.GPU
121
  def generate_image(
122
  prompt,
123
  resolution_choice,
124
+ custom_height,
125
+ custom_width,
126
+ use_custom_res,
127
+ num_inference_steps,
128
+ seed,
129
+ randomize_seed,
130
+ negative_prompt_text,
131
+ gallery_history, # 接收之前的图片列表
132
  progress=gr.Progress(track_tqdm=True)
133
  ):
134
+ """支持画廊历史记录的生成函数"""
135
+ if gallery_history is None:
136
+ gallery_history = []
137
+
138
  try:
 
139
  if not prompt or len(prompt.strip()) < 2:
140
+ raise gr.Error("❌ Please enter a meaningful prompt")
141
 
142
  prompt = prompt.strip()
143
  negative_prompt = negative_prompt_text.strip() if negative_prompt_text else None
144
 
145
  # 确定分辨率
146
  if use_custom_res and custom_height and custom_width:
 
147
  height = max(512, int(custom_height) - int(custom_height) % 8)
148
  width = max(512, int(custom_width) - int(custom_width) % 8)
149
  else:
 
150
  width, height = get_resolution(resolution_choice)
151
 
152
+ # 限制最大尺寸
 
 
 
 
 
 
153
  if height * width > 2048 * 2048:
154
+ raise gr.Error("❌ Resolution too large! Max pixels: 2048x2048")
155
 
156
+ # 处理种子
157
  if randomize_seed:
158
+ seed = random.randint(0, 2**32 - 1)
 
159
  seed = int(seed)
160
 
 
161
  gen_start = time.time()
162
 
 
163
  generator = torch.Generator("cuda").manual_seed(seed)
164
 
165
+ # 生成
 
 
 
166
  with torch.cuda.amp.autocast(dtype=torch.bfloat16):
167
  image = pipe(
168
  prompt=prompt,
169
  height=height,
170
  width=width,
171
  num_inference_steps=int(num_inference_steps),
172
+ guidance_scale=0.0, # Turbo 模型通常不需要 guidance
173
  generator=generator,
174
  negative_prompt=negative_prompt,
175
+ max_sequence_length=512, # 官方设置
176
  ).images[0]
177
+
 
 
 
 
178
  gen_time = time.time() - gen_start
179
+ info = f"✅ {width}x{height} | {gen_time:.2f}s | Seed: {seed}"
180
 
181
+ # 将新图片插入到列表最前面
182
+ # Gallery 接收的格式通常是 [(image, label), ...] 或者直接 image list
183
+ gallery_history.insert(0, (image, info))
184
 
185
+ return gallery_history, seed, info
186
 
 
 
187
  except Exception as e:
188
+ raise gr.Error(f"Error: {str(e)}")
189
+
190
+ # ==================== 界面样式 ====================
191
+ css = """
192
+ body { font-family: 'Inter', sans-serif; }
193
+ .gradio-container { max-width: 1280px !important; margin: 0 auto; }
194
+ #gallery-container { min-height: 500px; }
195
+ .generate-btn {
196
+ background: linear-gradient(90deg, #f59e0b 0%, #d97706 100%) !important;
197
+ border: none !important;
198
+ color: white !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  }
200
  """
201
 
202
+ # ==================== Gradio Blocks ====================
203
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="amber"), css=css, title="Z-Image-Turbo Fast") as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
 
 
205
  gr.Markdown(
206
  """
207
+ <div style="text-align: center; margin-bottom: 1rem">
208
+ <h1 style="font-size: 2.5rem; color: #d97706; margin: 0">⚡ Z-Image-Turbo Gallery</h1>
209
+ <p>Super fast generation with history • Optimized with Torch Compile</p>
 
 
210
  </div>
211
+ """
 
212
  )
213
 
214
+ with gr.Row():
215
+ # 左侧控制栏
216
+ with gr.Column(scale=4, min_width=300):
217
+ prompt = gr.Textbox(
218
+ label="Prompt",
219
+ placeholder="Describe your image...",
220
+ lines=3,
221
+ autofocus=True
222
+ )
223
+ negative_prompt = gr.Textbox(
224
+ label="Negative Prompt",
225
+ placeholder="Low quality, blurry...",
226
+ lines=1
227
+ )
228
+
229
  with gr.Group():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  with gr.Row():
231
+ res_preset = gr.Dropdown(
232
+ choices=["1024", "1280", "1536"],
233
+ value="1024",
234
+ label="Size Class",
 
 
 
 
 
235
  scale=1
236
  )
237
+ res_choice = gr.Dropdown(
238
+ choices=RES_CHOICES["1024"],
239
+ value=RES_CHOICES["1024"][0],
240
+ label="Resolution",
241
+ scale=2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  )
243
 
244
+ # 自定义分辨率折叠栏
245
+ with gr.Accordion("📐 Custom Resolution", open=False):
246
+ use_custom = gr.Checkbox(label="Use Custom Size", value=False)
 
 
 
 
 
 
 
 
247
  with gr.Row():
248
+ w_slider = gr.Slider(512, 1536, value=1024, step=64, label="Width")
249
+ h_slider = gr.Slider(512, 1536, value=1024, step=64, label="Height")
250
+
251
+ with gr.Accordion("⚙️ Settings", open=False):
252
+ steps = gr.Slider(4, 20, value=8, step=1, label="Steps (8 is optimal)")
253
+ with gr.Row():
254
+ use_random_seed = gr.Checkbox(label="Random Seed", value=True)
255
+ seed_input = gr.Number(label="Seed", value=42, precision=0, visible=False)
256
+
257
+ generate_btn = gr.Button("🚀 GENERATE", elem_classes="generate-btn", size="lg")
 
 
258
 
259
+ # 状态信息
260
+ last_seed = gr.Number(label="Last Seed", interactive=False, visible=True)
261
+ status_info = gr.Textbox(label="Status", interactive=False)
262
+
263
+ # 右侧画廊
264
+ with gr.Column(scale=6, min_width=500):
265
+ # Gallery 组件用于展示多图
266
+ output_gallery = gr.Gallery(
267
+ label="History",
268
+ columns=[2],
269
+ rows=[2],
270
+ height="auto",
271
+ object_fit="contain",
272
+ elem_id="gallery-container",
 
 
273
  show_share_button=True,
274
+ show_download_button=True,
275
+ interactive=False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
276
  )
277
+ clear_btn = gr.Button("🗑️ Clear History", variant="secondary")
278
+
279
+ # ==================== 事件交互 ====================
280
 
281
+ # 联动:分辨率预设 -> 分辨率列表
282
+ def update_res_list(preset):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
  return gr.Dropdown(choices=RES_CHOICES[preset], value=RES_CHOICES[preset][0])
284
 
285
+ res_preset.change(update_res_list, inputs=res_preset, outputs=res_choice)
 
 
 
 
 
 
 
 
286
 
287
+ # 联动:自定义分辨率显示
288
+ use_custom.change(
289
+ lambda x: (gr.update(visible=x), gr.update(visible=not x)),
290
+ inputs=use_custom,
291
+ outputs=[gr.Row(visible=False), res_choice] # 这里需要逻辑稍微调整,但为了简洁,主要通过use_custom参数在generate中控制
292
  )
293
 
294
+ # 联动:种子输入框显示
295
+ use_random_seed.change(
296
+ lambda x: gr.update(visible=not x),
297
+ inputs=use_random_seed,
298
+ outputs=seed_input
 
 
 
299
  )
300
 
301
+ # 生成事件
 
 
 
 
 
 
 
 
 
 
 
 
302
  generate_btn.click(
303
  fn=generate_image,
304
+ inputs=[
305
+ prompt, res_choice, h_slider, w_slider, use_custom,
306
+ steps, seed_input, use_random_seed, negative_prompt,
307
+ output_gallery # 传入当前的画廊状态
308
+ ],
309
+ outputs=[output_gallery, last_seed, status_info] # 更新画廊
 
 
 
 
 
 
310
  )
311
 
312
+ # 清除历史
313
+ clear_btn.click(lambda: ([], None, ""), outputs=[output_gallery, last_seed, status_info])
 
 
 
 
 
 
314
 
 
315
  if __name__ == "__main__":
316
+ demo.launch()