22# SPDX-License-Identifier: Apache-2.0
33import abc
44import inspect
5- from typing import Any , Dict , Optional
65import json
7- from botocore .response import StreamingBody
86import math
7+ from typing import Any , Dict , Optional
8+
9+ from botocore .response import StreamingBody
910
1011from amazon .opentelemetry .distro ._aws_attribute_keys import (
1112 AWS_BEDROCK_AGENT_ID ,
1415 AWS_BEDROCK_GUARDRAIL_ID ,
1516 AWS_BEDROCK_KNOWLEDGE_BASE_ID ,
1617)
17- from amazon .opentelemetry .distro ._aws_span_processing_util import GEN_AI_REQUEST_MODEL , GEN_AI_SYSTEM , GEN_AI_REQUEST_MAX_TOKENS , GEN_AI_REQUEST_TEMPERATURE , GEN_AI_REQUEST_TOP_P , GEN_AI_RESPONSE_FINISH_REASONS , GEN_AI_USAGE_INPUT_TOKENS , GEN_AI_USAGE_OUTPUT_TOKENS
18+ from amazon .opentelemetry .distro ._aws_span_processing_util import (
19+ GEN_AI_REQUEST_MAX_TOKENS ,
20+ GEN_AI_REQUEST_MODEL ,
21+ GEN_AI_REQUEST_TEMPERATURE ,
22+ GEN_AI_REQUEST_TOP_P ,
23+ GEN_AI_RESPONSE_FINISH_REASONS ,
24+ GEN_AI_SYSTEM ,
25+ GEN_AI_USAGE_INPUT_TOKENS ,
26+ GEN_AI_USAGE_OUTPUT_TOKENS ,
27+ )
1828from opentelemetry .instrumentation .botocore .extensions .types import (
1929 _AttributeMapT ,
2030 _AwsSdkCallContext ,
@@ -241,100 +251,101 @@ def extract_attributes(self, attributes: _AttributeMapT):
241251 attributes [GEN_AI_SYSTEM ] = _AWS_BEDROCK_SYSTEM
242252
243253 model_id = self ._call_context .params .get (_MODEL_ID )
244- #attributes["Testing"]= "Test"
254+ # attributes["Testing"]= "Test"
245255 if model_id :
246- attributes [GEN_AI_REQUEST_MODEL ] = model_id
247-
256+ attributes [GEN_AI_REQUEST_MODEL ] = model_id
257+
248258 # Get the request body if it exists
249- body = self ._call_context .params .get (' body' )
250- #print("This is the body :",body)
259+ body = self ._call_context .params .get (" body" )
260+ # print("This is the body :",body)
251261 if body :
252262 try :
253263 request_body = json .loads (body )
254-
255- if ' amazon.titan' in model_id :
264+
265+ if " amazon.titan" in model_id :
256266 self ._extract_titan_attributes (attributes , request_body )
257- elif ' anthropic.claude' in model_id :
267+ elif " anthropic.claude" in model_id :
258268 self ._extract_claude_attributes (attributes , request_body )
259- elif ' meta.llama' in model_id :
269+ elif " meta.llama" in model_id :
260270 self ._extract_llama_attributes (attributes , request_body )
261- elif ' cohere.command' in model_id :
271+ elif " cohere.command" in model_id :
262272 self ._extract_cohere_attributes (attributes , request_body )
263- elif ' ai21.jamba' in model_id :
273+ elif " ai21.jamba" in model_id :
264274 self ._extract_ai21_attributes (attributes , request_body )
265- elif ' mistral' in model_id :
275+ elif " mistral" in model_id :
266276 self ._extract_mistral_attributes (attributes , request_body )
267-
277+
268278 except json .JSONDecodeError :
269279 print ("Error: Unable to parse the body as JSON" )
280+
270281 def _extract_titan_attributes (self , attributes , request_body ):
271- config = request_body .get (' textGenerationConfig' , {})
272- self ._set_if_not_none (attributes , GEN_AI_REQUEST_TEMPERATURE , config .get (' temperature' ))
273- self ._set_if_not_none (attributes , GEN_AI_REQUEST_TOP_P , config .get (' topP' ))
274- self ._set_if_not_none (attributes , GEN_AI_REQUEST_MAX_TOKENS , config .get (' maxTokenCount' ))
282+ config = request_body .get (" textGenerationConfig" , {})
283+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_TEMPERATURE , config .get (" temperature" ))
284+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_TOP_P , config .get (" topP" ))
285+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_MAX_TOKENS , config .get (" maxTokenCount" ))
275286
276287 def _extract_claude_attributes (self , attributes , request_body ):
277- self ._set_if_not_none (attributes , GEN_AI_REQUEST_MAX_TOKENS , request_body .get (' max_tokens' ))
278- self ._set_if_not_none (attributes , GEN_AI_REQUEST_TEMPERATURE , request_body .get (' temperature' ))
279- self ._set_if_not_none (attributes , GEN_AI_REQUEST_TOP_P , request_body .get (' top_p' ))
288+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_MAX_TOKENS , request_body .get (" max_tokens" ))
289+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_TEMPERATURE , request_body .get (" temperature" ))
290+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_TOP_P , request_body .get (" top_p" ))
280291
281292 def _extract_cohere_attributes (self , attributes , request_body ):
282- prompt = request_body .get (' message' )
293+ prompt = request_body .get (" message" )
283294 if prompt :
284295 attributes [GEN_AI_USAGE_INPUT_TOKENS ] = math .ceil (len (prompt ) / 6 )
285- self ._set_if_not_none (attributes , GEN_AI_REQUEST_MAX_TOKENS , request_body .get (' max_tokens' ))
286- self ._set_if_not_none (attributes , GEN_AI_REQUEST_TEMPERATURE , request_body .get (' temperature' ))
287- self ._set_if_not_none (attributes , GEN_AI_REQUEST_TOP_P , request_body .get ('p' ))
296+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_MAX_TOKENS , request_body .get (" max_tokens" ))
297+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_TEMPERATURE , request_body .get (" temperature" ))
298+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_TOP_P , request_body .get ("p" ))
288299
289300 def _extract_ai21_attributes (self , attributes , request_body ):
290- self ._set_if_not_none (attributes , GEN_AI_REQUEST_MAX_TOKENS , request_body .get (' max_tokens' ))
291- self ._set_if_not_none (attributes , GEN_AI_REQUEST_TEMPERATURE , request_body .get (' temperature' ))
292- self ._set_if_not_none (attributes , GEN_AI_REQUEST_TOP_P , request_body .get (' top_p' ))
301+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_MAX_TOKENS , request_body .get (" max_tokens" ))
302+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_TEMPERATURE , request_body .get (" temperature" ))
303+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_TOP_P , request_body .get (" top_p" ))
293304
294305 def _extract_llama_attributes (self , attributes , request_body ):
295- self ._set_if_not_none (attributes , GEN_AI_REQUEST_MAX_TOKENS , request_body .get (' max_gen_len' ))
296- self ._set_if_not_none (attributes , GEN_AI_REQUEST_TEMPERATURE , request_body .get (' temperature' ))
297- self ._set_if_not_none (attributes , GEN_AI_REQUEST_TOP_P , request_body .get (' top_p' ))
306+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_MAX_TOKENS , request_body .get (" max_gen_len" ))
307+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_TEMPERATURE , request_body .get (" temperature" ))
308+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_TOP_P , request_body .get (" top_p" ))
298309
299310 def _extract_mistral_attributes (self , attributes , request_body ):
300311 print ("This is the request body:" , request_body )
301- prompt = request_body .get (' prompt' )
312+ prompt = request_body .get (" prompt" )
302313 if prompt :
303314 attributes [GEN_AI_USAGE_INPUT_TOKENS ] = math .ceil (len (prompt ) / 6 )
304- self ._set_if_not_none (attributes , GEN_AI_REQUEST_MAX_TOKENS , request_body .get (' max_tokens' ))
305- self ._set_if_not_none (attributes , GEN_AI_REQUEST_TEMPERATURE , request_body .get (' temperature' ))
306- self ._set_if_not_none (attributes , GEN_AI_REQUEST_TOP_P , request_body .get (' top_p' ))
315+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_MAX_TOKENS , request_body .get (" max_tokens" ))
316+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_TEMPERATURE , request_body .get (" temperature" ))
317+ self ._set_if_not_none (attributes , GEN_AI_REQUEST_TOP_P , request_body .get (" top_p" ))
307318
308319 @staticmethod
309320 def _set_if_not_none (attributes , key , value ):
310321 if value is not None :
311322 attributes [key ] = value
312-
323+
313324 def on_success (self , span : Span , result : Dict [str , Any ]):
314325 super ().on_success (span , result )
315-
326+
316327 model_id = self ._call_context .params .get (_MODEL_ID )
317328 if not model_id :
318329 return
319330
320- if ' body' in result and isinstance (result [' body' ], StreamingBody ):
331+ if " body" in result and isinstance (result [" body" ], StreamingBody ):
321332 try :
322333 # Read the entire content of the StreamingBody
323- body_content = result [' body' ].read ()
334+ body_content = result [" body" ].read ()
324335 # Decode the bytes to string and parse as JSON
325- response_body = json .loads (body_content .decode (' utf-8' ))
326-
327- if ' amazon.titan' in model_id :
336+ response_body = json .loads (body_content .decode (" utf-8" ))
337+
338+ if " amazon.titan" in model_id :
328339 self ._handle_amazon_titan_response (span , response_body )
329- elif ' anthropic.claude' in model_id :
340+ elif " anthropic.claude" in model_id :
330341 self ._handle_anthropic_claude_response (span , response_body )
331- elif ' meta.llama' in model_id :
342+ elif " meta.llama" in model_id :
332343 self ._handle_meta_llama_response (span , response_body )
333- elif ' cohere.command' in model_id :
344+ elif " cohere.command" in model_id :
334345 self ._handle_cohere_command_response (span , response_body )
335- elif ' ai21.jamba' in model_id :
346+ elif " ai21.jamba" in model_id :
336347 self ._handle_ai21_jamba_response (span , response_body )
337- elif ' mistral' in model_id :
348+ elif " mistral" in model_id :
338349 self ._handle_mistral_mistral_response (span , response_body )
339350
340351 except json .JSONDecodeError :
@@ -343,60 +354,60 @@ def on_success(self, span: Span, result: Dict[str, Any]):
343354 print (f"Error processing response: { str (e )} " )
344355 finally :
345356 # Make sure to close the stream
346- result [' body' ].close ()
357+ result [" body" ].close ()
347358
348359 def _handle_amazon_titan_response (self , span : Span , response_body : Dict [str , Any ]):
349- if ' inputTextTokenCount' in response_body :
350- span .set_attribute (GEN_AI_USAGE_INPUT_TOKENS , response_body [' inputTextTokenCount' ])
351-
352- result = response_body [' results' ][0 ]
353- if ' tokenCount' in result :
354- span .set_attribute (GEN_AI_USAGE_OUTPUT_TOKENS , result [' tokenCount' ])
355- if ' completionReason' in result :
356- span .set_attribute (GEN_AI_RESPONSE_FINISH_REASONS , [result [' completionReason' ]])
357-
360+ if " inputTextTokenCount" in response_body :
361+ span .set_attribute (GEN_AI_USAGE_INPUT_TOKENS , response_body [" inputTextTokenCount" ])
362+
363+ result = response_body [" results" ][0 ]
364+ if " tokenCount" in result :
365+ span .set_attribute (GEN_AI_USAGE_OUTPUT_TOKENS , result [" tokenCount" ])
366+ if " completionReason" in result :
367+ span .set_attribute (GEN_AI_RESPONSE_FINISH_REASONS , [result [" completionReason" ]])
368+
358369 def _handle_anthropic_claude_response (self , span : Span , response_body : Dict [str , Any ]):
359- if ' usage' in response_body :
360- usage = response_body [' usage' ]
361- if ' input_tokens' in usage :
362- span .set_attribute (GEN_AI_USAGE_INPUT_TOKENS , usage [' input_tokens' ])
363- if ' output_tokens' in usage :
364- span .set_attribute (GEN_AI_USAGE_OUTPUT_TOKENS , usage [' output_tokens' ])
365- if ' stop_reason' in response_body :
366- span .set_attribute (GEN_AI_RESPONSE_FINISH_REASONS , [response_body [' stop_reason' ]])
370+ if " usage" in response_body :
371+ usage = response_body [" usage" ]
372+ if " input_tokens" in usage :
373+ span .set_attribute (GEN_AI_USAGE_INPUT_TOKENS , usage [" input_tokens" ])
374+ if " output_tokens" in usage :
375+ span .set_attribute (GEN_AI_USAGE_OUTPUT_TOKENS , usage [" output_tokens" ])
376+ if " stop_reason" in response_body :
377+ span .set_attribute (GEN_AI_RESPONSE_FINISH_REASONS , [response_body [" stop_reason" ]])
367378
368379 def _handle_cohere_command_response (self , span : Span , response_body : Dict [str , Any ]):
369380 # Output tokens: Approximate from the response text
370- if ' text' in response_body :
371- span .set_attribute (GEN_AI_USAGE_OUTPUT_TOKENS , math .ceil (len (response_body [' text' ]) / 6 ))
372- if ' finish_reason' in response_body :
373- span .set_attribute (GEN_AI_RESPONSE_FINISH_REASONS , [response_body [' finish_reason' ]])
381+ if " text" in response_body :
382+ span .set_attribute (GEN_AI_USAGE_OUTPUT_TOKENS , math .ceil (len (response_body [" text" ]) / 6 ))
383+ if " finish_reason" in response_body :
384+ span .set_attribute (GEN_AI_RESPONSE_FINISH_REASONS , [response_body [" finish_reason" ]])
374385
375386 def _handle_ai21_jamba_response (self , span : Span , response_body : Dict [str , Any ]):
376- if ' usage' in response_body :
377- usage = response_body [' usage' ]
378- if ' prompt_tokens' in usage :
379- span .set_attribute (GEN_AI_USAGE_INPUT_TOKENS , usage [' prompt_tokens' ])
380- if ' completion_tokens' in usage :
381- span .set_attribute (GEN_AI_USAGE_OUTPUT_TOKENS , usage [' completion_tokens' ])
382- if ' choices' in response_body :
383- choices = response_body [' choices' ][0 ]
384- if ' finish_reason' in choices :
385- span .set_attribute (GEN_AI_RESPONSE_FINISH_REASONS , [choices [' finish_reason' ]])
387+ if " usage" in response_body :
388+ usage = response_body [" usage" ]
389+ if " prompt_tokens" in usage :
390+ span .set_attribute (GEN_AI_USAGE_INPUT_TOKENS , usage [" prompt_tokens" ])
391+ if " completion_tokens" in usage :
392+ span .set_attribute (GEN_AI_USAGE_OUTPUT_TOKENS , usage [" completion_tokens" ])
393+ if " choices" in response_body :
394+ choices = response_body [" choices" ][0 ]
395+ if " finish_reason" in choices :
396+ span .set_attribute (GEN_AI_RESPONSE_FINISH_REASONS , [choices [" finish_reason" ]])
386397
387398 def _handle_meta_llama_response (self , span : Span , response_body : Dict [str , Any ]):
388- if ' prompt_token_count' in response_body :
389- span .set_attribute (GEN_AI_USAGE_INPUT_TOKENS , response_body [' prompt_token_count' ])
390- if ' generation_token_count' in response_body :
391- span .set_attribute (GEN_AI_USAGE_OUTPUT_TOKENS , response_body [' generation_token_count' ])
392- if ' stop_reason' in response_body :
393- span .set_attribute (GEN_AI_RESPONSE_FINISH_REASONS , [response_body [' stop_reason' ]])
394-
399+ if " prompt_token_count" in response_body :
400+ span .set_attribute (GEN_AI_USAGE_INPUT_TOKENS , response_body [" prompt_token_count" ])
401+ if " generation_token_count" in response_body :
402+ span .set_attribute (GEN_AI_USAGE_OUTPUT_TOKENS , response_body [" generation_token_count" ])
403+ if " stop_reason" in response_body :
404+ span .set_attribute (GEN_AI_RESPONSE_FINISH_REASONS , [response_body [" stop_reason" ]])
405+
395406 def _handle_mistral_mistral_response (self , span : Span , response_body : Dict [str , Any ]):
396407 print ("This is the response body :" , response_body )
397408 if "outputs" in response_body :
398409 outputs = response_body ["outputs" ][0 ]
399410 if "text" in outputs :
400411 span .set_attribute (GEN_AI_USAGE_OUTPUT_TOKENS , math .ceil (len (outputs ["text" ]) / 6 ))
401- if ' stop_reason' in outputs :
402- span .set_attribute (GEN_AI_RESPONSE_FINISH_REASONS , [outputs [' stop_reason' ]])
412+ if " stop_reason" in outputs :
413+ span .set_attribute (GEN_AI_RESPONSE_FINISH_REASONS , [outputs [" stop_reason" ]])
0 commit comments