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 +3 -0
- openlit/instrumentation/anthropic/anthropic.py +2 -2
- openlit/instrumentation/anthropic/async_anthropic.py +2 -2
- openlit/instrumentation/bedrock/__init__.py +3 -3
- openlit/instrumentation/bedrock/bedrock.py +69 -307
- openlit/instrumentation/cohere/cohere.py +2 -2
- openlit/instrumentation/elevenlabs/__init__.py +70 -0
- openlit/instrumentation/elevenlabs/async_elevenlabs.py +117 -0
- openlit/instrumentation/elevenlabs/elevenlabs.py +123 -0
- openlit/instrumentation/groq/async_groq.py +10 -10
- openlit/instrumentation/groq/groq.py +10 -10
- openlit/instrumentation/mistral/async_mistral.py +4 -4
- openlit/instrumentation/mistral/mistral.py +4 -4
- openlit/instrumentation/openai/async_azure_openai.py +12 -12
- openlit/instrumentation/openai/async_openai.py +10 -10
- openlit/instrumentation/openai/azure_openai.py +12 -12
- openlit/instrumentation/openai/openai.py +10 -10
- openlit/instrumentation/transformers/transformers.py +1 -1
- openlit/semcov/__init__.py +5 -3
- {openlit-1.14.2.dist-info → openlit-1.16.2.dist-info}/METADATA +16 -16
- {openlit-1.14.2.dist-info → openlit-1.16.2.dist-info}/RECORD +23 -20
- {openlit-1.14.2.dist-info → openlit-1.16.2.dist-info}/LICENSE +0 -0
- {openlit-1.14.2.dist-info → openlit-1.16.2.dist-info}/WHEEL +0 -0
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
|
9
|
+
from openlit.instrumentation.bedrock.bedrock import converse
|
10
10
|
|
11
|
-
_instruments = ("boto3 >= 1.34.
|
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
|
-
|
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
|
15
|
-
from openlit.__helpers import handle_exception
|
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
|
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
|
-
|
92
|
-
|
93
|
-
|
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
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
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
|
-
|
241
|
-
|
242
|
-
message_prompt
|
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
|
-
|
387
|
-
|
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
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
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
|
-
|
431
|
-
|
432
|
-
|
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
|