99import requests
1010from datetime import datetime
1111import ast
12+ import json
1213import os
1314from typing import Any , Dict , List , Optional , Protocol
1415
@@ -56,18 +57,23 @@ def extract_openai_response(observations: List[Dict[str, Any]]) -> Optional[Dict
5657 """
5758 for obs in observations :
5859 if obs .get ("name" ) == "raw_gen_ai_request" and obs .get ("type" ) == "SPAN" :
59- metadata = obs .get ("metadata" , {})
60- attributes = metadata .get ("attributes" , {})
60+ metadata = obs .get ("metadata" ) or {}
61+ attributes = metadata .get ("attributes" ) or {}
6162
6263 result : Dict [str , Any ] = {}
6364
6465 for key , value in attributes .items ():
65- # Try to parse stringified Python literals, otherwise keep as-is
66+ # Try to parse stringified objects (could be Python repr or JSON)
6667 if isinstance (value , str ) and value .startswith (("[" , "{" )):
6768 try :
6869 result [key ] = ast .literal_eval (value )
69- except Exception :
70- result [key ] = value
70+ except Exception as e :
71+ logger .debug ("Failed to parse %s with ast.literal_eval: %s" , key , e )
72+ try :
73+ result [key ] = json .loads (value )
74+ except Exception as e :
75+ logger .debug ("Failed to parse %s with json.loads: %s" , key , e )
76+ result [key ] = value
7177 else :
7278 result [key ] = value
7379
@@ -129,7 +135,7 @@ def convert_trace_dict_to_evaluation_row(
129135 ):
130136 break # Break early if we've found all the metadata we need
131137
132- observations = trace .get ("observations" , [])
138+ observations = trace .get ("observations" ) or []
133139 # We can only extract when stored in OTEL format.
134140 openai_response = extract_openai_response (observations )
135141 if openai_response :
@@ -201,7 +207,7 @@ def extract_messages_from_trace_dict(
201207 # Fallback: use the last GENERATION observation which typically contains full chat history
202208 if not messages :
203209 try :
204- all_observations = trace .get ("observations" , [])
210+ all_observations = trace .get ("observations" ) or []
205211 gens = [obs for obs in all_observations if obs .get ("type" ) == "GENERATION" ]
206212 if gens :
207213 gens .sort (key = lambda x : x .get ("start_time" , "" ))
@@ -227,7 +233,7 @@ def get_final_generation_in_span_dict(trace: Dict[str, Any], span_name: str) ->
227233 The final generation dictionary, or None if not found
228234 """
229235 # Get all observations from the trace
230- all_observations = trace .get ("observations" , [])
236+ all_observations = trace .get ("observations" ) or []
231237
232238 # Find a span with the given name that has generation children
233239 parent_span = None
0 commit comments