lenML commited on
Commit
5902e2a
·
verified ·
1 Parent(s): 39c654b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +466 -130
app.py CHANGED
@@ -1,154 +1,490 @@
1
- import gradio as gr
2
- import numpy as np
3
- import random
4
-
5
- # import spaces #[uncomment to use ZeroGPU]
6
- from diffusers import DiffusionPipeline
7
  import torch
 
 
 
 
 
 
8
 
9
- device = "cuda" if torch.cuda.is_available() else "cpu"
10
- model_repo_id = "stabilityai/sdxl-turbo" # Replace to the model you would like to use
11
-
12
- if torch.cuda.is_available():
13
- torch_dtype = torch.float16
14
- else:
15
- torch_dtype = torch.float32
16
 
17
- pipe = DiffusionPipeline.from_pretrained(model_repo_id, torch_dtype=torch_dtype)
18
- pipe = pipe.to(device)
 
 
 
 
 
 
19
 
20
- MAX_SEED = np.iinfo(np.int32).max
21
- MAX_IMAGE_SIZE = 1024
22
 
 
 
 
 
 
 
 
23
 
24
- # @spaces.GPU #[uncomment to use ZeroGPU]
25
- def infer(
26
- prompt,
27
- negative_prompt,
28
- seed,
29
- randomize_seed,
30
- width,
31
- height,
32
- guidance_scale,
33
- num_inference_steps,
34
- progress=gr.Progress(track_tqdm=True),
35
- ):
36
- if randomize_seed:
37
- seed = random.randint(0, MAX_SEED)
38
 
39
- generator = torch.Generator().manual_seed(seed)
 
 
 
 
40
 
41
- image = pipe(
42
- prompt=prompt,
43
- negative_prompt=negative_prompt,
44
- guidance_scale=guidance_scale,
45
- num_inference_steps=num_inference_steps,
46
- width=width,
47
- height=height,
48
- generator=generator,
49
- ).images[0]
50
-
51
- return image, seed
52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
 
54
  examples = [
55
- "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k",
56
- "An astronaut riding a green horse",
57
- "A delicious ceviche cheesecake slice",
 
 
 
 
58
  ]
59
 
60
- css = """
61
- #col-container {
62
- margin: 0 auto;
63
- max-width: 640px;
64
- }
65
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
- with gr.Blocks(css=css) as demo:
68
- with gr.Column(elem_id="col-container"):
69
- gr.Markdown(" # Text-to-Image Gradio Template")
70
-
71
- with gr.Row():
72
- prompt = gr.Text(
73
- label="Prompt",
74
- show_label=False,
75
- max_lines=1,
76
- placeholder="Enter your prompt",
77
- container=False,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  )
79
-
80
- run_button = gr.Button("Run", scale=0, variant="primary")
81
-
82
- result = gr.Image(label="Result", show_label=False)
83
-
84
- with gr.Accordion("Advanced Settings", open=False):
85
- negative_prompt = gr.Text(
86
- label="Negative prompt",
87
- max_lines=1,
88
- placeholder="Enter a negative prompt",
89
- visible=False,
90
  )
91
-
92
- seed = gr.Slider(
93
- label="Seed",
94
- minimum=0,
95
- maximum=MAX_SEED,
96
- step=1,
97
- value=0,
98
  )
99
-
100
- randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
101
-
102
  with gr.Row():
103
- width = gr.Slider(
104
- label="Width",
105
- minimum=256,
106
- maximum=MAX_IMAGE_SIZE,
107
- step=32,
108
- value=1024, # Replace with defaults that work for your model
109
  )
110
-
111
- height = gr.Slider(
112
- label="Height",
113
- minimum=256,
114
- maximum=MAX_IMAGE_SIZE,
115
- step=32,
116
- value=1024, # Replace with defaults that work for your model
117
  )
118
-
119
- with gr.Row():
120
- guidance_scale = gr.Slider(
121
- label="Guidance scale",
122
- minimum=0.0,
123
- maximum=10.0,
124
- step=0.1,
125
- value=0.0, # Replace with defaults that work for your model
126
  )
127
-
128
- num_inference_steps = gr.Slider(
129
- label="Number of inference steps",
130
- minimum=1,
131
- maximum=50,
132
- step=1,
133
- value=2, # Replace with defaults that work for your model
134
- )
135
-
136
- gr.Examples(examples=examples, inputs=[prompt])
137
- gr.on(
138
- triggers=[run_button.click, prompt.submit],
139
- fn=infer,
140
- inputs=[
141
- prompt,
142
- negative_prompt,
143
- seed,
144
- randomize_seed,
145
- width,
146
- height,
147
- guidance_scale,
148
- num_inference_steps,
149
- ],
150
- outputs=[result, seed],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  )
152
 
 
153
  if __name__ == "__main__":
154
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import torch
2
+ import spaces
3
+ import gradio as gr
4
+ import time
5
+ from diffusers import DiffusionPipeline, DPMSolverMultistepScheduler
6
+ from huggingface_hub import hf_hub_download
7
+ import os
8
 
9
+ # ==================== 模型加载优化 ====================
10
+ print("🚀 Loading Z-Image-Turbo pipeline...")
11
+ start_time = time.time()
 
 
 
 
12
 
13
+ # 使用更高效的加载方式
14
+ pipe = DiffusionPipeline.from_pretrained(
15
+ "Tongyi-MAI/Z-Image-Turbo",
16
+ torch_dtype=torch.bfloat16,
17
+ variant="fp16", # 使用fp16变体减少内存
18
+ low_cpu_mem_usage=True,
19
+ use_safetensors=True,
20
+ )
21
 
22
+ # 快速移动到GPU
23
+ pipe.to("cuda")
24
 
25
+ # 启用内存优化
26
+ if hasattr(pipe, "enable_xformers_memory_efficient_attention"):
27
+ try:
28
+ pipe.enable_xformers_memory_efficient_attention()
29
+ print("✅ XFormers enabled")
30
+ except:
31
+ print("⚠️ XFormers not available, using default attention")
32
 
33
+ # 启用VAE切片减少内存
34
+ if hasattr(pipe.vae, "enable_slicing"):
35
+ pipe.vae.enable_slicing()
36
+ print("✅ VAE slicing enabled")
 
 
 
 
 
 
 
 
 
 
37
 
38
+ # 使用更快的调度器
39
+ pipe.scheduler = DPMSolverMultistepScheduler.from_config(
40
+ pipe.scheduler.config,
41
+ algorithm_type="sde-dpmsolver++"
42
+ )
43
 
44
+ load_time = time.time() - start_time
45
+ print(f"✅ Pipeline loaded in {load_time:.2f} seconds!")
 
 
 
 
 
 
 
 
 
46
 
47
+ # ==================== 生成函数 ====================
48
+ @spaces.GPU
49
+ def generate_image(
50
+ prompt,
51
+ height,
52
+ width,
53
+ num_inference_steps,
54
+ seed,
55
+ randomize_seed,
56
+ progress=gr.Progress(track_tqdm=True)
57
+ ):
58
+ """优化后的图像生成函数"""
59
+ try:
60
+ # 输入验证
61
+ if not prompt or len(prompt.strip()) < 2:
62
+ return None, 0, "❌ Please enter a meaningful prompt"
63
+
64
+ prompt = prompt.strip()
65
+
66
+ # 自动调整尺寸为8的倍数(模型要求)
67
+ height = int(height) - int(height) % 8
68
+ width = int(width) - int(width) % 8
69
+
70
+ # 限制最大尺寸防止OOM(T4 GPU限制)
71
+ MAX_SIZE = 1280
72
+ if height > MAX_SIZE or width > MAX_SIZE:
73
+ height = min(height, MAX_SIZE)
74
+ width = min(width, MAX_SIZE)
75
+
76
+ # 生成随机种子
77
+ if randomize_seed:
78
+ seed = torch.randint(0, 2**32 - 1, (1,)).item()
79
+
80
+ seed = int(seed)
81
+
82
+ # 记录开始时间
83
+ gen_start = time.time()
84
+
85
+ # 创建生成器
86
+ generator = torch.Generator("cuda").manual_seed(seed)
87
+
88
+ # 生成图像(使用torch.autocast混合精度)
89
+ with torch.autocast("cuda", dtype=torch.bfloat16):
90
+ image = pipe(
91
+ prompt=prompt,
92
+ height=height,
93
+ width=width,
94
+ num_inference_steps=int(num_inference_steps),
95
+ guidance_scale=0.0, # Z-Image不需要guidance
96
+ generator=generator,
97
+ output_type="pil",
98
+ ).images[0]
99
+
100
+ # 计算生成时间
101
+ gen_time = time.time() - gen_start
102
+
103
+ # 生成信息
104
+ info = f"✅ Generated {width}x{height} in {gen_time:.1f}s ({num_inference_steps} steps)"
105
+
106
+ return image, seed, info
107
+
108
+ except torch.cuda.OutOfMemoryError:
109
+ return None, seed, "💥 Out of memory! Try smaller image size (e.g., 768x768)"
110
+ except Exception as e:
111
+ error_msg = str(e)[:100] # 截断长错误消息
112
+ return None, seed, f"❌ Error: {error_msg}"
113
 
114
+ # ==================== 示例提示词 ====================
115
  examples = [
116
+ ["A beautiful Chinese woman in traditional red Hanfu, intricate embroidery, cinematic lighting, photorealistic"],
117
+ ["Cyberpunk city at night, neon lights, rainy streets, futuristic architecture, Blade Runner style"],
118
+ ["Majestic dragon flying over ancient Chinese palace, sunset, epic fantasy art"],
119
+ ["Cute anime girl with pink hair, cyberpunk street background, vibrant colors"],
120
+ ["Fantasy landscape with floating islands, waterfalls, magical creatures, digital painting"],
121
+ ["Portrait of a wise old samurai, detailed armor, cherry blossoms, studio lighting"],
122
+ ["Steampunk airship flying over Victorian London, gears and cogs, detailed"],
123
  ]
124
 
125
+ # ==================== 主题配置 ====================
126
+ custom_theme = gr.themes.Soft(
127
+ primary_hue="yellow",
128
+ secondary_hue="amber",
129
+ neutral_hue="slate",
130
+ font=gr.themes.GoogleFont("Inter"),
131
+ text_size="lg",
132
+ spacing_size="md",
133
+ radius_size="lg"
134
+ ).set(
135
+ button_primary_background_fill="*primary_500",
136
+ button_primary_background_fill_hover="*primary_600",
137
+ button_primary_border_color="*primary_500",
138
+ button_primary_text_color="white",
139
+ block_title_text_weight="600",
140
+ block_label_text_weight="500",
141
+ checkbox_label_background_fill_selected="*primary_500",
142
+ slider_color="*primary_500",
143
+ )
144
 
145
+ # ==================== Gradio界面 ====================
146
+ with gr.Blocks(
147
+ theme=custom_theme,
148
+ title="Z-Image-Turbo • Ultra-Fast AI Image Generator",
149
+ fill_height=True
150
+ ) as demo:
151
+
152
+ # 头部
153
+ gr.Markdown(
154
+ """
155
+ <div style="text-align: center;">
156
+ <h1 style="font-size: 2.8rem; 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;">
157
+ 🎨 Z-Image-Turbo</h1>
158
+ <p style="font-size: 1.1rem; color: #64748b; margin-bottom: 1.5rem;">
159
+ Generate stunning images in <strong>8 steps</strong> • Optimized for speed • Powered by Hugging Face</p>
160
+ </div>
161
+ """,
162
+ elem_id="header"
163
+ )
164
+
165
+ with gr.Row(equal_height=False, variant="panel"):
166
+ # 左侧控制面板
167
+ with gr.Column(scale=1, min_width=350):
168
+ with gr.Group():
169
+ prompt = gr.Textbox(
170
+ label="✨ Your Prompt",
171
+ placeholder="Describe the image you want to create...",
172
+ lines=4,
173
+ max_lines=8,
174
+ autofocus=True,
175
+ elem_id="prompt-box"
176
+ )
177
+
178
+ with gr.Row():
179
+ generate_btn = gr.Button(
180
+ "🚀 Generate Image",
181
+ variant="primary",
182
+ scale=2,
183
+ size="lg"
184
+ )
185
+ clear_btn = gr.Button(
186
+ "🗑️ Clear",
187
+ variant="secondary",
188
+ scale=1
189
+ )
190
+
191
+ # 高级设置
192
+ with gr.Accordion("⚙️ Advanced Settings", open=False):
193
+ with gr.Row():
194
+ height = gr.Slider(
195
+ label="Height",
196
+ minimum=512,
197
+ maximum=1280,
198
+ value=768,
199
+ step=64,
200
+ info="512-1280 pixels"
201
+ )
202
+ width = gr.Slider(
203
+ label="Width",
204
+ minimum=512,
205
+ maximum=1280,
206
+ value=768,
207
+ step=64,
208
+ info="512-1280 pixels"
209
+ )
210
+
211
+ num_inference_steps = gr.Slider(
212
+ label="Inference Steps",
213
+ minimum=4,
214
+ maximum=20,
215
+ value=8,
216
+ step=1,
217
+ info="8 steps recommended (fastest)"
218
+ )
219
+
220
+ with gr.Row():
221
+ randomize_seed = gr.Checkbox(
222
+ label="🎲 Random Seed",
223
+ value=True,
224
+ scale=1
225
+ )
226
+ seed = gr.Number(
227
+ label="Custom Seed",
228
+ value=42,
229
+ precision=0,
230
+ visible=False,
231
+ scale=2
232
+ )
233
+
234
+ # 显示/隐藏种子输入
235
+ def toggle_seed_visibility(randomize):
236
+ return gr.Number(visible=not randomize)
237
+
238
+ randomize_seed.change(
239
+ toggle_seed_visibility,
240
+ inputs=[randomize_seed],
241
+ outputs=[seed]
242
+ )
243
+
244
+ # 示例提示词
245
+ gr.Examples(
246
+ examples=examples,
247
+ inputs=[prompt],
248
+ label="💡 Try These Prompts",
249
+ examples_per_page=7,
250
+ cache_examples=True # 缓存示例结果
251
  )
252
+
253
+ # 右侧输出面板
254
+ with gr.Column(scale=1, min_width=350):
255
+ output_image = gr.Image(
256
+ label="Generated Image",
257
+ type="pil",
258
+ show_label=False,
259
+ height=500,
260
+ show_download_button=True,
261
+ show_share_button=True,
262
+ elem_id="output-image"
263
  )
264
+
265
+ # 生成信息
266
+ info_display = gr.Textbox(
267
+ label="ℹ️ Generation Info",
268
+ interactive=False,
269
+ value="Ready to generate!",
270
+ elem_id="info-display"
271
  )
272
+
 
 
273
  with gr.Row():
274
+ used_seed = gr.Number(
275
+ label="🎲 Seed Used",
276
+ value=0,
277
+ interactive=False,
278
+ scale=2
 
279
  )
280
+ copy_seed_btn = gr.Button(
281
+ "📋 Copy",
282
+ size="sm",
283
+ variant="secondary",
284
+ scale=1
 
 
285
  )
286
+
287
+ # 复制种子到剪贴板
288
+ copy_seed_btn.click(
289
+ lambda s: gr.Clipboard().copy(str(s)),
290
+ inputs=[used_seed],
291
+ outputs=[]
 
 
292
  )
293
+
294
+ # 页脚
295
+ gr.Markdown(
296
+ """
297
+ <div style="text-align: center; margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid #e2e8f0; color: #64748b; font-size: 0.9rem;">
298
+ <p style="margin-bottom: 0.5rem;">
299
+ <strong>Model:</strong> <a href="https://huggingface.co/Tongyi-MAI/Z-Image-Turbo" target="_blank" style="color: #f59e0b;">Z-Image-Turbo</a>
300
+ <strong>Demo by:</strong> <a href="https://x.com/realmrfakename" target="_blank" style="color: #f59e0b;">@mrfakename</a> •
301
+ <strong>Optimized for:</strong> Hugging Face Spaces
302
+ </p>
303
+ <p style="font-size: 0.85rem; opacity: 0.8;">
304
+ 💡 Tip: Use 8 steps for fastest generation. Image size affects generation speed and memory usage.
305
+ </p>
306
+ </div>
307
+ """,
308
+ elem_id="footer"
309
+ )
310
+
311
+ # ==================== 事件处理 ====================
312
+
313
+ # ���成按钮点击
314
+ generate_btn.click(
315
+ fn=generate_image,
316
+ inputs=[prompt, height, width, num_inference_steps, seed, randomize_seed],
317
+ outputs=[output_image, used_seed, info_display],
318
+ api_name="generate"
319
+ )
320
+
321
+ # Enter键提交
322
+ prompt.submit(
323
+ fn=generate_image,
324
+ inputs=[prompt, height, width, num_inference_steps, seed, randomize_seed],
325
+ outputs=[output_image, used_seed, info_display]
326
+ )
327
+
328
+ # 清除按钮
329
+ def clear_all():
330
+ return None, 0, "Cleared! Enter a new prompt..."
331
+
332
+ clear_btn.click(
333
+ fn=clear_all,
334
+ outputs=[output_image, used_seed, info_display]
335
+ )
336
+
337
+ # 用相同设置重新生成
338
+ def regenerate(prompt, height, width, steps, seed):
339
+ return generate_image(prompt, height, width, steps, seed, False)
340
+
341
+ # 添加键盘快捷键提示
342
+ gr.Markdown(
343
+ """
344
+ <div style="text-align: center; font-size: 0.8rem; opacity: 0.7; margin-top: 1rem;">
345
+ ⌨️ Shortcuts: Enter to generate • Ctrl+Enter for new line
346
+ </div>
347
+ """
348
  )
349
 
350
+ # ==================== 启动应用 ====================
351
  if __name__ == "__main__":
352
+ # 配置Hugging Face Spaces优化
353
+ demo.launch(
354
+ debug=False,
355
+ show_error=True,
356
+ share=False, # 在Spaces上不需要share
357
+ server_name="0.0.0.0",
358
+ server_port=7860,
359
+ allowed_paths=["./"],
360
+ favicon_path=None,
361
+ css="""
362
+ /* 全局样式 */
363
+ .gradio-container {
364
+ max-width: 1200px !important;
365
+ margin: 0 auto !important;
366
+ padding: 1rem !important;
367
+ }
368
+
369
+ /* 头部样式 */
370
+ #header h1 {
371
+ margin-bottom: 0.5rem !important;
372
+ }
373
+
374
+ /* 提示词输入框 */
375
+ #prompt-box {
376
+ min-height: 120px !important;
377
+ border-radius: 12px !important;
378
+ border: 2px solid #e2e8f0 !important;
379
+ transition: border-color 0.2s ease !important;
380
+ }
381
+
382
+ #prompt-box:focus {
383
+ border-color: #f59e0b !important;
384
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.1) !important;
385
+ }
386
+
387
+ /* 生成按钮 */
388
+ button.primary {
389
+ font-weight: 600 !important;
390
+ letter-spacing: 0.3px !important;
391
+ transition: all 0.2s ease !important;
392
+ }
393
+
394
+ button.primary:hover {
395
+ transform: translateY(-2px) !important;
396
+ box-shadow: 0 4px 12px rgba(245, 158, 11, 0.3) !important;
397
+ }
398
+
399
+ /* 输出图片 */
400
+ #output-image {
401
+ border-radius: 12px !important;
402
+ overflow: hidden !important;
403
+ border: 1px solid #e2e8f0 !important;
404
+ }
405
+
406
+ #output-image img {
407
+ border-radius: 10px !important;
408
+ transition: transform 0.3s ease !important;
409
+ }
410
+
411
+ #output-image img:hover {
412
+ transform: scale(1.01) !important;
413
+ }
414
+
415
+ /* 信息显示 */
416
+ #info-display {
417
+ background: #f8fafc !important;
418
+ border: 1px solid #e2e8f0 !important;
419
+ border-radius: 8px !important;
420
+ font-size: 0.9rem !important;
421
+ }
422
+
423
+ /* 页脚 */
424
+ #footer {
425
+ margin-top: 2rem !important;
426
+ }
427
+
428
+ #footer a {
429
+ font-weight: 500 !important;
430
+ }
431
+
432
+ /* 移动端适配 */
433
+ @media (max-width: 768px) {
434
+ .gradio-container {
435
+ padding: 0.5rem !important;
436
+ }
437
+
438
+ .gr-row {
439
+ flex-direction: column !important;
440
+ }
441
+
442
+ .gr-column {
443
+ min-width: 100% !important;
444
+ }
445
+
446
+ #header h1 {
447
+ font-size: 2rem !important;
448
+ }
449
+
450
+ #output-image {
451
+ height: 400px !important;
452
+ }
453
+ }
454
+
455
+ /* 暗色模式支持 */
456
+ @media (prefers-color-scheme: dark) {
457
+ body {
458
+ background: #0f172a !important;
459
+ }
460
+
461
+ .gradio-container {
462
+ background: #1e293b !important;
463
+ }
464
+
465
+ #info-display {
466
+ background: #334155 !important;
467
+ border-color: #475569 !important;
468
+ color: #e2e8f0 !important;
469
+ }
470
+ }
471
+
472
+ /* 加载动画 */
473
+ .spinner {
474
+ display: inline-block;
475
+ width: 16px;
476
+ height: 16px;
477
+ border: 2px solid rgba(245, 158, 11, 0.3);
478
+ border-radius: 50%;
479
+ border-top-color: #f59e0b;
480
+ animation: spin 1s ease-in-out infinite;
481
+ margin-right: 8px;
482
+ }
483
+
484
+ @keyframes spin {
485
+ to { transform: rotate(360deg); }
486
+ }
487
+ """,
488
+ analytics_enabled=True,
489
+ quiet=True # 减少日志输出
490
+ )