dream2589632147 commited on
Commit
acd25ee
·
verified ·
1 Parent(s): 5003e5c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +98 -57
app.py CHANGED
@@ -11,7 +11,6 @@ import random
11
  import gc
12
  from torchao.quantization import quantize_
13
  from torchao.quantization import Float8DynamicActivationFloat8WeightConfig, Int8WeightOnlyConfig
14
- import aoti
15
 
16
  # ------------------------
17
  # إعدادات النموذج
@@ -26,51 +25,75 @@ MAX_SEED = np.iinfo(np.int32).max
26
  FIXED_FPS = 16
27
  MIN_FRAMES_MODEL = 8
28
  MAX_FRAMES_MODEL = 480
29
- MIN_DURATION = round(MIN_FRAMES_MODEL/FIXED_FPS, 1)
30
- MAX_DURATION = round(MAX_FRAMES_MODEL/FIXED_FPS, 1)
31
 
32
  # ------------------------
33
  # تحميل النموذج
34
  # ------------------------
35
- pipe = WanImageToVideoPipeline.from_pretrained(MODEL_ID,
36
- transformer=WanTransformer3DModel.from_pretrained('cbensimon/Wan2.2-I2V-A14B-bf16-Diffusers',
 
 
 
 
37
  subfolder='transformer',
38
- torch_dtype=torch.bfloat16,
39
- device_map='cuda'),
40
- transformer_2=WanTransformer3DModel.from_pretrained('cbensimon/Wan2.2-I2V-A14B-bf16-Diffusers',
 
 
41
  subfolder='transformer_2',
42
- torch_dtype=torch.bfloat16,
43
- device_map='cuda'),
44
- torch_dtype=torch.bfloat16,
 
45
  ).to('cuda')
46
 
47
  pipe.load_lora_weights(
48
- "Kijai/WanVideo_comfy",
49
- weight_name="Lightx2v/lightx2v_I2V_14B_480p_cfg_step_distill_rank128_bf16.safetensors",
50
  adapter_name="lightx2v"
51
  )
52
- kwargs_lora = {"load_into_transformer_2": True}
53
  pipe.load_lora_weights(
54
- "Kijai/WanVideo_comfy",
55
- weight_name="Lightx2v/lightx2v_I2V_14B_480p_cfg_step_distill_rank128_bf16.safetensors",
56
- adapter_name="lightx2v_2", **kwargs_lora
 
57
  )
58
- pipe.set_adapters(["lightx2v", "lightx2v_2"], adapter_weights=[1., 1.])
59
- pipe.fuse_lora(adapter_names=["lightx2v"], lora_scale=3., components=["transformer"])
60
- pipe.fuse_lora(adapter_names=["lightx2v_2"], lora_scale=1., components=["transformer_2"])
61
- pipe.unload_lora_weights()
62
 
63
- quantize_(pipe.text_encoder, Int8WeightOnlyConfig())
64
- quantize_(pipe.transformer, Float8DynamicActivationFloat8WeightConfig())
65
- quantize_(pipe.transformer_2, Float8DynamicActivationFloat8WeightConfig())
66
- aoti.aoti_blocks_load(pipe.transformer, 'zerogpu-aoti/Wan2', variant='fp8da')
67
- aoti.aoti_blocks_load(pipe.transformer_2, 'zerogpu-aoti/Wan2', variant='fp8da')
68
 
69
  # ------------------------
70
- # الموجهات
71
  # ------------------------
72
- default_prompt_i2v = "ultra realistic cinematic footage, perfectly preserved facial identity and body structure across all frames..."
73
- default_negative_prompt = "low quality, low resolution, poor lighting, flickering, artifacted highlights, etc."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
 
75
  # ------------------------
76
  # أدوات الصورة والفيديو
@@ -79,30 +102,31 @@ def resize_image(image: Image.Image) -> Image.Image:
79
  width, height = image.size
80
  if width == height:
81
  return image.resize((SQUARE_DIM, SQUARE_DIM), Image.LANCZOS)
 
82
  aspect_ratio = width / height
83
  MAX_AR = MAX_DIM / MIN_DIM
84
  MIN_AR = MIN_DIM / MAX_DIM
85
- image_to_resize = image
86
  if aspect_ratio > MAX_AR:
87
- target_w, target_h = MAX_DIM, MIN_DIM
88
  crop_width = int(round(height * MAX_AR))
89
  left = (width - crop_width) // 2
90
- image_to_resize = image.crop((left, 0, left + crop_width, height))
91
  elif aspect_ratio < MIN_AR:
92
- target_w, target_h = MIN_DIM, MAX_DIM
93
  crop_height = int(round(width / MIN_AR))
94
  top = (height - crop_height) // 2
95
- image_to_resize = image.crop((0, top, width, top + crop_height))
 
 
 
 
96
  else:
97
- if width > height:
98
- target_w = MAX_DIM
99
- target_h = int(round(target_w / aspect_ratio))
100
- else:
101
- target_h = MAX_DIM
102
- target_w = int(round(target_h * aspect_ratio))
103
  final_w = max(MIN_DIM, min(MAX_DIM, round(target_w / MULTIPLE_OF) * MULTIPLE_OF))
104
  final_h = max(MIN_DIM, min(MAX_DIM, round(target_h / MULTIPLE_OF) * MULTIPLE_OF))
105
- return image_to_resize.resize((final_w, final_h), Image.LANCZOS)
 
106
 
107
  def get_num_frames(duration_seconds: float):
108
  return 1 + int(np.clip(int(round(duration_seconds * FIXED_FPS)), MIN_FRAMES_MODEL, MAX_FRAMES_MODEL))
@@ -111,16 +135,27 @@ def get_num_frames(duration_seconds: float):
111
  # عملية التوليد
112
  # ------------------------
113
  @spaces.GPU()
114
- def generate_video(input_image, prompt, steps=4, negative_prompt=default_negative_prompt,
115
- duration_seconds=3.5, guidance_scale=1, guidance_scale_2=1,
116
- seed=42, randomize_seed=False, progress=gr.Progress(track_tqdm=True)):
 
 
 
 
 
 
 
 
 
117
  if input_image is None:
118
- raise gr.Error("Please upload an input image.")
 
119
  num_frames = get_num_frames(duration_seconds)
120
  current_seed = random.randint(0, MAX_SEED) if randomize_seed else int(seed)
121
  resized_image = resize_image(input_image)
 
122
  with progress.tqdm(total=100) as pbar:
123
- pbar.set_description("Generating video...")
124
  output_frames_list = pipe(
125
  image=resized_image,
126
  prompt=prompt,
@@ -133,9 +168,13 @@ def generate_video(input_image, prompt, steps=4, negative_prompt=default_negativ
133
  num_inference_steps=int(steps),
134
  generator=torch.Generator(device="cuda").manual_seed(current_seed),
135
  ).frames[0]
 
136
  with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmpfile:
137
  video_path = tmpfile.name
 
138
  export_to_video(output_frames_list, video_path, fps=FIXED_FPS)
 
 
139
  return video_path, current_seed
140
 
141
  # ------------------------
@@ -144,34 +183,36 @@ def generate_video(input_image, prompt, steps=4, negative_prompt=default_negativ
144
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="violet")) as demo:
145
  gr.HTML("""
146
  <div style="text-align:center; padding:20px;">
147
- <h1 style="font-size: 2em;">Wan 2.2 Lightning Studio – AI Cinematic Video Generator - dream2589632147</h1>
148
- <p style="opacity:0.8;">Powered by dream2589632147 ⚡</p>
149
  </div>
150
  """)
151
-
152
  with gr.Row():
153
  with gr.Column(scale=1):
154
  input_image = gr.Image(label="🎞️ Input Image", type="pil")
155
  prompt = gr.Textbox(label="✨ Positive Prompt", value=default_prompt_i2v, lines=3)
156
  negative_prompt = gr.Textbox(label="🚫 Negative Prompt", value=default_negative_prompt, lines=3)
157
- duration = gr.Slider(MIN_DURATION, MAX_DURATION, value=3.5, step=0.1, label="Duration (seconds)")
158
  with gr.Accordion("⚙️ Advanced Settings", open=False):
159
  steps = gr.Slider(1, 30, value=6, step=1, label="Inference Steps")
160
- guidance_scale = gr.Slider(0.0, 10.0, value=1, step=0.5, label="Guidance Scale 1")
161
- guidance_scale_2 = gr.Slider(0.0, 10.0, value=1, step=0.5, label="Guidance Scale 2")
162
  seed = gr.Slider(0, MAX_SEED, value=42, step=1, label="Seed")
163
  randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
164
  generate_btn = gr.Button("🚀 Generate Cinematic Video", variant="primary")
165
 
166
  with gr.Column(scale=1):
167
- progress_text = gr.Textbox(label="Progress", interactive=False)
168
  video_output = gr.Video(label="🎬 Generated Video Preview", autoplay=True)
 
169
  download_btn = gr.File(label="⬇️ Download MP4")
170
 
171
- generate_btn.click(fn=generate_video,
172
- inputs=[input_image, prompt, steps, negative_prompt, duration,
173
- guidance_scale, guidance_scale_2, seed, randomize_seed],
174
- outputs=[video_output, seed])
 
 
175
 
176
  # زر تبديل الوضع الليلي/النهاري
177
  gr.HTML("""
 
11
  import gc
12
  from torchao.quantization import quantize_
13
  from torchao.quantization import Float8DynamicActivationFloat8WeightConfig, Int8WeightOnlyConfig
 
14
 
15
  # ------------------------
16
  # إعدادات النموذج
 
25
  FIXED_FPS = 16
26
  MIN_FRAMES_MODEL = 8
27
  MAX_FRAMES_MODEL = 480
28
+ MIN_DURATION = round(MIN_FRAMES_MODEL / FIXED_FPS, 1)
29
+ MAX_DURATION = round(MAX_FRAMES_MODEL / FIXED_FPS, 1)
30
 
31
  # ------------------------
32
  # تحميل النموذج
33
  # ------------------------
34
+ print("🔹 Loading model... Please wait, this may take a few minutes.")
35
+
36
+ pipe = WanImageToVideoPipeline.from_pretrained(
37
+ MODEL_ID,
38
+ transformer=WanTransformer3DModel.from_pretrained(
39
+ 'cbensimon/Wan2.2-I2V-A14B-bf16-Diffusers',
40
  subfolder='transformer',
41
+ torch_dtype=torch.float16,
42
+ device_map='cuda'
43
+ ),
44
+ transformer_2=WanTransformer3DModel.from_pretrained(
45
+ 'cbensimon/Wan2.2-I2V-A14B-bf16-Diffusers',
46
  subfolder='transformer_2',
47
+ torch_dtype=torch.float16,
48
+ device_map='cuda'
49
+ ),
50
+ torch_dtype=torch.float16
51
  ).to('cuda')
52
 
53
  pipe.load_lora_weights(
54
+ "Kijai/WanVideo_comfy",
55
+ weight_name="Lightx2v/lightx2v_I2V_14B_480p_cfg_step_distill_rank128_bf16.safetensors",
56
  adapter_name="lightx2v"
57
  )
 
58
  pipe.load_lora_weights(
59
+ "Kijai/WanVideo_comfy",
60
+ weight_name="Lightx2v/lightx2v_I2V_14B_480p_cfg_step_distill_rank128_bf16.safetensors",
61
+ adapter_name="lightx2v_2",
62
+ load_into_transformer_2=True
63
  )
64
+ pipe.set_adapters(["lightx2v", "lightx2v_2"], adapter_weights=[1.0, 1.0])
65
+ pipe.fuse_lora(adapter_names=["lightx2v"], lora_scale=3.0, components=["transformer"])
66
+ pipe.fuse_lora(adapter_names=["lightx2v_2"], lora_scale=1.0, components=["transformer_2"])
 
67
 
68
+ # لا نقوم بفك تحميل الـ LoRA بعد الدمج
 
 
 
 
69
 
70
  # ------------------------
71
+ # كوانتاز اختياري (تسريع وتحسين الذاكرة)
72
  # ------------------------
73
+ if torch.cuda.is_available():
74
+ try:
75
+ quantize_(pipe.text_encoder, Int8WeightOnlyConfig())
76
+ quantize_(pipe.transformer, Float8DynamicActivationFloat8WeightConfig())
77
+ quantize_(pipe.transformer_2, Float8DynamicActivationFloat8WeightConfig())
78
+ print("✅ Quantization applied successfully.")
79
+ except Exception as e:
80
+ print(f"⚠️ Quantization skipped due to: {e}")
81
+
82
+ # ------------------------
83
+ # الموجهات الافتراضية
84
+ # ------------------------
85
+ default_prompt_i2v = (
86
+ "ultra realistic cinematic footage, perfectly preserved facial identity and body structure "
87
+ "across all frames, stable anatomy and consistent body proportions, realistic muscle definition, "
88
+ "natural motion flow and breathing dynamics, seamless motion continuity, photorealistic clothing "
89
+ "preservation with accurate fabric movement and lighting response, consistent outfit color and texture, "
90
+ "high-fidelity skin texture, detailed lighting and shadows"
91
+ )
92
+
93
+ default_negative_prompt = (
94
+ "low quality, low resolution, poor lighting, underexposed, overexposed, noise, flickering, artifacts, "
95
+ "stutter, inconsistent motion, broken motion, distorted face, changing face, unnatural anatomy"
96
+ )
97
 
98
  # ------------------------
99
  # أدوات الصورة والفيديو
 
102
  width, height = image.size
103
  if width == height:
104
  return image.resize((SQUARE_DIM, SQUARE_DIM), Image.LANCZOS)
105
+
106
  aspect_ratio = width / height
107
  MAX_AR = MAX_DIM / MIN_DIM
108
  MIN_AR = MIN_DIM / MAX_DIM
109
+
110
  if aspect_ratio > MAX_AR:
 
111
  crop_width = int(round(height * MAX_AR))
112
  left = (width - crop_width) // 2
113
+ image = image.crop((left, 0, left + crop_width, height))
114
  elif aspect_ratio < MIN_AR:
 
115
  crop_height = int(round(width / MIN_AR))
116
  top = (height - crop_height) // 2
117
+ image = image.crop((0, top, width, top + crop_height))
118
+
119
+ if width > height:
120
+ target_w = MAX_DIM
121
+ target_h = int(round(target_w / aspect_ratio))
122
  else:
123
+ target_h = MAX_DIM
124
+ target_w = int(round(target_h * aspect_ratio))
125
+
 
 
 
126
  final_w = max(MIN_DIM, min(MAX_DIM, round(target_w / MULTIPLE_OF) * MULTIPLE_OF))
127
  final_h = max(MIN_DIM, min(MAX_DIM, round(target_h / MULTIPLE_OF) * MULTIPLE_OF))
128
+ return image.resize((final_w, final_h), Image.LANCZOS)
129
+
130
 
131
  def get_num_frames(duration_seconds: float):
132
  return 1 + int(np.clip(int(round(duration_seconds * FIXED_FPS)), MIN_FRAMES_MODEL, MAX_FRAMES_MODEL))
 
135
  # عملية التوليد
136
  # ------------------------
137
  @spaces.GPU()
138
+ def generate_video(
139
+ input_image,
140
+ prompt,
141
+ steps=4,
142
+ negative_prompt=default_negative_prompt,
143
+ duration_seconds=3.5,
144
+ guidance_scale=1.0,
145
+ guidance_scale_2=1.0,
146
+ seed=42,
147
+ randomize_seed=False,
148
+ progress=gr.Progress(track_tqdm=True)
149
+ ):
150
  if input_image is None:
151
+ raise gr.Error("⚠️ Please upload an input image first.")
152
+
153
  num_frames = get_num_frames(duration_seconds)
154
  current_seed = random.randint(0, MAX_SEED) if randomize_seed else int(seed)
155
  resized_image = resize_image(input_image)
156
+
157
  with progress.tqdm(total=100) as pbar:
158
+ pbar.set_description("🎬 Generating video...")
159
  output_frames_list = pipe(
160
  image=resized_image,
161
  prompt=prompt,
 
168
  num_inference_steps=int(steps),
169
  generator=torch.Generator(device="cuda").manual_seed(current_seed),
170
  ).frames[0]
171
+
172
  with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmpfile:
173
  video_path = tmpfile.name
174
+
175
  export_to_video(output_frames_list, video_path, fps=FIXED_FPS)
176
+ torch.cuda.empty_cache()
177
+ gc.collect()
178
  return video_path, current_seed
179
 
180
  # ------------------------
 
183
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="violet")) as demo:
184
  gr.HTML("""
185
  <div style="text-align:center; padding:20px;">
186
+ <h1 style="font-size: 2em;">Wan 2.2 Lightning Studio – AI Cinematic Video Generator</h1>
187
+ <p style="opacity:0.8;">⚡ Powered by dream2589632147</p>
188
  </div>
189
  """)
190
+
191
  with gr.Row():
192
  with gr.Column(scale=1):
193
  input_image = gr.Image(label="🎞️ Input Image", type="pil")
194
  prompt = gr.Textbox(label="✨ Positive Prompt", value=default_prompt_i2v, lines=3)
195
  negative_prompt = gr.Textbox(label="🚫 Negative Prompt", value=default_negative_prompt, lines=3)
196
+ duration = gr.Slider(MIN_DURATION, MAX_DURATION, value=3.5, step=0.1, label="🎬 Duration (seconds)")
197
  with gr.Accordion("⚙️ Advanced Settings", open=False):
198
  steps = gr.Slider(1, 30, value=6, step=1, label="Inference Steps")
199
+ guidance_scale = gr.Slider(0.0, 10.0, value=1.0, step=0.5, label="Guidance Scale 1")
200
+ guidance_scale_2 = gr.Slider(0.0, 10.0, value=1.0, step=0.5, label="Guidance Scale 2")
201
  seed = gr.Slider(0, MAX_SEED, value=42, step=1, label="Seed")
202
  randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
203
  generate_btn = gr.Button("🚀 Generate Cinematic Video", variant="primary")
204
 
205
  with gr.Column(scale=1):
 
206
  video_output = gr.Video(label="🎬 Generated Video Preview", autoplay=True)
207
+ seed_output = gr.Textbox(label="🎲 Seed Used", interactive=False)
208
  download_btn = gr.File(label="⬇️ Download MP4")
209
 
210
+ generate_btn.click(
211
+ fn=generate_video,
212
+ inputs=[input_image, prompt, steps, negative_prompt, duration,
213
+ guidance_scale, guidance_scale_2, seed, randomize_seed],
214
+ outputs=[video_output, seed_output]
215
+ )
216
 
217
  # زر تبديل الوضع الليلي/النهاري
218
  gr.HTML("""