Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions components/src/dynamo/common/protocols/video_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ class VideoData(BaseModel):
b64_json: Optional[str] = None
"""Base64-encoded video (if response_format is 'b64_json')."""

fps: Optional[int] = None
"""Actual video frame rate when reported by the model."""

audio_sample_rate: Optional[int] = None
"""Muxed audio sample rate when the generated video contains audio."""


class NvVideosResponse(BaseModel):
"""Response structure for video generation.
Expand Down
16 changes: 16 additions & 0 deletions components/src/dynamo/common/tests/test_video_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,19 @@ def test_video_response_wire_shape():
"created": 0,
"data": [{"output_format": "mp4", "url": "http://example.com/v.mp4"}],
}


def test_video_response_reports_media_metadata():
response = VideoData(
output_format="mp4",
url="http://example.com/v.mp4",
fps=24,
audio_sample_rate=32000,
)

assert response.model_dump(exclude_none=True) == {
"output_format": "mp4",
"url": "http://example.com/v.mp4",
"fps": 24,
"audio_sample_rate": 32000,
}
35 changes: 23 additions & 12 deletions components/src/dynamo/vllm/omni/omni_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,19 +358,14 @@ async def _generate_openai_mode(
)
except (ValueError, NotImplementedError, RuntimeError) as e:
logger.error(f"Invalid request {request_id}: {e}")
if (
isinstance(e, ValueError)
and request_type == RequestType.IMAGE_GENERATION
if isinstance(e, ValueError) and request_type in (
RequestType.IMAGE_GENERATION,
RequestType.VIDEO_GENERATION,
):
# /v1/images/generations folds worker output into
# NvImagesResponse, which has no failure shape, so the
# chat.completion.chunk _error_chunk returns is not a rejection
# the client can read. Re-raise as InvalidArgument instead: it is
# a registered binding exception, so errors.rs takes its message
# via .value(py).str() and the client sees the reason alone. A
# bare ValueError reaches the same 400 through engine.rs's
# fallback, but that path uses PyErr::to_string() and renders as
# "ValueError: <reason>", leaking the Python type to the API.
# Media endpoints cannot interpret the chat.completion.chunk
# returned by _error_chunk as a request rejection. Re-raise as
# the registered binding exception so the HTTP layer returns a
# 400 with the validation reason before generation begins.
Comment thread
GuanLuo marked this conversation as resolved.
raise InvalidArgument(str(e)) from e
yield self._error_chunk(request_id, str(e), request_type)
return
Expand Down Expand Up @@ -742,6 +737,12 @@ def _engine_inputs_from_video(
image: Pre-loaded PIL Image for I2V. When provided, the image is
attached to the prompt via ``multi_modal_data`` so vllm-omni's
I2V pipeline pre-process can use it.

Returns:
EngineInputs: Validated inputs for video generation.

Raises:
ValueError: If the frame rate or output format is unsupported.
"""
width, height = parse_size(req.size)
nvext = req.nvext or VideoNvExt()
Expand All @@ -753,6 +754,15 @@ def _engine_inputs_from_video(
default_fps=DEFAULT_VIDEO_FPS,
)
fps = nvext.fps if nvext.fps is not None else DEFAULT_VIDEO_FPS
if fps <= 0:
raise ValueError(f"fps must be greater than zero, got {fps}")

output_format = req.output_format.lower() if req.output_format else None
if output_format not in (None, "mp4"):
raise ValueError(
f"Unsupported output_format: {req.output_format!r}; "
Comment thread
GuanLuo marked this conversation as resolved.
"only 'mp4' is supported"
)

prompt = OmniTextPrompt(prompt=req.prompt)
if nvext.negative_prompt is not None:
Expand Down Expand Up @@ -799,5 +809,6 @@ def _engine_inputs_from_video(
request_type=RequestType.VIDEO_GENERATION,
fps=fps,
response_format=req.response_format,
output_format=output_format,
lora_request=lora_request,
)
Loading
Loading