ginipick commited on
Commit
f83c2b9
·
verified ·
1 Parent(s): 59d5bb3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +58 -43
app.py CHANGED
@@ -266,8 +266,8 @@ def resize_image_landscape(image: Image.Image) -> Image.Image:
266
  return image.resize((LANDSCAPE_WIDTH, LANDSCAPE_HEIGHT), Image.LANCZOS)
267
 
268
  def get_duration(input_image, prompt, steps, negative_prompt, duration_seconds, guidance_scale, guidance_scale_2, seed, randomize_seed):
269
- # Duration based on steps parameter
270
- return int(steps) * 15
271
 
272
  @spaces.GPU(duration=get_duration)
273
  def generate_video(
@@ -275,7 +275,7 @@ def generate_video(
275
  prompt,
276
  steps=4,
277
  negative_prompt=default_negative_prompt,
278
- duration_seconds=MAX_DURATION,
279
  guidance_scale=1,
280
  guidance_scale_2=1,
281
  seed=42,
@@ -286,61 +286,76 @@ def generate_video(
286
  if input_image is None:
287
  raise gr.Error("Please generate or upload an image first.")
288
 
289
- # Initialize pipeline if needed
290
- initialize_video_pipeline()
291
-
292
- if video_pipe is None:
293
- raise gr.Error("Video pipeline not initialized. Please check GPU availability.")
294
-
295
  try:
296
- # Ensure frames are divisible by 4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  num_frames = int(round(duration_seconds * FIXED_FPS))
298
- num_frames = np.clip(num_frames, MIN_FRAMES_MODEL, MAX_FRAMES_MODEL)
299
- # Round to nearest number divisible by 4
300
  num_frames = ((num_frames - 1) // 4) * 4 + 1
301
 
302
  current_seed = random.randint(0, MAX_SEED) if randomize_seed else int(seed)
303
- resized_image = resize_image_for_video(input_image)
304
 
305
- # Clear cache before generation
306
- torch.cuda.empty_cache()
307
- gc.collect()
308
 
309
- # Generate video with memory management
310
  with torch.inference_mode():
311
- output_frames_list = video_pipe(
312
- image=resized_image,
313
- prompt=prompt,
314
- negative_prompt=negative_prompt,
315
- height=resized_image.height,
316
- width=resized_image.width,
317
- num_frames=num_frames,
318
- guidance_scale=float(guidance_scale),
319
- guidance_scale_2=float(guidance_scale_2),
320
- num_inference_steps=int(steps),
321
- generator=torch.Generator(device="cuda").manual_seed(current_seed),
322
- ).frames[0]
 
323
 
324
  # Clear cache after generation
325
  torch.cuda.empty_cache()
326
  gc.collect()
327
 
 
328
  with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmpfile:
329
  video_path = tmpfile.name
330
 
331
  export_to_video(output_frames_list, video_path, fps=FIXED_FPS)
332
 
333
- return video_path, current_seed, "🎬 Video generated successfully!"
334
 
335
  except RuntimeError as e:
336
- if "out of memory" in str(e).lower() or "CUDA" in str(e):
337
- torch.cuda.empty_cache()
338
- gc.collect()
339
- raise gr.Error("GPU memory error. Try reducing the duration or number of steps.")
340
  else:
341
- raise gr.Error(f"Video generation error: {str(e)}")
342
  except Exception as e:
343
- raise gr.Error(f"Unexpected error: {str(e)}")
344
 
345
  # ===========================
346
  # Enhanced CSS
@@ -541,12 +556,12 @@ with gr.Blocks(css=css, theme=gr.themes.Base()) as demo:
541
  lines=3
542
  )
543
  duration_input = gr.Slider(
544
- minimum=MIN_DURATION,
545
- maximum=MAX_DURATION,
546
  step=0.1,
547
- value=3.5,
548
  label="Duration (seconds)",
549
- info=f"Clamped to {MIN_FRAMES_MODEL}-{MAX_FRAMES_MODEL} frames at {FIXED_FPS}fps"
550
  )
551
 
552
  with gr.Accordion("Advanced Settings", open=False):
@@ -568,10 +583,10 @@ with gr.Blocks(css=css, theme=gr.themes.Base()) as demo:
568
  )
569
  steps_slider = gr.Slider(
570
  minimum=1,
571
- maximum=30,
572
  step=1,
573
- value=6,
574
- label="Inference Steps"
575
  )
576
  guidance_1 = gr.Slider(
577
  minimum=0.0,
 
266
  return image.resize((LANDSCAPE_WIDTH, LANDSCAPE_HEIGHT), Image.LANCZOS)
267
 
268
  def get_duration(input_image, prompt, steps, negative_prompt, duration_seconds, guidance_scale, guidance_scale_2, seed, randomize_seed):
269
+ # Shorter duration for stability
270
+ return min(60, int(steps) * 10)
271
 
272
  @spaces.GPU(duration=get_duration)
273
  def generate_video(
 
275
  prompt,
276
  steps=4,
277
  negative_prompt=default_negative_prompt,
278
+ duration_seconds=2.0, # Reduced default
279
  guidance_scale=1,
280
  guidance_scale_2=1,
281
  seed=42,
 
286
  if input_image is None:
287
  raise gr.Error("Please generate or upload an image first.")
288
 
 
 
 
 
 
 
289
  try:
290
+ # Initialize pipeline if needed (simplified)
291
+ global video_pipe
292
+ if video_pipe is None:
293
+ print("Initializing video pipeline...")
294
+ video_pipe = WanImageToVideoPipeline.from_pretrained(
295
+ VIDEO_MODEL_ID,
296
+ torch_dtype=torch.bfloat16,
297
+ variant="fp16",
298
+ use_safetensors=True
299
+ ).to('cuda')
300
+
301
+ # Load Lightning LoRA for faster generation
302
+ try:
303
+ video_pipe.load_lora_weights("Kijai/WanVideo_comfy", weight_name="Wan22-Lightning-4-cfg1_bf16_v0.9.safetensors")
304
+ video_pipe.fuse_lora(lora_scale=1.0)
305
+ except:
306
+ pass
307
+
308
+ # Clear cache before generation
309
+ torch.cuda.empty_cache()
310
+ gc.collect()
311
+
312
+ # Ensure frames are divisible by 4 and limit to reasonable range
313
  num_frames = int(round(duration_seconds * FIXED_FPS))
314
+ num_frames = np.clip(num_frames, 9, 33) # Limit to 0.5-2 seconds
 
315
  num_frames = ((num_frames - 1) // 4) * 4 + 1
316
 
317
  current_seed = random.randint(0, MAX_SEED) if randomize_seed else int(seed)
 
318
 
319
+ # Resize image
320
+ resized_image = resize_image_for_video(input_image)
 
321
 
322
+ # Generate with reduced settings
323
  with torch.inference_mode():
324
+ with torch.autocast('cuda', dtype=torch.bfloat16):
325
+ output_frames_list = video_pipe(
326
+ image=resized_image,
327
+ prompt=prompt,
328
+ negative_prompt=negative_prompt,
329
+ height=resized_image.height,
330
+ width=resized_image.width,
331
+ num_frames=num_frames,
332
+ guidance_scale=float(guidance_scale),
333
+ guidance_scale_2=float(guidance_scale_2),
334
+ num_inference_steps=int(steps),
335
+ generator=torch.Generator(device="cuda").manual_seed(current_seed),
336
+ ).frames[0]
337
 
338
  # Clear cache after generation
339
  torch.cuda.empty_cache()
340
  gc.collect()
341
 
342
+ # Save video
343
  with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmpfile:
344
  video_path = tmpfile.name
345
 
346
  export_to_video(output_frames_list, video_path, fps=FIXED_FPS)
347
 
348
+ return video_path, current_seed, f"🎬 Video generated successfully! ({num_frames} frames)"
349
 
350
  except RuntimeError as e:
351
+ torch.cuda.empty_cache()
352
+ gc.collect()
353
+ if "out of memory" in str(e).lower():
354
+ raise gr.Error("GPU memory exceeded. Try reducing duration to 1-2 seconds and steps to 4.")
355
  else:
356
+ raise gr.Error(f"GPU error: {str(e)[:100]}")
357
  except Exception as e:
358
+ raise gr.Error(f"Error: {str(e)[:200]}")
359
 
360
  # ===========================
361
  # Enhanced CSS
 
556
  lines=3
557
  )
558
  duration_input = gr.Slider(
559
+ minimum=0.5,
560
+ maximum=2.0,
561
  step=0.1,
562
+ value=1.5,
563
  label="Duration (seconds)",
564
+ info="Shorter videos use less memory"
565
  )
566
 
567
  with gr.Accordion("Advanced Settings", open=False):
 
583
  )
584
  steps_slider = gr.Slider(
585
  minimum=1,
586
+ maximum=8,
587
  step=1,
588
+ value=4,
589
+ label="Inference Steps (4 recommended)"
590
  )
591
  guidance_1 = gr.Slider(
592
  minimum=0.0,