Skip to content

Commit e0adb97

Browse files
committed
Implemented a way for Google Model to analyze JSON file links when using DocumentUrl
1 parent c9e9d93 commit e0adb97

File tree

1 file changed

+53
-6
lines changed

1 file changed

+53
-6
lines changed

pydantic_ai_slim/pydantic_ai/models/google.py

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
BuiltinToolReturnPart,
2222
FilePart,
2323
FileUrl,
24+
DocumentUrl,
2425
FinishReason,
2526
ModelMessage,
2627
ModelRequest,
@@ -91,6 +92,13 @@
9192
'you can use the `google` optional group — `pip install "pydantic-ai-slim[google]"`'
9293
) from _import_error
9394

95+
96+
class Test():
97+
def __init__(self, num):
98+
self.num = num
99+
def multiply(self):
100+
return self.num * 3
101+
94102
LatestGoogleModelNames = Literal[
95103
'gemini-2.0-flash',
96104
'gemini-2.0-flash-lite',
@@ -567,17 +575,34 @@ async def _map_user_prompt(self, part: UserPromptPart) -> list[PartDict]:
567575
if isinstance(item, str):
568576
content.append({'text': item})
569577
elif isinstance(item, BinaryContent):
570-
inline_data_dict: BlobDict = {'data': item.data, 'mime_type': item.media_type}
571-
part_dict: PartDict = {'inline_data': inline_data_dict}
572-
if item.vendor_metadata:
573-
part_dict['video_metadata'] = cast(VideoMetadataDict, item.vendor_metadata)
574-
content.append(part_dict)
578+
if self._is_text_like_media_type(item.media_type):
579+
content.append({'text': item.data.decode('utf-8')})
580+
else:
581+
inline_data_dict: BlobDict = {'data': item.data, 'mime_type': item.media_type}
582+
part_dict: PartDict = {'inline_data': inline_data_dict}
583+
if item.vendor_metadata:
584+
part_dict['video_metadata'] = cast(VideoMetadataDict, item.vendor_metadata)
585+
content.append(part_dict)
586+
587+
elif isinstance(item, DocumentUrl):
588+
if self._is_text_like_media_type(item.media_type):
589+
downloaded_text = await download_item(item, data_format='text')
590+
content.append({'text': downloaded_text['data']})
591+
else:
592+
downloaded_item = await download_item(item, data_format='bytes')
593+
inline_data_dict: BlobDict = {
594+
'data': downloaded_item['data'],
595+
'mime_type': downloaded_item['data_type'],
596+
}
597+
content.append({'inline_data': inline_data_dict})
598+
575599
elif isinstance(item, VideoUrl) and item.is_youtube:
576600
file_data_dict: FileDataDict = {'file_uri': item.url, 'mime_type': item.media_type}
577601
part_dict: PartDict = {'file_data': file_data_dict}
578602
if item.vendor_metadata: # pragma: no branch
579603
part_dict['video_metadata'] = cast(VideoMetadataDict, item.vendor_metadata)
580604
content.append(part_dict)
605+
581606
elif isinstance(item, FileUrl):
582607
if item.force_download or (
583608
# google-gla does not support passing file urls directly, except for youtube videos
@@ -596,7 +621,29 @@ async def _map_user_prompt(self, part: UserPromptPart) -> list[PartDict]:
596621
content.append({'file_data': file_data_dict}) # pragma: lax no cover
597622
else:
598623
assert_never(item)
599-
return content
624+
625+
return content
626+
627+
@staticmethod
628+
def _is_text_like_media_type(media_type: str) -> bool:
629+
return (
630+
media_type.startswith('text/')
631+
or media_type == 'application/json'
632+
or media_type.endswith('+json')
633+
or media_type == 'application/xml'
634+
or media_type.endswith('+xml')
635+
or media_type in ('application/x-yaml', 'application/yaml')
636+
)
637+
@staticmethod
638+
def _inline_text_file_part(text: str, *, media_type: str, identifier: str) -> ChatCompletionContentPartTextParam:
639+
text = '\n'.join(
640+
[
641+
f'-----BEGIN FILE id="{identifier}" type="{media_type}"-----',
642+
text,
643+
f'-----END FILE id="{identifier}"-----',
644+
]
645+
)
646+
return {'text': text}
600647

601648
def _map_response_schema(self, o: OutputObjectDefinition) -> dict[str, Any]:
602649
response_schema = o.json_schema.copy()

0 commit comments

Comments
 (0)