HAL1993 commited on
Commit
148dde4
·
verified ·
1 Parent(s): 258473b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +35 -67
app.py CHANGED
@@ -1,3 +1,6 @@
 
 
 
1
  import spaces
2
  import torch
3
  import requests
@@ -19,7 +22,7 @@ from torchao.quantization import Int8WeightOnlyConfig
19
  import aoti
20
 
21
  # ------------------------------------------------------------
22
- # -------------------------- CONFIG ---------------------------
23
  # ------------------------------------------------------------
24
  MODEL_ID = "Wan-AI/Wan2.2-I2V-A14B-Diffusers"
25
 
@@ -45,7 +48,7 @@ default_negative_prompt = (
45
  )
46
 
47
  # ------------------------------------------------------------
48
- # ----------------------- MODEL LOADING -----------------------
49
  # ------------------------------------------------------------
50
  pipe = WanImageToVideoPipeline.from_pretrained(
51
  MODEL_ID,
@@ -70,6 +73,7 @@ pipe.load_lora_weights(
70
  weight_name="Lightx2v/lightx2v_I2V_14B_480p_cfg_step_distill_rank128_bf16.safetensors",
71
  adapter_name="lightx2v",
72
  )
 
73
  kwargs_lora = {"load_into_transformer_2": True}
74
  pipe.load_lora_weights(
75
  "Kijai/WanVideo_comfy",
@@ -77,6 +81,7 @@ pipe.load_lora_weights(
77
  adapter_name="lightx2v_2",
78
  **kwargs_lora,
79
  )
 
80
  pipe.set_adapters(["lightx2v", "lightx2v_2"], adapter_weights=[1.0, 1.0])
81
  pipe.fuse_lora(adapter_names=["lightx2v"], lora_scale=3.0, components=["transformer"])
82
  pipe.fuse_lora(adapter_names=["lightx2v_2"], lora_scale=1.0, components=["transformer_2"])
@@ -91,7 +96,7 @@ aoti.aoti_blocks_load(pipe.transformer, "zerogpu-aoti/Wan2", variant="fp8da")
91
  aoti.aoti_blocks_load(pipe.transformer_2, "zerogpu-aoti/Wan2", variant="fp8da")
92
 
93
  # ------------------------------------------------------------
94
- # -------------------------- HELPERS -------------------------
95
  # ------------------------------------------------------------
96
  def resize_image(image: Image.Image) -> Image.Image:
97
  """Resize / crop the input image so the model receives a valid size."""
@@ -117,6 +122,7 @@ def resize_image(image: Image.Image) -> Image.Image:
117
  top = (height - crop_h) // 2
118
  img = image.crop((0, top, width, top + crop_h))
119
  else:
 
120
  if width > height: # landscape
121
  target_w = MAX_DIM
122
  target_h = int(round(target_w / aspect_ratio))
@@ -125,6 +131,7 @@ def resize_image(image: Image.Image) -> Image.Image:
125
  target_w = int(round(target_h * aspect_ratio))
126
  img = image
127
 
 
128
  final_w = round(target_w / MULTIPLE_OF) * MULTIPLE_OF
129
  final_h = round(target_h / MULTIPLE_OF) * MULTIPLE_OF
130
  final_w = max(MIN_DIM, min(MAX_DIM, final_w))
@@ -134,6 +141,7 @@ def resize_image(image: Image.Image) -> Image.Image:
134
 
135
 
136
  def get_num_frames(duration_seconds: float) -> int:
 
137
  return 1 + int(
138
  np.clip(
139
  int(round(duration_seconds * FIXED_FPS)),
@@ -153,9 +161,12 @@ def get_duration(
153
  guidance_scale_2,
154
  seed,
155
  randomize_seed,
156
- progress,
157
  ):
158
- """Estimate how long the GPU will be needed – used by @spaces.GPU."""
 
 
 
159
  BASE_FRAMES_HEIGHT_WIDTH = 81 * 832 * 624
160
  BASE_STEP_DURATION = 15
161
 
@@ -165,34 +176,10 @@ def get_duration(
165
  step_duration = BASE_STEP_DURATION * factor ** 1.5
166
  est = 10 + int(steps) * step_duration
167
 
168
- # safety cap – we never want to block the GPU >30 s
169
  return min(est, 30)
170
 
171
 
172
- @spaces.GPU
173
- def translate_albanian_to_english(text):
174
- """Optional helper – not used in the UI but kept unchanged."""
175
- if not text.strip():
176
- raise gr.Error("Please enter a description.")
177
- for attempt in range(2):
178
- try:
179
- resp = requests.post(
180
- "https://hal1993-mdftranslation1234567890abcdef1234567890-fc073a6.hf.space/v1/translate",
181
- json={"from_language": "sq", "to_language": "en", "input_text": text},
182
- headers={"accept": "application/json", "Content-Type": "application/json"},
183
- timeout=5,
184
- )
185
- resp.raise_for_status()
186
- return resp.json().get("translate", "")
187
- except Exception as e:
188
- if attempt == 1:
189
- raise gr.Error("Translation failed. Please try again.") from e
190
- raise gr.Error("Translation failed. Please try again.")
191
-
192
-
193
- # ------------------------------------------------------------
194
- # -------------------------- MAIN FUNCTION ---------------------
195
- # ------------------------------------------------------------
196
  @spaces.GPU(duration=get_duration)
197
  def generate_video(
198
  input_image,
@@ -204,9 +191,12 @@ def generate_video(
204
  guidance_scale_2=1.5,
205
  seed=42,
206
  randomize_seed=False,
207
- progress=None, # made optional – no UI change
208
  ):
209
- """Generate a video from an image + prompt."""
 
 
 
210
  if input_image is None:
211
  raise gr.Error("Please upload an input image.")
212
 
@@ -247,12 +237,12 @@ def generate_video(
247
 
248
 
249
  # ------------------------------------------------------------
250
- # --------------------------- UI -------------------------------
251
  # ------------------------------------------------------------
252
  def create_demo():
253
  with gr.Blocks(css="", title="Fast Image to Video") as demo:
254
  # -----------------------------------------------------------------
255
- # 500‑error guard – **exactly the same** as in your original file
256
  # -----------------------------------------------------------------
257
  gr.HTML(
258
  """
@@ -266,7 +256,7 @@ def create_demo():
266
  )
267
 
268
  # -----------------------------------------------------------------
269
- # All your custom CSS / visual theme – **unaltered**
270
  # -----------------------------------------------------------------
271
  gr.HTML(
272
  """
@@ -276,7 +266,6 @@ def create_demo():
276
  @keyframes glow-hover {0%{box-shadow:0 0 20px rgba(0,255,128,0.7);}50%{box-shadow:0 0 20px rgba(0,255,128,0.9);}100%{box-shadow:0 0 20px rgba(0,255,128,0.7);}}
277
  @keyframes slide {0%{background-position:0% 50%;}50%{background-position:100% 50%;}100%{background-position:0% 50%;}}
278
  @keyframes pulse {0%,100%{opacity:0.7;}50%{opacity:1;}}
279
- @keyframes typewriter {0%{width:0;}100%{width:100%;}}
280
  body{
281
  background:#000 !important;
282
  color:#FFF !important;
@@ -295,7 +284,7 @@ def create_demo():
295
  body::before{
296
  content:"";
297
  display:block;
298
- height:600px; /* <-- this is the top gap you asked for */
299
  background:#000 !important;
300
  }
301
  .gr-blocks,.container{
@@ -378,7 +367,7 @@ def create_demo():
378
  box-sizing:border-box !important;
379
  display:block !important;
380
  }
381
- /* FORCE HIDE ALL GRADIO PROCESSING ELEMENTS - 100+ SELECTORS */
382
  .image-container[aria-label="Generated Video"] .progress-text,
383
  .image-container[aria-label="Generated Video"] .gr-progress,
384
  .image-container[aria-label="Generated Video"] .gr-progress-bar,
@@ -433,23 +422,9 @@ def create_demo():
433
  .image-container[aria-label="Input Image"] .file-upload,
434
  .image-container[aria-label="Input Image"] .file-preview,
435
  .image-container[aria-label="Input Image"] .image-actions,
436
- .image-container[aria-label="Input Image"] .gr-file-upload,
437
- .image-container[aria-label="Input Image"] .gr-file,
438
- .image-container[aria-label="Input Image"] .gr-actions,
439
- .image-container[aria-label="Input Image"] .gr-upload-button,
440
- .image-container[aria-label="Input Image"] .gr-image-toolbar,
441
- .image-container[aria-label="Input Image"] .gr-file-actions,
442
- .image-container[aria-label="Input Image"] .gr-upload-options,
443
  .image-container[aria-label="Generated Video"] .file-upload,
444
  .image-container[aria-label="Generated Video"] .file-preview,
445
- .image-container[aria-label="Generated Video"] .image-actions,
446
- .image-container[aria-label="Generated Video"] .gr-file-upload,
447
- .image-container[aria-label="Generated Video"] .gr-file,
448
- .image-container[aria-label="Generated Video"] .gr-actions,
449
- .image-container[aria-label="Generated Video"] .gr-upload-button,
450
- .image-container[aria-label="Generated Video"] .gr-image-toolbar,
451
- .image-container[aria-label="Generated Video"] .gr-file-actions,
452
- .image-container[aria-label="Generated Video"] .gr-upload-options{
453
  display:none!important;
454
  }
455
  .image-container[aria-label="Generated Video"].processing{
@@ -483,10 +458,6 @@ def create_demo():
483
  .image-container[aria-label="Generated Video"].processing *{
484
  display:none!important;
485
  }
486
- .image-container[aria-label="Generated Video"].processing video,
487
- .image-container[aria-label="Generated Video"].processing img{
488
- display:none!important;
489
- }
490
  input,textarea,.gr-dropdown,.gr-dropdown select{
491
  background:#000!important;
492
  color:#FFF!important;
@@ -497,10 +468,6 @@ def create_demo():
497
  max-width:100vw!important;
498
  box-sizing:border-box!important;
499
  }
500
- input:hover,textarea:hover,.gr-dropdown:hover,.gr-dropdown select:hover{
501
- box-shadow:0 0 8px rgba(255,255,255,0.3)!important;
502
- transition:box-shadow .3s;
503
- }
504
  .gr-button-primary{
505
  background:linear-gradient(90deg,rgba(0,255,128,0.3),rgba(0,200,100,0.3),rgba(0,255,128,0.3))!important;
506
  background-size:200% 100%;
@@ -561,10 +528,7 @@ def create_demo():
561
  .gr-button-primary:hover{
562
  box-shadow:0 0 12px rgba(0,255,128,0.9)!important;
563
  }
564
- .image-container{
565
- min-height:300px;
566
- box-shadow:0 0 8px rgba(255,255,255,0.3)!important;
567
- }
568
  .image-container[aria-label="Generated Video"].processing::before{
569
  font-size:1.2rem!important;
570
  }
@@ -574,7 +538,7 @@ def create_demo():
574
  )
575
 
576
  # -----------------------------------------------------------------
577
- # UI layout – **exactly the same structure you built**
578
  # -----------------------------------------------------------------
579
  with gr.Row(elem_id="general_items"):
580
  gr.Markdown("# ")
@@ -614,7 +578,7 @@ def create_demo():
614
  )
615
 
616
  # -----------------------------------------------------------------
617
- # Wiring – unchanged component order (matches generate_video signature)
618
  # -----------------------------------------------------------------
619
  generate_button.click(
620
  fn=generate_video,
@@ -628,6 +592,7 @@ def create_demo():
628
  gr.State(value=1.5), # guidance_scale_2
629
  gr.State(value=42), # seed
630
  gr.State(value=True), # randomize_seed
 
631
  ],
632
  outputs=[output_video, gr.State(value=42)],
633
  )
@@ -635,6 +600,9 @@ def create_demo():
635
  return demo
636
 
637
 
 
 
 
638
  if __name__ == "__main__":
639
  demo = create_demo()
640
  # keep the launch flags you originally used
 
1
+ # ------------------------------------------------------------
2
+ # IMPORTS
3
+ # ------------------------------------------------------------
4
  import spaces
5
  import torch
6
  import requests
 
22
  import aoti
23
 
24
  # ------------------------------------------------------------
25
+ # CONFIG
26
  # ------------------------------------------------------------
27
  MODEL_ID = "Wan-AI/Wan2.2-I2V-A14B-Diffusers"
28
 
 
48
  )
49
 
50
  # ------------------------------------------------------------
51
+ # MODEL LOADING
52
  # ------------------------------------------------------------
53
  pipe = WanImageToVideoPipeline.from_pretrained(
54
  MODEL_ID,
 
73
  weight_name="Lightx2v/lightx2v_I2V_14B_480p_cfg_step_distill_rank128_bf16.safetensors",
74
  adapter_name="lightx2v",
75
  )
76
+
77
  kwargs_lora = {"load_into_transformer_2": True}
78
  pipe.load_lora_weights(
79
  "Kijai/WanVideo_comfy",
 
81
  adapter_name="lightx2v_2",
82
  **kwargs_lora,
83
  )
84
+
85
  pipe.set_adapters(["lightx2v", "lightx2v_2"], adapter_weights=[1.0, 1.0])
86
  pipe.fuse_lora(adapter_names=["lightx2v"], lora_scale=3.0, components=["transformer"])
87
  pipe.fuse_lora(adapter_names=["lightx2v_2"], lora_scale=1.0, components=["transformer_2"])
 
96
  aoti.aoti_blocks_load(pipe.transformer_2, "zerogpu-aoti/Wan2", variant="fp8da")
97
 
98
  # ------------------------------------------------------------
99
+ # HELPERS
100
  # ------------------------------------------------------------
101
  def resize_image(image: Image.Image) -> Image.Image:
102
  """Resize / crop the input image so the model receives a valid size."""
 
122
  top = (height - crop_h) // 2
123
  img = image.crop((0, top, width, top + crop_h))
124
  else:
125
+ # No cropping needed – just compute target size
126
  if width > height: # landscape
127
  target_w = MAX_DIM
128
  target_h = int(round(target_w / aspect_ratio))
 
131
  target_w = int(round(target_h * aspect_ratio))
132
  img = image
133
 
134
+ # Round to the nearest multiple of MULTIPLE_OF and clamp
135
  final_w = round(target_w / MULTIPLE_OF) * MULTIPLE_OF
136
  final_h = round(target_h / MULTIPLE_OF) * MULTIPLE_OF
137
  final_w = max(MIN_DIM, min(MAX_DIM, final_w))
 
141
 
142
 
143
  def get_num_frames(duration_seconds: float) -> int:
144
+ """Number of frames the model will generate for the requested duration."""
145
  return 1 + int(
146
  np.clip(
147
  int(round(duration_seconds * FIXED_FPS)),
 
161
  guidance_scale_2,
162
  seed,
163
  randomize_seed,
164
+ progress, # <-- required by @spaces.GPU
165
  ):
166
+ """
167
+ Rough estimate of how long the GPU will be occupied.
168
+ Used by the @spaces.GPU decorator to enforce the 30‑second safety cap.
169
+ """
170
  BASE_FRAMES_HEIGHT_WIDTH = 81 * 832 * 624
171
  BASE_STEP_DURATION = 15
172
 
 
176
  step_duration = BASE_STEP_DURATION * factor ** 1.5
177
  est = 10 + int(steps) * step_duration
178
 
179
+ # Never block the GPU > 30 s
180
  return min(est, 30)
181
 
182
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  @spaces.GPU(duration=get_duration)
184
  def generate_video(
185
  input_image,
 
191
  guidance_scale_2=1.5,
192
  seed=42,
193
  randomize_seed=False,
194
+ progress=gr.Progress(track_tqdm=True), # <-- now mandatory
195
  ):
196
+ """
197
+ Generate a video from an image + prompt.
198
+ Returns (video_path, seed_used).
199
+ """
200
  if input_image is None:
201
  raise gr.Error("Please upload an input image.")
202
 
 
237
 
238
 
239
  # ------------------------------------------------------------
240
+ # UI unchanged visual / CSS / 500‑guard / unique‑link
241
  # ------------------------------------------------------------
242
  def create_demo():
243
  with gr.Blocks(css="", title="Fast Image to Video") as demo:
244
  # -----------------------------------------------------------------
245
+ # 500‑error guard – exactly the same as in your fork
246
  # -----------------------------------------------------------------
247
  gr.HTML(
248
  """
 
256
  )
257
 
258
  # -----------------------------------------------------------------
259
+ # Custom CSS kept verbatim
260
  # -----------------------------------------------------------------
261
  gr.HTML(
262
  """
 
266
  @keyframes glow-hover {0%{box-shadow:0 0 20px rgba(0,255,128,0.7);}50%{box-shadow:0 0 20px rgba(0,255,128,0.9);}100%{box-shadow:0 0 20px rgba(0,255,128,0.7);}}
267
  @keyframes slide {0%{background-position:0% 50%;}50%{background-position:100% 50%;}100%{background-position:0% 50%;}}
268
  @keyframes pulse {0%,100%{opacity:0.7;}50%{opacity:1;}}
 
269
  body{
270
  background:#000 !important;
271
  color:#FFF !important;
 
284
  body::before{
285
  content:"";
286
  display:block;
287
+ height:600px; /* <-- top gap you asked for */
288
  background:#000 !important;
289
  }
290
  .gr-blocks,.container{
 
367
  box-sizing:border-box !important;
368
  display:block !important;
369
  }
370
+ /* HIDE ALL GRADIO PROCESSING UI 100+ SELECTORS */
371
  .image-container[aria-label="Generated Video"] .progress-text,
372
  .image-container[aria-label="Generated Video"] .gr-progress,
373
  .image-container[aria-label="Generated Video"] .gr-progress-bar,
 
422
  .image-container[aria-label="Input Image"] .file-upload,
423
  .image-container[aria-label="Input Image"] .file-preview,
424
  .image-container[aria-label="Input Image"] .image-actions,
 
 
 
 
 
 
 
425
  .image-container[aria-label="Generated Video"] .file-upload,
426
  .image-container[aria-label="Generated Video"] .file-preview,
427
+ .image-container[aria-label="Generated Video"] .image-actions{
 
 
 
 
 
 
 
428
  display:none!important;
429
  }
430
  .image-container[aria-label="Generated Video"].processing{
 
458
  .image-container[aria-label="Generated Video"].processing *{
459
  display:none!important;
460
  }
 
 
 
 
461
  input,textarea,.gr-dropdown,.gr-dropdown select{
462
  background:#000!important;
463
  color:#FFF!important;
 
468
  max-width:100vw!important;
469
  box-sizing:border-box!important;
470
  }
 
 
 
 
471
  .gr-button-primary{
472
  background:linear-gradient(90deg,rgba(0,255,128,0.3),rgba(0,200,100,0.3),rgba(0,255,128,0.3))!important;
473
  background-size:200% 100%;
 
528
  .gr-button-primary:hover{
529
  box-shadow:0 0 12px rgba(0,255,128,0.9)!important;
530
  }
531
+ .image-container{min-height:300px;}
 
 
 
532
  .image-container[aria-label="Generated Video"].processing::before{
533
  font-size:1.2rem!important;
534
  }
 
538
  )
539
 
540
  # -----------------------------------------------------------------
541
+ # UI layout – unchanged component order (matches generate_video signature)
542
  # -----------------------------------------------------------------
543
  with gr.Row(elem_id="general_items"):
544
  gr.Markdown("# ")
 
578
  )
579
 
580
  # -----------------------------------------------------------------
581
+ # Wiring – keep the same order as the function signature
582
  # -----------------------------------------------------------------
583
  generate_button.click(
584
  fn=generate_video,
 
592
  gr.State(value=1.5), # guidance_scale_2
593
  gr.State(value=42), # seed
594
  gr.State(value=True), # randomize_seed
595
+ # progress is *not* passed – the @spaces.GPU decorator injects it
596
  ],
597
  outputs=[output_video, gr.State(value=42)],
598
  )
 
600
  return demo
601
 
602
 
603
+ # ------------------------------------------------------------
604
+ # MAIN
605
+ # ------------------------------------------------------------
606
  if __name__ == "__main__":
607
  demo = create_demo()
608
  # keep the launch flags you originally used