google-genai 1.12.1__py3-none-any.whl → 1.14.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 +59 -17
- google/genai/_base_url.py +50 -0
- google/genai/_live_converters.py +231 -203
- google/genai/_transformers.py +2 -2
- google/genai/batches.py +2 -2
- google/genai/caches.py +236 -198
- google/genai/chats.py +4 -4
- google/genai/client.py +21 -9
- google/genai/live.py +9 -6
- google/genai/models.py +260 -230
- google/genai/types.py +1380 -1045
- google/genai/version.py +1 -1
- {google_genai-1.12.1.dist-info → google_genai-1.14.0.dist-info}/METADATA +8 -6
- google_genai-1.14.0.dist-info/RECORD +30 -0
- {google_genai-1.12.1.dist-info → google_genai-1.14.0.dist-info}/WHEEL +1 -1
- google_genai-1.12.1.dist-info/RECORD +0 -29
- {google_genai-1.12.1.dist-info → google_genai-1.14.0.dist-info}/licenses/LICENSE +0 -0
- {google_genai-1.12.1.dist-info → google_genai-1.14.0.dist-info}/top_level.txt +0 -0
google/genai/_api_client.py
CHANGED
@@ -58,7 +58,9 @@ from .types import HttpOptionsOrDict
|
|
58
58
|
|
59
59
|
logger = logging.getLogger('google_genai._api_client')
|
60
60
|
CHUNK_SIZE = 8 * 1024 * 1024 # 8 MB chunk size
|
61
|
-
|
61
|
+
MAX_RETRY_COUNT = 3
|
62
|
+
INITIAL_RETRY_DELAY = 1 # second
|
63
|
+
DELAY_MULTIPLIER = 2
|
62
64
|
|
63
65
|
def _append_library_version_headers(headers: dict[str, str]) -> None:
|
64
66
|
"""Appends the telemetry header to the headers dict."""
|
@@ -283,6 +285,18 @@ class SyncHttpxClient(httpx.Client):
|
|
283
285
|
kwargs.setdefault('follow_redirects', True)
|
284
286
|
super().__init__(**kwargs)
|
285
287
|
|
288
|
+
def __del__(self) -> None:
|
289
|
+
"""Closes the httpx client."""
|
290
|
+
try:
|
291
|
+
if self.is_closed:
|
292
|
+
return
|
293
|
+
except Exception:
|
294
|
+
pass
|
295
|
+
try:
|
296
|
+
self.close()
|
297
|
+
except Exception:
|
298
|
+
pass
|
299
|
+
|
286
300
|
|
287
301
|
class AsyncHttpxClient(httpx.AsyncClient):
|
288
302
|
"""Async httpx client."""
|
@@ -292,6 +306,17 @@ class AsyncHttpxClient(httpx.AsyncClient):
|
|
292
306
|
kwargs.setdefault('follow_redirects', True)
|
293
307
|
super().__init__(**kwargs)
|
294
308
|
|
309
|
+
def __del__(self) -> None:
|
310
|
+
try:
|
311
|
+
if self.is_closed:
|
312
|
+
return
|
313
|
+
except Exception:
|
314
|
+
pass
|
315
|
+
try:
|
316
|
+
asyncio.get_running_loop().create_task(self.aclose())
|
317
|
+
except Exception:
|
318
|
+
pass
|
319
|
+
|
295
320
|
|
296
321
|
class BaseApiClient:
|
297
322
|
"""Client for calling HTTP APIs sending and receiving JSON."""
|
@@ -865,15 +890,23 @@ class BaseApiClient:
|
|
865
890
|
'Content-Length': str(chunk_size),
|
866
891
|
}
|
867
892
|
_populate_server_timeout_header(upload_headers, timeout_in_seconds)
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
893
|
+
retry_count = 0
|
894
|
+
while retry_count < MAX_RETRY_COUNT:
|
895
|
+
response = self._httpx_client.request(
|
896
|
+
method='POST',
|
897
|
+
url=upload_url,
|
898
|
+
headers=upload_headers,
|
899
|
+
content=file_chunk,
|
900
|
+
timeout=timeout_in_seconds,
|
901
|
+
)
|
902
|
+
if response.headers.get('x-goog-upload-status'):
|
903
|
+
break
|
904
|
+
delay_seconds = INITIAL_RETRY_DELAY * (DELAY_MULTIPLIER**retry_count)
|
905
|
+
retry_count += 1
|
906
|
+
time.sleep(delay_seconds)
|
907
|
+
|
875
908
|
offset += chunk_size
|
876
|
-
if response.headers
|
909
|
+
if response.headers.get('x-goog-upload-status') != 'active':
|
877
910
|
break # upload is complete or it has been interrupted.
|
878
911
|
if upload_size <= offset: # Status is not finalized.
|
879
912
|
raise ValueError(
|
@@ -881,7 +914,7 @@ class BaseApiClient:
|
|
881
914
|
f' finalized.'
|
882
915
|
)
|
883
916
|
|
884
|
-
if response.headers
|
917
|
+
if response.headers.get('x-goog-upload-status') != 'final':
|
885
918
|
raise ValueError(
|
886
919
|
'Failed to upload file: Upload status is not finalized.'
|
887
920
|
)
|
@@ -1013,13 +1046,22 @@ class BaseApiClient:
|
|
1013
1046
|
'Content-Length': str(chunk_size),
|
1014
1047
|
}
|
1015
1048
|
_populate_server_timeout_header(upload_headers, timeout_in_seconds)
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1049
|
+
|
1050
|
+
retry_count = 0
|
1051
|
+
while retry_count < MAX_RETRY_COUNT:
|
1052
|
+
response = await self._async_httpx_client.request(
|
1053
|
+
method='POST',
|
1054
|
+
url=upload_url,
|
1055
|
+
content=file_chunk,
|
1056
|
+
headers=upload_headers,
|
1057
|
+
timeout=timeout_in_seconds,
|
1058
|
+
)
|
1059
|
+
if response.headers.get('x-goog-upload-status'):
|
1060
|
+
break
|
1061
|
+
delay_seconds = INITIAL_RETRY_DELAY * (DELAY_MULTIPLIER**retry_count)
|
1062
|
+
retry_count += 1
|
1063
|
+
time.sleep(delay_seconds)
|
1064
|
+
|
1023
1065
|
offset += chunk_size
|
1024
1066
|
if response.headers.get('x-goog-upload-status') != 'active':
|
1025
1067
|
break # upload is complete or it has been interrupted.
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Copyright 2025 Google LLC
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
#
|
15
|
+
|
16
|
+
import os
|
17
|
+
from typing import Optional
|
18
|
+
|
19
|
+
from .types import HttpOptions
|
20
|
+
|
21
|
+
_default_base_gemini_url = None
|
22
|
+
_default_base_vertex_url = None
|
23
|
+
|
24
|
+
|
25
|
+
def set_default_base_urls(
|
26
|
+
gemini_url: Optional[str], vertex_url: Optional[str]
|
27
|
+
) -> None:
|
28
|
+
"""Overrides the base URLs for the Gemini API and Vertex AI API."""
|
29
|
+
global _default_base_gemini_url, _default_base_vertex_url
|
30
|
+
_default_base_gemini_url = gemini_url
|
31
|
+
_default_base_vertex_url = vertex_url
|
32
|
+
|
33
|
+
|
34
|
+
def get_base_url(
|
35
|
+
vertexai: bool,
|
36
|
+
http_options: Optional[HttpOptions] = None,
|
37
|
+
) -> Optional[str]:
|
38
|
+
"""Returns the default base URL based on the following priority.
|
39
|
+
|
40
|
+
1. Base URLs set via HttpOptions.
|
41
|
+
2. Base URLs set via the latest call to setDefaultBaseUrls.
|
42
|
+
3. Base URLs set via environment variables.
|
43
|
+
"""
|
44
|
+
if http_options and http_options.base_url:
|
45
|
+
return http_options.base_url
|
46
|
+
|
47
|
+
if vertexai:
|
48
|
+
return _default_base_vertex_url or os.getenv('GOOGLE_VERTEX_BASE_URL')
|
49
|
+
else:
|
50
|
+
return _default_base_gemini_url or os.getenv('GOOGLE_GEMINI_BASE_URL')
|