seawolf2357 commited on
Commit
d9a22b1
·
verified ·
1 Parent(s): 3cf2791

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +36 -119
app.py CHANGED
@@ -1,20 +1,13 @@
1
- # PyTorch 2.8 (temporary hack)
2
  import os
3
- os.system('pip install --upgrade --pre --extra-index-url https://download.pytorch.org/whl/nightly/cu126 "torch<2.9" spaces')
4
-
5
- # Actual demo code
6
  import spaces
7
  import torch
8
- from diffusers import WanPipeline, AutoencoderKLWan
9
- from diffusers.models.transformers.transformer_wan import WanTransformer3DModel
10
  from diffusers.utils.export_utils import export_to_video
11
  import gradio as gr
12
  import tempfile
13
  import numpy as np
14
- from PIL import Image
15
  import random
16
  import gc
17
- from optimization import optimize_pipeline_
18
 
19
 
20
  # =========================================================
@@ -23,16 +16,16 @@ from optimization import optimize_pipeline_
23
  GROQ_API_KEY = os.getenv("GROQ_API_KEY")
24
 
25
  # =========================================================
26
- # MODEL CONFIGURATION
27
  # =========================================================
28
- MODEL_ID = "Wan-AI/Wan2.2-T2V-A14B-Diffusers"
29
 
30
  LANDSCAPE_WIDTH = 832
31
  LANDSCAPE_HEIGHT = 480
32
  MAX_SEED = np.iinfo(np.int32).max
33
 
34
  FIXED_FPS = 16
35
- MIN_FRAMES_MODEL = 8
36
  MAX_FRAMES_MODEL = 81
37
 
38
  MIN_DURATION = round(MIN_FRAMES_MODEL/FIXED_FPS, 1)
@@ -41,48 +34,25 @@ MAX_DURATION = round(MAX_FRAMES_MODEL/FIXED_FPS, 1)
41
  # =========================================================
42
  # MODEL LOADING
43
  # =========================================================
44
- vae = AutoencoderKLWan.from_pretrained(
45
- "Wan-AI/Wan2.2-T2V-A14B-Diffusers",
46
- subfolder="vae",
47
- torch_dtype=torch.float32
48
- )
49
-
50
  pipe = WanPipeline.from_pretrained(
51
  MODEL_ID,
52
- transformer=WanTransformer3DModel.from_pretrained(
53
- 'linoyts/Wan2.2-T2V-A14B-Diffusers-BF16',
54
- subfolder='transformer',
55
- torch_dtype=torch.bfloat16,
56
- device_map='cuda',
57
- ),
58
- transformer_2=WanTransformer3DModel.from_pretrained(
59
- 'linoyts/Wan2.2-T2V-A14B-Diffusers-BF16',
60
- subfolder='transformer_2',
61
- torch_dtype=torch.bfloat16,
62
- device_map='cuda',
63
- ),
64
- vae=vae,
65
  torch_dtype=torch.bfloat16,
66
  ).to('cuda')
67
 
 
68
  for i in range(3):
69
  gc.collect()
70
  torch.cuda.synchronize()
71
  torch.cuda.empty_cache()
72
 
73
- optimize_pipeline_(
74
- pipe,
75
- prompt='prompt',
76
- height=LANDSCAPE_HEIGHT,
77
- width=LANDSCAPE_WIDTH,
78
- num_frames=MAX_FRAMES_MODEL,
79
- )
80
 
81
  # =========================================================
82
  # DEFAULT PROMPTS
83
  # =========================================================
84
  default_prompt_t2v = "Two anthropomorphic cats in comfy boxing gear and bright gloves fight intensely on a spotlighted stage."
85
- default_negative_prompt = "色调艳丽, 过曝, 静态, 细节模糊不清, 字幕, 风格, 作品, 画作, 画面, 静止, 整体发灰, 最差质量, 低质量, JPEG压缩残留, 丑陋的, 残缺的, 多余的手指, 画得不好的手部, 画得不好的脸部, 畸形的, 毁容的, 形态畸形的肢体, 手指融合, 静止不动的画面, 杂乱的背景, 三条腿, 背景人很多, 倒着走"
86
 
87
  # =========================================================
88
  # PROMPT ENHANCEMENT
@@ -136,41 +106,34 @@ def enhance_prompt(prompt: str) -> str:
136
  # =========================================================
137
  # GENERATION FUNCTIONS
138
  # =========================================================
139
- def get_duration(
140
- prompt,
141
- negative_prompt,
142
- enhance_prompt_option,
143
- duration_seconds,
144
- guidance_scale,
145
- guidance_scale_2,
146
- steps,
147
- seed,
148
- randomize_seed,
149
- progress,
150
- ):
151
- return steps * 15
152
-
153
-
154
- @spaces.GPU(duration=get_duration)
155
  def generate_video(
156
  prompt,
157
  negative_prompt=default_negative_prompt,
158
  enhance_prompt_option=False,
159
  duration_seconds=MAX_DURATION,
160
- guidance_scale=1,
161
- guidance_scale_2=3,
162
- steps=4,
163
  seed=42,
164
  randomize_seed=False,
165
  progress=gr.Progress(track_tqdm=True),
166
  ):
 
 
 
 
167
  # Enhance prompt if option is enabled
168
  final_prompt = prompt
169
  if enhance_prompt_option:
170
  final_prompt = enhance_prompt(prompt)
171
  print(f"Enhanced Prompt: {final_prompt}")
172
 
173
- num_frames = np.clip(int(round(duration_seconds * FIXED_FPS)), MIN_FRAMES_MODEL, MAX_FRAMES_MODEL)
 
 
 
 
 
174
  current_seed = random.randint(0, MAX_SEED) if randomize_seed else int(seed)
175
 
176
  output_frames_list = pipe(
@@ -180,7 +143,6 @@ def generate_video(
180
  width=LANDSCAPE_WIDTH,
181
  num_frames=num_frames,
182
  guidance_scale=float(guidance_scale),
183
- guidance_scale_2=float(guidance_scale_2),
184
  num_inference_steps=int(steps),
185
  generator=torch.Generator(device="cuda").manual_seed(current_seed),
186
  ).frames[0]
@@ -189,6 +151,10 @@ def generate_video(
189
  video_path = tmpfile.name
190
 
191
  export_to_video(output_frames_list, video_path, fps=FIXED_FPS)
 
 
 
 
192
 
193
  # Build info log
194
  actual_duration = num_frames / FIXED_FPS
@@ -201,7 +167,7 @@ def generate_video(
201
  • Resolution: {LANDSCAPE_WIDTH} x {LANDSCAPE_HEIGHT}
202
  {'=' * 50}
203
  ⚙️ Generation Settings:
204
- • Guidance Scale: {guidance_scale} / {guidance_scale_2}
205
  • Inference Steps: {steps}
206
  • Seed: {current_seed}
207
  • Prompt Enhanced: {'Yes' if enhance_prompt_option else 'No'}
@@ -446,16 +412,6 @@ button.secondary:active,
446
  font-size: 1.1rem !important;
447
  }
448
 
449
- /* ===== 🎨 이미지 출력 영역 ===== */
450
- .gr-image,
451
- .image-container {
452
- border: 4px solid #1F2937 !important;
453
- border-radius: 8px !important;
454
- box-shadow: 8px 8px 0px #1F2937 !important;
455
- overflow: hidden !important;
456
- background: #FFFFFF !important;
457
- }
458
-
459
  /* ===== 🎨 라벨 스타일 ===== */
460
  label,
461
  .gr-input-label,
@@ -482,14 +438,6 @@ input[type="range"] {
482
  accent-color: #3B82F6 !important;
483
  }
484
 
485
- /* ===== 🎨 정보 텍스트 ===== */
486
- .gr-info,
487
- .info {
488
- color: #6B7280 !important;
489
- font-family: 'Comic Neue', cursive !important;
490
- font-size: 0.9rem !important;
491
- }
492
-
493
  /* ===== 🎨 프로그레스 바 ===== */
494
  .progress-bar,
495
  .gr-progress-bar {
@@ -536,29 +484,6 @@ a:hover {
536
  color: #EF4444 !important;
537
  }
538
 
539
- /* ===== 🎨 Row/Column 간격 ===== */
540
- .gr-row {
541
- gap: 1.5rem !important;
542
- }
543
-
544
- .gr-column {
545
- gap: 1rem !important;
546
- }
547
-
548
- /* ===== 🎨 Examples 섹션 ===== */
549
- #examples .gr-sample {
550
- border: 3px solid #1F2937 !important;
551
- border-radius: 8px !important;
552
- box-shadow: 4px 4px 0px #1F2937 !important;
553
- background: #FFFFFF !important;
554
- transition: all 0.2s ease !important;
555
- }
556
-
557
- #examples .gr-sample:hover {
558
- transform: translate(-2px, -2px) !important;
559
- box-shadow: 6px 6px 0px #1F2937 !important;
560
- }
561
-
562
  /* ===== 반응형 조정 ===== */
563
  @media (max-width: 768px) {
564
  .header-text h1 {
@@ -580,7 +505,7 @@ a:hover {
580
  }
581
  }
582
 
583
- /* ===== 🎨 다크모드 비활성화 (코믹은 밝아야 함) ===== */
584
  @media (prefers-color-scheme: dark) {
585
  .gradio-container {
586
  background-color: #FEF9C3 !important;
@@ -631,7 +556,7 @@ with gr.Blocks() as demo:
631
  minimum=MIN_DURATION,
632
  maximum=MAX_DURATION,
633
  step=0.1,
634
- value=MAX_DURATION,
635
  label="⏱️ Duration (seconds)",
636
  info=f"Range: {MIN_DURATION}s - {MAX_DURATION}s at {FIXED_FPS}fps"
637
  )
@@ -663,25 +588,18 @@ with gr.Blocks() as demo:
663
  interactive=True
664
  )
665
  steps_slider = gr.Slider(
666
- minimum=1,
667
- maximum=30,
668
  step=1,
669
- value=4,
670
  label="Inference Steps"
671
  )
672
  guidance_scale_input = gr.Slider(
673
- minimum=0.0,
674
- maximum=10.0,
675
- step=0.5,
676
- value=1,
677
- label="Guidance Scale (High Noise)"
678
- )
679
- guidance_scale_2_input = gr.Slider(
680
- minimum=0.0,
681
- maximum=10.0,
682
  step=0.5,
683
- value=3,
684
- label="Guidance Scale 2 (Low Noise)"
685
  )
686
 
687
  with gr.Accordion("📜 Generation Info", open=True):
@@ -721,7 +639,7 @@ with gr.Blocks() as demo:
721
  # Examples section
722
  gr.Examples(
723
  examples=[
724
- ["POV selfie video, white cat with sunglasses standing on surfboard, relaxed smile, tropical beach behind. Surfboard tips, cat falls into ocean, camera plunges underwater with bubbles."],
725
  ["Two anthropomorphic cats in comfy boxing gear and bright gloves fight intensely on a spotlighted stage."],
726
  ["A cinematic shot of a boat sailing on a calm sea at sunset."],
727
  ["Drone footage flying over a futuristic city with flying cars."],
@@ -738,7 +656,6 @@ with gr.Blocks() as demo:
738
  enhance_prompt_checkbox,
739
  duration_seconds_input,
740
  guidance_scale_input,
741
- guidance_scale_2_input,
742
  steps_slider,
743
  seed_input,
744
  randomize_seed_checkbox
 
 
1
  import os
 
 
 
2
  import spaces
3
  import torch
4
+ from diffusers import WanPipeline
 
5
  from diffusers.utils.export_utils import export_to_video
6
  import gradio as gr
7
  import tempfile
8
  import numpy as np
 
9
  import random
10
  import gc
 
11
 
12
 
13
  # =========================================================
 
16
  GROQ_API_KEY = os.getenv("GROQ_API_KEY")
17
 
18
  # =========================================================
19
+ # MODEL CONFIGURATION - Using lighter 1.3B model
20
  # =========================================================
21
+ MODEL_ID = "Wan-AI/Wan2.1-T2V-1.3B-Diffusers"
22
 
23
  LANDSCAPE_WIDTH = 832
24
  LANDSCAPE_HEIGHT = 480
25
  MAX_SEED = np.iinfo(np.int32).max
26
 
27
  FIXED_FPS = 16
28
+ MIN_FRAMES_MODEL = 9 # Must be 4k+1: 5, 9, 13, 17...
29
  MAX_FRAMES_MODEL = 81
30
 
31
  MIN_DURATION = round(MIN_FRAMES_MODEL/FIXED_FPS, 1)
 
34
  # =========================================================
35
  # MODEL LOADING
36
  # =========================================================
37
+ print("Loading Wan 1.3B pipeline...")
 
 
 
 
 
38
  pipe = WanPipeline.from_pretrained(
39
  MODEL_ID,
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  torch_dtype=torch.bfloat16,
41
  ).to('cuda')
42
 
43
+ # Memory cleanup
44
  for i in range(3):
45
  gc.collect()
46
  torch.cuda.synchronize()
47
  torch.cuda.empty_cache()
48
 
49
+ print("Pipeline loaded successfully!")
 
 
 
 
 
 
50
 
51
  # =========================================================
52
  # DEFAULT PROMPTS
53
  # =========================================================
54
  default_prompt_t2v = "Two anthropomorphic cats in comfy boxing gear and bright gloves fight intensely on a spotlighted stage."
55
+ default_negative_prompt = "low quality, worst quality, blurry, distorted, deformed, ugly, bad anatomy, static, watermark, text, subtitle, oversaturated, underexposed"
56
 
57
  # =========================================================
58
  # PROMPT ENHANCEMENT
 
106
  # =========================================================
107
  # GENERATION FUNCTIONS
108
  # =========================================================
109
+ @spaces.GPU(duration=300)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  def generate_video(
111
  prompt,
112
  negative_prompt=default_negative_prompt,
113
  enhance_prompt_option=False,
114
  duration_seconds=MAX_DURATION,
115
+ guidance_scale=5.0,
116
+ steps=30,
 
117
  seed=42,
118
  randomize_seed=False,
119
  progress=gr.Progress(track_tqdm=True),
120
  ):
121
+ # Clear memory before generation
122
+ gc.collect()
123
+ torch.cuda.empty_cache()
124
+
125
  # Enhance prompt if option is enabled
126
  final_prompt = prompt
127
  if enhance_prompt_option:
128
  final_prompt = enhance_prompt(prompt)
129
  print(f"Enhanced Prompt: {final_prompt}")
130
 
131
+ # Calculate num_frames - must satisfy (num_frames - 1) % 4 == 0
132
+ raw_frames = int(round(duration_seconds * FIXED_FPS))
133
+ k = round((raw_frames - 1) / 4)
134
+ num_frames = 4 * k + 1
135
+ num_frames = np.clip(num_frames, MIN_FRAMES_MODEL, MAX_FRAMES_MODEL)
136
+
137
  current_seed = random.randint(0, MAX_SEED) if randomize_seed else int(seed)
138
 
139
  output_frames_list = pipe(
 
143
  width=LANDSCAPE_WIDTH,
144
  num_frames=num_frames,
145
  guidance_scale=float(guidance_scale),
 
146
  num_inference_steps=int(steps),
147
  generator=torch.Generator(device="cuda").manual_seed(current_seed),
148
  ).frames[0]
 
151
  video_path = tmpfile.name
152
 
153
  export_to_video(output_frames_list, video_path, fps=FIXED_FPS)
154
+
155
+ # Clear memory after generation
156
+ gc.collect()
157
+ torch.cuda.empty_cache()
158
 
159
  # Build info log
160
  actual_duration = num_frames / FIXED_FPS
 
167
  • Resolution: {LANDSCAPE_WIDTH} x {LANDSCAPE_HEIGHT}
168
  {'=' * 50}
169
  ⚙️ Generation Settings:
170
+ • Guidance Scale: {guidance_scale}
171
  • Inference Steps: {steps}
172
  • Seed: {current_seed}
173
  • Prompt Enhanced: {'Yes' if enhance_prompt_option else 'No'}
 
412
  font-size: 1.1rem !important;
413
  }
414
 
 
 
 
 
 
 
 
 
 
 
415
  /* ===== 🎨 라벨 스타일 ===== */
416
  label,
417
  .gr-input-label,
 
438
  accent-color: #3B82F6 !important;
439
  }
440
 
 
 
 
 
 
 
 
 
441
  /* ===== 🎨 프로그레스 바 ===== */
442
  .progress-bar,
443
  .gr-progress-bar {
 
484
  color: #EF4444 !important;
485
  }
486
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
  /* ===== 반응형 조정 ===== */
488
  @media (max-width: 768px) {
489
  .header-text h1 {
 
505
  }
506
  }
507
 
508
+ /* ===== 🎨 다크모드 비활성화 ===== */
509
  @media (prefers-color-scheme: dark) {
510
  .gradio-container {
511
  background-color: #FEF9C3 !important;
 
556
  minimum=MIN_DURATION,
557
  maximum=MAX_DURATION,
558
  step=0.1,
559
+ value=2.0,
560
  label="⏱️ Duration (seconds)",
561
  info=f"Range: {MIN_DURATION}s - {MAX_DURATION}s at {FIXED_FPS}fps"
562
  )
 
588
  interactive=True
589
  )
590
  steps_slider = gr.Slider(
591
+ minimum=10,
592
+ maximum=50,
593
  step=1,
594
+ value=30,
595
  label="Inference Steps"
596
  )
597
  guidance_scale_input = gr.Slider(
598
+ minimum=1.0,
599
+ maximum=15.0,
 
 
 
 
 
 
 
600
  step=0.5,
601
+ value=5.0,
602
+ label="Guidance Scale"
603
  )
604
 
605
  with gr.Accordion("📜 Generation Info", open=True):
 
639
  # Examples section
640
  gr.Examples(
641
  examples=[
642
+ ["POV selfie video, white cat with sunglasses standing on surfboard, relaxed smile, tropical beach behind."],
643
  ["Two anthropomorphic cats in comfy boxing gear and bright gloves fight intensely on a spotlighted stage."],
644
  ["A cinematic shot of a boat sailing on a calm sea at sunset."],
645
  ["Drone footage flying over a futuristic city with flying cars."],
 
656
  enhance_prompt_checkbox,
657
  duration_seconds_input,
658
  guidance_scale_input,
 
659
  steps_slider,
660
  seed_input,
661
  randomize_seed_checkbox