BoxOfColors commited on
Commit
3847eb5
·
1 Parent(s): 1a0c4c0

Patch Gradio's video-conversion race that kills the generation connection

Browse files

convert_video_to_playable_mp4() writes ffmpeg output to
Path(video_path).with_suffix(".mp4"), a no-op rename when the upload
is already *.mp4 (e.g. HEVC-in-mp4). It overwrites that file in place
while the browser is still streaming it for the preview widget, which
corrupts the response and — since HF Spaces multiplexes a tab over one
HTTP/2 connection — takes the whole connection down, including the
live generation job's SSE queue. Convert a copy instead so the file
being served is never mutated mid-stream.

Files changed (1) hide show
  1. app.py +25 -0
app.py CHANGED
@@ -29,6 +29,31 @@ import spaces
29
  import gradio as gr
30
  from huggingface_hub import HfApi, hf_hub_download, snapshot_download
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  # ================================================================== #
33
  # CHECKPOINT CONFIGURATION #
34
  # ================================================================== #
 
29
  import gradio as gr
30
  from huggingface_hub import HfApi, hf_hub_download, snapshot_download
31
 
32
+ # ------------------------------------------------------------------ #
33
+ # Gradio's own Video component (processing_utils.convert_video_to_ #
34
+ # playable_mp4) writes its ffmpeg output to Path(video_path) #
35
+ # .with_suffix(".mp4") — a no-op rename whenever the upload is #
36
+ # already named *.mp4 (e.g. HEVC-in-mp4). That makes it overwrite the #
37
+ # exact file the browser is concurrently streaming for the live #
38
+ # preview widget, corrupting the response mid-flight. Since HF Spaces #
39
+ # multiplexes a whole browser tab over one HTTP/2 connection, that #
40
+ # corrupted stream takes the *entire* connection down with it — even #
41
+ # unrelated in-flight requests like the generation job's SSE queue. #
42
+ # Patch it to convert a same-named copy instead, so the file the #
43
+ # browser already has a handle on is never mutated in place. #
44
+ import gradio.processing_utils as _gr_processing_utils
45
+ _gr_convert_video_to_playable_mp4 = _gr_processing_utils.convert_video_to_playable_mp4
46
+
47
+ def _patched_convert_video_to_playable_mp4(video_path: str) -> str:
48
+ p = Path(video_path)
49
+ if p.suffix.lower() == ".mp4":
50
+ copy_path = str(p.with_name(p.stem + "_gr_conv.mp4"))
51
+ shutil.copy2(video_path, copy_path)
52
+ video_path = copy_path
53
+ return _gr_convert_video_to_playable_mp4(video_path)
54
+
55
+ _gr_processing_utils.convert_video_to_playable_mp4 = _patched_convert_video_to_playable_mp4
56
+
57
  # ================================================================== #
58
  # CHECKPOINT CONFIGURATION #
59
  # ================================================================== #