Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -146,7 +146,7 @@ pipeline.to(dtype=torch.float16).to(gpu)
|
|
| 146 |
# --- Frame Streaming Video Generation Handler ---
|
| 147 |
@torch.no_grad()
|
| 148 |
@spaces.GPU
|
| 149 |
-
def video_generation_handler(prompt, seed, fps
|
| 150 |
"""
|
| 151 |
Generator function that yields RGB frames for display in gr.Image.
|
| 152 |
Includes timing delays for smooth playback.
|
|
@@ -230,8 +230,11 @@ def video_generation_handler(prompt, seed, fps, progress=gr.Progress()):
|
|
| 230 |
|
| 231 |
print(f"πΉ Decoded pixels shape: {pixels.shape}")
|
| 232 |
|
|
|
|
|
|
|
|
|
|
| 233 |
# Yield individual frames with timing delays
|
| 234 |
-
for frame_idx in range(
|
| 235 |
frame_tensor = pixels[0, frame_idx] # Get single frame [C, H, W]
|
| 236 |
|
| 237 |
# Normalize from [-1, 1] to [0, 255]
|
|
@@ -244,22 +247,47 @@ def video_generation_handler(prompt, seed, fps, progress=gr.Progress()):
|
|
| 244 |
all_frames_for_video.append(frame_np)
|
| 245 |
total_frames_yielded += 1
|
| 246 |
|
| 247 |
-
# Calculate progress
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
|
|
|
| 251 |
|
| 252 |
-
#
|
| 253 |
-
|
| 254 |
|
| 255 |
print(f"πΊ Yielding frame {total_frames_yielded}: shape {frame_np.shape}")
|
| 256 |
|
| 257 |
-
#
|
| 258 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 259 |
|
| 260 |
# Sleep between frames for smooth playback (except for the last frame)
|
| 261 |
-
|
| 262 |
-
|
|
|
|
| 263 |
|
| 264 |
current_start_frame += current_num_frames
|
| 265 |
|
|
@@ -270,10 +298,26 @@ def video_generation_handler(prompt, seed, fps, progress=gr.Progress()):
|
|
| 270 |
video_path = f"gradio_tmp/{seed}_{hashlib.md5(prompt.encode()).hexdigest()}.mp4"
|
| 271 |
imageio.mimwrite(video_path, all_frames_for_video, fps=fps, quality=8)
|
| 272 |
print(f"β
Video saved to {video_path}")
|
| 273 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 274 |
except Exception as e:
|
| 275 |
print(f"β οΈ Could not save final video: {e}")
|
| 276 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 277 |
|
| 278 |
# --- Gradio UI Layout ---
|
| 279 |
with gr.Blocks(theme=gr.themes.Soft(), title="Self-Forcing Frame Streaming Demo") as demo:
|
|
@@ -326,17 +370,22 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Self-Forcing Frame Streaming Demo"
|
|
| 326 |
|
| 327 |
final_video = gr.Video(
|
| 328 |
label="Final Rendered Video",
|
| 329 |
-
visible=
|
| 330 |
interactive=False,
|
| 331 |
-
height=400
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 332 |
)
|
| 333 |
|
| 334 |
# Connect the generator to the image display
|
| 335 |
start_btn.click(
|
| 336 |
fn=video_generation_handler,
|
| 337 |
inputs=[prompt, seed, fps],
|
| 338 |
-
outputs=[frame_display, final_video]
|
| 339 |
-
show_progress="full"
|
| 340 |
)
|
| 341 |
|
| 342 |
# --- Launch App ---
|
|
|
|
| 146 |
# --- Frame Streaming Video Generation Handler ---
|
| 147 |
@torch.no_grad()
|
| 148 |
@spaces.GPU
|
| 149 |
+
def video_generation_handler(prompt, seed, fps):
|
| 150 |
"""
|
| 151 |
Generator function that yields RGB frames for display in gr.Image.
|
| 152 |
Includes timing delays for smooth playback.
|
|
|
|
| 230 |
|
| 231 |
print(f"πΉ Decoded pixels shape: {pixels.shape}")
|
| 232 |
|
| 233 |
+
# Calculate actual frames that will be yielded for this block
|
| 234 |
+
actual_frames_this_block = pixels.shape[1]
|
| 235 |
+
|
| 236 |
# Yield individual frames with timing delays
|
| 237 |
+
for frame_idx in range(actual_frames_this_block):
|
| 238 |
frame_tensor = pixels[0, frame_idx] # Get single frame [C, H, W]
|
| 239 |
|
| 240 |
# Normalize from [-1, 1] to [0, 255]
|
|
|
|
| 247 |
all_frames_for_video.append(frame_np)
|
| 248 |
total_frames_yielded += 1
|
| 249 |
|
| 250 |
+
# Calculate progress based on blocks completed + current block progress
|
| 251 |
+
blocks_completed = idx
|
| 252 |
+
current_block_progress = (frame_idx + 1) / actual_frames_this_block
|
| 253 |
+
total_block_progress = (blocks_completed + current_block_progress) / num_blocks
|
| 254 |
+
frame_progress_percent = total_block_progress * 100
|
| 255 |
|
| 256 |
+
# Cap at 100% to avoid going over
|
| 257 |
+
frame_progress_percent = min(frame_progress_percent, 100.0)
|
| 258 |
|
| 259 |
print(f"πΊ Yielding frame {total_frames_yielded}: shape {frame_np.shape}")
|
| 260 |
|
| 261 |
+
# Create HTML status update
|
| 262 |
+
if frame_idx == actual_frames_this_block - 1 and idx + 1 == num_blocks: # Last frame
|
| 263 |
+
status_html = (
|
| 264 |
+
f"<div style='padding: 16px; border: 1px solid #198754; background-color: #d1e7dd; border-radius: 8px; font-family: sans-serif; text-align: center;'>"
|
| 265 |
+
f" <h4 style='margin: 0 0 8px 0; color: #0f5132; font-size: 18px;'>π Generation Complete!</h4>"
|
| 266 |
+
f" <p style='margin: 0; color: #0f5132;'>"
|
| 267 |
+
f" Total frames: {total_frames_yielded}. The final video is now available."
|
| 268 |
+
f" </p>"
|
| 269 |
+
f"</div>"
|
| 270 |
+
)
|
| 271 |
+
else: # Regular frames
|
| 272 |
+
status_html = (
|
| 273 |
+
f"<div style='padding: 10px; border: 1px solid #ddd; border-radius: 8px; font-family: sans-serif;'>"
|
| 274 |
+
f" <p style='margin: 0 0 8px 0; font-size: 16px; font-weight: bold;'>Generating Video...</p>"
|
| 275 |
+
f" <div style='background: #e9ecef; border-radius: 4px; width: 100%; overflow: hidden;'>"
|
| 276 |
+
f" <div style='width: {frame_progress_percent:.1f}%; height: 20px; background-color: #0d6efd; transition: width 0.2s;'></div>"
|
| 277 |
+
f" </div>"
|
| 278 |
+
f" <p style='margin: 8px 0 0 0; color: #555; font-size: 14px; text-align: right;'>"
|
| 279 |
+
f" Block {idx+1}/{num_blocks} | Frame {total_frames_yielded} | {frame_progress_percent:.1f}%"
|
| 280 |
+
f" </p>"
|
| 281 |
+
f"</div>"
|
| 282 |
+
)
|
| 283 |
+
|
| 284 |
+
# Yield frame with a small delay to ensure UI updates
|
| 285 |
+
yield gr.update(visible=True, value=frame_np), gr.update(visible=False), status_html
|
| 286 |
|
| 287 |
# Sleep between frames for smooth playback (except for the last frame)
|
| 288 |
+
# Add minimum delay to ensure UI can update
|
| 289 |
+
if not (frame_idx == actual_frames_this_block - 1 and idx + 1 == num_blocks):
|
| 290 |
+
time.sleep(max(frame_delay, 0.1)) # Minimum 100ms delay
|
| 291 |
|
| 292 |
current_start_frame += current_num_frames
|
| 293 |
|
|
|
|
| 298 |
video_path = f"gradio_tmp/{seed}_{hashlib.md5(prompt.encode()).hexdigest()}.mp4"
|
| 299 |
imageio.mimwrite(video_path, all_frames_for_video, fps=fps, quality=8)
|
| 300 |
print(f"β
Video saved to {video_path}")
|
| 301 |
+
final_status_html = (
|
| 302 |
+
f"<div style='padding: 16px; border: 1px solid #198754; background-color: #d1e7dd; border-radius: 8px; font-family: sans-serif; text-align: center;'>"
|
| 303 |
+
f" <h4 style='margin: 0 0 8px 0; color: #0f5132; font-size: 18px;'>π Generation Complete!</h4>"
|
| 304 |
+
f" <p style='margin: 0; color: #0f5132;'>"
|
| 305 |
+
f" Video saved successfully with {total_frames_yielded} frames at {fps} FPS."
|
| 306 |
+
f" </p>"
|
| 307 |
+
f"</div>"
|
| 308 |
+
)
|
| 309 |
+
yield gr.update(visible=False), gr.update(value=video_path, visible=True), final_status_html
|
| 310 |
except Exception as e:
|
| 311 |
print(f"β οΈ Could not save final video: {e}")
|
| 312 |
+
error_status_html = (
|
| 313 |
+
f"<div style='padding: 16px; border: 1px solid #dc3545; background-color: #f8d7da; border-radius: 8px; font-family: sans-serif; text-align: center;'>"
|
| 314 |
+
f" <h4 style='margin: 0 0 8px 0; color: #721c24; font-size: 18px;'>β οΈ Video Save Error</h4>"
|
| 315 |
+
f" <p style='margin: 0; color: #721c24;'>"
|
| 316 |
+
f" Could not save final video: {str(e)}"
|
| 317 |
+
f" </p>"
|
| 318 |
+
f"</div>"
|
| 319 |
+
)
|
| 320 |
+
yield None, None, error_status_html
|
| 321 |
|
| 322 |
# --- Gradio UI Layout ---
|
| 323 |
with gr.Blocks(theme=gr.themes.Soft(), title="Self-Forcing Frame Streaming Demo") as demo:
|
|
|
|
| 370 |
|
| 371 |
final_video = gr.Video(
|
| 372 |
label="Final Rendered Video",
|
| 373 |
+
visible=False,
|
| 374 |
interactive=False,
|
| 375 |
+
height=400,
|
| 376 |
+
autoplay=True
|
| 377 |
+
)
|
| 378 |
+
|
| 379 |
+
status_html = gr.HTML(
|
| 380 |
+
value="<div style='text-align: center; padding: 20px; color: #666;'>Ready to start generation...</div>",
|
| 381 |
+
label="Generation Status"
|
| 382 |
)
|
| 383 |
|
| 384 |
# Connect the generator to the image display
|
| 385 |
start_btn.click(
|
| 386 |
fn=video_generation_handler,
|
| 387 |
inputs=[prompt, seed, fps],
|
| 388 |
+
outputs=[frame_display, final_video, status_html]
|
|
|
|
| 389 |
)
|
| 390 |
|
| 391 |
# --- Launch App ---
|