Skip to content
Open
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
26 changes: 26 additions & 0 deletions google/genai/_base_transformers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

"""Base transformers for Google GenAI SDK."""
import base64

# Some fields don't accept url safe base64 encoding.
# We shouldn't use this transformer if the backend adhere to Cloud Type
# format https://cloud.google.com/docs/discovery/type-format.
# TODO(b/389133914,b/390320301): Remove the hack after backend fix the issue.
def t_bytes(data: bytes) -> str:
if not isinstance(data, bytes):
return data
return base64.b64encode(data).decode('ascii')
7 changes: 3 additions & 4 deletions google/genai/_operations_converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
# Code generated by the Google Gen AI SDK generator DO NOT EDIT.

from typing import Any, Optional, Union

from . import _transformers as t
from . import _base_transformers as base_t
from ._common import get_value_by_path as getv
from ._common import set_value_by_path as setv

Expand Down Expand Up @@ -108,7 +107,7 @@ def _Video_from_mldev(
setv(
to_object,
['video_bytes'],
t.t_bytes(getv(from_object, ['video', 'encodedVideo'])),
base_t.t_bytes(getv(from_object, ['video', 'encodedVideo'])),
)

if getv(from_object, ['encoding']) is not None:
Expand Down Expand Up @@ -214,7 +213,7 @@ def _Video_from_vertex(
setv(
to_object,
['video_bytes'],
t.t_bytes(getv(from_object, ['bytesBase64Encoded'])),
base_t.t_bytes(getv(from_object, ['bytesBase64Encoded'])),
)

if getv(from_object, ['mimeType']) is not None:
Expand Down
10 changes: 0 additions & 10 deletions google/genai/_transformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1156,16 +1156,6 @@ def t_tuning_job_status(status: str) -> Union[types.JobState, str]:
return status


# Some fields don't accept url safe base64 encoding.
# We shouldn't use this transformer if the backend adhere to Cloud Type
# format https://cloud.google.com/docs/discovery/type-format.
# TODO(b/389133914,b/390320301): Remove the hack after backend fix the issue.
def t_bytes(data: bytes) -> str:
if not isinstance(data, bytes):
return data
return base64.b64encode(data).decode('ascii')


def t_content_strict(content: types.ContentOrDict) -> types.Content:
if isinstance(content, dict):
return types.Content.model_validate(content)
Expand Down
15 changes: 8 additions & 7 deletions google/genai/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from urllib.parse import urlencode

from . import _api_module
from . import _base_transformers as base_t
from . import _common
from . import _extra_utils
from . import _mcp_utils
Expand Down Expand Up @@ -1260,7 +1261,7 @@ def _Image_to_mldev(
setv(
to_object,
['bytesBase64Encoded'],
t.t_bytes(getv(from_object, ['image_bytes'])),
base_t.t_bytes(getv(from_object, ['image_bytes'])),
)

if getv(from_object, ['mime_type']) is not None:
Expand Down Expand Up @@ -2502,7 +2503,7 @@ def _Image_to_vertex(
setv(
to_object,
['bytesBase64Encoded'],
t.t_bytes(getv(from_object, ['image_bytes'])),
base_t.t_bytes(getv(from_object, ['image_bytes'])),
)

if getv(from_object, ['mime_type']) is not None:
Expand Down Expand Up @@ -3394,7 +3395,7 @@ def _Video_to_vertex(
setv(
to_object,
['bytesBase64Encoded'],
t.t_bytes(getv(from_object, ['video_bytes'])),
base_t.t_bytes(getv(from_object, ['video_bytes'])),
)

if getv(from_object, ['mime_type']) is not None:
Expand Down Expand Up @@ -3921,7 +3922,7 @@ def _Image_from_mldev(
setv(
to_object,
['image_bytes'],
t.t_bytes(getv(from_object, ['bytesBase64Encoded'])),
base_t.t_bytes(getv(from_object, ['bytesBase64Encoded'])),
)

if getv(from_object, ['mimeType']) is not None:
Expand Down Expand Up @@ -4147,7 +4148,7 @@ def _Video_from_mldev(
setv(
to_object,
['video_bytes'],
t.t_bytes(getv(from_object, ['video', 'encodedVideo'])),
base_t.t_bytes(getv(from_object, ['video', 'encodedVideo'])),
)

if getv(from_object, ['encoding']) is not None:
Expand Down Expand Up @@ -4613,7 +4614,7 @@ def _Image_from_vertex(
setv(
to_object,
['image_bytes'],
t.t_bytes(getv(from_object, ['bytesBase64Encoded'])),
base_t.t_bytes(getv(from_object, ['bytesBase64Encoded'])),
)

if getv(from_object, ['mimeType']) is not None:
Expand Down Expand Up @@ -5023,7 +5024,7 @@ def _Video_from_vertex(
setv(
to_object,
['video_bytes'],
t.t_bytes(getv(from_object, ['bytesBase64Encoded'])),
base_t.t_bytes(getv(from_object, ['bytesBase64Encoded'])),
)

if getv(from_object, ['mimeType']) is not None:
Expand Down
2 changes: 1 addition & 1 deletion google/genai/tests/transformers/test_bytes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import base64

from ... import _transformers as t
from ... import _base_transformers as t

_RAW_BYTES = (
b'\xfb\xf6\x9bq\xd7\x9f\x82\x18\xa3\x92Y\xa7\xa2\x9a\xab\xb2\xdb\xaf\xc3\x1c\xb3\x00\x10\x83\x10Q\x87'
Expand Down
59 changes: 9 additions & 50 deletions google/genai/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@
from pydantic import ConfigDict, Field, PrivateAttr, model_validator
from typing_extensions import Self, TypedDict
from . import _common
from ._operations_converters import (
_GenerateVideosOperation_from_mldev,
_GenerateVideosOperation_from_vertex,
)


if sys.version_info >= (3, 10):
# Supports both Union[t1, t2] and t1 | t2
Expand Down Expand Up @@ -8674,58 +8679,12 @@ def from_api_response(
cls, api_response: Any, is_vertex_ai: bool = False
) -> Self:
"""Instantiates a GenerateVideosOperation from an API response."""
new_operation = cls()
new_operation.name = api_response.get('name', None)
new_operation.metadata = api_response.get('metadata', None)
new_operation.done = api_response.get('done', None)
new_operation.error = api_response.get('error', None)

if is_vertex_ai:
if api_response.get('response', None) is not None:
new_operation.response = GenerateVideosResponse(
generated_videos=[
GeneratedVideo(
video=Video(
uri=video.get('gcsUri', None),
video_bytes=video.get('bytesBase64Encoded', None),
mime_type=video.get('mimeType', None),
)
)
for video in api_response.get('response', {}).get('videos', [])
],
rai_media_filtered_count=api_response.get('response', {}).get(
'raiMediaFilteredCount', None
),
rai_media_filtered_reasons=api_response.get('response', {}).get(
'raiMediaFilteredReasons', None
),
)
response_dict = _GenerateVideosOperation_from_vertex(api_response)
else:
if api_response.get('response', None) is not None:
new_operation.response = GenerateVideosResponse(
generated_videos=[
GeneratedVideo(
video=Video(
uri=video.get('video', {}).get('uri', None),
video_bytes=video.get('video', {}).get(
'encodedVideo', None
),
mime_type=video.get('encoding', None),
)
)
for video in api_response.get('response', {})
.get('generateVideoResponse', {})
.get('generatedSamples', [])
],
rai_media_filtered_count=api_response.get('response', {})
.get('generateVideoResponse', {})
.get('raiMediaFilteredCount', None),
rai_media_filtered_reasons=api_response.get('response', {})
.get('generateVideoResponse', {})
.get('raiMediaFilteredReasons', None),
)
new_operation.result = new_operation.response
return new_operation
response_dict = _GenerateVideosOperation_from_mldev(api_response)

return cls._from_response(response=response_dict, kwargs={})


class GetTuningJobConfig(_common.BaseModel):
Expand Down