google-genai 1.43.0__py3-none-any.whl → 1.45.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- google/genai/_api_client.py +19 -4
- google/genai/_common.py +1 -3
- google/genai/_operations_converters.py +6 -6
- google/genai/_replay_api_client.py +8 -3
- google/genai/_transformers.py +63 -63
- google/genai/live.py +17 -4
- google/genai/models.py +38 -8
- google/genai/types.py +131 -16
- google/genai/version.py +1 -1
- {google_genai-1.43.0.dist-info → google_genai-1.45.0.dist-info}/METADATA +21 -1
- {google_genai-1.43.0.dist-info → google_genai-1.45.0.dist-info}/RECORD +14 -14
- {google_genai-1.43.0.dist-info → google_genai-1.45.0.dist-info}/WHEEL +0 -0
- {google_genai-1.43.0.dist-info → google_genai-1.45.0.dist-info}/licenses/LICENSE +0 -0
- {google_genai-1.43.0.dist-info → google_genai-1.45.0.dist-info}/top_level.txt +0 -0
google/genai/_api_client.py
CHANGED
|
@@ -547,6 +547,7 @@ class BaseApiClient:
|
|
|
547
547
|
http_options: Optional[HttpOptionsOrDict] = None,
|
|
548
548
|
):
|
|
549
549
|
self.vertexai = vertexai
|
|
550
|
+
self.custom_base_url = None
|
|
550
551
|
if self.vertexai is None:
|
|
551
552
|
if os.environ.get('GOOGLE_GENAI_USE_VERTEXAI', '0').lower() in [
|
|
552
553
|
'true',
|
|
@@ -628,11 +629,17 @@ class BaseApiClient:
|
|
|
628
629
|
)
|
|
629
630
|
self.api_key = None
|
|
630
631
|
|
|
632
|
+
self.custom_base_url = (
|
|
633
|
+
validated_http_options.base_url
|
|
634
|
+
if validated_http_options.base_url
|
|
635
|
+
else None
|
|
636
|
+
)
|
|
637
|
+
|
|
631
638
|
# Skip fetching project from ADC if base url is provided in http options.
|
|
632
639
|
if (
|
|
633
640
|
not self.project
|
|
634
641
|
and not self.api_key
|
|
635
|
-
and not
|
|
642
|
+
and not self.custom_base_url
|
|
636
643
|
):
|
|
637
644
|
credentials, self.project = load_auth(project=None)
|
|
638
645
|
if not self._credentials:
|
|
@@ -640,7 +647,7 @@ class BaseApiClient:
|
|
|
640
647
|
|
|
641
648
|
has_sufficient_auth = (self.project and self.location) or self.api_key
|
|
642
649
|
|
|
643
|
-
if not has_sufficient_auth and not
|
|
650
|
+
if not has_sufficient_auth and not self.custom_base_url:
|
|
644
651
|
# Skip sufficient auth check if base url is provided in http options.
|
|
645
652
|
raise ValueError(
|
|
646
653
|
'Project and location or API key must be set when using the Vertex '
|
|
@@ -648,9 +655,11 @@ class BaseApiClient:
|
|
|
648
655
|
)
|
|
649
656
|
if self.api_key or self.location == 'global':
|
|
650
657
|
self._http_options.base_url = f'https://aiplatform.googleapis.com/'
|
|
651
|
-
elif
|
|
658
|
+
elif self.custom_base_url and not has_sufficient_auth:
|
|
652
659
|
# Avoid setting default base url and api version if base_url provided.
|
|
653
|
-
|
|
660
|
+
# API gateway proxy can use the auth in custom headers, not url.
|
|
661
|
+
# Enable custom url if auth is not sufficient.
|
|
662
|
+
self._http_options.base_url = self.custom_base_url
|
|
654
663
|
else:
|
|
655
664
|
self._http_options.base_url = (
|
|
656
665
|
f'https://{self.location}-aiplatform.googleapis.com/'
|
|
@@ -683,6 +692,7 @@ class BaseApiClient:
|
|
|
683
692
|
client_args, async_client_args = self._ensure_httpx_ssl_ctx(
|
|
684
693
|
self._http_options
|
|
685
694
|
)
|
|
695
|
+
self._async_httpx_client_args = async_client_args
|
|
686
696
|
self._httpx_client = SyncHttpxClient(**client_args)
|
|
687
697
|
self._async_httpx_client = AsyncHttpxClient(**async_client_args)
|
|
688
698
|
if self._use_aiohttp():
|
|
@@ -897,6 +907,11 @@ class BaseApiClient:
|
|
|
897
907
|
)
|
|
898
908
|
|
|
899
909
|
def _websocket_base_url(self) -> str:
|
|
910
|
+
has_sufficient_auth = (self.project and self.location) or self.api_key
|
|
911
|
+
if self.custom_base_url and not has_sufficient_auth:
|
|
912
|
+
# API gateway proxy can use the auth in custom headers, not url.
|
|
913
|
+
# Enable custom url if auth is not sufficient.
|
|
914
|
+
return self.custom_base_url
|
|
900
915
|
url_parts = urlparse(self._http_options.base_url)
|
|
901
916
|
return url_parts._replace(scheme='wss').geturl() # type: ignore[arg-type, return-value]
|
|
902
917
|
|
google/genai/_common.py
CHANGED
|
@@ -272,9 +272,7 @@ def convert_to_dict(obj: object, convert_keys: bool = False) -> Any:
|
|
|
272
272
|
return convert_to_dict(obj.model_dump(exclude_none=True), convert_keys)
|
|
273
273
|
elif isinstance(obj, dict):
|
|
274
274
|
return {
|
|
275
|
-
maybe_snake_to_camel(key, convert_keys): convert_to_dict(
|
|
276
|
-
value, convert_keys
|
|
277
|
-
)
|
|
275
|
+
maybe_snake_to_camel(key, convert_keys): convert_to_dict(value)
|
|
278
276
|
for key, value in obj.items()
|
|
279
277
|
}
|
|
280
278
|
elif isinstance(obj, list):
|
|
@@ -201,11 +201,11 @@ def _GeneratedVideo_from_mldev(
|
|
|
201
201
|
parent_object: Optional[dict[str, Any]] = None,
|
|
202
202
|
) -> dict[str, Any]:
|
|
203
203
|
to_object: dict[str, Any] = {}
|
|
204
|
-
if getv(from_object, ['
|
|
204
|
+
if getv(from_object, ['video']) is not None:
|
|
205
205
|
setv(
|
|
206
206
|
to_object,
|
|
207
207
|
['video'],
|
|
208
|
-
_Video_from_mldev(getv(from_object, ['
|
|
208
|
+
_Video_from_mldev(getv(from_object, ['video']), to_object),
|
|
209
209
|
)
|
|
210
210
|
|
|
211
211
|
return to_object
|
|
@@ -261,14 +261,14 @@ def _Video_from_mldev(
|
|
|
261
261
|
parent_object: Optional[dict[str, Any]] = None,
|
|
262
262
|
) -> dict[str, Any]:
|
|
263
263
|
to_object: dict[str, Any] = {}
|
|
264
|
-
if getv(from_object, ['
|
|
265
|
-
setv(to_object, ['uri'], getv(from_object, ['
|
|
264
|
+
if getv(from_object, ['uri']) is not None:
|
|
265
|
+
setv(to_object, ['uri'], getv(from_object, ['uri']))
|
|
266
266
|
|
|
267
|
-
if getv(from_object, ['
|
|
267
|
+
if getv(from_object, ['encodedVideo']) is not None:
|
|
268
268
|
setv(
|
|
269
269
|
to_object,
|
|
270
270
|
['video_bytes'],
|
|
271
|
-
base_t.t_bytes(getv(from_object, ['
|
|
271
|
+
base_t.t_bytes(getv(from_object, ['encodedVideo'])),
|
|
272
272
|
)
|
|
273
273
|
|
|
274
274
|
if getv(from_object, ['encoding']) is not None:
|
|
@@ -56,8 +56,13 @@ def _normalize_json_case(obj: Any) -> Any:
|
|
|
56
56
|
return [_normalize_json_case(item) for item in obj]
|
|
57
57
|
elif isinstance(obj, enum.Enum):
|
|
58
58
|
return obj.value
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
elif isinstance(obj, str):
|
|
60
|
+
# Python >= 3.14 has a new division by zero error message.
|
|
61
|
+
if 'division by zero' in obj:
|
|
62
|
+
return obj.replace(
|
|
63
|
+
'division by zero', 'integer division or modulo by zero'
|
|
64
|
+
)
|
|
65
|
+
return obj
|
|
61
66
|
|
|
62
67
|
|
|
63
68
|
def _equals_ignore_key_case(obj1: Any, obj2: Any) -> bool:
|
|
@@ -88,7 +93,7 @@ def _equals_ignore_key_case(obj1: Any, obj2: Any) -> bool:
|
|
|
88
93
|
|
|
89
94
|
def _redact_version_numbers(version_string: str) -> str:
|
|
90
95
|
"""Redacts version numbers in the form x.y.z from a string."""
|
|
91
|
-
return re.sub(r'\d+\.\d+\.\d+', '{VERSION_NUMBER}', version_string)
|
|
96
|
+
return re.sub(r'\d+\.\d+\.\d+[a-zA-Z0-9]*', '{VERSION_NUMBER}', version_string)
|
|
92
97
|
|
|
93
98
|
|
|
94
99
|
def _redact_language_label(language_label: str) -> str:
|
google/genai/_transformers.py
CHANGED
|
@@ -41,28 +41,6 @@ from . import types
|
|
|
41
41
|
|
|
42
42
|
logger = logging.getLogger('google_genai._transformers')
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
def _is_duck_type_of(obj: Any, cls: type[pydantic.BaseModel]) -> bool:
|
|
46
|
-
"""Checks if an object has all of the fields of a Pydantic model.
|
|
47
|
-
|
|
48
|
-
This is a duck-typing alternative to `isinstance` to solve dual-import
|
|
49
|
-
problems. It returns False for dictionaries, which should be handled by
|
|
50
|
-
`isinstance(obj, dict)`.
|
|
51
|
-
|
|
52
|
-
Args:
|
|
53
|
-
obj: The object to check.
|
|
54
|
-
cls: The Pydantic model class to duck-type against.
|
|
55
|
-
|
|
56
|
-
Returns:
|
|
57
|
-
True if the object has all the fields defined in the Pydantic model, False
|
|
58
|
-
otherwise.
|
|
59
|
-
"""
|
|
60
|
-
if isinstance(obj, dict) or not hasattr(cls, 'model_fields'):
|
|
61
|
-
return False
|
|
62
|
-
|
|
63
|
-
# Check if the object has all of the Pydantic model's defined fields.
|
|
64
|
-
return all(hasattr(obj, field) for field in cls.model_fields)
|
|
65
|
-
|
|
66
44
|
if sys.version_info >= (3, 10):
|
|
67
45
|
VersionedUnionType = builtin_types.UnionType
|
|
68
46
|
_UNION_TYPES = (typing.Union, builtin_types.UnionType)
|
|
@@ -94,6 +72,28 @@ metric_name_sdk_api_map = {
|
|
|
94
72
|
metric_name_api_sdk_map = {v: k for k, v in metric_name_sdk_api_map.items()}
|
|
95
73
|
|
|
96
74
|
|
|
75
|
+
def _is_duck_type_of(obj: Any, cls: type[pydantic.BaseModel]) -> bool:
|
|
76
|
+
"""Checks if an object has all of the fields of a Pydantic model.
|
|
77
|
+
|
|
78
|
+
This is a duck-typing alternative to `isinstance` to solve dual-import
|
|
79
|
+
problems. It returns False for dictionaries, which should be handled by
|
|
80
|
+
`isinstance(obj, dict)`.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
obj: The object to check.
|
|
84
|
+
cls: The Pydantic model class to duck-type against.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
True if the object has all the fields defined in the Pydantic model, False
|
|
88
|
+
otherwise.
|
|
89
|
+
"""
|
|
90
|
+
if isinstance(obj, dict) or not hasattr(cls, 'model_fields'):
|
|
91
|
+
return False
|
|
92
|
+
|
|
93
|
+
# Check if the object has all of the Pydantic model's defined fields.
|
|
94
|
+
return all(hasattr(obj, field) for field in cls.model_fields)
|
|
95
|
+
|
|
96
|
+
|
|
97
97
|
def _resource_name(
|
|
98
98
|
client: _api_client.BaseApiClient,
|
|
99
99
|
resource_name: str,
|
|
@@ -306,7 +306,7 @@ def t_function_response(
|
|
|
306
306
|
raise ValueError('function_response is required.')
|
|
307
307
|
if isinstance(function_response, dict):
|
|
308
308
|
return types.FunctionResponse.model_validate(function_response)
|
|
309
|
-
elif
|
|
309
|
+
elif _is_duck_type_of(function_response, types.FunctionResponse):
|
|
310
310
|
return function_response
|
|
311
311
|
else:
|
|
312
312
|
raise TypeError(
|
|
@@ -342,8 +342,8 @@ def t_blob(blob: types.BlobImageUnionDict) -> types.Blob:
|
|
|
342
342
|
if not blob:
|
|
343
343
|
raise ValueError('blob is required.')
|
|
344
344
|
|
|
345
|
-
if
|
|
346
|
-
return blob
|
|
345
|
+
if _is_duck_type_of(blob, types.Blob):
|
|
346
|
+
return blob # type: ignore[return-value]
|
|
347
347
|
|
|
348
348
|
if isinstance(blob, dict):
|
|
349
349
|
return types.Blob.model_validate(blob)
|
|
@@ -383,10 +383,10 @@ def t_part(part: Optional[types.PartUnionDict]) -> types.Part:
|
|
|
383
383
|
raise ValueError('content part is required.')
|
|
384
384
|
if isinstance(part, str):
|
|
385
385
|
return types.Part(text=part)
|
|
386
|
-
if
|
|
387
|
-
if not part.uri or not part.mime_type:
|
|
386
|
+
if _is_duck_type_of(part, types.File):
|
|
387
|
+
if not part.uri or not part.mime_type: # type: ignore[union-attr]
|
|
388
388
|
raise ValueError('file uri and mime_type are required.')
|
|
389
|
-
return types.Part.from_uri(file_uri=part.uri, mime_type=part.mime_type)
|
|
389
|
+
return types.Part.from_uri(file_uri=part.uri, mime_type=part.mime_type) # type: ignore[union-attr]
|
|
390
390
|
if isinstance(part, dict):
|
|
391
391
|
try:
|
|
392
392
|
return types.Part.model_validate(part)
|
|
@@ -449,8 +449,8 @@ def t_content(
|
|
|
449
449
|
) -> types.Content:
|
|
450
450
|
if content is None:
|
|
451
451
|
raise ValueError('content is required.')
|
|
452
|
-
if
|
|
453
|
-
return content
|
|
452
|
+
if _is_duck_type_of(content, types.Content):
|
|
453
|
+
return content # type: ignore[return-value]
|
|
454
454
|
if isinstance(content, dict):
|
|
455
455
|
try:
|
|
456
456
|
return types.Content.model_validate(content)
|
|
@@ -461,15 +461,15 @@ def t_content(
|
|
|
461
461
|
if possible_part.function_call
|
|
462
462
|
else types.UserContent(parts=[possible_part])
|
|
463
463
|
)
|
|
464
|
-
if
|
|
465
|
-
return types.UserContent(parts=[t_part(content)])
|
|
466
|
-
if
|
|
464
|
+
if _is_duck_type_of(content, types.File):
|
|
465
|
+
return types.UserContent(parts=[t_part(content)]) # type: ignore[arg-type]
|
|
466
|
+
if _is_duck_type_of(content, types.Part):
|
|
467
467
|
return (
|
|
468
|
-
types.ModelContent(parts=[content])
|
|
469
|
-
if content.function_call
|
|
470
|
-
else types.UserContent(parts=[content])
|
|
468
|
+
types.ModelContent(parts=[content]) # type: ignore[arg-type]
|
|
469
|
+
if content.function_call # type: ignore[union-attr]
|
|
470
|
+
else types.UserContent(parts=[content]) # type: ignore[arg-type]
|
|
471
471
|
)
|
|
472
|
-
return types.UserContent(parts=content)
|
|
472
|
+
return types.UserContent(parts=content) # type: ignore[arg-type]
|
|
473
473
|
|
|
474
474
|
|
|
475
475
|
def t_contents_for_embed(
|
|
@@ -516,8 +516,8 @@ def t_contents(
|
|
|
516
516
|
) -> TypeGuard[types.PartUnionDict]:
|
|
517
517
|
if (
|
|
518
518
|
isinstance(part, str)
|
|
519
|
-
or
|
|
520
|
-
or
|
|
519
|
+
or _is_duck_type_of(part, types.File)
|
|
520
|
+
or _is_duck_type_of(part, types.Part)
|
|
521
521
|
):
|
|
522
522
|
return True
|
|
523
523
|
|
|
@@ -884,12 +884,12 @@ def t_schema(
|
|
|
884
884
|
return types.Schema.model_validate(origin)
|
|
885
885
|
if isinstance(origin, EnumMeta):
|
|
886
886
|
return _process_enum(origin, client)
|
|
887
|
-
if
|
|
888
|
-
if dict(origin) == dict(types.Schema()):
|
|
887
|
+
if _is_duck_type_of(origin, types.Schema):
|
|
888
|
+
if dict(origin) == dict(types.Schema()): # type: ignore [arg-type]
|
|
889
889
|
# response_schema value was coerced to an empty Schema instance because
|
|
890
890
|
# it did not adhere to the Schema field annotation
|
|
891
891
|
_raise_for_unsupported_schema_type(origin)
|
|
892
|
-
schema = origin.model_dump(exclude_unset=True)
|
|
892
|
+
schema = origin.model_dump(exclude_unset=True) # type: ignore[union-attr]
|
|
893
893
|
process_schema(schema, client)
|
|
894
894
|
return types.Schema.model_validate(schema)
|
|
895
895
|
|
|
@@ -926,8 +926,8 @@ def t_speech_config(
|
|
|
926
926
|
) -> Optional[types.SpeechConfig]:
|
|
927
927
|
if not origin:
|
|
928
928
|
return None
|
|
929
|
-
if
|
|
930
|
-
return origin
|
|
929
|
+
if _is_duck_type_of(origin, types.SpeechConfig):
|
|
930
|
+
return origin # type: ignore[return-value]
|
|
931
931
|
if isinstance(origin, str):
|
|
932
932
|
return types.SpeechConfig(
|
|
933
933
|
voice_config=types.VoiceConfig(
|
|
@@ -943,17 +943,17 @@ def t_speech_config(
|
|
|
943
943
|
def t_live_speech_config(
|
|
944
944
|
origin: types.SpeechConfigOrDict,
|
|
945
945
|
) -> Optional[types.SpeechConfig]:
|
|
946
|
-
if
|
|
946
|
+
if _is_duck_type_of(origin, types.SpeechConfig):
|
|
947
947
|
speech_config = origin
|
|
948
948
|
if isinstance(origin, dict):
|
|
949
949
|
speech_config = types.SpeechConfig.model_validate(origin)
|
|
950
950
|
|
|
951
|
-
if speech_config.multi_speaker_voice_config is not None:
|
|
951
|
+
if speech_config.multi_speaker_voice_config is not None: # type: ignore[union-attr]
|
|
952
952
|
raise ValueError(
|
|
953
953
|
'multi_speaker_voice_config is not supported in the live API.'
|
|
954
954
|
)
|
|
955
955
|
|
|
956
|
-
return speech_config
|
|
956
|
+
return speech_config # type: ignore[return-value]
|
|
957
957
|
|
|
958
958
|
|
|
959
959
|
def t_tool(
|
|
@@ -969,7 +969,7 @@ def t_tool(
|
|
|
969
969
|
)
|
|
970
970
|
]
|
|
971
971
|
)
|
|
972
|
-
elif McpTool is not None and
|
|
972
|
+
elif McpTool is not None and _is_duck_type_of(origin, McpTool):
|
|
973
973
|
return mcp_to_gemini_tool(origin)
|
|
974
974
|
elif isinstance(origin, dict):
|
|
975
975
|
return types.Tool.model_validate(origin)
|
|
@@ -1012,13 +1012,13 @@ def t_batch_job_source(
|
|
|
1012
1012
|
) -> types.BatchJobSource:
|
|
1013
1013
|
if isinstance(src, dict):
|
|
1014
1014
|
src = types.BatchJobSource(**src)
|
|
1015
|
-
if
|
|
1015
|
+
if _is_duck_type_of(src, types.BatchJobSource):
|
|
1016
1016
|
vertex_sources = sum(
|
|
1017
|
-
[src.gcs_uri is not None, src.bigquery_uri is not None]
|
|
1017
|
+
[src.gcs_uri is not None, src.bigquery_uri is not None] # type: ignore[union-attr]
|
|
1018
1018
|
)
|
|
1019
1019
|
mldev_sources = sum([
|
|
1020
|
-
src.inlined_requests is not None,
|
|
1021
|
-
src.file_name is not None,
|
|
1020
|
+
src.inlined_requests is not None, # type: ignore[union-attr]
|
|
1021
|
+
src.file_name is not None, # type: ignore[union-attr]
|
|
1022
1022
|
])
|
|
1023
1023
|
if client.vertexai:
|
|
1024
1024
|
if mldev_sources or vertex_sources != 1:
|
|
@@ -1033,7 +1033,7 @@ def t_batch_job_source(
|
|
|
1033
1033
|
'`inlined_embed_content_requests`, or `embed_content_file_name` '
|
|
1034
1034
|
'must be set, other sources are not supported in Gemini API.'
|
|
1035
1035
|
)
|
|
1036
|
-
return src
|
|
1036
|
+
return src # type: ignore[return-value]
|
|
1037
1037
|
|
|
1038
1038
|
elif isinstance(src, list):
|
|
1039
1039
|
return types.BatchJobSource(inlined_requests=src)
|
|
@@ -1063,7 +1063,7 @@ def t_embedding_batch_job_source(
|
|
|
1063
1063
|
if isinstance(src, dict):
|
|
1064
1064
|
src = types.EmbeddingsBatchJobSource(**src)
|
|
1065
1065
|
|
|
1066
|
-
if
|
|
1066
|
+
if _is_duck_type_of(src, types.EmbeddingsBatchJobSource):
|
|
1067
1067
|
mldev_sources = sum([
|
|
1068
1068
|
src.inlined_requests is not None,
|
|
1069
1069
|
src.file_name is not None,
|
|
@@ -1098,7 +1098,7 @@ def t_batch_job_destination(
|
|
|
1098
1098
|
)
|
|
1099
1099
|
else:
|
|
1100
1100
|
raise ValueError(f'Unsupported destination: {dest}')
|
|
1101
|
-
elif
|
|
1101
|
+
elif _is_duck_type_of(dest, types.BatchJobDestination):
|
|
1102
1102
|
return dest
|
|
1103
1103
|
else:
|
|
1104
1104
|
raise ValueError(f'Unsupported destination: {dest}')
|
|
@@ -1198,13 +1198,13 @@ def t_file_name(
|
|
|
1198
1198
|
name: Optional[Union[str, types.File, types.Video, types.GeneratedVideo]],
|
|
1199
1199
|
) -> str:
|
|
1200
1200
|
# Remove the files/ prefix since it's added to the url path.
|
|
1201
|
-
if
|
|
1202
|
-
name = name.name
|
|
1203
|
-
elif
|
|
1204
|
-
name = name.uri
|
|
1205
|
-
elif
|
|
1206
|
-
if name.video is not None:
|
|
1207
|
-
name = name.video.uri
|
|
1201
|
+
if _is_duck_type_of(name, types.File):
|
|
1202
|
+
name = name.name # type: ignore[union-attr]
|
|
1203
|
+
elif _is_duck_type_of(name, types.Video):
|
|
1204
|
+
name = name.uri # type: ignore[union-attr]
|
|
1205
|
+
elif _is_duck_type_of(name, types.GeneratedVideo):
|
|
1206
|
+
if name.video is not None: # type: ignore[union-attr]
|
|
1207
|
+
name = name.video.uri # type: ignore[union-attr]
|
|
1208
1208
|
else:
|
|
1209
1209
|
name = None
|
|
1210
1210
|
|
|
@@ -1247,7 +1247,7 @@ def t_tuning_job_status(status: str) -> Union[types.JobState, str]:
|
|
|
1247
1247
|
def t_content_strict(content: types.ContentOrDict) -> types.Content:
|
|
1248
1248
|
if isinstance(content, dict):
|
|
1249
1249
|
return types.Content.model_validate(content)
|
|
1250
|
-
elif
|
|
1250
|
+
elif _is_duck_type_of(content, types.Content):
|
|
1251
1251
|
return content
|
|
1252
1252
|
else:
|
|
1253
1253
|
raise ValueError(
|
google/genai/live.py
CHANGED
|
@@ -980,7 +980,8 @@ class AsyncLive(_api_module.BaseModule):
|
|
|
980
980
|
api_key = self._api_client.api_key
|
|
981
981
|
version = self._api_client._http_options.api_version
|
|
982
982
|
uri = f'{base_url}/ws/google.cloud.aiplatform.{version}.LlmBidiService/BidiGenerateContent'
|
|
983
|
-
|
|
983
|
+
original_headers = self._api_client._http_options.headers
|
|
984
|
+
headers = original_headers.copy() if original_headers is not None else {}
|
|
984
985
|
|
|
985
986
|
request_dict = _common.convert_to_dict(
|
|
986
987
|
live_converters._LiveConnectParameters_to_vertex(
|
|
@@ -1012,12 +1013,24 @@ class AsyncLive(_api_module.BaseModule):
|
|
|
1012
1013
|
bearer_token = creds.token
|
|
1013
1014
|
original_headers = self._api_client._http_options.headers
|
|
1014
1015
|
headers = original_headers.copy() if original_headers is not None else {}
|
|
1015
|
-
headers
|
|
1016
|
+
if not headers.get('Authorization'):
|
|
1017
|
+
headers['Authorization'] = f'Bearer {bearer_token}'
|
|
1016
1018
|
version = self._api_client._http_options.api_version
|
|
1017
|
-
|
|
1019
|
+
|
|
1020
|
+
has_sufficient_auth = (
|
|
1021
|
+
self._api_client.project and self._api_client.location
|
|
1022
|
+
)
|
|
1023
|
+
if self._api_client.custom_base_url and not has_sufficient_auth:
|
|
1024
|
+
# API gateway proxy can use the auth in custom headers, not url.
|
|
1025
|
+
# Enable custom url if auth is not sufficient.
|
|
1026
|
+
uri = self._api_client.custom_base_url
|
|
1027
|
+
# Keep the model as is.
|
|
1028
|
+
transformed_model = model
|
|
1029
|
+
else:
|
|
1030
|
+
uri = f'{base_url}/ws/google.cloud.aiplatform.{version}.LlmBidiService/BidiGenerateContent'
|
|
1018
1031
|
location = self._api_client.location
|
|
1019
1032
|
project = self._api_client.project
|
|
1020
|
-
if transformed_model.startswith('publishers/'):
|
|
1033
|
+
if transformed_model.startswith('publishers/') and project and location:
|
|
1021
1034
|
transformed_model = (
|
|
1022
1035
|
f'projects/{project}/locations/{location}/' + transformed_model
|
|
1023
1036
|
)
|
google/genai/models.py
CHANGED
|
@@ -2262,11 +2262,11 @@ def _GeneratedVideo_from_mldev(
|
|
|
2262
2262
|
parent_object: Optional[dict[str, Any]] = None,
|
|
2263
2263
|
) -> dict[str, Any]:
|
|
2264
2264
|
to_object: dict[str, Any] = {}
|
|
2265
|
-
if getv(from_object, ['
|
|
2265
|
+
if getv(from_object, ['video']) is not None:
|
|
2266
2266
|
setv(
|
|
2267
2267
|
to_object,
|
|
2268
2268
|
['video'],
|
|
2269
|
-
_Video_from_mldev(getv(from_object, ['
|
|
2269
|
+
_Video_from_mldev(getv(from_object, ['video']), to_object),
|
|
2270
2270
|
)
|
|
2271
2271
|
|
|
2272
2272
|
return to_object
|
|
@@ -3680,14 +3680,14 @@ def _Video_from_mldev(
|
|
|
3680
3680
|
parent_object: Optional[dict[str, Any]] = None,
|
|
3681
3681
|
) -> dict[str, Any]:
|
|
3682
3682
|
to_object: dict[str, Any] = {}
|
|
3683
|
-
if getv(from_object, ['
|
|
3684
|
-
setv(to_object, ['uri'], getv(from_object, ['
|
|
3683
|
+
if getv(from_object, ['uri']) is not None:
|
|
3684
|
+
setv(to_object, ['uri'], getv(from_object, ['uri']))
|
|
3685
3685
|
|
|
3686
|
-
if getv(from_object, ['
|
|
3686
|
+
if getv(from_object, ['encodedVideo']) is not None:
|
|
3687
3687
|
setv(
|
|
3688
3688
|
to_object,
|
|
3689
3689
|
['video_bytes'],
|
|
3690
|
-
base_t.t_bytes(getv(from_object, ['
|
|
3690
|
+
base_t.t_bytes(getv(from_object, ['encodedVideo'])),
|
|
3691
3691
|
)
|
|
3692
3692
|
|
|
3693
3693
|
if getv(from_object, ['encoding']) is not None:
|
|
@@ -3723,12 +3723,12 @@ def _Video_to_mldev(
|
|
|
3723
3723
|
) -> dict[str, Any]:
|
|
3724
3724
|
to_object: dict[str, Any] = {}
|
|
3725
3725
|
if getv(from_object, ['uri']) is not None:
|
|
3726
|
-
setv(to_object, ['
|
|
3726
|
+
setv(to_object, ['uri'], getv(from_object, ['uri']))
|
|
3727
3727
|
|
|
3728
3728
|
if getv(from_object, ['video_bytes']) is not None:
|
|
3729
3729
|
setv(
|
|
3730
3730
|
to_object,
|
|
3731
|
-
['
|
|
3731
|
+
['encodedVideo'],
|
|
3732
3732
|
base_t.t_bytes(getv(from_object, ['video_bytes'])),
|
|
3733
3733
|
)
|
|
3734
3734
|
|
|
@@ -5448,6 +5448,36 @@ class Models(_api_module.BaseModule):
|
|
|
5448
5448
|
'Source and prompt/image/video are mutually exclusive.'
|
|
5449
5449
|
+ ' Please only use source.'
|
|
5450
5450
|
)
|
|
5451
|
+
# Gemini Developer API does not support video bytes.
|
|
5452
|
+
video_dct: dict[str, Any] = {}
|
|
5453
|
+
if not self._api_client.vertexai and video:
|
|
5454
|
+
if isinstance(video, types.Video):
|
|
5455
|
+
video_dct = video.model_dump()
|
|
5456
|
+
else:
|
|
5457
|
+
video_dct = dict(video)
|
|
5458
|
+
|
|
5459
|
+
if video_dct.get('uri') and video_dct.get('video_bytes'):
|
|
5460
|
+
video = types.Video(
|
|
5461
|
+
uri=video_dct.get('uri'), mime_type=video_dct.get('mime_type')
|
|
5462
|
+
)
|
|
5463
|
+
elif not self._api_client.vertexai and source:
|
|
5464
|
+
if isinstance(source, types.GenerateVideosSource):
|
|
5465
|
+
source_dct = source.model_dump()
|
|
5466
|
+
video_dct = source_dct.get('video', {})
|
|
5467
|
+
else:
|
|
5468
|
+
source_dct = dict(source)
|
|
5469
|
+
if isinstance(source_dct.get('video'), types.Video):
|
|
5470
|
+
video_obj: types.Video = source_dct.get('video', types.Video())
|
|
5471
|
+
video_dct = video_obj.model_dump()
|
|
5472
|
+
if video_dct and video_dct.get('uri') and video_dct.get('video_bytes'):
|
|
5473
|
+
source = types.GenerateVideosSource(
|
|
5474
|
+
prompt=source_dct.get('prompt'),
|
|
5475
|
+
image=source_dct.get('image'),
|
|
5476
|
+
video=types.Video(
|
|
5477
|
+
uri=video_dct.get('uri'),
|
|
5478
|
+
mime_type=video_dct.get('mime_type'),
|
|
5479
|
+
),
|
|
5480
|
+
)
|
|
5451
5481
|
return self._generate_videos(
|
|
5452
5482
|
model=model,
|
|
5453
5483
|
prompt=prompt,
|
google/genai/types.py
CHANGED
|
@@ -1696,6 +1696,10 @@ class JSONSchema(_common.BaseModel):
|
|
|
1696
1696
|
' matches the instance successfully.'
|
|
1697
1697
|
),
|
|
1698
1698
|
)
|
|
1699
|
+
additional_properties: Optional[Any] = Field(
|
|
1700
|
+
default=None,
|
|
1701
|
+
description="""Can either be a boolean or an object; controls the presence of additional properties.""",
|
|
1702
|
+
)
|
|
1699
1703
|
any_of: Optional[list['JSONSchema']] = Field(
|
|
1700
1704
|
default=None,
|
|
1701
1705
|
description=(
|
|
@@ -1704,6 +1708,20 @@ class JSONSchema(_common.BaseModel):
|
|
|
1704
1708
|
' keyword’s value.'
|
|
1705
1709
|
),
|
|
1706
1710
|
)
|
|
1711
|
+
unique_items: Optional[bool] = Field(
|
|
1712
|
+
default=None,
|
|
1713
|
+
description="""Boolean value that indicates whether the items in an array are unique.""",
|
|
1714
|
+
)
|
|
1715
|
+
ref: Optional[str] = Field(
|
|
1716
|
+
default=None,
|
|
1717
|
+
alias='$ref',
|
|
1718
|
+
description="""Allows indirect references between schema nodes.""",
|
|
1719
|
+
)
|
|
1720
|
+
defs: Optional[dict[str, 'JSONSchema']] = Field(
|
|
1721
|
+
default=None,
|
|
1722
|
+
alias='$defs',
|
|
1723
|
+
description="""Schema definitions to be used with $ref.""",
|
|
1724
|
+
)
|
|
1707
1725
|
|
|
1708
1726
|
|
|
1709
1727
|
class Schema(_common.BaseModel):
|
|
@@ -1915,7 +1933,7 @@ class Schema(_common.BaseModel):
|
|
|
1915
1933
|
list_schema_field_names: tuple[str, ...] = (
|
|
1916
1934
|
'any_of', # 'one_of', 'all_of', 'not' to come
|
|
1917
1935
|
)
|
|
1918
|
-
dict_schema_field_names: tuple[str, ...] = ('properties',)
|
|
1936
|
+
dict_schema_field_names: tuple[str, ...] = ('properties',)
|
|
1919
1937
|
|
|
1920
1938
|
related_field_names_by_type: dict[str, tuple[str, ...]] = {
|
|
1921
1939
|
JSONSchemaType.NUMBER.value: (
|
|
@@ -1964,6 +1982,23 @@ class Schema(_common.BaseModel):
|
|
|
1964
1982
|
# placeholder for potential gemini api unsupported fields
|
|
1965
1983
|
gemini_api_unsupported_field_names: tuple[str, ...] = ()
|
|
1966
1984
|
|
|
1985
|
+
def _resolve_ref(
|
|
1986
|
+
ref_path: str, root_schema_dict: dict[str, Any]
|
|
1987
|
+
) -> dict[str, Any]:
|
|
1988
|
+
"""Helper to resolve a $ref path."""
|
|
1989
|
+
current = root_schema_dict
|
|
1990
|
+
for part in ref_path.lstrip('#/').split('/'):
|
|
1991
|
+
if part == '$defs':
|
|
1992
|
+
part = 'defs'
|
|
1993
|
+
current = current[part]
|
|
1994
|
+
current.pop('title', None)
|
|
1995
|
+
if 'properties' in current and current['properties'] is not None:
|
|
1996
|
+
for prop_schema in current['properties'].values():
|
|
1997
|
+
if isinstance(prop_schema, dict):
|
|
1998
|
+
prop_schema.pop('title', None)
|
|
1999
|
+
|
|
2000
|
+
return current
|
|
2001
|
+
|
|
1967
2002
|
def normalize_json_schema_type(
|
|
1968
2003
|
json_schema_type: Optional[
|
|
1969
2004
|
Union[JSONSchemaType, Sequence[JSONSchemaType], str, Sequence[str]]
|
|
@@ -1972,11 +2007,16 @@ class Schema(_common.BaseModel):
|
|
|
1972
2007
|
"""Returns (non_null_types, nullable)"""
|
|
1973
2008
|
if json_schema_type is None:
|
|
1974
2009
|
return [], False
|
|
1975
|
-
|
|
1976
|
-
|
|
2010
|
+
type_sequence: Sequence[Union[JSONSchemaType, str]]
|
|
2011
|
+
if isinstance(json_schema_type, str) or not isinstance(
|
|
2012
|
+
json_schema_type, Sequence
|
|
2013
|
+
):
|
|
2014
|
+
type_sequence = [json_schema_type]
|
|
2015
|
+
else:
|
|
2016
|
+
type_sequence = json_schema_type
|
|
1977
2017
|
non_null_types = []
|
|
1978
2018
|
nullable = False
|
|
1979
|
-
for type_value in
|
|
2019
|
+
for type_value in type_sequence:
|
|
1980
2020
|
if isinstance(type_value, JSONSchemaType):
|
|
1981
2021
|
type_value = type_value.value
|
|
1982
2022
|
if type_value == JSONSchemaType.NULL.value:
|
|
@@ -1996,7 +2036,10 @@ class Schema(_common.BaseModel):
|
|
|
1996
2036
|
for field_name, field_value in json_schema_dict.items():
|
|
1997
2037
|
if field_value is None:
|
|
1998
2038
|
continue
|
|
1999
|
-
if field_name not in google_schema_field_names
|
|
2039
|
+
if field_name not in google_schema_field_names and field_name not in [
|
|
2040
|
+
'ref',
|
|
2041
|
+
'defs',
|
|
2042
|
+
]:
|
|
2000
2043
|
raise ValueError(
|
|
2001
2044
|
f'JSONSchema field "{field_name}" is not supported by the '
|
|
2002
2045
|
'Schema object. And the "raise_error_on_unsupported_field" '
|
|
@@ -2026,12 +2069,19 @@ class Schema(_common.BaseModel):
|
|
|
2026
2069
|
)
|
|
2027
2070
|
|
|
2028
2071
|
def convert_json_schema(
|
|
2029
|
-
|
|
2072
|
+
current_json_schema: JSONSchema,
|
|
2073
|
+
root_json_schema_dict: dict[str, Any],
|
|
2030
2074
|
api_option: Literal['VERTEX_AI', 'GEMINI_API'],
|
|
2031
2075
|
raise_error_on_unsupported_field: bool,
|
|
2032
2076
|
) -> 'Schema':
|
|
2033
2077
|
schema = Schema()
|
|
2034
|
-
json_schema_dict =
|
|
2078
|
+
json_schema_dict = current_json_schema.model_dump()
|
|
2079
|
+
|
|
2080
|
+
if json_schema_dict.get('ref'):
|
|
2081
|
+
json_schema_dict = _resolve_ref(
|
|
2082
|
+
json_schema_dict['ref'], root_json_schema_dict
|
|
2083
|
+
)
|
|
2084
|
+
|
|
2035
2085
|
raise_error_if_cannot_convert(
|
|
2036
2086
|
json_schema_dict=json_schema_dict,
|
|
2037
2087
|
api_option=api_option,
|
|
@@ -2057,6 +2107,7 @@ class Schema(_common.BaseModel):
|
|
|
2057
2107
|
non_null_types, nullable = normalize_json_schema_type(
|
|
2058
2108
|
json_schema_dict.get('type', None)
|
|
2059
2109
|
)
|
|
2110
|
+
is_union_like_type = len(non_null_types) > 1
|
|
2060
2111
|
if len(non_null_types) > 1:
|
|
2061
2112
|
logger.warning(
|
|
2062
2113
|
'JSONSchema type is union-like, e.g. ["null", "string", "array"]. '
|
|
@@ -2086,11 +2137,14 @@ class Schema(_common.BaseModel):
|
|
|
2086
2137
|
# Pass 2: the JSONSchema.type is not union-like,
|
|
2087
2138
|
# e.g. 'string', ['string'], ['null', 'string'].
|
|
2088
2139
|
for field_name, field_value in json_schema_dict.items():
|
|
2089
|
-
if field_value is None:
|
|
2140
|
+
if field_value is None or field_name == 'defs':
|
|
2090
2141
|
continue
|
|
2091
2142
|
if field_name in schema_field_names:
|
|
2143
|
+
if field_name == 'items' and not field_value:
|
|
2144
|
+
continue
|
|
2092
2145
|
schema_field_value: 'Schema' = convert_json_schema(
|
|
2093
|
-
|
|
2146
|
+
current_json_schema=JSONSchema(**field_value),
|
|
2147
|
+
root_json_schema_dict=root_json_schema_dict,
|
|
2094
2148
|
api_option=api_option,
|
|
2095
2149
|
raise_error_on_unsupported_field=raise_error_on_unsupported_field,
|
|
2096
2150
|
)
|
|
@@ -2098,17 +2152,21 @@ class Schema(_common.BaseModel):
|
|
|
2098
2152
|
elif field_name in list_schema_field_names:
|
|
2099
2153
|
list_schema_field_value: list['Schema'] = [
|
|
2100
2154
|
convert_json_schema(
|
|
2101
|
-
|
|
2155
|
+
current_json_schema=JSONSchema(**this_field_value),
|
|
2156
|
+
root_json_schema_dict=root_json_schema_dict,
|
|
2102
2157
|
api_option=api_option,
|
|
2103
2158
|
raise_error_on_unsupported_field=raise_error_on_unsupported_field,
|
|
2104
2159
|
)
|
|
2105
2160
|
for this_field_value in field_value
|
|
2106
2161
|
]
|
|
2107
2162
|
setattr(schema, field_name, list_schema_field_value)
|
|
2163
|
+
if not schema.type and not is_union_like_type:
|
|
2164
|
+
schema.type = Type('OBJECT')
|
|
2108
2165
|
elif field_name in dict_schema_field_names:
|
|
2109
2166
|
dict_schema_field_value: dict[str, 'Schema'] = {
|
|
2110
2167
|
key: convert_json_schema(
|
|
2111
|
-
|
|
2168
|
+
current_json_schema=JSONSchema(**value),
|
|
2169
|
+
root_json_schema_dict=root_json_schema_dict,
|
|
2112
2170
|
api_option=api_option,
|
|
2113
2171
|
raise_error_on_unsupported_field=raise_error_on_unsupported_field,
|
|
2114
2172
|
)
|
|
@@ -2116,20 +2174,52 @@ class Schema(_common.BaseModel):
|
|
|
2116
2174
|
}
|
|
2117
2175
|
setattr(schema, field_name, dict_schema_field_value)
|
|
2118
2176
|
elif field_name == 'type':
|
|
2119
|
-
# non_null_types can only be empty or have one element.
|
|
2120
|
-
# because already handled union-like case above.
|
|
2121
2177
|
non_null_types, nullable = normalize_json_schema_type(field_value)
|
|
2122
2178
|
if nullable:
|
|
2123
2179
|
schema.nullable = True
|
|
2124
2180
|
if non_null_types:
|
|
2125
2181
|
schema.type = Type(non_null_types[0])
|
|
2126
2182
|
else:
|
|
2127
|
-
|
|
2183
|
+
if (
|
|
2184
|
+
hasattr(schema, field_name)
|
|
2185
|
+
and field_name != 'additional_properties'
|
|
2186
|
+
):
|
|
2187
|
+
setattr(schema, field_name, field_value)
|
|
2188
|
+
|
|
2189
|
+
if (
|
|
2190
|
+
schema.type == 'ARRAY'
|
|
2191
|
+
and schema.items
|
|
2192
|
+
and not schema.items.model_dump(exclude_unset=True)
|
|
2193
|
+
):
|
|
2194
|
+
schema.items = None
|
|
2195
|
+
|
|
2196
|
+
if schema.any_of and len(schema.any_of) == 2:
|
|
2197
|
+
nullable_part = None
|
|
2198
|
+
type_part = None
|
|
2199
|
+
for part in schema.any_of:
|
|
2200
|
+
# A schema representing `None` will either be of type NULL or just be nullable.
|
|
2201
|
+
part_dict = part.model_dump(exclude_unset=True)
|
|
2202
|
+
if part_dict == {'nullable': True} or part_dict == {'type': 'NULL'}:
|
|
2203
|
+
nullable_part = part
|
|
2204
|
+
else:
|
|
2205
|
+
type_part = part
|
|
2206
|
+
|
|
2207
|
+
# If we found both parts, unwrap them into a single schema.
|
|
2208
|
+
if nullable_part and type_part:
|
|
2209
|
+
default_value = schema.default
|
|
2210
|
+
schema = type_part
|
|
2211
|
+
schema.nullable = True
|
|
2212
|
+
# Carry the default value over to the unwrapped schema
|
|
2213
|
+
if default_value is not None:
|
|
2214
|
+
schema.default = default_value
|
|
2128
2215
|
|
|
2129
2216
|
return schema
|
|
2130
2217
|
|
|
2218
|
+
# This is the initial call to the recursive function.
|
|
2219
|
+
root_schema_dict = json_schema.model_dump()
|
|
2131
2220
|
return convert_json_schema(
|
|
2132
|
-
|
|
2221
|
+
current_json_schema=json_schema,
|
|
2222
|
+
root_json_schema_dict=root_schema_dict,
|
|
2133
2223
|
api_option=api_option,
|
|
2134
2224
|
raise_error_on_unsupported_field=raise_error_on_unsupported_field,
|
|
2135
2225
|
)
|
|
@@ -2371,7 +2461,32 @@ class FunctionDeclaration(_common.BaseModel):
|
|
|
2371
2461
|
json_schema_dict = _automatic_function_calling_util._add_unevaluated_items_to_fixed_len_tuple_schema(
|
|
2372
2462
|
json_schema_dict
|
|
2373
2463
|
)
|
|
2374
|
-
|
|
2464
|
+
if 'prefixItems' in json_schema_dict:
|
|
2465
|
+
parameters_json_schema[name] = json_schema_dict
|
|
2466
|
+
continue
|
|
2467
|
+
|
|
2468
|
+
union_args = typing.get_args(param.annotation)
|
|
2469
|
+
has_primitive = any(
|
|
2470
|
+
_automatic_function_calling_util._is_builtin_primitive_or_compound(
|
|
2471
|
+
arg
|
|
2472
|
+
)
|
|
2473
|
+
for arg in union_args
|
|
2474
|
+
)
|
|
2475
|
+
if (
|
|
2476
|
+
'$ref' in json_schema_dict or '$defs' in json_schema_dict
|
|
2477
|
+
) and has_primitive:
|
|
2478
|
+
# This is a complex schema with a primitive (e.g., str | MyModel)
|
|
2479
|
+
# that is better represented by raw JSON schema.
|
|
2480
|
+
parameters_json_schema[name] = json_schema_dict
|
|
2481
|
+
continue
|
|
2482
|
+
|
|
2483
|
+
schema = Schema.from_json_schema(
|
|
2484
|
+
json_schema=JSONSchema(**json_schema_dict),
|
|
2485
|
+
api_option=api_option,
|
|
2486
|
+
)
|
|
2487
|
+
if param.default is not inspect.Parameter.empty:
|
|
2488
|
+
schema.default = param.default
|
|
2489
|
+
parameters_properties[name] = schema
|
|
2375
2490
|
except Exception as e:
|
|
2376
2491
|
_automatic_function_calling_util._raise_for_unsupported_param(
|
|
2377
2492
|
param, callable.__name__, e
|
google/genai/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: google-genai
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.45.0
|
|
4
4
|
Summary: GenAI Python SDK
|
|
5
5
|
Author-email: Google LLC <googleapis-packages@google.com>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -15,6 +15,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
19
|
Classifier: Topic :: Internet
|
|
19
20
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
21
|
Requires-Python: >=3.9
|
|
@@ -279,6 +280,25 @@ http_options = types.HttpOptions(
|
|
|
279
280
|
client=Client(..., http_options=http_options)
|
|
280
281
|
```
|
|
281
282
|
|
|
283
|
+
### Custom base url
|
|
284
|
+
|
|
285
|
+
In some cases you might need a custom base url (for example, API gateway proxy
|
|
286
|
+
server) and bypass some authentication checks for project, location, or API key.
|
|
287
|
+
You may pass the custom base url like this:
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
|
|
291
|
+
base_url = 'https://test-api-gateway-proxy.com'
|
|
292
|
+
client = Client(
|
|
293
|
+
vertexai=True,
|
|
294
|
+
http_options={
|
|
295
|
+
'base_url': base_url,
|
|
296
|
+
'headers': {'Authorization': 'Bearer test_token'},
|
|
297
|
+
},
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
```
|
|
301
|
+
|
|
282
302
|
## Types
|
|
283
303
|
|
|
284
304
|
Parameter types can be specified as either dictionaries(`TypedDict`) or
|
|
@@ -1,39 +1,39 @@
|
|
|
1
1
|
google/genai/__init__.py,sha256=SKz_9WQKA3R4OpJIDJlgssVfizLNDG2tuWtOD9pxrPE,729
|
|
2
2
|
google/genai/_adapters.py,sha256=Kok38miNYJff2n--l0zEK_hbq0y2rWOH7k75J7SMYbQ,1744
|
|
3
|
-
google/genai/_api_client.py,sha256=
|
|
3
|
+
google/genai/_api_client.py,sha256=3rR0I0naOvkeSFlmSK7WCn56z29hHuR71-i6ryqs1Bc,62734
|
|
4
4
|
google/genai/_api_module.py,sha256=lj8eUWx8_LBGBz-49qz6_ywWm3GYp3d8Bg5JoOHbtbI,902
|
|
5
5
|
google/genai/_automatic_function_calling_util.py,sha256=xXNkJR-pzSMkeSXMz3Jw-kMHFbTJEiRJ3wocuwtWW4I,11627
|
|
6
6
|
google/genai/_base_transformers.py,sha256=wljA6m4tLl4XLGlBC2DNOls5N9-X9tffBq0M7i8jgpw,1034
|
|
7
7
|
google/genai/_base_url.py,sha256=E5H4dew14Y16qfnB3XRnjSCi19cJVlkaMNoM_8ip-PM,1597
|
|
8
|
-
google/genai/_common.py,sha256=
|
|
8
|
+
google/genai/_common.py,sha256=6_psdFl0iBRwgyIKOuGtugpTCHPGB2zZzsJCVcI_2oI,24114
|
|
9
9
|
google/genai/_extra_utils.py,sha256=YLw64xzAKD_fQJp327-GGZM3kQ0sVdhNXMeDaaNkVFE,23011
|
|
10
10
|
google/genai/_live_converters.py,sha256=jhGi2U7G8XC27qE-9LY6B-jc5mAHK1vS_Nx9_-jBNF0,42115
|
|
11
11
|
google/genai/_local_tokenizer_loader.py,sha256=cGN1F0f7hNjRIGCGTLeox7IGAZf_YcvZjSp2rCyhUak,7465
|
|
12
12
|
google/genai/_mcp_utils.py,sha256=HuWJ8FUjquv40Mf_QjcL5r5yXWrS-JjINsjlOSbbyAc,3870
|
|
13
|
-
google/genai/_operations_converters.py,sha256=
|
|
14
|
-
google/genai/_replay_api_client.py,sha256=
|
|
13
|
+
google/genai/_operations_converters.py,sha256=8w4WSeA_KSyc56JcL1MTknZHIds0gF3E8YdriluUJfY,8708
|
|
14
|
+
google/genai/_replay_api_client.py,sha256=oCPZULWpmjahOn5pvY7KkCB_cksNwm7pc4nuTnqqqV8,22956
|
|
15
15
|
google/genai/_test_api_client.py,sha256=4ruFIy5_1qcbKqqIBu3HSQbpSOBrxiecBtDZaTGFR1s,4797
|
|
16
16
|
google/genai/_tokens_converters.py,sha256=xQY6yWtt7iJtfygfmd29d9mjjGKOpy0xG3yTdlr7APk,14137
|
|
17
|
-
google/genai/_transformers.py,sha256=
|
|
17
|
+
google/genai/_transformers.py,sha256=tx6FecRkfQbEmmgXZrb8ndIRacAfluKIFlyQilslWG0,42782
|
|
18
18
|
google/genai/batches.py,sha256=wWkpsY7-a_jxkpkAu6PlbJ2VKRS7j8vy_a-BRPI-BZY,74986
|
|
19
19
|
google/genai/caches.py,sha256=uQLFO0JuzBGm1Gv92v2Dqp_QQ4qoPTX1vqI1grHyfKU,44788
|
|
20
20
|
google/genai/chats.py,sha256=pIBw8d13llupLn4a7vP6vnpbzDcvCCrZZ-Q2r8Cvo7g,16652
|
|
21
21
|
google/genai/client.py,sha256=bwKV5gHKpxzmfFTtoudQ_hEz5QfUzKYMJHYT-AnQfNU,13066
|
|
22
22
|
google/genai/errors.py,sha256=dLH0Bo8-Y0K7zKASU5O0y_0FSKpSFJn8JPcnwIUvtIM,6089
|
|
23
23
|
google/genai/files.py,sha256=2TkcZo7iviHA48OEjc9YnyirZ-umBUN7Z4Gdr4nHyJI,31551
|
|
24
|
-
google/genai/live.py,sha256=
|
|
24
|
+
google/genai/live.py,sha256=1YfDR2VTqeHp2YJkgX2j1KHDaLcGCLN4Y6O9T4cM-4U,40996
|
|
25
25
|
google/genai/live_music.py,sha256=Y7I7jh5SAKgyjBIMLboH0oTnZJ18uOT2SpRDKURvp94,6783
|
|
26
26
|
google/genai/local_tokenizer.py,sha256=EKZ72cV2Zfutlo_efMOPnLRNZN4WQe57rD3G80cF340,14109
|
|
27
|
-
google/genai/models.py,sha256=
|
|
27
|
+
google/genai/models.py,sha256=TDLTUqTaUPxsm7NBACd_T9M9fo7vkjvpsskO0zNkMzQ,226022
|
|
28
28
|
google/genai/operations.py,sha256=KgM5vsagUnAMGk9wKxuQYBUh_6bwrPQ9BzZvydiumQA,16208
|
|
29
29
|
google/genai/pagers.py,sha256=m0SfWWn1EJs2k1On3DZx371qb8g2BRm_188ExsicIRc,7098
|
|
30
30
|
google/genai/py.typed,sha256=RsMFoLwBkAvY05t6izop4UHZtqOPLiKp3GkIEizzmQY,40
|
|
31
31
|
google/genai/tokens.py,sha256=4BPW0gGWFeFVk3INkuY2tfREnsrvzQDhouvRI6_F9Q8,12235
|
|
32
32
|
google/genai/tunings.py,sha256=VmCBW_RR16QbzVpimi7pTEv6XTVeyDGpwqmJqetUj0o,58175
|
|
33
|
-
google/genai/types.py,sha256=
|
|
34
|
-
google/genai/version.py,sha256=
|
|
35
|
-
google_genai-1.
|
|
36
|
-
google_genai-1.
|
|
37
|
-
google_genai-1.
|
|
38
|
-
google_genai-1.
|
|
39
|
-
google_genai-1.
|
|
33
|
+
google/genai/types.py,sha256=dHxmIaGE8kN1QqZU0k_o3ubDpFifyF9hf1AqC4SfUm0,565049
|
|
34
|
+
google/genai/version.py,sha256=5PMgawnATApGV9ARgdK3dp0AjM505-kzZ7a_U4_QYWU,627
|
|
35
|
+
google_genai-1.45.0.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
|
36
|
+
google_genai-1.45.0.dist-info/METADATA,sha256=BuK4IlwvidL2zzmghBQwy950jDKW8NYl-z3p7qKMrCY,45766
|
|
37
|
+
google_genai-1.45.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
38
|
+
google_genai-1.45.0.dist-info/top_level.txt,sha256=_1QvSJIhFAGfxb79D6DhB7SUw2X6T4rwnz_LLrbcD3c,7
|
|
39
|
+
google_genai-1.45.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|