google-genai 1.11.0__py3-none-any.whl → 1.12.1__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 +25 -41
- google/genai/_automatic_function_calling_util.py +4 -24
- google/genai/_common.py +40 -37
- google/genai/_extra_utils.py +7 -7
- google/genai/_live_converters.py +2487 -0
- google/genai/_replay_api_client.py +32 -26
- google/genai/_transformers.py +46 -81
- google/genai/batches.py +45 -45
- google/genai/caches.py +126 -126
- google/genai/chats.py +13 -9
- google/genai/client.py +3 -2
- google/genai/errors.py +6 -6
- google/genai/files.py +38 -38
- google/genai/live.py +69 -17
- google/genai/models.py +388 -388
- google/genai/operations.py +33 -33
- google/genai/pagers.py +2 -2
- google/genai/py.typed +1 -0
- google/genai/tunings.py +70 -70
- google/genai/types.py +456 -24
- google/genai/version.py +1 -1
- {google_genai-1.11.0.dist-info → google_genai-1.12.1.dist-info}/METADATA +1 -1
- google_genai-1.12.1.dist-info/RECORD +29 -0
- {google_genai-1.11.0.dist-info → google_genai-1.12.1.dist-info}/WHEEL +1 -1
- google/genai/live_converters.py +0 -1298
- google_genai-1.11.0.dist-info/RECORD +0 -28
- {google_genai-1.11.0.dist-info → google_genai-1.12.1.dist-info}/licenses/LICENSE +0 -0
- {google_genai-1.11.0.dist-info → google_genai-1.12.1.dist-info}/top_level.txt +0 -0
google/genai/files.py
CHANGED
@@ -36,9 +36,9 @@ logger = logging.getLogger('google_genai.files')
|
|
36
36
|
|
37
37
|
def _ListFilesConfig_to_mldev(
|
38
38
|
api_client: BaseApiClient,
|
39
|
-
from_object: Union[dict, object],
|
40
|
-
parent_object: Optional[dict] = None,
|
41
|
-
) -> dict:
|
39
|
+
from_object: Union[dict[str, Any], object],
|
40
|
+
parent_object: Optional[dict[str, Any]] = None,
|
41
|
+
) -> dict[str, Any]:
|
42
42
|
to_object: dict[str, Any] = {}
|
43
43
|
|
44
44
|
if getv(from_object, ['page_size']) is not None:
|
@@ -58,9 +58,9 @@ def _ListFilesConfig_to_mldev(
|
|
58
58
|
|
59
59
|
def _ListFilesParameters_to_mldev(
|
60
60
|
api_client: BaseApiClient,
|
61
|
-
from_object: Union[dict, object],
|
62
|
-
parent_object: Optional[dict] = None,
|
63
|
-
) -> dict:
|
61
|
+
from_object: Union[dict[str, Any], object],
|
62
|
+
parent_object: Optional[dict[str, Any]] = None,
|
63
|
+
) -> dict[str, Any]:
|
64
64
|
to_object: dict[str, Any] = {}
|
65
65
|
if getv(from_object, ['config']) is not None:
|
66
66
|
setv(
|
@@ -76,9 +76,9 @@ def _ListFilesParameters_to_mldev(
|
|
76
76
|
|
77
77
|
def _FileStatus_to_mldev(
|
78
78
|
api_client: BaseApiClient,
|
79
|
-
from_object: Union[dict, object],
|
80
|
-
parent_object: Optional[dict] = None,
|
81
|
-
) -> dict:
|
79
|
+
from_object: Union[dict[str, Any], object],
|
80
|
+
parent_object: Optional[dict[str, Any]] = None,
|
81
|
+
) -> dict[str, Any]:
|
82
82
|
to_object: dict[str, Any] = {}
|
83
83
|
if getv(from_object, ['details']) is not None:
|
84
84
|
setv(to_object, ['details'], getv(from_object, ['details']))
|
@@ -94,9 +94,9 @@ def _FileStatus_to_mldev(
|
|
94
94
|
|
95
95
|
def _File_to_mldev(
|
96
96
|
api_client: BaseApiClient,
|
97
|
-
from_object: Union[dict, object],
|
98
|
-
parent_object: Optional[dict] = None,
|
99
|
-
) -> dict:
|
97
|
+
from_object: Union[dict[str, Any], object],
|
98
|
+
parent_object: Optional[dict[str, Any]] = None,
|
99
|
+
) -> dict[str, Any]:
|
100
100
|
to_object: dict[str, Any] = {}
|
101
101
|
if getv(from_object, ['name']) is not None:
|
102
102
|
setv(to_object, ['name'], getv(from_object, ['name']))
|
@@ -151,9 +151,9 @@ def _File_to_mldev(
|
|
151
151
|
|
152
152
|
def _CreateFileParameters_to_mldev(
|
153
153
|
api_client: BaseApiClient,
|
154
|
-
from_object: Union[dict, object],
|
155
|
-
parent_object: Optional[dict] = None,
|
156
|
-
) -> dict:
|
154
|
+
from_object: Union[dict[str, Any], object],
|
155
|
+
parent_object: Optional[dict[str, Any]] = None,
|
156
|
+
) -> dict[str, Any]:
|
157
157
|
to_object: dict[str, Any] = {}
|
158
158
|
if getv(from_object, ['file']) is not None:
|
159
159
|
setv(
|
@@ -170,9 +170,9 @@ def _CreateFileParameters_to_mldev(
|
|
170
170
|
|
171
171
|
def _GetFileParameters_to_mldev(
|
172
172
|
api_client: BaseApiClient,
|
173
|
-
from_object: Union[dict, object],
|
174
|
-
parent_object: Optional[dict] = None,
|
175
|
-
) -> dict:
|
173
|
+
from_object: Union[dict[str, Any], object],
|
174
|
+
parent_object: Optional[dict[str, Any]] = None,
|
175
|
+
) -> dict[str, Any]:
|
176
176
|
to_object: dict[str, Any] = {}
|
177
177
|
if getv(from_object, ['name']) is not None:
|
178
178
|
setv(
|
@@ -189,9 +189,9 @@ def _GetFileParameters_to_mldev(
|
|
189
189
|
|
190
190
|
def _DeleteFileParameters_to_mldev(
|
191
191
|
api_client: BaseApiClient,
|
192
|
-
from_object: Union[dict, object],
|
193
|
-
parent_object: Optional[dict] = None,
|
194
|
-
) -> dict:
|
192
|
+
from_object: Union[dict[str, Any], object],
|
193
|
+
parent_object: Optional[dict[str, Any]] = None,
|
194
|
+
) -> dict[str, Any]:
|
195
195
|
to_object: dict[str, Any] = {}
|
196
196
|
if getv(from_object, ['name']) is not None:
|
197
197
|
setv(
|
@@ -208,9 +208,9 @@ def _DeleteFileParameters_to_mldev(
|
|
208
208
|
|
209
209
|
def _FileStatus_from_mldev(
|
210
210
|
api_client: BaseApiClient,
|
211
|
-
from_object: Union[dict, object],
|
212
|
-
parent_object: Optional[dict] = None,
|
213
|
-
) -> dict:
|
211
|
+
from_object: Union[dict[str, Any], object],
|
212
|
+
parent_object: Optional[dict[str, Any]] = None,
|
213
|
+
) -> dict[str, Any]:
|
214
214
|
to_object: dict[str, Any] = {}
|
215
215
|
if getv(from_object, ['details']) is not None:
|
216
216
|
setv(to_object, ['details'], getv(from_object, ['details']))
|
@@ -226,9 +226,9 @@ def _FileStatus_from_mldev(
|
|
226
226
|
|
227
227
|
def _File_from_mldev(
|
228
228
|
api_client: BaseApiClient,
|
229
|
-
from_object: Union[dict, object],
|
230
|
-
parent_object: Optional[dict] = None,
|
231
|
-
) -> dict:
|
229
|
+
from_object: Union[dict[str, Any], object],
|
230
|
+
parent_object: Optional[dict[str, Any]] = None,
|
231
|
+
) -> dict[str, Any]:
|
232
232
|
to_object: dict[str, Any] = {}
|
233
233
|
if getv(from_object, ['name']) is not None:
|
234
234
|
setv(to_object, ['name'], getv(from_object, ['name']))
|
@@ -283,9 +283,9 @@ def _File_from_mldev(
|
|
283
283
|
|
284
284
|
def _ListFilesResponse_from_mldev(
|
285
285
|
api_client: BaseApiClient,
|
286
|
-
from_object: Union[dict, object],
|
287
|
-
parent_object: Optional[dict] = None,
|
288
|
-
) -> dict:
|
286
|
+
from_object: Union[dict[str, Any], object],
|
287
|
+
parent_object: Optional[dict[str, Any]] = None,
|
288
|
+
) -> dict[str, Any]:
|
289
289
|
to_object: dict[str, Any] = {}
|
290
290
|
if getv(from_object, ['nextPageToken']) is not None:
|
291
291
|
setv(to_object, ['next_page_token'], getv(from_object, ['nextPageToken']))
|
@@ -305,9 +305,9 @@ def _ListFilesResponse_from_mldev(
|
|
305
305
|
|
306
306
|
def _CreateFileResponse_from_mldev(
|
307
307
|
api_client: BaseApiClient,
|
308
|
-
from_object: Union[dict, object],
|
309
|
-
parent_object: Optional[dict] = None,
|
310
|
-
) -> dict:
|
308
|
+
from_object: Union[dict[str, Any], object],
|
309
|
+
parent_object: Optional[dict[str, Any]] = None,
|
310
|
+
) -> dict[str, Any]:
|
311
311
|
to_object: dict[str, Any] = {}
|
312
312
|
if getv(from_object, ['httpHeaders']) is not None:
|
313
313
|
setv(to_object, ['http_headers'], getv(from_object, ['httpHeaders']))
|
@@ -317,9 +317,9 @@ def _CreateFileResponse_from_mldev(
|
|
317
317
|
|
318
318
|
def _DeleteFileResponse_from_mldev(
|
319
319
|
api_client: BaseApiClient,
|
320
|
-
from_object: Union[dict, object],
|
321
|
-
parent_object: Optional[dict] = None,
|
322
|
-
) -> dict:
|
320
|
+
from_object: Union[dict[str, Any], object],
|
321
|
+
parent_object: Optional[dict[str, Any]] = None,
|
322
|
+
) -> dict[str, Any]:
|
323
323
|
to_object: dict[str, Any] = {}
|
324
324
|
|
325
325
|
return to_object
|
@@ -596,7 +596,7 @@ class Files(_api_module.BaseModule):
|
|
596
596
|
def upload(
|
597
597
|
self,
|
598
598
|
*,
|
599
|
-
file: Union[str, pathlib.Path, os.PathLike, io.IOBase],
|
599
|
+
file: Union[str, pathlib.Path, os.PathLike[str], io.IOBase],
|
600
600
|
config: Optional[types.UploadFileConfigOrDict] = None,
|
601
601
|
) -> types.File:
|
602
602
|
"""Calls the API to upload a file using a supported file service.
|
@@ -1068,7 +1068,7 @@ class AsyncFiles(_api_module.BaseModule):
|
|
1068
1068
|
async def upload(
|
1069
1069
|
self,
|
1070
1070
|
*,
|
1071
|
-
file: Union[str, pathlib.Path, os.PathLike, io.IOBase],
|
1071
|
+
file: Union[str, pathlib.Path, os.PathLike[str], io.IOBase],
|
1072
1072
|
config: Optional[types.UploadFileConfigOrDict] = None,
|
1073
1073
|
) -> types.File:
|
1074
1074
|
"""Calls the API to upload a file asynchronously using a supported file service.
|
google/genai/live.py
CHANGED
@@ -35,14 +35,14 @@ from . import types
|
|
35
35
|
from ._api_client import BaseApiClient
|
36
36
|
from ._common import get_value_by_path as getv
|
37
37
|
from ._common import set_value_by_path as setv
|
38
|
-
from . import live_converters
|
38
|
+
from . import _live_converters as live_converters
|
39
39
|
from .models import _Content_to_mldev
|
40
40
|
from .models import _Content_to_vertex
|
41
41
|
|
42
42
|
|
43
43
|
try:
|
44
|
-
from websockets.asyncio.client import ClientConnection
|
45
|
-
from websockets.asyncio.client import connect
|
44
|
+
from websockets.asyncio.client import ClientConnection
|
45
|
+
from websockets.asyncio.client import connect
|
46
46
|
except ModuleNotFoundError:
|
47
47
|
# This try/except is for TAP, mypy complains about it which is why we have the type: ignore
|
48
48
|
from websockets.client import ClientConnection # type: ignore
|
@@ -60,7 +60,7 @@ class AsyncSession:
|
|
60
60
|
"""[Preview] AsyncSession."""
|
61
61
|
|
62
62
|
def __init__(
|
63
|
-
self, api_client:
|
63
|
+
self, api_client: BaseApiClient, websocket: ClientConnection
|
64
64
|
):
|
65
65
|
self._api_client = api_client
|
66
66
|
self._ws = websocket
|
@@ -80,7 +80,7 @@ class AsyncSession:
|
|
80
80
|
]
|
81
81
|
] = None,
|
82
82
|
end_of_turn: Optional[bool] = False,
|
83
|
-
):
|
83
|
+
) -> None:
|
84
84
|
"""[Deprecated] Send input to the model.
|
85
85
|
|
86
86
|
> **Warning**: This method is deprecated and will be removed in a future
|
@@ -127,7 +127,7 @@ class AsyncSession:
|
|
127
127
|
]
|
128
128
|
] = None,
|
129
129
|
turn_complete: bool = True,
|
130
|
-
):
|
130
|
+
) -> None:
|
131
131
|
"""Send non-realtime, turn based content to the model.
|
132
132
|
|
133
133
|
There are two ways to send messages to the live API:
|
@@ -203,8 +203,18 @@ class AsyncSession:
|
|
203
203
|
|
204
204
|
await self._ws.send(json.dumps({'client_content': client_content_dict}))
|
205
205
|
|
206
|
-
async def send_realtime_input(
|
207
|
-
|
206
|
+
async def send_realtime_input(
|
207
|
+
self,
|
208
|
+
*,
|
209
|
+
media: Optional[types.BlobImageUnionDict] = None,
|
210
|
+
audio: Optional[types.BlobOrDict] = None,
|
211
|
+
audio_stream_end: Optional[bool] = None,
|
212
|
+
video: Optional[types.BlobImageUnionDict] = None,
|
213
|
+
text: Optional[str] = None,
|
214
|
+
activity_start: Optional[types.ActivityStartOrDict] = None,
|
215
|
+
activity_end: Optional[types.ActivityEndOrDict] = None,
|
216
|
+
) -> None:
|
217
|
+
"""Send realtime input to the model, only send one argument per call.
|
208
218
|
|
209
219
|
Use `send_realtime_input` for realtime audio chunks and video
|
210
220
|
frames(images).
|
@@ -227,7 +237,7 @@ class AsyncSession:
|
|
227
237
|
from google.genai import types
|
228
238
|
|
229
239
|
import PIL.Image
|
230
|
-
|
240
|
+
|
231
241
|
import os
|
232
242
|
|
233
243
|
if os.environ.get('GOOGLE_GENAI_USE_VERTEXAI'):
|
@@ -254,9 +264,46 @@ class AsyncSession:
|
|
254
264
|
print(f'{msg.text}')
|
255
265
|
```
|
256
266
|
"""
|
257
|
-
|
258
|
-
|
259
|
-
|
267
|
+
kwargs:dict[str, Any] = {}
|
268
|
+
if media is not None:
|
269
|
+
kwargs['media'] = media
|
270
|
+
if audio is not None:
|
271
|
+
kwargs['audio'] = audio
|
272
|
+
if audio_stream_end is not None:
|
273
|
+
kwargs['audio_stream_end'] = audio_stream_end
|
274
|
+
if video is not None:
|
275
|
+
kwargs['video'] = video
|
276
|
+
if text is not None:
|
277
|
+
kwargs['text'] = text
|
278
|
+
if activity_start is not None:
|
279
|
+
kwargs['activity_start'] = activity_start
|
280
|
+
if activity_end is not None:
|
281
|
+
kwargs['activity_end'] = activity_end
|
282
|
+
|
283
|
+
if len(kwargs) != 1:
|
284
|
+
raise ValueError(
|
285
|
+
f'Only one argument can be set, got {len(kwargs)}:'
|
286
|
+
f' {list(kwargs.keys())}'
|
287
|
+
)
|
288
|
+
realtime_input = types.LiveSendRealtimeInputParameters.model_validate(
|
289
|
+
kwargs
|
290
|
+
)
|
291
|
+
|
292
|
+
if self._api_client.vertexai:
|
293
|
+
realtime_input_dict = (
|
294
|
+
live_converters._LiveSendRealtimeInputParameters_to_vertex(
|
295
|
+
api_client=self._api_client, from_object=realtime_input
|
296
|
+
)
|
297
|
+
)
|
298
|
+
else:
|
299
|
+
realtime_input_dict = (
|
300
|
+
live_converters._LiveSendRealtimeInputParameters_to_mldev(
|
301
|
+
api_client=self._api_client, from_object=realtime_input
|
302
|
+
)
|
303
|
+
)
|
304
|
+
realtime_input_dict = _common.convert_to_dict(realtime_input_dict)
|
305
|
+
realtime_input_dict = _common.encode_unserializable_types(
|
306
|
+
realtime_input_dict
|
260
307
|
)
|
261
308
|
await self._ws.send(json.dumps({'realtime_input': realtime_input_dict}))
|
262
309
|
|
@@ -267,7 +314,7 @@ class AsyncSession:
|
|
267
314
|
types.FunctionResponseOrDict,
|
268
315
|
Sequence[types.FunctionResponseOrDict],
|
269
316
|
],
|
270
|
-
):
|
317
|
+
) -> None:
|
271
318
|
"""Send a tool response to the session.
|
272
319
|
|
273
320
|
Use `send_tool_response` to reply to `LiveServerToolCall` messages
|
@@ -337,6 +384,10 @@ class AsyncSession:
|
|
337
384
|
tool_response_dict = live_converters._LiveClientToolResponse_to_mldev(
|
338
385
|
api_client=self._api_client, from_object=tool_response
|
339
386
|
)
|
387
|
+
for response in tool_response_dict.get('functionResponses', []):
|
388
|
+
if response.get('id') is None:
|
389
|
+
raise ValueError(_FUNCTION_RESPONSE_REQUIRES_ID)
|
390
|
+
|
340
391
|
await self._ws.send(json.dumps({'tool_response': tool_response_dict}))
|
341
392
|
|
342
393
|
async def receive(self) -> AsyncIterator[types.LiveServerMessage]:
|
@@ -468,7 +519,7 @@ class AsyncSession:
|
|
468
519
|
data_stream: AsyncIterator[bytes],
|
469
520
|
mime_type: str,
|
470
521
|
stop_event: asyncio.Event,
|
471
|
-
):
|
522
|
+
) -> None:
|
472
523
|
async for data in data_stream:
|
473
524
|
model_input = types.LiveClientRealtimeInput(
|
474
525
|
media_chunks=[types.Blob(data=data, mime_type=mime_type)]
|
@@ -787,7 +838,6 @@ class AsyncSession:
|
|
787
838
|
await self._ws.close()
|
788
839
|
|
789
840
|
|
790
|
-
|
791
841
|
class AsyncLive(_api_module.BaseModule):
|
792
842
|
"""[Preview] AsyncLive."""
|
793
843
|
|
@@ -815,6 +865,8 @@ class AsyncLive(_api_module.BaseModule):
|
|
815
865
|
print(message)
|
816
866
|
"""
|
817
867
|
base_url = self._api_client._websocket_base_url()
|
868
|
+
if isinstance(base_url, bytes):
|
869
|
+
base_url = base_url.decode('utf-8')
|
818
870
|
transformed_model = t.t_model(self._api_client, model)
|
819
871
|
|
820
872
|
parameter_model = _t_live_connect_config(self._api_client, config)
|
@@ -841,13 +893,13 @@ class AsyncLive(_api_module.BaseModule):
|
|
841
893
|
request = json.dumps(request_dict)
|
842
894
|
else:
|
843
895
|
# Get bearer token through Application Default Credentials.
|
844
|
-
creds, _ = google.auth.default(
|
896
|
+
creds, _ = google.auth.default( # type: ignore[no-untyped-call]
|
845
897
|
scopes=['https://www.googleapis.com/auth/cloud-platform']
|
846
898
|
)
|
847
899
|
|
848
900
|
# creds.valid is False, and creds.token is None
|
849
901
|
# Need to refresh credentials to populate those
|
850
|
-
auth_req = google.auth.transport.requests.Request()
|
902
|
+
auth_req = google.auth.transport.requests.Request() # type: ignore[no-untyped-call]
|
851
903
|
creds.refresh(auth_req)
|
852
904
|
bearer_token = creds.token
|
853
905
|
headers = self._api_client._http_options.headers
|