dream2589632147 commited on
Commit
60ba488
·
verified ·
1 Parent(s): 7abbdaa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +62 -70
app.py CHANGED
@@ -1,8 +1,6 @@
1
  import spaces
2
  import torch
3
  import os
4
- import subprocess
5
- import gradio as gr
6
  import sys
7
  # 🌟 إضافة هذا لإزالة تحذير tokenizers
8
  os.environ["TOKENIZERS_PARALLELISM"] = "false"
@@ -20,7 +18,6 @@ except ImportError as e:
20
  import tempfile
21
  import numpy as np
22
  from PIL import Image
23
- import random
24
  import gc
25
  # (بقية تعريفات الثوابت و MODELS كما هي)
26
  MODEL_ID = "Wan-AI/Wan2.2-I2V-A14B-Diffusers"
@@ -49,26 +46,6 @@ MIN_FRAMES_MODEL = 8
49
  MAX_FRAMES_MODEL = 720 # 45 ثانية عند 16 FPS (45 * 16 = 720)
50
  MIN_DURATION = round(MIN_FRAMES_MODEL / FIXED_FPS, 1)
51
  MAX_DURATION = round(MAX_FRAMES_MODEL / FIXED_FPS, 1)
52
- # Load the pipeline
53
- pipe = WanImageToVideoPipeline.from_pretrained(
54
- MODEL_ID,
55
- torch_dtype=torch.bfloat16,
56
- ).to('cuda')
57
- pipe.enable_model_cpu_offload() # 🌟 تحسين: offload إلى CPU لتوفير 40% GPU memory
58
- # Load LoRA with error handling for key mismatches
59
- try:
60
- pipe.load_lora_weights(
61
- "Kijai/WanVideo_comfy",
62
- weight_name="Lightx2v/lightx2v_I2V_14B_480p_cfg_step_distill_rank128_bf16.safetensors",
63
- adapter_name="lightx2v",
64
- low_cpu_mem_usage=True # Helps with memory during load
65
- )
66
- print("LoRA weights loaded successfully!")
67
- except Exception as e:
68
- print(f"Warning: LoRA load failed (possible key mismatch): {e}")
69
- print("Proceeding without LoRA for now.")
70
- gc.collect() # Free up memory after loads
71
- torch.cuda.empty_cache()
72
  # 🌟 وظيفة لتحضير الصورة حسب الـ preset
73
  def prepare_image(image, preset_key):
74
  if image is None:
@@ -104,69 +81,84 @@ def prepare_image(image, preset_key):
104
  image = image.resize((width, height), Image.Resampling.LANCZOS)
105
 
106
  return image
107
- # 🌟 وظيفة لتوليد الفيديو من الصورة والـ prompt
 
108
  @torch.no_grad()
109
- def generate_video(image, prompt, negative_prompt, num_frames, preset_key, guidance_scale=7.5, num_inference_steps=20): # Reduced default steps to 20 for faster/less memory
110
- if image is None:
111
- raise ValueError("No image provided!")
112
-
113
- prepared_image = prepare_image(image, preset_key)
114
- height, width = prepared_image.size[1], prepared_image.size[0]
115
-
116
- # Clamp num_frames
117
- num_frames = max(MIN_FRAMES_MODEL, min(num_frames, MAX_FRAMES_MODEL))
118
-
119
- # Memory check and cleanup before generation
120
- if torch.cuda.is_available():
121
- print(f"GPU Memory before generation: {torch.cuda.memory_allocated() / 1024**3:.2f} GB")
122
- torch.cuda.empty_cache()
123
-
124
- video_frames = pipe(
125
- prompt=prompt,
126
- image=prepared_image,
127
- negative_prompt=negative_prompt,
128
- num_frames=num_frames,
129
- height=height,
130
- width=width,
131
- guidance_scale=guidance_scale,
132
- num_inference_steps=num_inference_steps,
133
- ).frames[0]
134
-
135
- # Export to temporary MP4
136
- with tempfile.TemporaryDirectory() as tmpdirname:
137
- temp_video_path = os.path.join(tmpdirname, "temp_video.mp4")
138
- export_to_video(video_frames, temp_video_path, fps=FIXED_FPS)
139
- return temp_video_path
140
- # 🌟 الوظيفة الرئيسية للتطبيق: توليد فيديو من صورة ونص فقط
141
- @spaces.GPU # إضافة هذا لتفعيل GPU في Hugging Face Spaces
142
- def generate_video_only(image, prompt, negative_prompt, num_frames, preset_key):
143
  try:
144
- # توليد الفيديو
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  print("Generating video...")
146
- final_video = generate_video(image, prompt, negative_prompt, num_frames, preset_key)
147
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  # Cleanup after generation
 
149
  gc.collect()
150
  if torch.cuda.is_available():
151
  torch.cuda.empty_cache()
152
-
153
- return final_video, "Success!"
154
  except torch.cuda.OutOfMemoryError:
155
- return None, "Error: Out of GPU memory. Try reducing frames or resolution."
156
  except Exception as e:
157
  return None, f"Error: {str(e)}"
158
  # 🌟 إعداد الواجهة بـ Gradio
159
  with gr.Blocks(title="Wan2.2 Image-to-Video Generator") as demo:
160
  gr.Markdown("# 🌟 Wan2.2 I2V Generator")
161
- gr.Markdown("Upload an image, add a prompt, and generate a video! Note: For T4 GPU, use <32 frames for best results.")
162
 
163
  with gr.Row():
164
  with gr.Column(scale=1):
165
  image_input = gr.Image(type="pil", label="Input Image")
166
  prompt_input = gr.Textbox(label="Prompt", placeholder="A dynamic scene from the image...", lines=2)
167
  negative_prompt_input = gr.Textbox(label="Negative Prompt", placeholder="blurry, low quality", lines=1)
168
- num_frames_slider = gr.Slider(MIN_FRAMES_MODEL, MAX_FRAMES_MODEL, value=16, step=8, label="Number of Frames (Max 45s at 16 FPS)") # Default to 16 to avoid OOM
169
  preset_dropdown = gr.Dropdown(choices=list(DIMENSION_PRESETS.keys()), value="Custom (Default)", label="Output Preset")
 
170
  generate_btn = gr.Button("Generate Video", variant="primary")
171
 
172
  with gr.Column(scale=1):
@@ -181,7 +173,7 @@ with gr.Blocks(title="Wan2.2 Image-to-Video Generator") as demo:
181
 
182
  generate_btn.click(
183
  fn=generate_video_only,
184
- inputs=[image_input, prompt_input, negative_prompt_input, num_frames_slider, preset_dropdown],
185
  outputs=[output_video, status_output]
186
  )
187
 
@@ -189,11 +181,11 @@ with gr.Blocks(title="Wan2.2 Image-to-Video Generator") as demo:
189
  gr.Examples(
190
  examples=[
191
  [
192
- None, # No example image; user to upload
193
  "The person in the image starts walking towards the camera with a smile.",
194
  "static, blurry",
195
- 16, # Reduced for example
196
- "YouTube Full HD (16:9)"
197
  ]
198
  ],
199
  inputs=[image_input, prompt_input, negative_prompt_input, num_frames_slider, preset_dropdown]
 
1
  import spaces
2
  import torch
3
  import os
 
 
4
  import sys
5
  # 🌟 إضافة هذا لإزالة تحذير tokenizers
6
  os.environ["TOKENIZERS_PARALLELISM"] = "false"
 
18
  import tempfile
19
  import numpy as np
20
  from PIL import Image
 
21
  import gc
22
  # (بقية تعريفات الثوابت و MODELS كما هي)
23
  MODEL_ID = "Wan-AI/Wan2.2-I2V-A14B-Diffusers"
 
46
  MAX_FRAMES_MODEL = 720 # 45 ثانية عند 16 FPS (45 * 16 = 720)
47
  MIN_DURATION = round(MIN_FRAMES_MODEL / FIXED_FPS, 1)
48
  MAX_DURATION = round(MAX_FRAMES_MODEL / FIXED_FPS, 1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  # 🌟 وظيفة لتحضير الصورة حسب الـ preset
50
  def prepare_image(image, preset_key):
51
  if image is None:
 
81
  image = image.resize((width, height), Image.Resampling.LANCZOS)
82
 
83
  return image
84
+ # 🌟 الوظيفة الرئيسية للتطبيق: توليد فيديو من صورة ونص فقط (مع lazy loading للنموذج)
85
+ @spaces.GPU(duration=600) # 10 دقائق timeout للسماح بوقت أطول
86
  @torch.no_grad()
87
+ def generate_video_only(image, prompt, negative_prompt, num_frames, preset_key, guidance_scale=7.5, num_inference_steps=10): # Reduced steps to 10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  try:
89
+ # Lazy load the pipeline inside the function to avoid startup issues
90
+ print("Loading model...")
91
+ pipe = WanImageToVideoPipeline.from_pretrained(
92
+ MODEL_ID,
93
+ torch_dtype=torch.bfloat16,
94
+ ).to('cuda')
95
+ pipe.enable_model_cpu_offload() # Offload to CPU for memory savings
96
+
97
+ # Optional: Load LoRA if possible
98
+ try:
99
+ pipe.load_lora_weights(
100
+ "Kijai/WanVideo_comfy",
101
+ weight_name="Lightx2v/lightx2v_I2V_14B_480p_cfg_step_distill_rank128_bf16.safetensors",
102
+ adapter_name="lightx2v",
103
+ low_cpu_mem_usage=True
104
+ )
105
+ print("LoRA weights loaded successfully!")
106
+ except Exception as e:
107
+ print(f"Warning: LoRA load failed: {e}")
108
+ print("Proceeding without LoRA.")
109
+
110
+ # Memory cleanup before generation
111
+ gc.collect()
112
+ if torch.cuda.is_available():
113
+ torch.cuda.empty_cache()
114
+ print(f"GPU Memory before generation: {torch.cuda.memory_allocated() / 1024**3:.2f} GB")
115
+
116
+ # Prepare image and generate
117
+ prepared_image = prepare_image(image, preset_key)
118
+ height, width = prepared_image.size[1], prepared_image.size[0]
119
+ num_frames = max(MIN_FRAMES_MODEL, min(num_frames, MAX_FRAMES_MODEL))
120
+
121
  print("Generating video...")
122
+ video_frames = pipe(
123
+ prompt=prompt,
124
+ image=prepared_image,
125
+ negative_prompt=negative_prompt,
126
+ num_frames=num_frames,
127
+ height=height,
128
+ width=width,
129
+ guidance_scale=guidance_scale,
130
+ num_inference_steps=num_inference_steps,
131
+ ).frames[0]
132
+
133
+ # Export to temporary MP4
134
+ with tempfile.TemporaryDirectory() as tmpdirname:
135
+ temp_video_path = os.path.join(tmpdirname, "temp_video.mp4")
136
+ export_to_video(video_frames, temp_video_path, fps=FIXED_FPS)
137
+
138
  # Cleanup after generation
139
+ del pipe # Delete to free memory
140
  gc.collect()
141
  if torch.cuda.is_available():
142
  torch.cuda.empty_cache()
143
+
144
+ return temp_video_path, "Success! Video generated."
145
  except torch.cuda.OutOfMemoryError:
146
+ return None, "Error: Out of GPU memory. Try fewer frames (e.g., 8) or lower resolution."
147
  except Exception as e:
148
  return None, f"Error: {str(e)}"
149
  # 🌟 إعداد الواجهة بـ Gradio
150
  with gr.Blocks(title="Wan2.2 Image-to-Video Generator") as demo:
151
  gr.Markdown("# 🌟 Wan2.2 I2V Generator")
152
+ gr.Markdown("Upload an image, add a prompt, and generate a video! **Tip: Start with 8 frames on free T4 GPU to avoid timeouts.**")
153
 
154
  with gr.Row():
155
  with gr.Column(scale=1):
156
  image_input = gr.Image(type="pil", label="Input Image")
157
  prompt_input = gr.Textbox(label="Prompt", placeholder="A dynamic scene from the image...", lines=2)
158
  negative_prompt_input = gr.Textbox(label="Negative Prompt", placeholder="blurry, low quality", lines=1)
159
+ num_frames_slider = gr.Slider(MIN_FRAMES_MODEL, 32, value=8, step=8, label="Number of Frames (Start low to test)") # Limited to 32 max for free tier
160
  preset_dropdown = gr.Dropdown(choices=list(DIMENSION_PRESETS.keys()), value="Custom (Default)", label="Output Preset")
161
+ steps_slider = gr.Slider(5, 20, value=10, step=5, label="Inference Steps (Lower = Faster)")
162
  generate_btn = gr.Button("Generate Video", variant="primary")
163
 
164
  with gr.Column(scale=1):
 
173
 
174
  generate_btn.click(
175
  fn=generate_video_only,
176
+ inputs=[image_input, prompt_input, negative_prompt_input, num_frames_slider, preset_dropdown, gr.State(7.5), steps_slider], # Added steps
177
  outputs=[output_video, status_output]
178
  )
179
 
 
181
  gr.Examples(
182
  examples=[
183
  [
184
+ None, # No example image; user to upload
185
  "The person in the image starts walking towards the camera with a smile.",
186
  "static, blurry",
187
+ 8,
188
+ "Custom (Default)"
189
  ]
190
  ],
191
  inputs=[image_input, prompt_input, negative_prompt_input, num_frames_slider, preset_dropdown]