LogicGoInfotechSpaces commited on
Commit
33da647
·
1 Parent(s): 1de2238

Fix connection reset: Improve video streaming, increase timeouts, and add better error handling

Browse files
Files changed (2) hide show
  1. Dockerfile +1 -1
  2. fastapi_app.py +85 -5
Dockerfile CHANGED
@@ -27,6 +27,6 @@ EXPOSE 7860
27
  ENV FACE_SWAP_API_KEY=""
28
  ENV OMP_NUM_THREADS=1
29
 
30
- CMD ["python3", "-m", "uvicorn", "fastapi_app:app", "--host", "0.0.0.0", "--port", "7860"]
31
 
32
 
 
27
  ENV FACE_SWAP_API_KEY=""
28
  ENV OMP_NUM_THREADS=1
29
 
30
+ CMD ["python3", "-m", "uvicorn", "fastapi_app:app", "--host", "0.0.0.0", "--port", "7860", "--timeout-keep-alive", "1800", "--timeout-graceful-shutdown", "30"]
31
 
32
 
fastapi_app.py CHANGED
@@ -92,9 +92,12 @@ def swap_video_file(
92
  cv2.imwrite(src_path, src_bgr)
93
  shutil.copy(video_path, dst_video_path)
94
  frame_paths = extract_frames(dst_video_path, frames_dir)
95
- logger.info("Extracted %s frames to %s", len(frame_paths), frames_dir)
 
96
 
97
  for idx, frame_path in enumerate(frame_paths):
 
 
98
  swapped_name = f"swapped_{idx:05d}.jpg"
99
  out_path = os.path.join(swapped_dir, swapped_name)
100
  try:
@@ -392,18 +395,51 @@ async def swap_video(
392
  video_path = tmp_video.name
393
 
394
  try:
 
395
  output_path, _ = swap_video_file(src_bgr, source_face_idx, video_path, destination_face_idx, add_audio, workdir)
 
 
 
 
 
 
 
 
396
  except Exception as exc:
397
  logger.exception("Video swap failed: %s", exc)
398
  shutil.rmtree(workdir, ignore_errors=True)
399
- raise HTTPException(status_code=500, detail="Video swap failed") from exc
400
 
401
  def cleanup() -> None:
402
  shutil.rmtree(workdir, ignore_errors=True)
403
  logger.info("Cleaned up workdir %s", workdir)
404
 
405
  background_tasks.add_task(cleanup)
406
- return StreamingResponse(open(output_path, "rb"), media_type="video/mp4")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
407
 
408
 
409
  @app.post("/swap/video/all-faces")
@@ -484,7 +520,29 @@ async def swap_video_all_faces(
484
  logger.info("Cleaned up workdir %s", workdir)
485
 
486
  background_tasks.add_task(cleanup)
487
- return StreamingResponse(open(output_path, "rb"), media_type="video/mp4")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
 
489
 
490
  @app.post("/swap/video/custom-mapping")
@@ -573,7 +631,29 @@ async def swap_video_custom_mapping(
573
  logger.info("Cleaned up workdir %s", workdir)
574
 
575
  background_tasks.add_task(cleanup)
576
- return StreamingResponse(open(output_path, "rb"), media_type="video/mp4")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
577
 
578
 
579
  @app.post("/swap/video/single-src-multi-video")
 
92
  cv2.imwrite(src_path, src_bgr)
93
  shutil.copy(video_path, dst_video_path)
94
  frame_paths = extract_frames(dst_video_path, frames_dir)
95
+ total_frames = len(frame_paths)
96
+ logger.info("Extracted %s frames to %s", total_frames, frames_dir)
97
 
98
  for idx, frame_path in enumerate(frame_paths):
99
+ if idx % 50 == 0 or idx == total_frames - 1:
100
+ logger.info("Processing frame %s/%s (%.1f%%)", idx + 1, total_frames, (idx + 1) / total_frames * 100)
101
  swapped_name = f"swapped_{idx:05d}.jpg"
102
  out_path = os.path.join(swapped_dir, swapped_name)
103
  try:
 
395
  video_path = tmp_video.name
396
 
397
  try:
398
+ logger.info("Starting video processing...")
399
  output_path, _ = swap_video_file(src_bgr, source_face_idx, video_path, destination_face_idx, add_audio, workdir)
400
+ logger.info("Video processing completed: %s", output_path)
401
+
402
+ if not os.path.exists(output_path):
403
+ raise HTTPException(status_code=500, detail="Output video file was not created")
404
+
405
+ file_size = os.path.getsize(output_path)
406
+ logger.info("Output video size: %s bytes", file_size)
407
+
408
  except Exception as exc:
409
  logger.exception("Video swap failed: %s", exc)
410
  shutil.rmtree(workdir, ignore_errors=True)
411
+ raise HTTPException(status_code=500, detail=f"Video swap failed: {str(exc)}") from exc
412
 
413
  def cleanup() -> None:
414
  shutil.rmtree(workdir, ignore_errors=True)
415
  logger.info("Cleaned up workdir %s", workdir)
416
 
417
  background_tasks.add_task(cleanup)
418
+
419
+ def iterfile():
420
+ try:
421
+ with open(output_path, "rb") as f:
422
+ while True:
423
+ chunk = f.read(8192) # Read in 8KB chunks
424
+ if not chunk:
425
+ break
426
+ yield chunk
427
+ except Exception as e:
428
+ logger.error("Error streaming video file: %s", e)
429
+ raise
430
+
431
+ file_size = os.path.getsize(output_path)
432
+ logger.info("Streaming video file: %s bytes", file_size)
433
+
434
+ return StreamingResponse(
435
+ iterfile(),
436
+ media_type="video/mp4",
437
+ headers={
438
+ "Content-Disposition": "attachment; filename=swapped_video.mp4",
439
+ "Content-Length": str(file_size),
440
+ "Accept-Ranges": "bytes"
441
+ }
442
+ )
443
 
444
 
445
  @app.post("/swap/video/all-faces")
 
520
  logger.info("Cleaned up workdir %s", workdir)
521
 
522
  background_tasks.add_task(cleanup)
523
+
524
+ def iterfile():
525
+ try:
526
+ with open(output_path, "rb") as f:
527
+ while True:
528
+ chunk = f.read(8192)
529
+ if not chunk:
530
+ break
531
+ yield chunk
532
+ except Exception as e:
533
+ logger.error("Error streaming video file: %s", e)
534
+ raise
535
+
536
+ file_size = os.path.getsize(output_path)
537
+ return StreamingResponse(
538
+ iterfile(),
539
+ media_type="video/mp4",
540
+ headers={
541
+ "Content-Disposition": "attachment; filename=swapped_video.mp4",
542
+ "Content-Length": str(file_size),
543
+ "Accept-Ranges": "bytes"
544
+ }
545
+ )
546
 
547
 
548
  @app.post("/swap/video/custom-mapping")
 
631
  logger.info("Cleaned up workdir %s", workdir)
632
 
633
  background_tasks.add_task(cleanup)
634
+
635
+ def iterfile():
636
+ try:
637
+ with open(output_path, "rb") as f:
638
+ while True:
639
+ chunk = f.read(8192)
640
+ if not chunk:
641
+ break
642
+ yield chunk
643
+ except Exception as e:
644
+ logger.error("Error streaming video file: %s", e)
645
+ raise
646
+
647
+ file_size = os.path.getsize(output_path)
648
+ return StreamingResponse(
649
+ iterfile(),
650
+ media_type="video/mp4",
651
+ headers={
652
+ "Content-Disposition": "attachment; filename=swapped_video.mp4",
653
+ "Content-Length": str(file_size),
654
+ "Accept-Ranges": "bytes"
655
+ }
656
+ )
657
 
658
 
659
  @app.post("/swap/video/single-src-multi-video")