google-genai 1.40.0__py3-none-any.whl → 1.42.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 +2 -1
- google/genai/_common.py +213 -77
- google/genai/_extra_utils.py +72 -1
- google/genai/_live_converters.py +729 -3078
- google/genai/_replay_api_client.py +8 -4
- google/genai/_tokens_converters.py +20 -424
- google/genai/_transformers.py +42 -12
- google/genai/batches.py +113 -1063
- google/genai/caches.py +67 -863
- google/genai/errors.py +9 -2
- google/genai/files.py +29 -268
- google/genai/live.py +10 -11
- google/genai/live_music.py +24 -27
- google/genai/models.py +322 -1835
- google/genai/operations.py +6 -32
- google/genai/tokens.py +2 -12
- google/genai/tunings.py +24 -197
- google/genai/types.py +187 -5
- google/genai/version.py +1 -1
- {google_genai-1.40.0.dist-info → google_genai-1.42.0.dist-info}/METADATA +40 -38
- google_genai-1.42.0.dist-info/RECORD +39 -0
- google_genai-1.40.0.dist-info/RECORD +0 -39
- {google_genai-1.40.0.dist-info → google_genai-1.42.0.dist-info}/WHEEL +0 -0
- {google_genai-1.40.0.dist-info → google_genai-1.42.0.dist-info}/licenses/LICENSE +0 -0
- {google_genai-1.40.0.dist-info → google_genai-1.42.0.dist-info}/top_level.txt +0 -0
google/genai/_transformers.py
CHANGED
@@ -41,6 +41,28 @@ 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
|
+
|
44
66
|
if sys.version_info >= (3, 10):
|
45
67
|
VersionedUnionType = builtin_types.UnionType
|
46
68
|
_UNION_TYPES = (typing.Union, builtin_types.UnionType)
|
@@ -366,9 +388,12 @@ def t_part(part: Optional[types.PartUnionDict]) -> types.Part:
|
|
366
388
|
raise ValueError('file uri and mime_type are required.')
|
367
389
|
return types.Part.from_uri(file_uri=part.uri, mime_type=part.mime_type)
|
368
390
|
if isinstance(part, dict):
|
369
|
-
|
370
|
-
|
371
|
-
|
391
|
+
try:
|
392
|
+
return types.Part.model_validate(part)
|
393
|
+
except pydantic.ValidationError:
|
394
|
+
return types.Part(file_data=types.FileData.model_validate(part))
|
395
|
+
if _is_duck_type_of(part, types.Part):
|
396
|
+
return part # type: ignore[return-value]
|
372
397
|
|
373
398
|
if 'image' in part.__class__.__name__.lower():
|
374
399
|
try:
|
@@ -420,7 +445,7 @@ ContentType = Union[types.Content, types.ContentDict, types.PartUnionDict]
|
|
420
445
|
|
421
446
|
|
422
447
|
def t_content(
|
423
|
-
content:
|
448
|
+
content: Union[ContentType, types.ContentDict, None],
|
424
449
|
) -> types.Content:
|
425
450
|
if content is None:
|
426
451
|
raise ValueError('content is required.')
|
@@ -430,12 +455,14 @@ def t_content(
|
|
430
455
|
try:
|
431
456
|
return types.Content.model_validate(content)
|
432
457
|
except pydantic.ValidationError:
|
433
|
-
possible_part =
|
458
|
+
possible_part = t_part(content) # type: ignore[arg-type]
|
434
459
|
return (
|
435
460
|
types.ModelContent(parts=[possible_part])
|
436
461
|
if possible_part.function_call
|
437
462
|
else types.UserContent(parts=[possible_part])
|
438
463
|
)
|
464
|
+
if isinstance(content, types.File):
|
465
|
+
return types.UserContent(parts=[t_part(content)])
|
439
466
|
if isinstance(content, types.Part):
|
440
467
|
return (
|
441
468
|
types.ModelContent(parts=[content])
|
@@ -495,11 +522,18 @@ def t_contents(
|
|
495
522
|
return True
|
496
523
|
|
497
524
|
if isinstance(part, dict):
|
525
|
+
if not part:
|
526
|
+
# Empty dict should be considered as Content, not Part.
|
527
|
+
return False
|
498
528
|
try:
|
499
529
|
types.Part.model_validate(part)
|
500
530
|
return True
|
501
531
|
except pydantic.ValidationError:
|
502
|
-
|
532
|
+
try:
|
533
|
+
types.FileData.model_validate(part)
|
534
|
+
return True
|
535
|
+
except pydantic.ValidationError:
|
536
|
+
return False
|
503
537
|
|
504
538
|
if 'image' in part.__class__.__name__.lower():
|
505
539
|
try:
|
@@ -553,16 +587,12 @@ def t_contents(
|
|
553
587
|
# append to result
|
554
588
|
# if list, we only accept a list of types.PartUnion
|
555
589
|
for content in contents:
|
556
|
-
if (
|
557
|
-
isinstance(content, types.Content)
|
558
|
-
# only allowed inner list is a list of types.PartUnion
|
559
|
-
or isinstance(content, list)
|
560
|
-
):
|
590
|
+
if _is_duck_type_of(content, types.Content) or isinstance(content, list):
|
561
591
|
_append_accumulated_parts_as_content(result, accumulated_parts)
|
562
592
|
if isinstance(content, list):
|
563
593
|
result.append(types.UserContent(parts=content)) # type: ignore[arg-type]
|
564
594
|
else:
|
565
|
-
result.append(content)
|
595
|
+
result.append(content) # type: ignore[arg-type]
|
566
596
|
elif _is_part(content):
|
567
597
|
_handle_current_part(result, accumulated_parts, content)
|
568
598
|
elif isinstance(content, dict):
|