google-genai 1.9.0__py3-none-any.whl → 1.11.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/live.py CHANGED
@@ -13,14 +13,14 @@
13
13
  # limitations under the License.
14
14
  #
15
15
 
16
- """Live client. The live module is experimental."""
16
+ """[Preview] Live API client."""
17
17
 
18
18
  import asyncio
19
19
  import base64
20
20
  import contextlib
21
21
  import json
22
22
  import logging
23
- from typing import Any, AsyncIterator, Dict, Optional, Sequence, Union, get_args
23
+ from typing import Any, AsyncIterator, Dict, Optional, Sequence, Union, cast, get_args
24
24
  import warnings
25
25
 
26
26
  import google.auth
@@ -33,21 +33,12 @@ from . import _transformers as t
33
33
  from . import client
34
34
  from . import types
35
35
  from ._api_client import BaseApiClient
36
- from ._common import experimental_warning
37
36
  from ._common import get_value_by_path as getv
38
37
  from ._common import set_value_by_path as setv
39
- from .models import _Content_from_mldev
40
- from .models import _Content_from_vertex
38
+ from . import live_converters
41
39
  from .models import _Content_to_mldev
42
40
  from .models import _Content_to_vertex
43
- from .models import _GenerateContentConfig_to_mldev
44
- from .models import _GenerateContentConfig_to_vertex
45
- from .models import _SafetySetting_to_mldev
46
- from .models import _SafetySetting_to_vertex
47
- from .models import _SpeechConfig_to_mldev
48
- from .models import _SpeechConfig_to_vertex
49
- from .models import _Tool_to_mldev
50
- from .models import _Tool_to_vertex
41
+
51
42
 
52
43
  try:
53
44
  from websockets.asyncio.client import ClientConnection # type: ignore
@@ -65,61 +56,8 @@ _FUNCTION_RESPONSE_REQUIRES_ID = (
65
56
  )
66
57
 
67
58
 
68
- def _ClientContent_to_mldev(
69
- api_client: BaseApiClient,
70
- from_object: types.LiveClientContent,
71
- ) -> dict:
72
- client_content = from_object.model_dump(exclude_none=True, mode='json')
73
- if 'turns' in client_content:
74
- client_content['turns'] = [
75
- _Content_to_mldev(api_client=api_client, from_object=item)
76
- for item in client_content['turns']
77
- ]
78
- return client_content
79
-
80
-
81
- def _ClientContent_to_vertex(
82
- api_client: BaseApiClient,
83
- from_object: types.LiveClientContent,
84
- ) -> dict:
85
- client_content = from_object.model_dump(exclude_none=True, mode='json')
86
- if 'turns' in client_content:
87
- client_content['turns'] = [
88
- _Content_to_vertex(api_client=api_client, from_object=item)
89
- for item in client_content['turns']
90
- ]
91
- return client_content
92
-
93
-
94
- def _ToolResponse_to_mldev(
95
- api_client: BaseApiClient,
96
- from_object: types.LiveClientToolResponse,
97
- ) -> dict:
98
- tool_response = from_object.model_dump(exclude_none=True, mode='json')
99
- for response in tool_response.get('function_responses', []):
100
- if response.get('id') is None:
101
- raise ValueError(_FUNCTION_RESPONSE_REQUIRES_ID)
102
- return tool_response
103
-
104
-
105
- def _ToolResponse_to_vertex(
106
- api_client: BaseApiClient,
107
- from_object: types.LiveClientToolResponse,
108
- ) -> dict:
109
- tool_response = from_object.model_dump(exclude_none=True, mode='json')
110
- return tool_response
111
-
112
-
113
- def _AudioTranscriptionConfig_to_vertex(
114
- api_client: BaseApiClient,
115
- from_object: types.AudioTranscriptionConfig,
116
- ) -> dict:
117
- audio_transcription: dict[str, Any] = {}
118
- return audio_transcription
119
-
120
-
121
59
  class AsyncSession:
122
- """AsyncSession. The live module is experimental."""
60
+ """[Preview] AsyncSession."""
123
61
 
124
62
  def __init__(
125
63
  self, api_client: client.BaseApiClient, websocket: ClientConnection
@@ -143,7 +81,12 @@ class AsyncSession:
143
81
  ] = None,
144
82
  end_of_turn: Optional[bool] = False,
145
83
  ):
146
- """Send input to the model.
84
+ """[Deprecated] Send input to the model.
85
+
86
+ > **Warning**: This method is deprecated and will be removed in a future
87
+ version (not before Q3 2025). Please use one of the more specific methods:
88
+ `send_client_content`, `send_realtime_input`, or `send_tool_response`
89
+ instead.
147
90
 
148
91
  The method will send the input request to the server.
149
92
 
@@ -162,6 +105,14 @@ class AsyncSession:
162
105
  async for message in session.receive():
163
106
  print(message)
164
107
  """
108
+ warnings.warn(
109
+ 'The `session.send` method is deprecated and will be removed in a '
110
+ 'future version (not before Q3 2025).\n'
111
+ 'Please use one of the more specific methods: `send_client_content`, '
112
+ '`send_realtime_input`, or `send_tool_response` instead.',
113
+ DeprecationWarning,
114
+ stacklevel=2,
115
+ )
165
116
  client_message = self._parse_client_message(input, end_of_turn)
166
117
  await self._ws.send(json.dumps(client_message))
167
118
 
@@ -218,8 +169,14 @@ class AsyncSession:
218
169
  ```
219
170
  import google.genai
220
171
  from google.genai import types
172
+ import os
173
+
174
+ if os.environ.get('GOOGLE_GENAI_USE_VERTEXAI'):
175
+ MODEL_NAME = 'gemini-2.0-flash-live-preview-04-09'
176
+ else:
177
+ MODEL_NAME = 'gemini-2.0-flash-live-001';
221
178
 
222
- client = genai.Client(http_options={'api_version': 'v1alpha'})
179
+ client = genai.Client()
223
180
  async with client.aio.live.connect(
224
181
  model=MODEL_NAME,
225
182
  config={"response_modalities": ["TEXT"]}
@@ -233,14 +190,14 @@ class AsyncSession:
233
190
  print(msg.text)
234
191
  ```
235
192
  """
236
- client_content = _t_client_content(turns, turn_complete)
193
+ client_content = t.t_client_content(turns, turn_complete)
237
194
 
238
195
  if self._api_client.vertexai:
239
- client_content_dict = _ClientContent_to_vertex(
196
+ client_content_dict = live_converters._LiveClientContent_to_vertex(
240
197
  api_client=self._api_client, from_object=client_content
241
198
  )
242
199
  else:
243
- client_content_dict = _ClientContent_to_mldev(
200
+ client_content_dict = live_converters._LiveClientContent_to_mldev(
244
201
  api_client=self._api_client, from_object=client_content
245
202
  )
246
203
 
@@ -270,8 +227,16 @@ class AsyncSession:
270
227
  from google.genai import types
271
228
 
272
229
  import PIL.Image
230
+
231
+ import os
273
232
 
274
- client = genai.Client(http_options= {'api_version': 'v1alpha'})
233
+ if os.environ.get('GOOGLE_GENAI_USE_VERTEXAI'):
234
+ MODEL_NAME = 'gemini-2.0-flash-live-preview-04-09'
235
+ else:
236
+ MODEL_NAME = 'gemini-2.0-flash-live-001';
237
+
238
+
239
+ client = genai.Client()
275
240
 
276
241
  async with client.aio.live.connect(
277
242
  model=MODEL_NAME,
@@ -289,7 +254,7 @@ class AsyncSession:
289
254
  print(f'{msg.text}')
290
255
  ```
291
256
  """
292
- realtime_input = _t_realtime_input(media)
257
+ realtime_input = t.t_realtime_input(media)
293
258
  realtime_input_dict = realtime_input.model_dump(
294
259
  exclude_none=True, mode='json'
295
260
  )
@@ -320,7 +285,14 @@ class AsyncSession:
320
285
  from google import genai
321
286
  from google.genai import types
322
287
 
323
- client = genai.Client(http_options={'api_version': 'v1alpha'})
288
+ import os
289
+
290
+ if os.environ.get('GOOGLE_GENAI_USE_VERTEXAI'):
291
+ MODEL_NAME = 'gemini-2.0-flash-live-preview-04-09'
292
+ else:
293
+ MODEL_NAME = 'gemini-2.0-flash-live-001';
294
+
295
+ client = genai.Client()
324
296
 
325
297
  tools = [{'function_declarations': [{'name': 'turn_on_the_lights'}]}]
326
298
  config = {
@@ -329,13 +301,13 @@ class AsyncSession:
329
301
  }
330
302
 
331
303
  async with client.aio.live.connect(
332
- model='gemini-2.0-flash-exp',
304
+ model='models/gemini-2.0-flash-live-001',
333
305
  config=config
334
306
  ) as session:
335
307
  prompt = "Turn on the lights please"
336
308
  await session.send_client_content(
337
- turns=prompt,
338
- turn_complete=True)
309
+ turns={"parts": [{'text': prompt}]}
310
+ )
339
311
 
340
312
  async for chunk in session.receive():
341
313
  if chunk.server_content:
@@ -356,13 +328,13 @@ class AsyncSession:
356
328
 
357
329
  print('_'*80)
358
330
  """
359
- tool_response = _t_tool_response(function_responses)
331
+ tool_response = t.t_tool_response(function_responses)
360
332
  if self._api_client.vertexai:
361
- tool_response_dict = _ToolResponse_to_vertex(
333
+ tool_response_dict = live_converters._LiveClientToolResponse_to_vertex(
362
334
  api_client=self._api_client, from_object=tool_response
363
335
  )
364
336
  else:
365
- tool_response_dict = _ToolResponse_to_mldev(
337
+ tool_response_dict = live_converters._LiveClientToolResponse_to_mldev(
366
338
  api_client=self._api_client, from_object=tool_response
367
339
  )
368
340
  await self._ws.send(json.dumps({'tool_response': tool_response_dict}))
@@ -375,8 +347,6 @@ class AsyncSession:
375
347
  is function call, user must call `send` with the function response to
376
348
  continue the turn.
377
349
 
378
- The live module is experimental.
379
-
380
350
  Yields:
381
351
  The model responses from the server.
382
352
 
@@ -401,15 +371,18 @@ class AsyncSession:
401
371
  async def start_stream(
402
372
  self, *, stream: AsyncIterator[bytes], mime_type: str
403
373
  ) -> AsyncIterator[types.LiveServerMessage]:
404
- """start a live session from a data stream.
374
+ """[Deprecated] Start a live session from a data stream.
375
+
376
+ > **Warning**: This method is deprecated and will be removed in a future
377
+ version (not before Q2 2025). Please use one of the more specific methods:
378
+ `send_client_content`, `send_realtime_input`, or `send_tool_response`
379
+ instead.
405
380
 
406
381
  The interaction terminates when the input stream is complete.
407
382
  This method will start two async tasks. One task will be used to send the
408
383
  input stream to the model and the other task will be used to receive the
409
384
  responses from the model.
410
385
 
411
- The live module is experimental.
412
-
413
386
  Args:
414
387
  stream: An iterator that yields the model response.
415
388
  mime_type: The MIME type of the data in the stream.
@@ -432,6 +405,13 @@ class AsyncSession:
432
405
  mime_type = 'audio/pcm'):
433
406
  play_audio_chunk(audio.data)
434
407
  """
408
+ warnings.warn(
409
+ 'Setting `AsyncSession.start_stream` is deprecated, '
410
+ 'and will be removed in a future release (not before Q3 2025). '
411
+ 'Please use the `receive`, and `send_realtime_input`, methods instead.',
412
+ DeprecationWarning,
413
+ stacklevel=4,
414
+ )
435
415
  stop_event = asyncio.Event()
436
416
  # Start the send loop. When stream is complete stop_event is set.
437
417
  asyncio.create_task(self._send_loop(stream, mime_type, stop_event))
@@ -465,7 +445,7 @@ class AsyncSession:
465
445
  try:
466
446
  raw_response = await self._ws.recv(decode=False)
467
447
  except TypeError:
468
- raw_response = await self._ws.recv()
448
+ raw_response = await self._ws.recv() # type: ignore[assignment]
469
449
  if raw_response:
470
450
  try:
471
451
  response = json.loads(raw_response)
@@ -473,10 +453,11 @@ class AsyncSession:
473
453
  raise ValueError(f'Failed to parse response: {raw_response!r}')
474
454
  else:
475
455
  response = {}
456
+
476
457
  if self._api_client.vertexai:
477
- response_dict = self._LiveServerMessage_from_vertex(response)
458
+ response_dict = live_converters._LiveServerMessage_from_vertex(self._api_client, response)
478
459
  else:
479
- response_dict = self._LiveServerMessage_from_mldev(response)
460
+ response_dict = live_converters._LiveServerMessage_from_mldev(self._api_client, response)
480
461
 
481
462
  return types.LiveServerMessage._from_response(
482
463
  response=response_dict, kwargs=parameter_model.model_dump()
@@ -498,152 +479,6 @@ class AsyncSession:
498
479
  # Give a chance for the receiver to process the last response.
499
480
  stop_event.set()
500
481
 
501
- def _LiveServerContent_from_mldev(
502
- self,
503
- from_object: Union[dict, object],
504
- ) -> Dict[str, Any]:
505
- to_object: dict[str, Any] = {}
506
- if getv(from_object, ['modelTurn']) is not None:
507
- setv(
508
- to_object,
509
- ['model_turn'],
510
- _Content_from_mldev(
511
- self._api_client,
512
- getv(from_object, ['modelTurn']),
513
- ),
514
- )
515
- if getv(from_object, ['turnComplete']) is not None:
516
- setv(to_object, ['turn_complete'], getv(from_object, ['turnComplete']))
517
- if getv(from_object, ['interrupted']) is not None:
518
- setv(to_object, ['interrupted'], getv(from_object, ['interrupted']))
519
- if getv(from_object, ['generationComplete']) is not None:
520
- setv(
521
- to_object,
522
- ['generation_complete'],
523
- getv(from_object, ['generationComplete']),
524
- )
525
- return to_object
526
-
527
- def _LiveToolCall_from_mldev(
528
- self,
529
- from_object: Union[dict, object],
530
- ) -> Dict[str, Any]:
531
- to_object: dict[str, Any] = {}
532
- if getv(from_object, ['functionCalls']) is not None:
533
- setv(
534
- to_object,
535
- ['function_calls'],
536
- getv(from_object, ['functionCalls']),
537
- )
538
- return to_object
539
-
540
- def _LiveToolCall_from_vertex(
541
- self,
542
- from_object: Union[dict, object],
543
- ) -> Dict[str, Any]:
544
- to_object: dict[str, Any] = {}
545
- if getv(from_object, ['functionCalls']) is not None:
546
- setv(
547
- to_object,
548
- ['function_calls'],
549
- getv(from_object, ['functionCalls']),
550
- )
551
- return to_object
552
-
553
- def _LiveServerMessage_from_mldev(
554
- self,
555
- from_object: Union[dict, object],
556
- ) -> Dict[str, Any]:
557
- to_object: dict[str, Any] = {}
558
- if getv(from_object, ['serverContent']) is not None:
559
- setv(
560
- to_object,
561
- ['server_content'],
562
- self._LiveServerContent_from_mldev(
563
- getv(from_object, ['serverContent'])
564
- ),
565
- )
566
- if getv(from_object, ['toolCall']) is not None:
567
- setv(
568
- to_object,
569
- ['tool_call'],
570
- self._LiveToolCall_from_mldev(getv(from_object, ['toolCall'])),
571
- )
572
- if getv(from_object, ['toolCallCancellation']) is not None:
573
- setv(
574
- to_object,
575
- ['tool_call_cancellation'],
576
- getv(from_object, ['toolCallCancellation']),
577
- )
578
- return to_object
579
-
580
- def _LiveServerContent_from_vertex(
581
- self,
582
- from_object: Union[dict, object],
583
- ) -> Dict[str, Any]:
584
- to_object: dict[str, Any] = {}
585
- if getv(from_object, ['modelTurn']) is not None:
586
- setv(
587
- to_object,
588
- ['model_turn'],
589
- _Content_from_vertex(
590
- self._api_client,
591
- getv(from_object, ['modelTurn']),
592
- ),
593
- )
594
- if getv(from_object, ['turnComplete']) is not None:
595
- setv(to_object, ['turn_complete'], getv(from_object, ['turnComplete']))
596
- if getv(from_object, ['generationComplete']) is not None:
597
- setv(
598
- to_object,
599
- ['generation_complete'],
600
- getv(from_object, ['generationComplete']),
601
- )
602
- # Vertex supports transcription.
603
- if getv(from_object, ['inputTranscription']) is not None:
604
- setv(
605
- to_object,
606
- ['input_transcription'],
607
- getv(from_object, ['inputTranscription']),
608
- )
609
- if getv(from_object, ['outputTranscription']) is not None:
610
- setv(
611
- to_object,
612
- ['output_transcription'],
613
- getv(from_object, ['outputTranscription']),
614
- )
615
- if getv(from_object, ['interrupted']) is not None:
616
- setv(to_object, ['interrupted'], getv(from_object, ['interrupted']))
617
- return to_object
618
-
619
- def _LiveServerMessage_from_vertex(
620
- self,
621
- from_object: Union[dict, object],
622
- ) -> Dict[str, Any]:
623
- to_object: dict[str, Any] = {}
624
- if getv(from_object, ['serverContent']) is not None:
625
- setv(
626
- to_object,
627
- ['server_content'],
628
- self._LiveServerContent_from_vertex(
629
- getv(from_object, ['serverContent'])
630
- ),
631
- )
632
-
633
- if getv(from_object, ['toolCall']) is not None:
634
- setv(
635
- to_object,
636
- ['tool_call'],
637
- self._LiveToolCall_from_vertex(getv(from_object, ['toolCall'])),
638
- )
639
- if getv(from_object, ['toolCallCancellation']) is not None:
640
- setv(
641
- to_object,
642
- ['tool_call_cancellation'],
643
- getv(from_object, ['toolCallCancellation']),
644
- )
645
- return to_object
646
-
647
482
  def _parse_client_message(
648
483
  self,
649
484
  input: Optional[
@@ -947,325 +782,16 @@ class AsyncSession:
947
782
 
948
783
  return client_message
949
784
 
950
- async def close(self):
785
+ async def close(self) -> None:
951
786
  # Close the websocket connection.
952
787
  await self._ws.close()
953
788
 
954
789
 
955
- def _t_content_strict(content: types.ContentOrDict):
956
- if isinstance(content, dict):
957
- return types.Content.model_validate(content)
958
- elif isinstance(content, types.Content):
959
- return content
960
- else:
961
- raise ValueError(
962
- f'Could not convert input (type "{type(content)}") to '
963
- '`types.Content`'
964
- )
965
-
966
-
967
- def _t_contents_strict(
968
- contents: Union[Sequence[types.ContentOrDict], types.ContentOrDict]):
969
- if isinstance(contents, Sequence):
970
- return [_t_content_strict(content) for content in contents]
971
- else:
972
- return [_t_content_strict(contents)]
973
-
974
-
975
- def _t_client_content(
976
- turns: Optional[
977
- Union[Sequence[types.ContentOrDict], types.ContentOrDict]
978
- ] = None,
979
- turn_complete: bool = True,
980
- ) -> types.LiveClientContent:
981
- if turns is None:
982
- return types.LiveClientContent(turn_complete=turn_complete)
983
-
984
- try:
985
- return types.LiveClientContent(
986
- turns=_t_contents_strict(contents=turns),
987
- turn_complete=turn_complete,
988
- )
989
- except Exception as e:
990
- raise ValueError(
991
- f'Could not convert input (type "{type(turns)}") to '
992
- '`types.LiveClientContent`'
993
- ) from e
994
-
995
-
996
- def _t_realtime_input(
997
- media: t.BlobUnion,
998
- ) -> types.LiveClientRealtimeInput:
999
- try:
1000
- return types.LiveClientRealtimeInput(media_chunks=[t.t_blob(blob=media)])
1001
- except Exception as e:
1002
- raise ValueError(
1003
- f'Could not convert input (type "{type(input)}") to '
1004
- '`types.LiveClientRealtimeInput`'
1005
- ) from e
1006
-
1007
-
1008
- def _t_tool_response(
1009
- input: Union[
1010
- types.FunctionResponseOrDict,
1011
- Sequence[types.FunctionResponseOrDict],
1012
- ],
1013
- ) -> types.LiveClientToolResponse:
1014
- if not input:
1015
- raise ValueError(f'A tool response is required, got: \n{input}')
1016
-
1017
- try:
1018
- return types.LiveClientToolResponse(
1019
- function_responses=t.t_function_responses(function_responses=input)
1020
- )
1021
- except Exception as e:
1022
- raise ValueError(
1023
- f'Could not convert input (type "{type(input)}") to '
1024
- '`types.LiveClientToolResponse`'
1025
- ) from e
1026
-
1027
790
 
1028
791
  class AsyncLive(_api_module.BaseModule):
1029
- """AsyncLive. The live module is experimental."""
792
+ """[Preview] AsyncLive."""
1030
793
 
1031
- def _LiveSetup_to_mldev(
1032
- self, model: str, config: Optional[types.LiveConnectConfig] = None
1033
- ):
1034
794
 
1035
- to_object: dict[str, Any] = {}
1036
- if getv(config, ['generation_config']) is not None:
1037
- setv(
1038
- to_object,
1039
- ['generationConfig'],
1040
- _GenerateContentConfig_to_mldev(
1041
- self._api_client,
1042
- getv(config, ['generation_config']),
1043
- to_object,
1044
- ),
1045
- )
1046
- if getv(config, ['response_modalities']) is not None:
1047
- if getv(to_object, ['generationConfig']) is not None:
1048
- to_object['generationConfig']['responseModalities'] = getv(
1049
- config, ['response_modalities']
1050
- )
1051
- else:
1052
- to_object['generationConfig'] = {
1053
- 'responseModalities': getv(config, ['response_modalities'])
1054
- }
1055
- if getv(config, ['speech_config']) is not None:
1056
- if getv(to_object, ['generationConfig']) is not None:
1057
- to_object['generationConfig']['speechConfig'] = _SpeechConfig_to_mldev(
1058
- self._api_client,
1059
- t.t_speech_config(
1060
- self._api_client, getv(config, ['speech_config'])
1061
- ),
1062
- to_object,
1063
- )
1064
- else:
1065
- to_object['generationConfig'] = {
1066
- 'speechConfig': _SpeechConfig_to_mldev(
1067
- self._api_client,
1068
- t.t_speech_config(
1069
- self._api_client, getv(config, ['speech_config'])
1070
- ),
1071
- to_object,
1072
- )
1073
- }
1074
- if getv(config, ['temperature']) is not None:
1075
- if getv(to_object, ['generationConfig']) is not None:
1076
- to_object['generationConfig']['temperature'] = getv(
1077
- config, ['temperature']
1078
- )
1079
- else:
1080
- to_object['generationConfig'] = {
1081
- 'temperature': getv(config, ['temperature'])
1082
- }
1083
- if getv(config, ['top_p']) is not None:
1084
- if getv(to_object, ['generationConfig']) is not None:
1085
- to_object['generationConfig']['topP'] = getv(config, ['top_p'])
1086
- else:
1087
- to_object['generationConfig'] = {'topP': getv(config, ['top_p'])}
1088
- if getv(config, ['top_k']) is not None:
1089
- if getv(to_object, ['generationConfig']) is not None:
1090
- to_object['generationConfig']['topK'] = getv(config, ['top_k'])
1091
- else:
1092
- to_object['generationConfig'] = {'topK': getv(config, ['top_k'])}
1093
- if getv(config, ['max_output_tokens']) is not None:
1094
- if getv(to_object, ['generationConfig']) is not None:
1095
- to_object['generationConfig']['maxOutputTokens'] = getv(
1096
- config, ['max_output_tokens']
1097
- )
1098
- else:
1099
- to_object['generationConfig'] = {
1100
- 'maxOutputTokens': getv(config, ['max_output_tokens'])
1101
- }
1102
- if getv(config, ['seed']) is not None:
1103
- if getv(to_object, ['generationConfig']) is not None:
1104
- to_object['generationConfig']['seed'] = getv(config, ['seed'])
1105
- else:
1106
- to_object['generationConfig'] = {'seed': getv(config, ['seed'])}
1107
- if getv(config, ['system_instruction']) is not None:
1108
- setv(
1109
- to_object,
1110
- ['systemInstruction'],
1111
- _Content_to_mldev(
1112
- self._api_client,
1113
- t.t_content(
1114
- self._api_client, getv(config, ['system_instruction'])
1115
- ),
1116
- to_object,
1117
- ),
1118
- )
1119
- if getv(config, ['tools']) is not None:
1120
- setv(
1121
- to_object,
1122
- ['tools'],
1123
- [
1124
- _Tool_to_mldev(
1125
- self._api_client, t.t_tool(self._api_client, item), to_object
1126
- )
1127
- for item in t.t_tools(self._api_client, getv(config, ['tools']))
1128
- ],
1129
- )
1130
-
1131
- return_value = {'setup': {'model': model}}
1132
- return_value['setup'].update(to_object)
1133
- return return_value
1134
-
1135
- def _LiveSetup_to_vertex(
1136
- self, model: str, config: Optional[types.LiveConnectConfig] = None
1137
- ):
1138
-
1139
- to_object: dict[str, Any] = {}
1140
-
1141
- if getv(config, ['generation_config']) is not None:
1142
- setv(
1143
- to_object,
1144
- ['generationConfig'],
1145
- _GenerateContentConfig_to_vertex(
1146
- self._api_client,
1147
- getv(config, ['generation_config']),
1148
- to_object,
1149
- ),
1150
- )
1151
- if getv(config, ['response_modalities']) is not None:
1152
- if getv(to_object, ['generationConfig']) is not None:
1153
- to_object['generationConfig']['responseModalities'] = getv(
1154
- config, ['response_modalities']
1155
- )
1156
- else:
1157
- to_object['generationConfig'] = {
1158
- 'responseModalities': getv(config, ['response_modalities'])
1159
- }
1160
- else:
1161
- # Set default to AUDIO to align with MLDev API.
1162
- if getv(to_object, ['generationConfig']) is not None:
1163
- to_object['generationConfig'].update({'responseModalities': ['AUDIO']})
1164
- else:
1165
- to_object.update(
1166
- {'generationConfig': {'responseModalities': ['AUDIO']}}
1167
- )
1168
- if getv(config, ['speech_config']) is not None:
1169
- if getv(to_object, ['generationConfig']) is not None:
1170
- to_object['generationConfig']['speechConfig'] = _SpeechConfig_to_vertex(
1171
- self._api_client,
1172
- t.t_speech_config(
1173
- self._api_client, getv(config, ['speech_config'])
1174
- ),
1175
- to_object,
1176
- )
1177
- else:
1178
- to_object['generationConfig'] = {
1179
- 'speechConfig': _SpeechConfig_to_vertex(
1180
- self._api_client,
1181
- t.t_speech_config(
1182
- self._api_client, getv(config, ['speech_config'])
1183
- ),
1184
- to_object,
1185
- )
1186
- }
1187
- if getv(config, ['temperature']) is not None:
1188
- if getv(to_object, ['generationConfig']) is not None:
1189
- to_object['generationConfig']['temperature'] = getv(
1190
- config, ['temperature']
1191
- )
1192
- else:
1193
- to_object['generationConfig'] = {
1194
- 'temperature': getv(config, ['temperature'])
1195
- }
1196
- if getv(config, ['top_p']) is not None:
1197
- if getv(to_object, ['generationConfig']) is not None:
1198
- to_object['generationConfig']['topP'] = getv(config, ['top_p'])
1199
- else:
1200
- to_object['generationConfig'] = {'topP': getv(config, ['top_p'])}
1201
- if getv(config, ['top_k']) is not None:
1202
- if getv(to_object, ['generationConfig']) is not None:
1203
- to_object['generationConfig']['topK'] = getv(config, ['top_k'])
1204
- else:
1205
- to_object['generationConfig'] = {'topK': getv(config, ['top_k'])}
1206
- if getv(config, ['max_output_tokens']) is not None:
1207
- if getv(to_object, ['generationConfig']) is not None:
1208
- to_object['generationConfig']['maxOutputTokens'] = getv(
1209
- config, ['max_output_tokens']
1210
- )
1211
- else:
1212
- to_object['generationConfig'] = {
1213
- 'maxOutputTokens': getv(config, ['max_output_tokens'])
1214
- }
1215
- if getv(config, ['seed']) is not None:
1216
- if getv(to_object, ['generationConfig']) is not None:
1217
- to_object['generationConfig']['seed'] = getv(config, ['seed'])
1218
- else:
1219
- to_object['generationConfig'] = {'seed': getv(config, ['seed'])}
1220
- if getv(config, ['system_instruction']) is not None:
1221
- setv(
1222
- to_object,
1223
- ['systemInstruction'],
1224
- _Content_to_vertex(
1225
- self._api_client,
1226
- t.t_content(
1227
- self._api_client, getv(config, ['system_instruction'])
1228
- ),
1229
- to_object,
1230
- ),
1231
- )
1232
- if getv(config, ['tools']) is not None:
1233
- setv(
1234
- to_object,
1235
- ['tools'],
1236
- [
1237
- _Tool_to_vertex(
1238
- self._api_client, t.t_tool(self._api_client, item), to_object
1239
- )
1240
- for item in t.t_tools(self._api_client, getv(config, ['tools']))
1241
- ],
1242
- )
1243
- if getv(config, ['input_audio_transcription']) is not None:
1244
- setv(
1245
- to_object,
1246
- ['inputAudioTranscription'],
1247
- _AudioTranscriptionConfig_to_vertex(
1248
- self._api_client,
1249
- getv(config, ['input_audio_transcription']),
1250
- ),
1251
- )
1252
- if getv(config, ['output_audio_transcription']) is not None:
1253
- setv(
1254
- to_object,
1255
- ['outputAudioTranscription'],
1256
- _AudioTranscriptionConfig_to_vertex(
1257
- self._api_client,
1258
- getv(config, ['output_audio_transcription']),
1259
- ),
1260
- )
1261
-
1262
- return_value = {'setup': {'model': model}}
1263
- return_value['setup'].update(to_object)
1264
- return return_value
1265
-
1266
- @experimental_warning(
1267
- 'The live API is experimental and may change in future versions.',
1268
- )
1269
795
  @contextlib.asynccontextmanager
1270
796
  async def connect(
1271
797
  self,
@@ -1273,9 +799,9 @@ class AsyncLive(_api_module.BaseModule):
1273
799
  model: str,
1274
800
  config: Optional[types.LiveConnectConfigOrDict] = None,
1275
801
  ) -> AsyncIterator[AsyncSession]:
1276
- """Connect to the live server.
802
+ """[Preview] Connect to the live server.
1277
803
 
1278
- The live module is experimental.
804
+ Note: the live API is currently in preview.
1279
805
 
1280
806
  Usage:
1281
807
 
@@ -1290,44 +816,28 @@ class AsyncLive(_api_module.BaseModule):
1290
816
  """
1291
817
  base_url = self._api_client._websocket_base_url()
1292
818
  transformed_model = t.t_model(self._api_client, model)
1293
- # Ensure the config is a LiveConnectConfig.
1294
- if config is None:
1295
- parameter_model = types.LiveConnectConfig()
1296
- elif isinstance(config, dict):
1297
- if config.get('system_instruction') is None:
1298
- system_instruction = None
1299
- else:
1300
- system_instruction = t.t_content(
1301
- self._api_client, config.get('system_instruction')
1302
- )
1303
- parameter_model = types.LiveConnectConfig(
1304
- generation_config=config.get('generation_config'),
1305
- response_modalities=config.get('response_modalities'),
1306
- speech_config=config.get('speech_config'),
1307
- temperature=config.get('temperature'),
1308
- top_p=config.get('top_p'),
1309
- top_k=config.get('top_k'),
1310
- max_output_tokens=config.get('max_output_tokens'),
1311
- seed=config.get('seed'),
1312
- system_instruction=system_instruction,
1313
- tools=config.get('tools'),
1314
- input_audio_transcription=config.get('input_audio_transcription'),
1315
- output_audio_transcription=config.get('output_audio_transcription'),
1316
- )
1317
- else:
1318
- parameter_model = config
819
+
820
+ parameter_model = _t_live_connect_config(self._api_client, config)
1319
821
 
1320
822
  if self._api_client.api_key:
1321
823
  api_key = self._api_client.api_key
1322
824
  version = self._api_client._http_options.api_version
1323
825
  uri = f'{base_url}/ws/google.ai.generativelanguage.{version}.GenerativeService.BidiGenerateContent?key={api_key}'
1324
826
  headers = self._api_client._http_options.headers
827
+
1325
828
  request_dict = _common.convert_to_dict(
1326
- self._LiveSetup_to_mldev(
1327
- model=transformed_model,
1328
- config=parameter_model,
829
+ live_converters._LiveConnectParameters_to_mldev(
830
+ api_client=self._api_client,
831
+ from_object=types.LiveConnectParameters(
832
+ model=transformed_model,
833
+ config=parameter_model,
834
+ ).model_dump(exclude_none=True)
1329
835
  )
1330
836
  )
837
+ del request_dict['config']
838
+
839
+ setv(request_dict, ['setup', 'model'], transformed_model)
840
+
1331
841
  request = json.dumps(request_dict)
1332
842
  else:
1333
843
  # Get bearer token through Application Default Credentials.
@@ -1354,11 +864,19 @@ class AsyncLive(_api_module.BaseModule):
1354
864
  f'projects/{project}/locations/{location}/' + transformed_model
1355
865
  )
1356
866
  request_dict = _common.convert_to_dict(
1357
- self._LiveSetup_to_vertex(
1358
- model=transformed_model,
1359
- config=parameter_model,
867
+ live_converters._LiveConnectParameters_to_vertex(
868
+ api_client=self._api_client,
869
+ from_object=types.LiveConnectParameters(
870
+ model=transformed_model,
871
+ config=parameter_model,
872
+ ).model_dump(exclude_none=True)
1360
873
  )
1361
874
  )
875
+ del request_dict['config']
876
+
877
+ if getv(request_dict, ['setup', 'generationConfig', 'responseModalities']) is None:
878
+ setv(request_dict, ['setup', 'generationConfig', 'responseModalities'], ['AUDIO'])
879
+
1362
880
  request = json.dumps(request_dict)
1363
881
 
1364
882
  try:
@@ -1374,3 +892,41 @@ class AsyncLive(_api_module.BaseModule):
1374
892
  logger.info(await ws.recv())
1375
893
 
1376
894
  yield AsyncSession(api_client=self._api_client, websocket=ws)
895
+
896
+
897
+ def _t_live_connect_config(
898
+ api_client: BaseApiClient,
899
+ config: Optional[types.LiveConnectConfigOrDict],
900
+ ) -> types.LiveConnectConfig:
901
+ # Ensure the config is a LiveConnectConfig.
902
+ if config is None:
903
+ parameter_model = types.LiveConnectConfig()
904
+ elif isinstance(config, dict):
905
+ if getv(config, ['system_instruction']) is not None:
906
+ converted_system_instruction = t.t_content(
907
+ api_client, getv(config, ['system_instruction'])
908
+ )
909
+ else:
910
+ converted_system_instruction = None
911
+ parameter_model = types.LiveConnectConfig(**config)
912
+ parameter_model.system_instruction = converted_system_instruction
913
+ else:
914
+ if config.system_instruction is None:
915
+ system_instruction = None
916
+ else:
917
+ system_instruction = t.t_content(
918
+ api_client, getv(config, ['system_instruction'])
919
+ )
920
+ parameter_model = config
921
+ parameter_model.system_instruction = system_instruction
922
+
923
+ if parameter_model.generation_config is not None:
924
+ warnings.warn(
925
+ 'Setting `LiveConnectConfig.generation_config` is deprecated, '
926
+ 'please set the fields on `LiveConnectConfig` directly. This will '
927
+ 'become an error in a future version (not before Q3 2025)',
928
+ DeprecationWarning,
929
+ stacklevel=4,
930
+ )
931
+
932
+ return parameter_model