google-genai 1.33.0__py3-none-any.whl → 1.53.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 +361 -208
- google/genai/_common.py +260 -69
- google/genai/_extra_utils.py +142 -12
- google/genai/_live_converters.py +691 -2746
- google/genai/_local_tokenizer_loader.py +0 -9
- google/genai/_operations_converters.py +186 -99
- google/genai/_replay_api_client.py +48 -51
- google/genai/_tokens_converters.py +169 -489
- google/genai/_transformers.py +193 -90
- google/genai/batches.py +1014 -1307
- google/genai/caches.py +458 -1107
- google/genai/client.py +101 -0
- google/genai/documents.py +532 -0
- google/genai/errors.py +58 -4
- google/genai/file_search_stores.py +1296 -0
- google/genai/files.py +108 -358
- google/genai/live.py +90 -32
- google/genai/live_music.py +24 -27
- google/genai/local_tokenizer.py +36 -3
- google/genai/models.py +2308 -3375
- google/genai/operations.py +129 -21
- google/genai/pagers.py +7 -1
- google/genai/tokens.py +2 -12
- google/genai/tunings.py +770 -436
- google/genai/types.py +4341 -1218
- google/genai/version.py +1 -1
- {google_genai-1.33.0.dist-info → google_genai-1.53.0.dist-info}/METADATA +359 -201
- google_genai-1.53.0.dist-info/RECORD +41 -0
- google_genai-1.33.0.dist-info/RECORD +0 -39
- {google_genai-1.33.0.dist-info → google_genai-1.53.0.dist-info}/WHEEL +0 -0
- {google_genai-1.33.0.dist-info → google_genai-1.53.0.dist-info}/licenses/LICENSE +0 -0
- {google_genai-1.33.0.dist-info → google_genai-1.53.0.dist-info}/top_level.txt +0 -0
google/genai/_transformers.py
CHANGED
|
@@ -64,6 +64,45 @@ else:
|
|
|
64
64
|
McpTool = None
|
|
65
65
|
|
|
66
66
|
|
|
67
|
+
metric_name_sdk_api_map = {
|
|
68
|
+
'exact_match': 'exactMatchSpec',
|
|
69
|
+
'bleu': 'bleuSpec',
|
|
70
|
+
'rouge_spec': 'rougeSpec',
|
|
71
|
+
}
|
|
72
|
+
metric_name_api_sdk_map = {v: k for k, v in metric_name_sdk_api_map.items()}
|
|
73
|
+
|
|
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
|
+
all_matched = all(hasattr(obj, field) for field in cls.model_fields)
|
|
95
|
+
if not all_matched and isinstance(obj, pydantic.BaseModel):
|
|
96
|
+
# Check the other way around if obj is a Pydantic model.
|
|
97
|
+
# Check if the Pydantic model has all of the object's defined fields.
|
|
98
|
+
try:
|
|
99
|
+
obj_private = cls()
|
|
100
|
+
all_matched = all(hasattr(obj_private, f) for f in type(obj).model_fields)
|
|
101
|
+
except ValueError:
|
|
102
|
+
return False
|
|
103
|
+
return all_matched
|
|
104
|
+
|
|
105
|
+
|
|
67
106
|
def _resource_name(
|
|
68
107
|
client: _api_client.BaseApiClient,
|
|
69
108
|
resource_name: str,
|
|
@@ -160,6 +199,8 @@ def _resource_name(
|
|
|
160
199
|
def t_model(client: _api_client.BaseApiClient, model: str) -> str:
|
|
161
200
|
if not model:
|
|
162
201
|
raise ValueError('model is required.')
|
|
202
|
+
if '..' in model or '?' in model or '&' in model:
|
|
203
|
+
raise ValueError('invalid model parameter.')
|
|
163
204
|
if client.vertexai:
|
|
164
205
|
if (
|
|
165
206
|
model.startswith('projects/')
|
|
@@ -276,7 +317,7 @@ def t_function_response(
|
|
|
276
317
|
raise ValueError('function_response is required.')
|
|
277
318
|
if isinstance(function_response, dict):
|
|
278
319
|
return types.FunctionResponse.model_validate(function_response)
|
|
279
|
-
elif
|
|
320
|
+
elif _is_duck_type_of(function_response, types.FunctionResponse):
|
|
280
321
|
return function_response
|
|
281
322
|
else:
|
|
282
323
|
raise TypeError(
|
|
@@ -309,24 +350,25 @@ def t_blobs(
|
|
|
309
350
|
|
|
310
351
|
|
|
311
352
|
def t_blob(blob: types.BlobImageUnionDict) -> types.Blob:
|
|
312
|
-
try:
|
|
313
|
-
import PIL.Image
|
|
314
|
-
|
|
315
|
-
PIL_Image = PIL.Image.Image
|
|
316
|
-
except ImportError:
|
|
317
|
-
PIL_Image = None
|
|
318
|
-
|
|
319
353
|
if not blob:
|
|
320
354
|
raise ValueError('blob is required.')
|
|
321
355
|
|
|
322
|
-
if
|
|
323
|
-
return blob
|
|
356
|
+
if _is_duck_type_of(blob, types.Blob):
|
|
357
|
+
return blob # type: ignore[return-value]
|
|
324
358
|
|
|
325
359
|
if isinstance(blob, dict):
|
|
326
360
|
return types.Blob.model_validate(blob)
|
|
327
361
|
|
|
328
|
-
if
|
|
329
|
-
|
|
362
|
+
if 'image' in blob.__class__.__name__.lower():
|
|
363
|
+
try:
|
|
364
|
+
import PIL.Image
|
|
365
|
+
|
|
366
|
+
PIL_Image = PIL.Image.Image
|
|
367
|
+
except ImportError:
|
|
368
|
+
PIL_Image = None
|
|
369
|
+
|
|
370
|
+
if PIL_Image is not None and isinstance(blob, PIL_Image):
|
|
371
|
+
return pil_to_blob(blob)
|
|
330
372
|
|
|
331
373
|
raise TypeError(
|
|
332
374
|
f'Could not parse input as Blob. Unsupported blob type: {type(blob)}'
|
|
@@ -348,27 +390,32 @@ def t_audio_blob(blob: types.BlobOrDict) -> types.Blob:
|
|
|
348
390
|
|
|
349
391
|
|
|
350
392
|
def t_part(part: Optional[types.PartUnionDict]) -> types.Part:
|
|
351
|
-
try:
|
|
352
|
-
import PIL.Image
|
|
353
|
-
|
|
354
|
-
PIL_Image = PIL.Image.Image
|
|
355
|
-
except ImportError:
|
|
356
|
-
PIL_Image = None
|
|
357
|
-
|
|
358
393
|
if part is None:
|
|
359
394
|
raise ValueError('content part is required.')
|
|
360
395
|
if isinstance(part, str):
|
|
361
396
|
return types.Part(text=part)
|
|
362
|
-
if
|
|
363
|
-
|
|
364
|
-
if isinstance(part, types.File):
|
|
365
|
-
if not part.uri or not part.mime_type:
|
|
397
|
+
if _is_duck_type_of(part, types.File):
|
|
398
|
+
if not part.uri or not part.mime_type: # type: ignore[union-attr]
|
|
366
399
|
raise ValueError('file uri and mime_type are required.')
|
|
367
|
-
return types.Part.from_uri(file_uri=part.uri, mime_type=part.mime_type)
|
|
400
|
+
return types.Part.from_uri(file_uri=part.uri, mime_type=part.mime_type) # type: ignore[union-attr]
|
|
368
401
|
if isinstance(part, dict):
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
402
|
+
try:
|
|
403
|
+
return types.Part.model_validate(part)
|
|
404
|
+
except pydantic.ValidationError:
|
|
405
|
+
return types.Part(file_data=types.FileData.model_validate(part))
|
|
406
|
+
if _is_duck_type_of(part, types.Part):
|
|
407
|
+
return part # type: ignore[return-value]
|
|
408
|
+
|
|
409
|
+
if 'image' in part.__class__.__name__.lower():
|
|
410
|
+
try:
|
|
411
|
+
import PIL.Image
|
|
412
|
+
|
|
413
|
+
PIL_Image = PIL.Image.Image
|
|
414
|
+
except ImportError:
|
|
415
|
+
PIL_Image = None
|
|
416
|
+
|
|
417
|
+
if PIL_Image is not None and isinstance(part, PIL_Image):
|
|
418
|
+
return types.Part(inline_data=pil_to_blob(part))
|
|
372
419
|
raise ValueError(f'Unsupported content part type: {type(part)}')
|
|
373
420
|
|
|
374
421
|
|
|
@@ -409,29 +456,31 @@ ContentType = Union[types.Content, types.ContentDict, types.PartUnionDict]
|
|
|
409
456
|
|
|
410
457
|
|
|
411
458
|
def t_content(
|
|
412
|
-
content:
|
|
459
|
+
content: Union[ContentType, types.ContentDict, None],
|
|
413
460
|
) -> types.Content:
|
|
414
461
|
if content is None:
|
|
415
462
|
raise ValueError('content is required.')
|
|
416
|
-
if
|
|
417
|
-
return content
|
|
463
|
+
if _is_duck_type_of(content, types.Content):
|
|
464
|
+
return content # type: ignore[return-value]
|
|
418
465
|
if isinstance(content, dict):
|
|
419
466
|
try:
|
|
420
467
|
return types.Content.model_validate(content)
|
|
421
468
|
except pydantic.ValidationError:
|
|
422
|
-
possible_part =
|
|
469
|
+
possible_part = t_part(content) # type: ignore[arg-type]
|
|
423
470
|
return (
|
|
424
471
|
types.ModelContent(parts=[possible_part])
|
|
425
472
|
if possible_part.function_call
|
|
426
473
|
else types.UserContent(parts=[possible_part])
|
|
427
474
|
)
|
|
428
|
-
if
|
|
475
|
+
if _is_duck_type_of(content, types.File):
|
|
476
|
+
return types.UserContent(parts=[t_part(content)]) # type: ignore[arg-type]
|
|
477
|
+
if _is_duck_type_of(content, types.Part):
|
|
429
478
|
return (
|
|
430
|
-
types.ModelContent(parts=[content])
|
|
431
|
-
if content.function_call
|
|
432
|
-
else types.UserContent(parts=[content])
|
|
479
|
+
types.ModelContent(parts=[content]) # type: ignore[arg-type]
|
|
480
|
+
if content.function_call # type: ignore[union-attr]
|
|
481
|
+
else types.UserContent(parts=[content]) # type: ignore[arg-type]
|
|
433
482
|
)
|
|
434
|
-
return types.UserContent(parts=content)
|
|
483
|
+
return types.UserContent(parts=content) # type: ignore[arg-type]
|
|
435
484
|
|
|
436
485
|
|
|
437
486
|
def t_contents_for_embed(
|
|
@@ -470,13 +519,6 @@ def t_contents(
|
|
|
470
519
|
if not isinstance(contents, list):
|
|
471
520
|
return [t_content(contents)]
|
|
472
521
|
|
|
473
|
-
try:
|
|
474
|
-
import PIL.Image
|
|
475
|
-
|
|
476
|
-
PIL_Image = PIL.Image.Image
|
|
477
|
-
except ImportError:
|
|
478
|
-
PIL_Image = None
|
|
479
|
-
|
|
480
522
|
result: list[types.Content] = []
|
|
481
523
|
accumulated_parts: list[types.Part] = []
|
|
482
524
|
|
|
@@ -485,18 +527,35 @@ def t_contents(
|
|
|
485
527
|
) -> TypeGuard[types.PartUnionDict]:
|
|
486
528
|
if (
|
|
487
529
|
isinstance(part, str)
|
|
488
|
-
or
|
|
489
|
-
or (
|
|
490
|
-
or isinstance(part, types.Part)
|
|
530
|
+
or _is_duck_type_of(part, types.File)
|
|
531
|
+
or _is_duck_type_of(part, types.Part)
|
|
491
532
|
):
|
|
492
533
|
return True
|
|
493
534
|
|
|
494
535
|
if isinstance(part, dict):
|
|
536
|
+
if not part:
|
|
537
|
+
# Empty dict should be considered as Content, not Part.
|
|
538
|
+
return False
|
|
495
539
|
try:
|
|
496
540
|
types.Part.model_validate(part)
|
|
497
541
|
return True
|
|
498
542
|
except pydantic.ValidationError:
|
|
499
|
-
|
|
543
|
+
try:
|
|
544
|
+
types.FileData.model_validate(part)
|
|
545
|
+
return True
|
|
546
|
+
except pydantic.ValidationError:
|
|
547
|
+
return False
|
|
548
|
+
|
|
549
|
+
if 'image' in part.__class__.__name__.lower():
|
|
550
|
+
try:
|
|
551
|
+
import PIL.Image
|
|
552
|
+
|
|
553
|
+
PIL_Image = PIL.Image.Image
|
|
554
|
+
except ImportError:
|
|
555
|
+
PIL_Image = None
|
|
556
|
+
|
|
557
|
+
if PIL_Image is not None and isinstance(part, PIL_Image):
|
|
558
|
+
return True
|
|
500
559
|
|
|
501
560
|
return False
|
|
502
561
|
|
|
@@ -539,16 +598,12 @@ def t_contents(
|
|
|
539
598
|
# append to result
|
|
540
599
|
# if list, we only accept a list of types.PartUnion
|
|
541
600
|
for content in contents:
|
|
542
|
-
if (
|
|
543
|
-
isinstance(content, types.Content)
|
|
544
|
-
# only allowed inner list is a list of types.PartUnion
|
|
545
|
-
or isinstance(content, list)
|
|
546
|
-
):
|
|
601
|
+
if _is_duck_type_of(content, types.Content) or isinstance(content, list):
|
|
547
602
|
_append_accumulated_parts_as_content(result, accumulated_parts)
|
|
548
603
|
if isinstance(content, list):
|
|
549
604
|
result.append(types.UserContent(parts=content)) # type: ignore[arg-type]
|
|
550
605
|
else:
|
|
551
|
-
result.append(content)
|
|
606
|
+
result.append(content) # type: ignore[arg-type]
|
|
552
607
|
elif _is_part(content):
|
|
553
608
|
_handle_current_part(result, accumulated_parts, content)
|
|
554
609
|
elif isinstance(content, dict):
|
|
@@ -840,12 +895,12 @@ def t_schema(
|
|
|
840
895
|
return types.Schema.model_validate(origin)
|
|
841
896
|
if isinstance(origin, EnumMeta):
|
|
842
897
|
return _process_enum(origin, client)
|
|
843
|
-
if
|
|
844
|
-
if dict(origin) == dict(types.Schema()):
|
|
898
|
+
if _is_duck_type_of(origin, types.Schema):
|
|
899
|
+
if dict(origin) == dict(types.Schema()): # type: ignore [arg-type]
|
|
845
900
|
# response_schema value was coerced to an empty Schema instance because
|
|
846
901
|
# it did not adhere to the Schema field annotation
|
|
847
902
|
_raise_for_unsupported_schema_type(origin)
|
|
848
|
-
schema = origin.model_dump(exclude_unset=True)
|
|
903
|
+
schema = origin.model_dump(exclude_unset=True) # type: ignore[union-attr]
|
|
849
904
|
process_schema(schema, client)
|
|
850
905
|
return types.Schema.model_validate(schema)
|
|
851
906
|
|
|
@@ -882,8 +937,8 @@ def t_speech_config(
|
|
|
882
937
|
) -> Optional[types.SpeechConfig]:
|
|
883
938
|
if not origin:
|
|
884
939
|
return None
|
|
885
|
-
if
|
|
886
|
-
return origin
|
|
940
|
+
if _is_duck_type_of(origin, types.SpeechConfig):
|
|
941
|
+
return origin # type: ignore[return-value]
|
|
887
942
|
if isinstance(origin, str):
|
|
888
943
|
return types.SpeechConfig(
|
|
889
944
|
voice_config=types.VoiceConfig(
|
|
@@ -899,17 +954,17 @@ def t_speech_config(
|
|
|
899
954
|
def t_live_speech_config(
|
|
900
955
|
origin: types.SpeechConfigOrDict,
|
|
901
956
|
) -> Optional[types.SpeechConfig]:
|
|
902
|
-
if
|
|
957
|
+
if _is_duck_type_of(origin, types.SpeechConfig):
|
|
903
958
|
speech_config = origin
|
|
904
959
|
if isinstance(origin, dict):
|
|
905
960
|
speech_config = types.SpeechConfig.model_validate(origin)
|
|
906
961
|
|
|
907
|
-
if speech_config.multi_speaker_voice_config is not None:
|
|
962
|
+
if speech_config.multi_speaker_voice_config is not None: # type: ignore[union-attr]
|
|
908
963
|
raise ValueError(
|
|
909
964
|
'multi_speaker_voice_config is not supported in the live API.'
|
|
910
965
|
)
|
|
911
966
|
|
|
912
|
-
return speech_config
|
|
967
|
+
return speech_config # type: ignore[return-value]
|
|
913
968
|
|
|
914
969
|
|
|
915
970
|
def t_tool(
|
|
@@ -925,7 +980,7 @@ def t_tool(
|
|
|
925
980
|
)
|
|
926
981
|
]
|
|
927
982
|
)
|
|
928
|
-
elif McpTool is not None and
|
|
983
|
+
elif McpTool is not None and _is_duck_type_of(origin, McpTool):
|
|
929
984
|
return mcp_to_gemini_tool(origin)
|
|
930
985
|
elif isinstance(origin, dict):
|
|
931
986
|
return types.Tool.model_validate(origin)
|
|
@@ -964,32 +1019,32 @@ def t_cached_content_name(client: _api_client.BaseApiClient, name: str) -> str:
|
|
|
964
1019
|
|
|
965
1020
|
def t_batch_job_source(
|
|
966
1021
|
client: _api_client.BaseApiClient,
|
|
967
|
-
src:
|
|
968
|
-
str, List[types.InlinedRequestOrDict], types.BatchJobSourceOrDict
|
|
969
|
-
],
|
|
1022
|
+
src: types.BatchJobSourceUnionDict,
|
|
970
1023
|
) -> types.BatchJobSource:
|
|
971
1024
|
if isinstance(src, dict):
|
|
972
1025
|
src = types.BatchJobSource(**src)
|
|
973
|
-
if
|
|
1026
|
+
if _is_duck_type_of(src, types.BatchJobSource):
|
|
1027
|
+
vertex_sources = sum(
|
|
1028
|
+
[src.gcs_uri is not None, src.bigquery_uri is not None] # type: ignore[union-attr]
|
|
1029
|
+
)
|
|
1030
|
+
mldev_sources = sum([
|
|
1031
|
+
src.inlined_requests is not None, # type: ignore[union-attr]
|
|
1032
|
+
src.file_name is not None, # type: ignore[union-attr]
|
|
1033
|
+
])
|
|
974
1034
|
if client.vertexai:
|
|
975
|
-
if
|
|
976
|
-
raise ValueError(
|
|
977
|
-
'Only one of `gcs_uri` or `bigquery_uri` can be set.'
|
|
978
|
-
)
|
|
979
|
-
elif not src.gcs_uri and not src.bigquery_uri:
|
|
1035
|
+
if mldev_sources or vertex_sources != 1:
|
|
980
1036
|
raise ValueError(
|
|
981
|
-
'
|
|
1037
|
+
'Exactly one of `gcs_uri` or `bigquery_uri` must be set, other '
|
|
1038
|
+
'sources are not supported in Vertex AI.'
|
|
982
1039
|
)
|
|
983
1040
|
else:
|
|
984
|
-
if
|
|
1041
|
+
if vertex_sources or mldev_sources != 1:
|
|
985
1042
|
raise ValueError(
|
|
986
|
-
'
|
|
1043
|
+
'Exactly one of `inlined_requests`, `file_name`, '
|
|
1044
|
+
'`inlined_embed_content_requests`, or `embed_content_file_name` '
|
|
1045
|
+
'must be set, other sources are not supported in Gemini API.'
|
|
987
1046
|
)
|
|
988
|
-
|
|
989
|
-
raise ValueError(
|
|
990
|
-
'One of `inlined_requests` or `file_name` must be set.'
|
|
991
|
-
)
|
|
992
|
-
return src
|
|
1047
|
+
return src # type: ignore[return-value]
|
|
993
1048
|
|
|
994
1049
|
elif isinstance(src, list):
|
|
995
1050
|
return types.BatchJobSource(inlined_requests=src)
|
|
@@ -1012,6 +1067,29 @@ def t_batch_job_source(
|
|
|
1012
1067
|
raise ValueError(f'Unsupported source: {src}')
|
|
1013
1068
|
|
|
1014
1069
|
|
|
1070
|
+
def t_embedding_batch_job_source(
|
|
1071
|
+
client: _api_client.BaseApiClient,
|
|
1072
|
+
src: types.EmbeddingsBatchJobSourceOrDict,
|
|
1073
|
+
) -> types.EmbeddingsBatchJobSource:
|
|
1074
|
+
if isinstance(src, dict):
|
|
1075
|
+
src = types.EmbeddingsBatchJobSource(**src)
|
|
1076
|
+
|
|
1077
|
+
if _is_duck_type_of(src, types.EmbeddingsBatchJobSource):
|
|
1078
|
+
mldev_sources = sum([
|
|
1079
|
+
src.inlined_requests is not None,
|
|
1080
|
+
src.file_name is not None,
|
|
1081
|
+
])
|
|
1082
|
+
if mldev_sources != 1:
|
|
1083
|
+
raise ValueError(
|
|
1084
|
+
'Exactly one of `inlined_requests`, `file_name`, '
|
|
1085
|
+
'`inlined_embed_content_requests`, or `embed_content_file_name` '
|
|
1086
|
+
'must be set, other sources are not supported in Gemini API.'
|
|
1087
|
+
)
|
|
1088
|
+
return src
|
|
1089
|
+
else:
|
|
1090
|
+
raise ValueError(f'Unsupported source type: {type(src)}')
|
|
1091
|
+
|
|
1092
|
+
|
|
1015
1093
|
def t_batch_job_destination(
|
|
1016
1094
|
dest: Union[str, types.BatchJobDestinationOrDict],
|
|
1017
1095
|
) -> types.BatchJobDestination:
|
|
@@ -1031,12 +1109,29 @@ def t_batch_job_destination(
|
|
|
1031
1109
|
)
|
|
1032
1110
|
else:
|
|
1033
1111
|
raise ValueError(f'Unsupported destination: {dest}')
|
|
1034
|
-
elif
|
|
1112
|
+
elif _is_duck_type_of(dest, types.BatchJobDestination):
|
|
1035
1113
|
return dest
|
|
1036
1114
|
else:
|
|
1037
1115
|
raise ValueError(f'Unsupported destination: {dest}')
|
|
1038
1116
|
|
|
1039
1117
|
|
|
1118
|
+
def t_recv_batch_job_destination(dest: dict[str, Any]) -> dict[str, Any]:
|
|
1119
|
+
# Rename inlinedResponses if it looks like an embedding response.
|
|
1120
|
+
inline_responses = dest.get('inlinedResponses', {}).get(
|
|
1121
|
+
'inlinedResponses', []
|
|
1122
|
+
)
|
|
1123
|
+
if not inline_responses:
|
|
1124
|
+
return dest
|
|
1125
|
+
for response in inline_responses:
|
|
1126
|
+
inner_response = response.get('response', {})
|
|
1127
|
+
if not inner_response:
|
|
1128
|
+
continue
|
|
1129
|
+
if 'embedding' in inner_response:
|
|
1130
|
+
dest['inlinedEmbedContentResponses'] = dest.pop('inlinedResponses')
|
|
1131
|
+
break
|
|
1132
|
+
return dest
|
|
1133
|
+
|
|
1134
|
+
|
|
1040
1135
|
def t_batch_job_name(client: _api_client.BaseApiClient, name: str) -> str:
|
|
1041
1136
|
if not client.vertexai:
|
|
1042
1137
|
mldev_pattern = r'batches/[^/]+$'
|
|
@@ -1060,12 +1155,16 @@ def t_job_state(state: str) -> str:
|
|
|
1060
1155
|
return 'JOB_STATE_UNSPECIFIED'
|
|
1061
1156
|
elif state == 'BATCH_STATE_PENDING':
|
|
1062
1157
|
return 'JOB_STATE_PENDING'
|
|
1158
|
+
elif state == 'BATCH_STATE_RUNNING':
|
|
1159
|
+
return 'JOB_STATE_RUNNING'
|
|
1063
1160
|
elif state == 'BATCH_STATE_SUCCEEDED':
|
|
1064
1161
|
return 'JOB_STATE_SUCCEEDED'
|
|
1065
1162
|
elif state == 'BATCH_STATE_FAILED':
|
|
1066
1163
|
return 'JOB_STATE_FAILED'
|
|
1067
1164
|
elif state == 'BATCH_STATE_CANCELLED':
|
|
1068
1165
|
return 'JOB_STATE_CANCELLED'
|
|
1166
|
+
elif state == 'BATCH_STATE_EXPIRED':
|
|
1167
|
+
return 'JOB_STATE_EXPIRED'
|
|
1069
1168
|
else:
|
|
1070
1169
|
return state
|
|
1071
1170
|
|
|
@@ -1110,13 +1209,13 @@ def t_file_name(
|
|
|
1110
1209
|
name: Optional[Union[str, types.File, types.Video, types.GeneratedVideo]],
|
|
1111
1210
|
) -> str:
|
|
1112
1211
|
# Remove the files/ prefix since it's added to the url path.
|
|
1113
|
-
if
|
|
1114
|
-
name = name.name
|
|
1115
|
-
elif
|
|
1116
|
-
name = name.uri
|
|
1117
|
-
elif
|
|
1118
|
-
if name.video is not None:
|
|
1119
|
-
name = name.video.uri
|
|
1212
|
+
if _is_duck_type_of(name, types.File):
|
|
1213
|
+
name = name.name # type: ignore[union-attr]
|
|
1214
|
+
elif _is_duck_type_of(name, types.Video):
|
|
1215
|
+
name = name.uri # type: ignore[union-attr]
|
|
1216
|
+
elif _is_duck_type_of(name, types.GeneratedVideo):
|
|
1217
|
+
if name.video is not None: # type: ignore[union-attr]
|
|
1218
|
+
name = name.video.uri # type: ignore[union-attr]
|
|
1120
1219
|
else:
|
|
1121
1220
|
name = None
|
|
1122
1221
|
|
|
@@ -1159,7 +1258,7 @@ def t_tuning_job_status(status: str) -> Union[types.JobState, str]:
|
|
|
1159
1258
|
def t_content_strict(content: types.ContentOrDict) -> types.Content:
|
|
1160
1259
|
if isinstance(content, dict):
|
|
1161
1260
|
return types.Content.model_validate(content)
|
|
1162
|
-
elif
|
|
1261
|
+
elif _is_duck_type_of(content, types.Content):
|
|
1163
1262
|
return content
|
|
1164
1263
|
else:
|
|
1165
1264
|
raise ValueError(
|
|
@@ -1250,10 +1349,14 @@ def t_metrics(
|
|
|
1250
1349
|
|
|
1251
1350
|
elif hasattr(metric, 'prompt_template') and metric.prompt_template:
|
|
1252
1351
|
pointwise_spec = {'metric_prompt_template': metric.prompt_template}
|
|
1253
|
-
system_instruction = getv(
|
|
1352
|
+
system_instruction = getv(
|
|
1353
|
+
metric, ['judge_model_system_instruction']
|
|
1354
|
+
)
|
|
1254
1355
|
if system_instruction:
|
|
1255
1356
|
pointwise_spec['system_instruction'] = system_instruction
|
|
1256
|
-
return_raw_output = getv(
|
|
1357
|
+
return_raw_output = getv(
|
|
1358
|
+
metric, ['return_raw_output']
|
|
1359
|
+
)
|
|
1257
1360
|
if return_raw_output:
|
|
1258
1361
|
pointwise_spec['custom_output_format_config'] = { # type: ignore[assignment]
|
|
1259
1362
|
'return_raw_output': return_raw_output
|