1414from sentry_sdk .utils import event_from_exception
1515
1616if TYPE_CHECKING :
17- from typing import Any , Dict
17+ from typing import Any , Dict , List
1818 from datetime import datetime
1919
2020try :
@@ -35,6 +35,68 @@ def _get_metadata_dict(kwargs: "Dict[str, Any]") -> "Dict[str, Any]":
3535 return metadata
3636
3737
38+ def _convert_message_parts (messages : "List[Dict[str, Any]]" ) -> "List[Dict[str, Any]]" :
39+ """
40+ Convert the message parts from OpenAI format to the `gen_ai.request.messages` format.
41+ e.g:
42+ {
43+ "role": "user",
44+ "content": [
45+ {
46+ "text": "How many ponies do you see in the image?",
47+ "type": "text"
48+ },
49+ {
50+ "type": "image_url",
51+ "image_url": {
52+ "url": "data:image/jpeg;base64,...",
53+ "detail": "high"
54+ }
55+ }
56+ ]
57+ }
58+ becomes:
59+ {
60+ "role": "user",
61+ "content": [
62+ {
63+ "text": "How many ponies do you see in the image?",
64+ "type": "text"
65+ },
66+ {
67+ "type": "blob",
68+ "modality": "image",
69+ "mime_type": "image/jpeg",
70+ "content": "data:image/jpeg;base64,..."
71+ }
72+ ]
73+ }
74+ """
75+
76+ def _map_item (item : "Dict[str, Any]" ) -> "Dict[str, Any]" :
77+ if item .get ("type" ) == "image_url" :
78+ image_url = item .get ("image_url" ) or {}
79+ if image_url .get ("url" , "" ).startswith ("data:" ):
80+ return {
81+ "type" : "blob" ,
82+ "modality" : "image" ,
83+ "mime_type" : item ["image_url" ]["url" ].split (";base64," )[0 ],
84+ "content" : item ["image_url" ]["url" ].split (";base64," )[1 ],
85+ }
86+ else :
87+ return {
88+ "type" : "uri" ,
89+ "uri" : item ["image_url" ]["url" ],
90+ }
91+ return item
92+
93+ for message in messages :
94+ content = message .get ("content" )
95+ if isinstance (content , list ):
96+ message ["content" ] = [_map_item (item ) for item in content ]
97+ return messages
98+
99+
38100def _input_callback (kwargs : "Dict[str, Any]" ) -> None :
39101 """Handle the start of a request."""
40102 integration = sentry_sdk .get_client ().get_integration (LiteLLMIntegration )
@@ -101,6 +163,7 @@ def _input_callback(kwargs: "Dict[str, Any]") -> None:
101163 messages = kwargs .get ("messages" , [])
102164 if messages :
103165 scope = sentry_sdk .get_current_scope ()
166+ messages = _convert_message_parts (messages )
104167 messages_data = truncate_and_annotate_messages (messages , span , scope )
105168 if messages_data is not None :
106169 set_data_normalized (
0 commit comments