openlit 1.14.2__py3-none-any.whl → 1.16.2__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.
openlit/__init__.py CHANGED
@@ -31,6 +31,7 @@ from openlit.instrumentation.vertexai import VertexAIInstrumentor
31
31
  from openlit.instrumentation.groq import GroqInstrumentor
32
32
  from openlit.instrumentation.ollama import OllamaInstrumentor
33
33
  from openlit.instrumentation.gpt4all import GPT4AllInstrumentor
34
+ from openlit.instrumentation.elevenlabs import ElevenLabsInstrumentor
34
35
  from openlit.instrumentation.langchain import LangChainInstrumentor
35
36
  from openlit.instrumentation.llamaindex import LlamaIndexInstrumentor
36
37
  from openlit.instrumentation.haystack import HaystackInstrumentor
@@ -192,6 +193,7 @@ def init(environment="default", application_name="default", tracer=None, otlp_en
192
193
  "groq": "groq",
193
194
  "ollama": "ollama",
194
195
  "gpt4all": "gpt4all",
196
+ "elevenlabs": "elevenlabs",
195
197
  "langchain": "langchain",
196
198
  "llama_index": "llama_index",
197
199
  "haystack": "haystack",
@@ -267,6 +269,7 @@ def init(environment="default", application_name="default", tracer=None, otlp_en
267
269
  "groq": GroqInstrumentor(),
268
270
  "ollama": OllamaInstrumentor(),
269
271
  "gpt4all": GPT4AllInstrumentor(),
272
+ "elevenlabs": ElevenLabsInstrumentor(),
270
273
  "langchain": LangChainInstrumentor(),
271
274
  "llama_index": LlamaIndexInstrumentor(),
272
275
  "haystack": HaystackInstrumentor(),
@@ -120,7 +120,7 @@ def messages(gen_ai_endpoint, version, environment, application_name, tracer,
120
120
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MODEL,
121
121
  kwargs.get("model", "claude-3-sonnet-20240229"))
122
122
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MAX_TOKENS,
123
- kwargs.get("max_tokens", ""))
123
+ kwargs.get("max_tokens", -1))
124
124
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_IS_STREAM,
125
125
  True)
126
126
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TEMPERATURE,
@@ -224,7 +224,7 @@ def messages(gen_ai_endpoint, version, environment, application_name, tracer,
224
224
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MODEL,
225
225
  kwargs.get("model", "claude-3-sonnet-20240229"))
226
226
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MAX_TOKENS,
227
- kwargs.get("max_tokens", ""))
227
+ kwargs.get("max_tokens", -1))
228
228
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_IS_STREAM,
229
229
  False)
230
230
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TEMPERATURE,
@@ -120,7 +120,7 @@ def async_messages(gen_ai_endpoint, version, environment, application_name,
120
120
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MODEL,
121
121
  kwargs.get("model", "claude-3-sonnet-20240229"))
122
122
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MAX_TOKENS,
123
- kwargs.get("max_tokens", ""))
123
+ kwargs.get("max_tokens", -1))
124
124
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_IS_STREAM,
125
125
  True)
126
126
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TEMPERATURE,
@@ -224,7 +224,7 @@ def async_messages(gen_ai_endpoint, version, environment, application_name,
224
224
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MODEL,
225
225
  kwargs.get("model", "claude-3-sonnet-20240229"))
226
226
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MAX_TOKENS,
227
- kwargs.get("max_tokens", ""))
227
+ kwargs.get("max_tokens", -1))
228
228
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_IS_STREAM,
229
229
  False)
230
230
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TEMPERATURE,
@@ -6,9 +6,9 @@ import importlib.metadata
6
6
  from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
7
7
  from wrapt import wrap_function_wrapper
8
8
 
9
- from openlit.instrumentation.bedrock.bedrock import chat
9
+ from openlit.instrumentation.bedrock.bedrock import converse
10
10
 
11
- _instruments = ("boto3 >= 1.34.93",)
11
+ _instruments = ("boto3 >= 1.34.138",)
12
12
 
13
13
  class BedrockInstrumentor(BaseInstrumentor):
14
14
  """
@@ -32,7 +32,7 @@ class BedrockInstrumentor(BaseInstrumentor):
32
32
  wrap_function_wrapper(
33
33
  "botocore.client",
34
34
  "ClientCreator.create_client",
35
- chat("bedrock.invoke_model", version, environment, application_name,
35
+ converse("bedrock.converse", version, environment, application_name,
36
36
  tracer, pricing_info, trace_content, metrics, disable_metrics),
37
37
  )
38
38
 
@@ -4,15 +4,14 @@ Module for monitoring Amazon Bedrock API calls.
4
4
  """
5
5
 
6
6
  import logging
7
- import json
8
7
  from botocore.response import StreamingBody
9
8
  from botocore.exceptions import ReadTimeoutError, ResponseStreamingError
10
9
  from urllib3.exceptions import ProtocolError as URLLib3ProtocolError
11
10
  from urllib3.exceptions import ReadTimeoutError as URLLib3ReadTimeoutError
12
11
  from opentelemetry.trace import SpanKind, Status, StatusCode
13
12
  from opentelemetry.sdk.resources import TELEMETRY_SDK_NAME
14
- from openlit.__helpers import get_chat_model_cost, get_embed_model_cost, get_image_model_cost
15
- from openlit.__helpers import handle_exception, general_tokens
13
+ from openlit.__helpers import get_chat_model_cost
14
+ from openlit.__helpers import handle_exception
16
15
  from openlit.semcov import SemanticConvetion
17
16
 
18
17
  # Initialize logger for logging potential issues and operations
@@ -49,7 +48,7 @@ class CustomStreamWrapper(StreamingBody):
49
48
  return data_chunk
50
49
 
51
50
 
52
- def chat(gen_ai_endpoint, version, environment, application_name, tracer,
51
+ def converse(gen_ai_endpoint, version, environment, application_name, tracer,
53
52
  pricing_info, trace_content, metrics, disable_metrics):
54
53
  """
55
54
  Generates a telemetry wrapper for messages to collect metrics.
@@ -80,166 +79,24 @@ def chat(gen_ai_endpoint, version, environment, application_name, tracer,
80
79
  Returns:
81
80
  Response from the original method.
82
81
  """
83
- def handle_image(span, model, request_body, response_body):
84
- cost = 0
85
- if "amazon" in model:
86
- # pylint: disable=line-too-long
87
- size = str(request_body.get("imageGenerationConfig", {}).get("width", 1024)) + "x" + str(request_body.get("imageGenerationConfig", {}).get("height", 1024))
88
- quality = request_body.get("imageGenerationConfig", {}).get("quality", "standard")
89
- n = request_body.get("imageGenerationConfig", {}).get("numberOfImages", 1)
90
82
 
91
- span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_IMAGE_SIZE,
92
- size)
93
- span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_IMAGE_QUALITY,
94
- quality)
95
- # Calculate cost of the operation
96
- cost = n * get_image_model_cost(model,
97
- pricing_info, size, quality)
98
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
99
- cost)
100
- if trace_content:
101
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_PROMPT,
102
- request_body.get("textToImageParams")["text"])
103
-
104
- span.set_status(Status(StatusCode.OK))
105
-
106
- if disable_metrics is False:
107
- attributes = {
108
- TELEMETRY_SDK_NAME:
109
- "openlit",
110
- SemanticConvetion.GEN_AI_APPLICATION_NAME:
111
- application_name,
112
- SemanticConvetion.GEN_AI_SYSTEM:
113
- SemanticConvetion.GEN_AI_SYSTEM_BEDROCK,
114
- SemanticConvetion.GEN_AI_ENVIRONMENT:
115
- environment,
116
- SemanticConvetion.GEN_AI_TYPE:
117
- SemanticConvetion.GEN_AI_TYPE_IMAGE,
118
- SemanticConvetion.GEN_AI_REQUEST_MODEL:
119
- model
120
- }
121
-
122
- metrics["genai_requests"].add(1, attributes)
123
- metrics["genai_cost"].record(cost, attributes)
124
-
125
- def handle_embed(span, model, request_body, response_body):
126
- prompt_tokens, cost = 0, 0
127
- if "amazon" in model:
128
- prompt_tokens = response_body["inputTextTokenCount"]
129
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
130
- prompt_tokens)
131
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
132
- prompt_tokens)
133
- # Calculate cost of the operation
134
- cost = get_embed_model_cost(model,
135
- pricing_info, prompt_tokens)
136
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
137
- cost)
138
- if trace_content:
139
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_PROMPT,
140
- request_body["inputText"])
141
-
142
- span.set_status(Status(StatusCode.OK))
143
-
144
- if disable_metrics is False:
145
- attributes = {
146
- TELEMETRY_SDK_NAME:
147
- "openlit",
148
- SemanticConvetion.GEN_AI_APPLICATION_NAME:
149
- application_name,
150
- SemanticConvetion.GEN_AI_SYSTEM:
151
- SemanticConvetion.GEN_AI_SYSTEM_BEDROCK,
152
- SemanticConvetion.GEN_AI_ENVIRONMENT:
153
- environment,
154
- SemanticConvetion.GEN_AI_TYPE:
155
- SemanticConvetion.GEN_AI_TYPE_EMBEDDING,
156
- SemanticConvetion.GEN_AI_REQUEST_MODEL:
157
- model
158
- }
159
-
160
- metrics["genai_requests"].add(1, attributes)
161
- metrics["genai_total_tokens"].add(
162
- prompt_tokens, attributes
163
- )
164
- metrics["genai_prompt_tokens"].add(prompt_tokens, attributes)
165
- metrics["genai_cost"].record(cost, attributes)
166
-
167
- def handle_chat(span, model, request_body, response_body):
168
- prompt_tokens, completion_tokens, cost = 0, 0, 0
169
-
170
- if "amazon" in model:
171
- prompt_tokens = response_body["inputTextTokenCount"]
172
- completion_tokens = response_body["results"][0]["tokenCount"]
173
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
174
- prompt_tokens)
175
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COMPLETION_TOKENS,
176
- completion_tokens)
177
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
178
- completion_tokens +
179
- prompt_tokens)
180
- span.set_attribute(SemanticConvetion.GEN_AI_RESPONSE_FINISH_REASON,
181
- response_body["results"][0]["completionReason"])
182
-
183
- # Calculate cost of the operation
184
- cost = get_chat_model_cost(model,
185
- pricing_info, prompt_tokens,
186
- completion_tokens)
187
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
188
- cost)
189
-
190
- if trace_content:
191
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_PROMPT,
192
- request_body["inputText"])
193
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_COMPLETION,
194
- response_body["results"][0]["outputText"])
195
-
196
- elif "mistral" in model:
197
- prompt_tokens = general_tokens(request_body["prompt"])
198
- completion_tokens = general_tokens(response_body["outputs"][0]["text"])
199
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
200
- prompt_tokens)
201
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COMPLETION_TOKENS,
202
- completion_tokens)
203
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
204
- prompt_tokens + completion_tokens)
205
- span.set_attribute(SemanticConvetion.GEN_AI_RESPONSE_FINISH_REASON,
206
- response_body["outputs"][0]["stop_reason"])
207
- # Calculate cost of the operation
208
- cost = get_chat_model_cost(model,
209
- pricing_info, prompt_tokens,
210
- completion_tokens)
211
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
212
- cost)
213
-
214
- if trace_content:
215
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_PROMPT,
216
- request_body["prompt"])
217
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_COMPLETION,
218
- response_body["outputs"][0]["text"])
219
-
220
- elif "anthropic" in model:
221
- prompt_tokens = response_body["usage"]["input_tokens"]
222
- completion_tokens = response_body["usage"]["output_tokens"]
223
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
224
- prompt_tokens)
225
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COMPLETION_TOKENS,
226
- completion_tokens)
227
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
228
- completion_tokens +
229
- prompt_tokens)
230
- span.set_attribute(SemanticConvetion.GEN_AI_RESPONSE_FINISH_REASON,
231
- response_body["stop_reason"])
83
+ def converse_wrapper(original_method, *method_args, **method_kwargs):
84
+ """
85
+ Adds instrumentation to the invoke model call.
232
86
 
233
- # Calculate cost of the operation
234
- cost = get_chat_model_cost(model,
235
- pricing_info, prompt_tokens,
236
- completion_tokens)
237
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
238
- cost)
87
+ Args:
88
+ original_method: The original invoke model method.
89
+ *method_args: Positional arguments for the method.
90
+ **method_kwargs: Keyword arguments for the method.
91
+ Returns:
92
+ The modified response with telemetry.
93
+ """
94
+ with tracer.start_as_current_span(gen_ai_endpoint, kind=SpanKind.CLIENT) as span:
95
+ response = original_method(*method_args, **method_kwargs)
239
96
 
240
- if trace_content:
241
- # Format 'messages' into a single string
242
- message_prompt = request_body["messages"]
97
+ try:
98
+ message_prompt = method_kwargs.get("messages", "")
99
+ print(message_prompt)
243
100
  formatted_messages = []
244
101
  for message in message_prompt:
245
102
  role = message["role"]
@@ -256,145 +113,10 @@ def chat(gen_ai_endpoint, version, environment, application_name, tracer,
256
113
  else:
257
114
  formatted_messages.append(f"{role}: {content}")
258
115
  prompt = "\n".join(formatted_messages)
259
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_PROMPT,
260
- prompt)
261
-
262
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_COMPLETION,
263
- response_body["content"][0]["text"])
264
- elif "meta" in model:
265
- prompt_tokens = response_body["prompt_token_count"]
266
- completion_tokens = response_body["generation_token_count"]
267
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
268
- prompt_tokens)
269
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COMPLETION_TOKENS,
270
- completion_tokens)
271
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
272
- completion_tokens +
273
- prompt_tokens)
274
- span.set_attribute(SemanticConvetion.GEN_AI_RESPONSE_FINISH_REASON,
275
- response_body["stop_reason"])
276
-
277
- # Calculate cost of the operation
278
- cost = get_chat_model_cost(model,
279
- pricing_info, prompt_tokens,
280
- completion_tokens)
281
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
282
- cost)
283
-
284
- if trace_content:
285
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_PROMPT,
286
- request_body["prompt"])
287
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_COMPLETION,
288
- response_body["generation"])
289
-
290
- elif "cohere" in model and "command-r" not in model:
291
- prompt_tokens = general_tokens(request_body["prompt"])
292
- completion_tokens = general_tokens(response_body["generations"][0]["text"])
293
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
294
- prompt_tokens)
295
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COMPLETION_TOKENS,
296
- completion_tokens)
297
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
298
- prompt_tokens + completion_tokens)
299
- span.set_attribute(SemanticConvetion.GEN_AI_RESPONSE_FINISH_REASON,
300
- response_body["generations"][0]["finish_reason"])
301
- # Calculate cost of the operation
302
- cost = get_chat_model_cost(model,
303
- pricing_info, prompt_tokens,
304
- completion_tokens)
305
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
306
- cost)
307
-
308
- if trace_content:
309
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_PROMPT,
310
- request_body["prompt"])
311
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_COMPLETION,
312
- response_body["generations"][0]["text"])
313
- elif "ai21" in model:
314
- prompt_tokens = general_tokens(request_body["prompt"])
315
- completion_tokens = general_tokens(response_body["completions"][0]["data"]["text"])
316
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
317
- prompt_tokens)
318
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COMPLETION_TOKENS,
319
- completion_tokens)
320
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
321
- prompt_tokens + completion_tokens)
322
- span.set_attribute(SemanticConvetion.GEN_AI_RESPONSE_FINISH_REASON,
323
- response_body["completions"][0]["finishReason"]["reason"])
324
- # Calculate cost of the operation
325
- cost = get_chat_model_cost(model,
326
- pricing_info, prompt_tokens,
327
- completion_tokens)
328
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
329
- cost)
330
-
331
- if trace_content:
332
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_PROMPT,
333
- request_body["prompt"])
334
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_COMPLETION,
335
- response_body["completions"][0]["data"]["text"])
336
-
337
- span.set_status(Status(StatusCode.OK))
338
-
339
- if disable_metrics is False:
340
- attributes = {
341
- TELEMETRY_SDK_NAME:
342
- "openlit",
343
- SemanticConvetion.GEN_AI_APPLICATION_NAME:
344
- application_name,
345
- SemanticConvetion.GEN_AI_SYSTEM:
346
- SemanticConvetion.GEN_AI_SYSTEM_BEDROCK,
347
- SemanticConvetion.GEN_AI_ENVIRONMENT:
348
- environment,
349
- SemanticConvetion.GEN_AI_TYPE:
350
- SemanticConvetion.GEN_AI_TYPE_CHAT,
351
- SemanticConvetion.GEN_AI_REQUEST_MODEL:
352
- model
353
- }
354
-
355
- metrics["genai_requests"].add(1, attributes)
356
- metrics["genai_total_tokens"].add(
357
- prompt_tokens + completion_tokens, attributes
358
- )
359
- metrics["genai_completion_tokens"].add(completion_tokens, attributes)
360
- metrics["genai_prompt_tokens"].add(prompt_tokens, attributes)
361
- metrics["genai_cost"].record(cost, attributes)
362
-
363
- def add_instrumentation(original_method, *method_args, **method_kwargs):
364
- """
365
- Adds instrumentation to the invoke model call.
366
-
367
- Args:
368
- original_method: The original invoke model method.
369
- *method_args: Positional arguments for the method.
370
- **method_kwargs: Keyword arguments for the method.
371
- Returns:
372
- The modified response with telemetry.
373
- """
374
- with tracer.start_as_current_span(gen_ai_endpoint, kind=SpanKind.CLIENT) as span:
375
- response = original_method(*method_args, **method_kwargs)
376
-
377
- try:
378
- # Modify the response body to be reusable
379
- response["body"] = CustomStreamWrapper(
380
- response["body"]._raw_stream, response["body"]._content_length
381
- )
382
- request_body = json.loads(method_kwargs.get("body"))
383
- response_body = json.loads(response.get("body").read())
384
116
 
385
117
  model = method_kwargs.get("modelId", "amazon.titan-text-express-v1")
386
- if ("stability" in model or "image" in model) and "embed-image" not in model:
387
- generation = "image"
388
- span.set_attribute(SemanticConvetion.GEN_AI_TYPE,
389
- SemanticConvetion.GEN_AI_TYPE_IMAGE)
390
- elif "embed" in model and "embed-image" not in model:
391
- generation = "embeddings"
392
- span.set_attribute(SemanticConvetion.GEN_AI_TYPE,
393
- SemanticConvetion.GEN_AI_TYPE_EMBEDDING)
394
- else:
395
- generation = "chat"
396
- span.set_attribute(SemanticConvetion.GEN_AI_TYPE,
397
- SemanticConvetion.GEN_AI_TYPE_CHAT)
118
+ input_tokens = response["usage"]["inputTokens"]
119
+ output_tokens = response["usage"]["outputTokens"]
398
120
 
399
121
  span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
400
122
  span.set_attribute(SemanticConvetion.GEN_AI_SYSTEM,
@@ -407,12 +129,51 @@ def chat(gen_ai_endpoint, version, environment, application_name, tracer,
407
129
  application_name)
408
130
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MODEL,
409
131
  model)
410
- if generation == "chat":
411
- handle_chat(span, model, request_body, response_body)
412
- elif generation == "embeddings":
413
- handle_embed(span, model, request_body, response_body)
414
- elif generation == "image":
415
- handle_image(span, model, request_body, response_body)
132
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
133
+ input_tokens)
134
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COMPLETION_TOKENS,
135
+ output_tokens)
136
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
137
+ input_tokens + output_tokens)
138
+
139
+ # Calculate cost of the operation
140
+ cost = get_chat_model_cost(model,
141
+ pricing_info, input_tokens,
142
+ output_tokens)
143
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
144
+ cost)
145
+
146
+ if trace_content:
147
+ span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_PROMPT,
148
+ prompt)
149
+ span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_COMPLETION,
150
+ response["output"]["message"]["content"][0]["text"])
151
+
152
+ span.set_status(Status(StatusCode.OK))
153
+
154
+ if disable_metrics is False:
155
+ attributes = {
156
+ TELEMETRY_SDK_NAME:
157
+ "openlit",
158
+ SemanticConvetion.GEN_AI_APPLICATION_NAME:
159
+ application_name,
160
+ SemanticConvetion.GEN_AI_SYSTEM:
161
+ SemanticConvetion.GEN_AI_SYSTEM_BEDROCK,
162
+ SemanticConvetion.GEN_AI_ENVIRONMENT:
163
+ environment,
164
+ SemanticConvetion.GEN_AI_TYPE:
165
+ SemanticConvetion.GEN_AI_TYPE_CHAT,
166
+ SemanticConvetion.GEN_AI_REQUEST_MODEL:
167
+ model
168
+ }
169
+
170
+ metrics["genai_requests"].add(1, attributes)
171
+ metrics["genai_total_tokens"].add(
172
+ input_tokens + output_tokens, attributes
173
+ )
174
+ metrics["genai_completion_tokens"].add(output_tokens, attributes)
175
+ metrics["genai_prompt_tokens"].add(input_tokens, attributes)
176
+ metrics["genai_cost"].record(cost, attributes)
416
177
 
417
178
  return response
418
179
 
@@ -427,9 +188,10 @@ def chat(gen_ai_endpoint, version, environment, application_name, tracer,
427
188
  client = wrapped(*args, **kwargs)
428
189
 
429
190
  # Replace the original method with the instrumented one
430
- original_invoke_model = client.invoke_model
431
- client.invoke_model = lambda *args, **kwargs: add_instrumentation(original_invoke_model,
432
- *args, **kwargs)
191
+ if kwargs.get("service_name") == "bedrock-runtime":
192
+ original_invoke_model = client.converse
193
+ client.converse = lambda *args, **kwargs: converse_wrapper(original_invoke_model,
194
+ *args, **kwargs)
433
195
 
434
196
  return client
435
197
 
@@ -193,7 +193,7 @@ def chat(gen_ai_endpoint, version, environment, application_name, tracer,
193
193
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TEMPERATURE,
194
194
  kwargs.get("temperature", 0.3))
195
195
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MAX_TOKENS,
196
- kwargs.get("max_tokens", ""))
196
+ kwargs.get("max_tokens", -1))
197
197
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_SEED,
198
198
  kwargs.get("seed", ""))
199
199
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_FREQUENCY_PENALTY,
@@ -336,7 +336,7 @@ def chat_stream(gen_ai_endpoint, version, environment, application_name,
336
336
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TEMPERATURE,
337
337
  kwargs.get("temperature", 0.3))
338
338
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MAX_TOKENS,
339
- kwargs.get("max_tokens", ""))
339
+ kwargs.get("max_tokens", -1))
340
340
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_SEED,
341
341
  kwargs.get("seed", ""))
342
342
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_FREQUENCY_PENALTY,
@@ -0,0 +1,70 @@
1
+ # pylint: disable=useless-return, bad-staticmethod-argument, disable=duplicate-code
2
+ """Initializer of Auto Instrumentation of ElevenLabs Functions"""
3
+
4
+ from typing import Collection
5
+ import importlib.metadata
6
+ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
7
+ from wrapt import wrap_function_wrapper
8
+
9
+ from openlit.instrumentation.elevenlabs.elevenlabs import (
10
+ generate
11
+ )
12
+ from openlit.instrumentation.elevenlabs.async_elevenlabs import (
13
+ async_generate
14
+ )
15
+
16
+ _instruments = ("elevenlabs >= 1.4.0",)
17
+
18
+ class ElevenLabsInstrumentor(BaseInstrumentor):
19
+ """
20
+ An instrumentor for ElevenLabs's client library.
21
+ """
22
+
23
+ def instrumentation_dependencies(self) -> Collection[str]:
24
+ return _instruments
25
+
26
+ def _instrument(self, **kwargs):
27
+ application_name = kwargs.get("application_name", "default")
28
+ environment = kwargs.get("environment", "default")
29
+ tracer = kwargs.get("tracer")
30
+ metrics = kwargs.get("metrics_dict")
31
+ pricing_info = kwargs.get("pricing_info", {})
32
+ trace_content = kwargs.get("trace_content", False)
33
+ disable_metrics = kwargs.get("disable_metrics")
34
+ version = importlib.metadata.version("elevenlabs")
35
+
36
+ # sync generate
37
+ wrap_function_wrapper(
38
+ "elevenlabs.client",
39
+ "ElevenLabs.generate",
40
+ generate("elevenlabs.generate", version, environment, application_name,
41
+ tracer, pricing_info, trace_content, metrics, disable_metrics),
42
+ )
43
+
44
+ # sync text_to_speech.convert
45
+ wrap_function_wrapper(
46
+ "elevenlabs.text_to_speech.client",
47
+ "TextToSpeechClient.convert",
48
+ generate("elevenlabs.text_to_speech", version, environment, application_name,
49
+ tracer, pricing_info, trace_content, metrics, disable_metrics),
50
+ )
51
+
52
+ # async generate
53
+ wrap_function_wrapper(
54
+ "elevenlabs.client",
55
+ "AsyncElevenLabs.generate",
56
+ async_generate("elevenlabs.generate", version, environment, application_name,
57
+ tracer, pricing_info, trace_content, metrics, disable_metrics),
58
+ )
59
+
60
+ # sync text_to_speech.convert
61
+ wrap_function_wrapper(
62
+ "elevenlabs.text_to_speech.client",
63
+ "AsyncTextToSpeechClient.convert",
64
+ generate("elevenlabs.text_to_speech", version, environment, application_name,
65
+ tracer, pricing_info, trace_content, metrics, disable_metrics),
66
+ )
67
+
68
+ def _uninstrument(self, **kwargs):
69
+ # Proper uninstrumentation logic to revert patched methods
70
+ pass