Spaces:
Running on Zero
Running on Zero
Update app.py
Browse files
app.py
CHANGED
|
@@ -135,8 +135,6 @@ def interpolate_bits(frames_np, multiplier=2, scale=1.0):
|
|
| 135 |
|
| 136 |
# Handle input shape
|
| 137 |
if isinstance(frames_np, list):
|
| 138 |
-
# Convert list of arrays to one big array for easier shape handling if needed,
|
| 139 |
-
# but here we just grab dims from first frame
|
| 140 |
T = len(frames_np)
|
| 141 |
H, W, C = frames_np[0].shape
|
| 142 |
else:
|
|
@@ -144,7 +142,6 @@ def interpolate_bits(frames_np, multiplier=2, scale=1.0):
|
|
| 144 |
|
| 145 |
# 1. No Interpolation Case
|
| 146 |
if multiplier < 2:
|
| 147 |
-
# Just convert 4D array to list of 3D arrays
|
| 148 |
if isinstance(frames_np, np.ndarray):
|
| 149 |
return list(frames_np)
|
| 150 |
return frames_np
|
|
@@ -159,19 +156,14 @@ def interpolate_bits(frames_np, multiplier=2, scale=1.0):
|
|
| 159 |
|
| 160 |
# Helper: Numpy (H, W, C) Float -> Tensor (1, C, H, W) Half
|
| 161 |
def to_tensor(frame_np):
|
| 162 |
-
# frame_np is float32 0-1
|
| 163 |
t = torch.from_numpy(frame_np).to(device)
|
| 164 |
-
# HWC -> CHW
|
| 165 |
t = t.permute(2, 0, 1).unsqueeze(0)
|
| 166 |
return F.pad(t, padding).half()
|
| 167 |
|
| 168 |
# Helper: Tensor (1, C, H, W) Half -> Numpy (H, W, C) Float
|
| 169 |
def from_tensor(tensor):
|
| 170 |
-
# Crop padding
|
| 171 |
t = tensor[0, :, :H, :W]
|
| 172 |
-
# CHW -> HWC
|
| 173 |
t = t.permute(1, 2, 0)
|
| 174 |
-
# Keep as float32, range 0-1
|
| 175 |
return t.float().cpu().numpy()
|
| 176 |
|
| 177 |
def make_inference(I0, I1, n):
|
|
@@ -194,25 +186,17 @@ def interpolate_bits(frames_np, multiplier=2, scale=1.0):
|
|
| 194 |
output_frames =[]
|
| 195 |
|
| 196 |
# Process Frames
|
| 197 |
-
# Load first frame into GPU
|
| 198 |
I1 = to_tensor(frames_np[0])
|
| 199 |
-
|
| 200 |
total_steps = T - 1
|
| 201 |
|
| 202 |
with tqdm(total=total_steps, desc="Interpolating", unit="frame") as pbar:
|
| 203 |
-
|
| 204 |
for i in range(total_steps):
|
| 205 |
I0 = I1
|
| 206 |
-
# Add original frame to output
|
| 207 |
output_frames.append(from_tensor(I0))
|
| 208 |
|
| 209 |
-
# Load next frame
|
| 210 |
I1 = to_tensor(frames_np[i+1])
|
| 211 |
-
|
| 212 |
-
# Generate intermediate frames
|
| 213 |
mid_tensors = make_inference(I0, I1, n_interp)
|
| 214 |
|
| 215 |
-
# Append intermediate frames
|
| 216 |
for mid in mid_tensors:
|
| 217 |
output_frames.append(from_tensor(mid))
|
| 218 |
|
|
@@ -220,7 +204,6 @@ def interpolate_bits(frames_np, multiplier=2, scale=1.0):
|
|
| 220 |
pbar.update(50)
|
| 221 |
pbar.update(total_steps % 50)
|
| 222 |
|
| 223 |
-
# Add the very last frame
|
| 224 |
output_frames.append(from_tensor(I1))
|
| 225 |
|
| 226 |
# Cleanup
|
|
@@ -264,21 +247,10 @@ pipe = WanImageToVideoPipeline.from_pretrained(
|
|
| 264 |
).to('cuda')
|
| 265 |
original_scheduler = copy.deepcopy(pipe.scheduler)
|
| 266 |
|
| 267 |
-
# if os.path.exists(CACHE_DIR):
|
| 268 |
-
# shutil.rmtree(CACHE_DIR)
|
| 269 |
-
# print("Deleted Hugging Face cache.")
|
| 270 |
-
# else:
|
| 271 |
-
# print("No hub cache found.")
|
| 272 |
-
|
| 273 |
quantize_(pipe.text_encoder, Int8WeightOnlyConfig())
|
| 274 |
quantize_(pipe.transformer, Float8DynamicActivationFloat8WeightConfig())
|
| 275 |
quantize_(pipe.transformer_2, Float8DynamicActivationFloat8WeightConfig())
|
| 276 |
|
| 277 |
-
# aoti.aoti_blocks_load(pipe.transformer, 'zerogpu-aoti/Wan2', variant='fp8da')
|
| 278 |
-
# aoti.aoti_blocks_load(pipe.transformer_2, 'zerogpu-aoti/Wan2', variant='fp8da')
|
| 279 |
-
|
| 280 |
-
# pipe.vae.enable_slicing()
|
| 281 |
-
# pipe.vae.enable_tiling()
|
| 282 |
|
| 283 |
default_prompt_i2v = "make this image come alive, cinematic motion, smooth animation"
|
| 284 |
default_negative_prompt = "色调艳丽, 过曝, 静态, 细节模糊不清, 字幕, 风格, 作品, 画作, 画面, 静止, 整体发灰, 最差质量, 低质量, JPEG压缩残留, 丑陋的, 残缺的, 多余的手指, 画得不好的手部, 画得不好的脸部, 畸形的, 毁容的, 形态畸形的肢体, 手指融合, 静止不动的画面, 杂乱的背景, 三条腿, 背景人很多, 倒着走"
|
|
@@ -382,7 +354,6 @@ def get_inference_duration(
|
|
| 382 |
return total_time
|
| 383 |
|
| 384 |
|
| 385 |
-
|
| 386 |
@spaces.GPU(duration=get_inference_duration, size='xlarge')
|
| 387 |
def run_inference(
|
| 388 |
resized_image,
|
|
@@ -431,7 +402,7 @@ def run_inference(
|
|
| 431 |
output_type="np"
|
| 432 |
)
|
| 433 |
|
| 434 |
-
raw_frames_np = result.frames[0]
|
| 435 |
pipe.scheduler = original_scheduler
|
| 436 |
|
| 437 |
frame_factor = frame_multiplier // FIXED_FPS
|
|
@@ -568,17 +539,55 @@ with gr.Blocks(theme=gr.themes.Soft(), css=CSS, delete_cache=(3600, 3700)) as de
|
|
| 568 |
generate_button = gr.Button("Generate Video", variant="primary")
|
| 569 |
|
| 570 |
with gr.Column():
|
| 571 |
-
# ASSIGNED elem_id="generated-video" so JS can find it
|
| 572 |
video_output = gr.Video(label="Generated Video", autoplay=True, sources=["upload"], show_download_button=True, show_share_button=True, interactive=False, elem_id="generated-video")
|
| 573 |
|
| 574 |
-
# --- Frame Grabbing UI ---
|
| 575 |
with gr.Row():
|
| 576 |
grab_frame_btn = gr.Button("📸 Use Current Frame as Input", variant="secondary")
|
| 577 |
timestamp_box = gr.Number(value=0, label="Timestamp", visible=True, elem_id="hidden-timestamp")
|
| 578 |
-
# -------------------------
|
| 579 |
|
| 580 |
file_output = gr.File(label="Download Video")
|
| 581 |
|
| 582 |
-
ui_inputs =[
|
| 583 |
-
input_image_component,
|
| 584 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 135 |
|
| 136 |
# Handle input shape
|
| 137 |
if isinstance(frames_np, list):
|
|
|
|
|
|
|
| 138 |
T = len(frames_np)
|
| 139 |
H, W, C = frames_np[0].shape
|
| 140 |
else:
|
|
|
|
| 142 |
|
| 143 |
# 1. No Interpolation Case
|
| 144 |
if multiplier < 2:
|
|
|
|
| 145 |
if isinstance(frames_np, np.ndarray):
|
| 146 |
return list(frames_np)
|
| 147 |
return frames_np
|
|
|
|
| 156 |
|
| 157 |
# Helper: Numpy (H, W, C) Float -> Tensor (1, C, H, W) Half
|
| 158 |
def to_tensor(frame_np):
|
|
|
|
| 159 |
t = torch.from_numpy(frame_np).to(device)
|
|
|
|
| 160 |
t = t.permute(2, 0, 1).unsqueeze(0)
|
| 161 |
return F.pad(t, padding).half()
|
| 162 |
|
| 163 |
# Helper: Tensor (1, C, H, W) Half -> Numpy (H, W, C) Float
|
| 164 |
def from_tensor(tensor):
|
|
|
|
| 165 |
t = tensor[0, :, :H, :W]
|
|
|
|
| 166 |
t = t.permute(1, 2, 0)
|
|
|
|
| 167 |
return t.float().cpu().numpy()
|
| 168 |
|
| 169 |
def make_inference(I0, I1, n):
|
|
|
|
| 186 |
output_frames =[]
|
| 187 |
|
| 188 |
# Process Frames
|
|
|
|
| 189 |
I1 = to_tensor(frames_np[0])
|
|
|
|
| 190 |
total_steps = T - 1
|
| 191 |
|
| 192 |
with tqdm(total=total_steps, desc="Interpolating", unit="frame") as pbar:
|
|
|
|
| 193 |
for i in range(total_steps):
|
| 194 |
I0 = I1
|
|
|
|
| 195 |
output_frames.append(from_tensor(I0))
|
| 196 |
|
|
|
|
| 197 |
I1 = to_tensor(frames_np[i+1])
|
|
|
|
|
|
|
| 198 |
mid_tensors = make_inference(I0, I1, n_interp)
|
| 199 |
|
|
|
|
| 200 |
for mid in mid_tensors:
|
| 201 |
output_frames.append(from_tensor(mid))
|
| 202 |
|
|
|
|
| 204 |
pbar.update(50)
|
| 205 |
pbar.update(total_steps % 50)
|
| 206 |
|
|
|
|
| 207 |
output_frames.append(from_tensor(I1))
|
| 208 |
|
| 209 |
# Cleanup
|
|
|
|
| 247 |
).to('cuda')
|
| 248 |
original_scheduler = copy.deepcopy(pipe.scheduler)
|
| 249 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 250 |
quantize_(pipe.text_encoder, Int8WeightOnlyConfig())
|
| 251 |
quantize_(pipe.transformer, Float8DynamicActivationFloat8WeightConfig())
|
| 252 |
quantize_(pipe.transformer_2, Float8DynamicActivationFloat8WeightConfig())
|
| 253 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 254 |
|
| 255 |
default_prompt_i2v = "make this image come alive, cinematic motion, smooth animation"
|
| 256 |
default_negative_prompt = "色调艳丽, 过曝, 静态, 细节模糊不清, 字幕, 风格, 作品, 画作, 画面, 静止, 整体发灰, 最差质量, 低质量, JPEG压缩残留, 丑陋的, 残缺的, 多余的手指, 画得不好的手部, 画得不好的脸部, 畸形的, 毁容的, 形态畸形的肢体, 手指融合, 静止不动的画面, 杂乱的背景, 三条腿, 背景人很多, 倒着走"
|
|
|
|
| 354 |
return total_time
|
| 355 |
|
| 356 |
|
|
|
|
| 357 |
@spaces.GPU(duration=get_inference_duration, size='xlarge')
|
| 358 |
def run_inference(
|
| 359 |
resized_image,
|
|
|
|
| 402 |
output_type="np"
|
| 403 |
)
|
| 404 |
|
| 405 |
+
raw_frames_np = result.frames[0]
|
| 406 |
pipe.scheduler = original_scheduler
|
| 407 |
|
| 408 |
frame_factor = frame_multiplier // FIXED_FPS
|
|
|
|
| 539 |
generate_button = gr.Button("Generate Video", variant="primary")
|
| 540 |
|
| 541 |
with gr.Column():
|
|
|
|
| 542 |
video_output = gr.Video(label="Generated Video", autoplay=True, sources=["upload"], show_download_button=True, show_share_button=True, interactive=False, elem_id="generated-video")
|
| 543 |
|
|
|
|
| 544 |
with gr.Row():
|
| 545 |
grab_frame_btn = gr.Button("📸 Use Current Frame as Input", variant="secondary")
|
| 546 |
timestamp_box = gr.Number(value=0, label="Timestamp", visible=True, elem_id="hidden-timestamp")
|
|
|
|
| 547 |
|
| 548 |
file_output = gr.File(label="Download Video")
|
| 549 |
|
| 550 |
+
ui_inputs = [
|
| 551 |
+
input_image_component,
|
| 552 |
+
last_image_component,
|
| 553 |
+
prompt_input,
|
| 554 |
+
steps_slider,
|
| 555 |
+
negative_prompt_input,
|
| 556 |
+
duration_seconds_input,
|
| 557 |
+
guidance_scale_input,
|
| 558 |
+
guidance_scale_2_input,
|
| 559 |
+
seed_input,
|
| 560 |
+
randomize_seed_checkbox,
|
| 561 |
+
quality_slider,
|
| 562 |
+
scheduler_dropdown,
|
| 563 |
+
flow_shift_slider,
|
| 564 |
+
frame_multi,
|
| 565 |
+
play_result_video,
|
| 566 |
+
safe_mode_checkbox
|
| 567 |
+
]
|
| 568 |
+
|
| 569 |
+
generate_button.click(
|
| 570 |
+
fn=generate_video,
|
| 571 |
+
inputs=ui_inputs,
|
| 572 |
+
outputs=[video_output, file_output, seed_input]
|
| 573 |
+
)
|
| 574 |
+
|
| 575 |
+
grab_frame_btn.click(
|
| 576 |
+
fn=None,
|
| 577 |
+
inputs=None,
|
| 578 |
+
outputs=[timestamp_box],
|
| 579 |
+
js=get_timestamp_js
|
| 580 |
+
)
|
| 581 |
+
|
| 582 |
+
timestamp_box.change(
|
| 583 |
+
fn=extract_frame,
|
| 584 |
+
inputs=[video_output, timestamp_box],
|
| 585 |
+
outputs=[input_image_component]
|
| 586 |
+
)
|
| 587 |
+
|
| 588 |
+
if __name__ == "__main__":
|
| 589 |
+
demo.queue().launch(
|
| 590 |
+
mcp_server=True,
|
| 591 |
+
ssr_mode=False,
|
| 592 |
+
show_error=True,
|
| 593 |
+
)
|