fix(vertex-ai): map veo video size to resolution

This commit is contained in:
Emerson Gomes 2026-06-18 17:35:28 -05:00
parent cc8e128d53
commit 1e4b30e4ed
No known key found for this signature in database
GPG key ID: D3DF28AB5D1B5E17
4 changed files with 78 additions and 9 deletions

View file

@ -91,6 +91,13 @@ class VertexAIVideoConfig(BaseVideoConfig, VertexBase):
3. Extract video data (base64) from response
"""
_OPENAI_VIDEO_SIZE_TO_ASPECT_RATIO: dict[str, str] = {
"1280x720": "16:9",
"1920x1080": "16:9",
"720x1280": "9:16",
"1080x1920": "9:16",
}
def __init__(self):
BaseVideoConfig.__init__(self)
VertexBase.__init__(self)
@ -133,6 +140,8 @@ class VertexAIVideoConfig(BaseVideoConfig, VertexBase):
- prompt prompt (in instances)
- input_reference image (in instances)
- size aspectRatio (e.g., "1280x720" "16:9")
- size resolution when inferable ("1280x720"/"720x1280" "720p",
"1920x1080"/"1080x1920" "1080p"); skipped if ``resolution`` is already set
- seconds durationSeconds (defaults to 4 seconds if not provided)
"""
mapped_params: Final[dict[str, Any]] = {}
@ -147,6 +156,9 @@ class VertexAIVideoConfig(BaseVideoConfig, VertexBase):
if "parameters" in video_create_optional_params:
mapped_params["parameters"] = video_create_optional_params["parameters"]
if "resolution" in video_create_optional_params:
mapped_params["resolution"] = video_create_optional_params["resolution"]
# Map size to aspectRatio
if "size" in video_create_optional_params:
size: Final = video_create_optional_params["size"]
@ -154,6 +166,15 @@ class VertexAIVideoConfig(BaseVideoConfig, VertexBase):
aspect_ratio: Final = self._convert_size_to_aspect_ratio(size)
if aspect_ratio:
mapped_params["aspectRatio"] = aspect_ratio
nested_params: Final = video_create_optional_params.get("parameters")
has_resolution = "resolution" in mapped_params or (
isinstance(nested_params, dict)
and nested_params.get("resolution") is not None
)
if not has_resolution:
inferred_resolution = self._convert_size_to_resolution(size)
if inferred_resolution is not None:
mapped_params["resolution"] = inferred_resolution
# Map seconds to durationSeconds, default to 4 seconds (matching OpenAI)
if "seconds" in video_create_optional_params:
@ -177,14 +198,21 @@ class VertexAIVideoConfig(BaseVideoConfig, VertexBase):
if not size:
return None
aspect_ratio_map: Final = {
"1280x720": "16:9",
"1920x1080": "16:9",
"720x1280": "9:16",
"1080x1920": "9:16",
}
return self._OPENAI_VIDEO_SIZE_TO_ASPECT_RATIO.get(size, "16:9")
return aspect_ratio_map.get(size, "16:9")
def _convert_size_to_resolution(self, size: str) -> str | None:
if not size or size not in self._OPENAI_VIDEO_SIZE_TO_ASPECT_RATIO:
return None
try:
width, height = size.split("x", 1)
smaller_edge = min(int(width), int(height))
except (ValueError, TypeError):
return None
if smaller_edge == 720:
return "720p"
if smaller_edge == 1080:
return "1080p"
return None
def validate_environment(
self,

View file

@ -39352,7 +39352,8 @@
"output_cost_per_second_1080p": 0.08,
"source": "https://cloud.google.com/gemini-enterprise-agent-platform/generative-ai/pricing#veo",
"supported_modalities": [
"text"
"text",
"image"
],
"supported_output_modalities": [
"video"

View file

@ -39352,7 +39352,8 @@
"output_cost_per_second_1080p": 0.08,
"source": "https://cloud.google.com/gemini-enterprise-agent-platform/generative-ai/pricing#veo",
"supported_modalities": [
"text"
"text",
"image"
],
"supported_output_modalities": [
"video"

View file

@ -153,6 +153,7 @@ class TestVertexAIVideoConfig:
assert info["max_input_tokens"] == 1024
assert info["output_cost_per_second"] == 0.05
assert info["output_cost_per_second_1080p"] == 0.08
assert info["supported_modalities"] == ["text", "image"]
def test_veo_31_lite_provider_routing_from_local_model_map(
self, monkeypatch: pytest.MonkeyPatch
@ -284,6 +285,44 @@ class TestVertexAIVideoConfig:
assert mapped["durationSeconds"] == 8
assert mapped["aspectRatio"] == "16:9"
assert mapped["resolution"] == "720p"
def test_map_openai_size_to_1080p_resolution(self):
mapped = self.config.map_openai_params(
video_create_optional_params={"size": "1920x1080"},
model=VEO_31_LITE_VERTEX_MODEL,
drop_params=False,
)
assert mapped["aspectRatio"] == "16:9"
assert mapped["resolution"] == "1080p"
def test_map_openai_size_does_not_override_provider_resolution(self):
mapped = self.config.map_openai_params(
video_create_optional_params={
"size": "1920x1080",
"parameters": {"resolution": "720p"},
},
model=VEO_31_LITE_VERTEX_MODEL,
drop_params=False,
)
assert mapped["aspectRatio"] == "16:9"
assert "resolution" not in mapped
assert mapped["parameters"] == {"resolution": "720p"}
def test_map_openai_size_does_not_override_direct_resolution(self):
mapped = self.config.map_openai_params(
video_create_optional_params={
"size": "1920x1080",
"resolution": "720p",
},
model=VEO_31_LITE_VERTEX_MODEL,
drop_params=False,
)
assert mapped["aspectRatio"] == "16:9"
assert mapped["resolution"] == "720p"
def test_map_openai_params_default_duration(self):
"""Test that durationSeconds is omitted when not provided."""