Spaces:
Sleeping
Sleeping
Update server.py
Browse files
server.py
CHANGED
|
@@ -235,6 +235,7 @@ def process_video_segment(
|
|
| 235 |
4. Mux processed video with original audio
|
| 236 |
"""
|
| 237 |
ffmpeg_video_proc = None
|
|
|
|
| 238 |
temp_wav = output_path.replace(".mp4", "_audio.wav")
|
| 239 |
temp_video_path = output_path.replace(".mp4", "_noaudio.mp4")
|
| 240 |
|
|
@@ -324,7 +325,7 @@ def process_video_segment(
|
|
| 324 |
frame = cv2.resize(frame, (target_width, target_height), interpolation=cv2.INTER_LANCZOS4)
|
| 325 |
frame = apply_color_grading_wedding_retro(frame)
|
| 326 |
|
| 327 |
-
# Set caption for this frame (empty if none)
|
| 328 |
current_caption = frame_caption_map.get(processed_frames, "")
|
| 329 |
|
| 330 |
if current_caption:
|
|
@@ -337,9 +338,9 @@ def process_video_segment(
|
|
| 337 |
progress = (processed_frames / target_frames) * 100
|
| 338 |
print(f"Progress: {progress:.1f}%")
|
| 339 |
|
|
|
|
| 340 |
ffmpeg_video_proc.stdin.close()
|
| 341 |
ffmpeg_video_proc.wait()
|
| 342 |
-
cap.release()
|
| 343 |
|
| 344 |
if ffmpeg_video_proc.returncode != 0:
|
| 345 |
print(f"β FFmpeg video encoding failed (code {ffmpeg_video_proc.returncode})")
|
|
@@ -388,6 +389,10 @@ def process_video_segment(
|
|
| 388 |
return False
|
| 389 |
|
| 390 |
finally:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 391 |
for tmp in [temp_video_path, temp_wav]:
|
| 392 |
if tmp and os.path.exists(tmp):
|
| 393 |
try:
|
|
@@ -439,11 +444,12 @@ async def process_movie_segments(movie_name: str) -> bool:
|
|
| 439 |
print(f"No segment JSON files found for {movie_name}")
|
| 440 |
return False
|
| 441 |
|
| 442 |
-
print(f"Found {len(segment_files)} segments")
|
| 443 |
temp_dir = tempfile.mkdtemp()
|
| 444 |
|
| 445 |
try:
|
| 446 |
for segment_file in segment_files:
|
|
|
|
| 447 |
try:
|
| 448 |
segment_path = hf_hub_download(
|
| 449 |
repo_id=HF_DATASET_REPO,
|
|
@@ -460,7 +466,7 @@ async def process_movie_segments(movie_name: str) -> bool:
|
|
| 460 |
start_time = segment_data.get("start_time", "00:00:00")
|
| 461 |
end_time = segment_data.get("end_time", "00:10:00")
|
| 462 |
|
| 463 |
-
print(f"
|
| 464 |
|
| 465 |
output_filename = f"segment-{segment_number:02d}.mp4"
|
| 466 |
output_path = os.path.join(temp_dir, output_filename)
|
|
@@ -473,7 +479,8 @@ async def process_movie_segments(movie_name: str) -> bool:
|
|
| 473 |
)
|
| 474 |
|
| 475 |
if not success:
|
| 476 |
-
print(f"Failed to process segment {segment_number}")
|
|
|
|
| 477 |
continue
|
| 478 |
|
| 479 |
upload_path = f"{READY_VIDEOS_FOLDER}/{movie_name}/{output_filename}"
|
|
@@ -489,8 +496,15 @@ async def process_movie_segments(movie_name: str) -> bool:
|
|
| 489 |
)
|
| 490 |
print(f"β Segment {segment_number} uploaded successfully")
|
| 491 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 492 |
except Exception as e:
|
| 493 |
-
print(f"β Error processing segment: {e}")
|
| 494 |
processing_state["error_count"] += 1
|
| 495 |
continue
|
| 496 |
|
|
@@ -506,7 +520,7 @@ async def process_movie_segments(movie_name: str) -> bool:
|
|
| 506 |
except Exception as e:
|
| 507 |
processing_state["error_count"] += 1
|
| 508 |
processing_state["last_error"] = str(e)
|
| 509 |
-
print(f"β Error: {e}")
|
| 510 |
return False
|
| 511 |
|
| 512 |
|
|
@@ -516,8 +530,7 @@ async def scan_and_process_videos():
|
|
| 516 |
print("Video processing already running, skipping...")
|
| 517 |
return
|
| 518 |
|
| 519 |
-
|
| 520 |
-
startup_delay = int(os.getenv("STARTUP_DELAY", 5)) # Default 5 seconds for testing
|
| 521 |
print(f"Waiting {startup_delay} seconds before starting video processing...")
|
| 522 |
await asyncio.sleep(startup_delay)
|
| 523 |
|
|
@@ -540,7 +553,7 @@ async def scan_and_process_videos():
|
|
| 540 |
if len(parts) >= 2:
|
| 541 |
movie_folders.add(parts[1])
|
| 542 |
|
| 543 |
-
print(f"Found {len(movie_folders)} movies to process")
|
| 544 |
|
| 545 |
for movie_name in sorted(movie_folders):
|
| 546 |
await process_movie_segments(movie_name)
|
|
@@ -553,19 +566,20 @@ async def scan_and_process_videos():
|
|
| 553 |
print("="*80 + "\n")
|
| 554 |
|
| 555 |
except Exception as e:
|
| 556 |
-
print(f"Critical error: {e}")
|
| 557 |
processing_state["last_error"] = str(e)
|
| 558 |
finally:
|
| 559 |
processing_state["is_running"] = False
|
|
|
|
| 560 |
|
| 561 |
|
| 562 |
@app.on_event("startup")
|
| 563 |
async def startup_event():
|
| 564 |
-
"""Load Whisper in background, then kick off video processing
|
| 565 |
loop = asyncio.get_event_loop()
|
| 566 |
# Load Whisper model in thread so it doesn't block the event loop / health check
|
| 567 |
await loop.run_in_executor(None, _load_whisper_model)
|
| 568 |
-
# Kick off processing task (has its own
|
| 569 |
asyncio.create_task(scan_and_process_videos())
|
| 570 |
|
| 571 |
|
|
@@ -618,5 +632,5 @@ async def trigger_processing():
|
|
| 618 |
|
| 619 |
if __name__ == "__main__":
|
| 620 |
print("Starting Video Processing Service on port 7860...")
|
| 621 |
-
print("Whisper will load at startup, processing begins
|
| 622 |
-
uvicorn.run(app, host="0.0.0.0", port=7860)
|
|
|
|
| 235 |
4. Mux processed video with original audio
|
| 236 |
"""
|
| 237 |
ffmpeg_video_proc = None
|
| 238 |
+
cap = None # Declared here so finally block can always release it
|
| 239 |
temp_wav = output_path.replace(".mp4", "_audio.wav")
|
| 240 |
temp_video_path = output_path.replace(".mp4", "_noaudio.mp4")
|
| 241 |
|
|
|
|
| 325 |
frame = cv2.resize(frame, (target_width, target_height), interpolation=cv2.INTER_LANCZOS4)
|
| 326 |
frame = apply_color_grading_wedding_retro(frame)
|
| 327 |
|
| 328 |
+
# Set caption for this frame (empty if none)
|
| 329 |
current_caption = frame_caption_map.get(processed_frames, "")
|
| 330 |
|
| 331 |
if current_caption:
|
|
|
|
| 338 |
progress = (processed_frames / target_frames) * 100
|
| 339 |
print(f"Progress: {progress:.1f}%")
|
| 340 |
|
| 341 |
+
# Close stdin and wait for FFmpeg to finish encoding
|
| 342 |
ffmpeg_video_proc.stdin.close()
|
| 343 |
ffmpeg_video_proc.wait()
|
|
|
|
| 344 |
|
| 345 |
if ffmpeg_video_proc.returncode != 0:
|
| 346 |
print(f"β FFmpeg video encoding failed (code {ffmpeg_video_proc.returncode})")
|
|
|
|
| 389 |
return False
|
| 390 |
|
| 391 |
finally:
|
| 392 |
+
# Always release VideoCapture regardless of success or failure
|
| 393 |
+
if cap is not None:
|
| 394 |
+
cap.release()
|
| 395 |
+
# Always clean up temp files
|
| 396 |
for tmp in [temp_video_path, temp_wav]:
|
| 397 |
if tmp and os.path.exists(tmp):
|
| 398 |
try:
|
|
|
|
| 444 |
print(f"No segment JSON files found for {movie_name}")
|
| 445 |
return False
|
| 446 |
|
| 447 |
+
print(f"Found {len(segment_files)} segments: {segment_files}")
|
| 448 |
temp_dir = tempfile.mkdtemp()
|
| 449 |
|
| 450 |
try:
|
| 451 |
for segment_file in segment_files:
|
| 452 |
+
print(f"\nββ Processing file: {segment_file}")
|
| 453 |
try:
|
| 454 |
segment_path = hf_hub_download(
|
| 455 |
repo_id=HF_DATASET_REPO,
|
|
|
|
| 466 |
start_time = segment_data.get("start_time", "00:00:00")
|
| 467 |
end_time = segment_data.get("end_time", "00:10:00")
|
| 468 |
|
| 469 |
+
print(f"Processing segment {segment_number}: {start_time} to {end_time}")
|
| 470 |
|
| 471 |
output_filename = f"segment-{segment_number:02d}.mp4"
|
| 472 |
output_path = os.path.join(temp_dir, output_filename)
|
|
|
|
| 479 |
)
|
| 480 |
|
| 481 |
if not success:
|
| 482 |
+
print(f"β Failed to process segment {segment_number}, continuing to next...")
|
| 483 |
+
processing_state["error_count"] += 1
|
| 484 |
continue
|
| 485 |
|
| 486 |
upload_path = f"{READY_VIDEOS_FOLDER}/{movie_name}/{output_filename}"
|
|
|
|
| 496 |
)
|
| 497 |
print(f"β Segment {segment_number} uploaded successfully")
|
| 498 |
|
| 499 |
+
# Clean up the output file after successful upload
|
| 500 |
+
if os.path.exists(output_path):
|
| 501 |
+
try:
|
| 502 |
+
os.remove(output_path)
|
| 503 |
+
except Exception:
|
| 504 |
+
pass
|
| 505 |
+
|
| 506 |
except Exception as e:
|
| 507 |
+
print(f"β Error processing segment file {segment_file}: {e}")
|
| 508 |
processing_state["error_count"] += 1
|
| 509 |
continue
|
| 510 |
|
|
|
|
| 520 |
except Exception as e:
|
| 521 |
processing_state["error_count"] += 1
|
| 522 |
processing_state["last_error"] = str(e)
|
| 523 |
+
print(f"β Error in process_movie_segments: {e}")
|
| 524 |
return False
|
| 525 |
|
| 526 |
|
|
|
|
| 530 |
print("Video processing already running, skipping...")
|
| 531 |
return
|
| 532 |
|
| 533 |
+
startup_delay = int(os.getenv("STARTUP_DELAY", 5))
|
|
|
|
| 534 |
print(f"Waiting {startup_delay} seconds before starting video processing...")
|
| 535 |
await asyncio.sleep(startup_delay)
|
| 536 |
|
|
|
|
| 553 |
if len(parts) >= 2:
|
| 554 |
movie_folders.add(parts[1])
|
| 555 |
|
| 556 |
+
print(f"Found {len(movie_folders)} movies to process: {sorted(movie_folders)}")
|
| 557 |
|
| 558 |
for movie_name in sorted(movie_folders):
|
| 559 |
await process_movie_segments(movie_name)
|
|
|
|
| 566 |
print("="*80 + "\n")
|
| 567 |
|
| 568 |
except Exception as e:
|
| 569 |
+
print(f"Critical error in scan_and_process_videos: {e}")
|
| 570 |
processing_state["last_error"] = str(e)
|
| 571 |
finally:
|
| 572 |
processing_state["is_running"] = False
|
| 573 |
+
processing_state["current_file"] = None
|
| 574 |
|
| 575 |
|
| 576 |
@app.on_event("startup")
|
| 577 |
async def startup_event():
|
| 578 |
+
"""Load Whisper in background, then kick off video processing."""
|
| 579 |
loop = asyncio.get_event_loop()
|
| 580 |
# Load Whisper model in thread so it doesn't block the event loop / health check
|
| 581 |
await loop.run_in_executor(None, _load_whisper_model)
|
| 582 |
+
# Kick off processing task (has its own startup delay inside)
|
| 583 |
asyncio.create_task(scan_and_process_videos())
|
| 584 |
|
| 585 |
|
|
|
|
| 632 |
|
| 633 |
if __name__ == "__main__":
|
| 634 |
print("Starting Video Processing Service on port 7860...")
|
| 635 |
+
print("Whisper will load at startup, processing begins after startup delay")
|
| 636 |
+
uvicorn.run(app, host="0.0.0.0", port=7860)
|