Update handler.py
Browse files- handler.py +17 -17
handler.py
CHANGED
|
@@ -5,11 +5,11 @@ Outputs: GIF, WebM, ZIP(frames)
|
|
| 5 |
This version includes:
|
| 6 |
- Defensive patches to avoid hosted runtime failing with:
|
| 7 |
"`ffmpeg` is not a registered plugin name."
|
| 8 |
-
- Robust frame extraction for shapes like (T,H,W,C)
|
| 9 |
- Output encoders:
|
| 10 |
- GIF: Pillow only (no ffmpeg)
|
| 11 |
- ZIP: PNG frames zipped (no ffmpeg)
|
| 12 |
-
- WebM: imageio + imageio-ffmpeg (
|
| 13 |
|
| 14 |
IMPORTANT:
|
| 15 |
- HF gateway often requires top-level { "inputs": {...} }.
|
|
@@ -87,7 +87,7 @@ def _patch_hf_toolkit_ffmpeg_plugin() -> dict:
|
|
| 87 |
except Exception as e:
|
| 88 |
diag["details"].append(f"failed wrapping {fn_name}: {e}")
|
| 89 |
|
| 90 |
-
#
|
| 91 |
dummy_mod_name = "huggingface_inference_toolkit.plugins.ffmpeg"
|
| 92 |
if dummy_mod_name not in sys.modules:
|
| 93 |
dummy = types.ModuleType(dummy_mod_name)
|
|
@@ -119,7 +119,7 @@ import imageio
|
|
| 119 |
try:
|
| 120 |
import imageio_ffmpeg # type: ignore
|
| 121 |
_FFMPEG_EXE = imageio_ffmpeg.get_ffmpeg_exe()
|
| 122 |
-
# Force absolute path;
|
| 123 |
os.environ["IMAGEIO_FFMPEG_EXE"] = _FFMPEG_EXE
|
| 124 |
except Exception:
|
| 125 |
_FFMPEG_EXE = ""
|
|
@@ -145,7 +145,7 @@ def _clamp_uint8_frame(frame: np.ndarray) -> np.ndarray:
|
|
| 145 |
if not isinstance(frame, np.ndarray):
|
| 146 |
frame = np.array(frame)
|
| 147 |
|
| 148 |
-
# squeeze batch dim
|
| 149 |
if frame.ndim == 4 and frame.shape[0] == 1:
|
| 150 |
frame = frame[0]
|
| 151 |
|
|
@@ -199,7 +199,11 @@ def _encode_gif(frames: List[np.ndarray], fps: int) -> bytes:
|
|
| 199 |
|
| 200 |
def _encode_webm(frames: List[np.ndarray], fps: int, quality: str = "good") -> bytes:
|
| 201 |
"""
|
| 202 |
-
Encode WebM (VP9) via imageio.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
"""
|
| 204 |
if not frames:
|
| 205 |
raise ValueError("No frames to encode WebM.")
|
|
@@ -223,7 +227,6 @@ def _encode_webm(frames: List[np.ndarray], fps: int, quality: str = "good") -> b
|
|
| 223 |
out_path,
|
| 224 |
fps=max(1, fps),
|
| 225 |
format="FFMPEG",
|
| 226 |
-
executable=_FFMPEG_EXE if _FFMPEG_EXE else None,
|
| 227 |
codec="libvpx-vp9",
|
| 228 |
ffmpeg_params=[
|
| 229 |
"-pix_fmt", "yuv420p",
|
|
@@ -344,7 +347,7 @@ class EndpointHandler:
|
|
| 344 |
self.pipe = None
|
| 345 |
self.init_error: Optional[str] = None
|
| 346 |
|
| 347 |
-
print("=== CUSTOM handler.py LOADED (
|
| 348 |
print(f"=== HF toolkit patch diag: {HF_TOOLKIT_PATCH_DIAG} ===", flush=True)
|
| 349 |
print(f"=== imageio-ffmpeg exe: {_FFMPEG_EXE} ===", flush=True)
|
| 350 |
|
|
@@ -488,24 +491,21 @@ class EndpointHandler:
|
|
| 488 |
|
| 489 |
frames: List[np.ndarray] = []
|
| 490 |
|
| 491 |
-
# 1) output.frames —
|
| 492 |
if hasattr(output, "frames") and getattr(output, "frames") is not None:
|
| 493 |
frames_raw = getattr(output, "frames")
|
| 494 |
arr = np.array(frames_raw)
|
| 495 |
|
| 496 |
-
#
|
| 497 |
if arr.ndim == 4:
|
| 498 |
frames = [arr[t] for t in range(arr.shape[0])]
|
| 499 |
-
|
| 500 |
-
# Sometimes: (B, T, H, W, C)
|
| 501 |
elif arr.ndim == 5:
|
| 502 |
arr = arr[0]
|
| 503 |
frames = [arr[t] for t in range(arr.shape[0])]
|
| 504 |
-
|
| 505 |
-
# Rare: list-of-frames already
|
| 506 |
elif isinstance(frames_raw, list):
|
| 507 |
frames = [np.array(f) for f in frames_raw]
|
| 508 |
-
|
| 509 |
else:
|
| 510 |
raise ValueError(f"Unexpected frames shape: {arr.shape}")
|
| 511 |
|
|
@@ -522,12 +522,12 @@ class EndpointHandler:
|
|
| 522 |
except Exception:
|
| 523 |
arr = np.array(vids)
|
| 524 |
|
| 525 |
-
#
|
| 526 |
if arr.ndim == 5:
|
| 527 |
arr = arr[0]
|
| 528 |
|
|
|
|
| 529 |
if arr.ndim == 4 and arr.shape[1] in (1, 3, 4):
|
| 530 |
-
# (T,C,H,W) -> (T,H,W,C)
|
| 531 |
arr = np.transpose(arr, (0, 2, 3, 1))
|
| 532 |
|
| 533 |
if arr.ndim != 4:
|
|
|
|
| 5 |
This version includes:
|
| 6 |
- Defensive patches to avoid hosted runtime failing with:
|
| 7 |
"`ffmpeg` is not a registered plugin name."
|
| 8 |
+
- Robust frame extraction for shapes like (T,H,W,C), (B,T,H,W,C), (T,C,H,W), (B,T,C,H,W)
|
| 9 |
- Output encoders:
|
| 10 |
- GIF: Pillow only (no ffmpeg)
|
| 11 |
- ZIP: PNG frames zipped (no ffmpeg)
|
| 12 |
+
- WebM: imageio + imageio-ffmpeg via IMAGEIO_FFMPEG_EXE env var (NO executable= arg)
|
| 13 |
|
| 14 |
IMPORTANT:
|
| 15 |
- HF gateway often requires top-level { "inputs": {...} }.
|
|
|
|
| 87 |
except Exception as e:
|
| 88 |
diag["details"].append(f"failed wrapping {fn_name}: {e}")
|
| 89 |
|
| 90 |
+
# Dummy module injection (helps if toolkit tries importing a plugin module)
|
| 91 |
dummy_mod_name = "huggingface_inference_toolkit.plugins.ffmpeg"
|
| 92 |
if dummy_mod_name not in sys.modules:
|
| 93 |
dummy = types.ModuleType(dummy_mod_name)
|
|
|
|
| 119 |
try:
|
| 120 |
import imageio_ffmpeg # type: ignore
|
| 121 |
_FFMPEG_EXE = imageio_ffmpeg.get_ffmpeg_exe()
|
| 122 |
+
# Force absolute ffmpeg path via env var; do NOT use imageio executable= param (not supported here).
|
| 123 |
os.environ["IMAGEIO_FFMPEG_EXE"] = _FFMPEG_EXE
|
| 124 |
except Exception:
|
| 125 |
_FFMPEG_EXE = ""
|
|
|
|
| 145 |
if not isinstance(frame, np.ndarray):
|
| 146 |
frame = np.array(frame)
|
| 147 |
|
| 148 |
+
# squeeze batch dim (rare)
|
| 149 |
if frame.ndim == 4 and frame.shape[0] == 1:
|
| 150 |
frame = frame[0]
|
| 151 |
|
|
|
|
| 199 |
|
| 200 |
def _encode_webm(frames: List[np.ndarray], fps: int, quality: str = "good") -> bytes:
|
| 201 |
"""
|
| 202 |
+
Encode WebM (VP9) via imageio.
|
| 203 |
+
|
| 204 |
+
IMPORTANT:
|
| 205 |
+
- Do NOT pass executable=...; HF's imageio build can reject that parameter.
|
| 206 |
+
- We rely on IMAGEIO_FFMPEG_EXE env var set at import time.
|
| 207 |
"""
|
| 208 |
if not frames:
|
| 209 |
raise ValueError("No frames to encode WebM.")
|
|
|
|
| 227 |
out_path,
|
| 228 |
fps=max(1, fps),
|
| 229 |
format="FFMPEG",
|
|
|
|
| 230 |
codec="libvpx-vp9",
|
| 231 |
ffmpeg_params=[
|
| 232 |
"-pix_fmt", "yuv420p",
|
|
|
|
| 347 |
self.pipe = None
|
| 348 |
self.init_error: Optional[str] = None
|
| 349 |
|
| 350 |
+
print("=== CUSTOM handler.py LOADED (webm uses IMAGEIO_FFMPEG_EXE only) ===", flush=True)
|
| 351 |
print(f"=== HF toolkit patch diag: {HF_TOOLKIT_PATCH_DIAG} ===", flush=True)
|
| 352 |
print(f"=== imageio-ffmpeg exe: {_FFMPEG_EXE} ===", flush=True)
|
| 353 |
|
|
|
|
| 491 |
|
| 492 |
frames: List[np.ndarray] = []
|
| 493 |
|
| 494 |
+
# 1) output.frames — may be list OR ndarray/tensor-like
|
| 495 |
if hasattr(output, "frames") and getattr(output, "frames") is not None:
|
| 496 |
frames_raw = getattr(output, "frames")
|
| 497 |
arr = np.array(frames_raw)
|
| 498 |
|
| 499 |
+
# (T,H,W,C)
|
| 500 |
if arr.ndim == 4:
|
| 501 |
frames = [arr[t] for t in range(arr.shape[0])]
|
| 502 |
+
# (B,T,H,W,C)
|
|
|
|
| 503 |
elif arr.ndim == 5:
|
| 504 |
arr = arr[0]
|
| 505 |
frames = [arr[t] for t in range(arr.shape[0])]
|
| 506 |
+
# list-of-frames
|
|
|
|
| 507 |
elif isinstance(frames_raw, list):
|
| 508 |
frames = [np.array(f) for f in frames_raw]
|
|
|
|
| 509 |
else:
|
| 510 |
raise ValueError(f"Unexpected frames shape: {arr.shape}")
|
| 511 |
|
|
|
|
| 522 |
except Exception:
|
| 523 |
arr = np.array(vids)
|
| 524 |
|
| 525 |
+
# (B,T,C,H,W) or (B,T,H,W,C) or (T,C,H,W) or (T,H,W,C)
|
| 526 |
if arr.ndim == 5:
|
| 527 |
arr = arr[0]
|
| 528 |
|
| 529 |
+
# (T,C,H,W) -> (T,H,W,C)
|
| 530 |
if arr.ndim == 4 and arr.shape[1] in (1, 3, 4):
|
|
|
|
| 531 |
arr = np.transpose(arr, (0, 2, 3, 1))
|
| 532 |
|
| 533 |
if arr.ndim != 4:
|