opentelemetry-instrumentation-openai 0.38.6__tar.gz → 0.49.6__tar.gz
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.
- {opentelemetry_instrumentation_openai-0.38.6 → opentelemetry_instrumentation_openai-0.49.6}/PKG-INFO +7 -7
- {opentelemetry_instrumentation_openai-0.38.6 → opentelemetry_instrumentation_openai-0.49.6}/opentelemetry/instrumentation/openai/__init__.py +3 -4
- {opentelemetry_instrumentation_openai-0.38.6 → opentelemetry_instrumentation_openai-0.49.6}/opentelemetry/instrumentation/openai/shared/__init__.py +148 -65
- {opentelemetry_instrumentation_openai-0.38.6 → opentelemetry_instrumentation_openai-0.49.6}/opentelemetry/instrumentation/openai/shared/chat_wrappers.py +537 -231
- opentelemetry_instrumentation_openai-0.49.6/opentelemetry/instrumentation/openai/shared/completion_wrappers.py +292 -0
- opentelemetry_instrumentation_openai-0.49.6/opentelemetry/instrumentation/openai/shared/config.py +15 -0
- {opentelemetry_instrumentation_openai-0.38.6 → opentelemetry_instrumentation_openai-0.49.6}/opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py +85 -31
- opentelemetry_instrumentation_openai-0.49.6/opentelemetry/instrumentation/openai/shared/event_emitter.py +108 -0
- opentelemetry_instrumentation_openai-0.49.6/opentelemetry/instrumentation/openai/shared/event_models.py +41 -0
- {opentelemetry_instrumentation_openai-0.38.6 → opentelemetry_instrumentation_openai-0.49.6}/opentelemetry/instrumentation/openai/shared/image_gen_wrappers.py +1 -1
- opentelemetry_instrumentation_openai-0.49.6/opentelemetry/instrumentation/openai/shared/span_utils.py +0 -0
- {opentelemetry_instrumentation_openai-0.38.6 → opentelemetry_instrumentation_openai-0.49.6}/opentelemetry/instrumentation/openai/utils.py +40 -9
- {opentelemetry_instrumentation_openai-0.38.6 → opentelemetry_instrumentation_openai-0.49.6}/opentelemetry/instrumentation/openai/v0/__init__.py +32 -11
- {opentelemetry_instrumentation_openai-0.38.6 → opentelemetry_instrumentation_openai-0.49.6}/opentelemetry/instrumentation/openai/v1/__init__.py +177 -69
- opentelemetry_instrumentation_openai-0.49.6/opentelemetry/instrumentation/openai/v1/assistant_wrappers.py +329 -0
- {opentelemetry_instrumentation_openai-0.38.6 → opentelemetry_instrumentation_openai-0.49.6}/opentelemetry/instrumentation/openai/v1/event_handler_wrapper.py +35 -17
- opentelemetry_instrumentation_openai-0.49.6/opentelemetry/instrumentation/openai/v1/responses_wrappers.py +1113 -0
- opentelemetry_instrumentation_openai-0.49.6/opentelemetry/instrumentation/openai/version.py +1 -0
- {opentelemetry_instrumentation_openai-0.38.6 → opentelemetry_instrumentation_openai-0.49.6}/pyproject.toml +8 -8
- opentelemetry_instrumentation_openai-0.38.6/opentelemetry/instrumentation/openai/shared/completion_wrappers.py +0 -240
- opentelemetry_instrumentation_openai-0.38.6/opentelemetry/instrumentation/openai/shared/config.py +0 -10
- opentelemetry_instrumentation_openai-0.38.6/opentelemetry/instrumentation/openai/v1/assistant_wrappers.py +0 -231
- opentelemetry_instrumentation_openai-0.38.6/opentelemetry/instrumentation/openai/version.py +0 -1
- {opentelemetry_instrumentation_openai-0.38.6 → opentelemetry_instrumentation_openai-0.49.6}/README.md +0 -0
{opentelemetry_instrumentation_openai-0.38.6 → opentelemetry_instrumentation_openai-0.49.6}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: opentelemetry-instrumentation-openai
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.49.6
|
|
4
4
|
Summary: OpenTelemetry OpenAI instrumentation
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Author: Gal Kleinman
|
|
@@ -13,12 +13,12 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
17
|
Provides-Extra: instruments
|
|
17
|
-
Requires-Dist: opentelemetry-api (>=1.
|
|
18
|
-
Requires-Dist: opentelemetry-instrumentation (>=0.
|
|
19
|
-
Requires-Dist: opentelemetry-semantic-conventions (>=0.
|
|
20
|
-
Requires-Dist: opentelemetry-semantic-conventions-ai (
|
|
21
|
-
Requires-Dist: tiktoken (>=0.6.0,<1)
|
|
18
|
+
Requires-Dist: opentelemetry-api (>=1.38.0,<2.0.0)
|
|
19
|
+
Requires-Dist: opentelemetry-instrumentation (>=0.59b0)
|
|
20
|
+
Requires-Dist: opentelemetry-semantic-conventions (>=0.59b0)
|
|
21
|
+
Requires-Dist: opentelemetry-semantic-conventions-ai (>=0.4.13,<0.5.0)
|
|
22
22
|
Project-URL: Repository, https://github.com/traceloop/openllmetry/tree/main/packages/opentelemetry-instrumentation-openai
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
from typing import Callable, Collection, Optional
|
|
2
|
-
from typing_extensions import Coroutine
|
|
3
2
|
|
|
4
3
|
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
|
5
|
-
|
|
6
4
|
from opentelemetry.instrumentation.openai.shared.config import Config
|
|
7
5
|
from opentelemetry.instrumentation.openai.utils import is_openai_v1
|
|
6
|
+
from typing_extensions import Coroutine
|
|
8
7
|
|
|
9
8
|
_instruments = ("openai >= 0.27.0",)
|
|
10
9
|
|
|
@@ -15,21 +14,21 @@ class OpenAIInstrumentor(BaseInstrumentor):
|
|
|
15
14
|
def __init__(
|
|
16
15
|
self,
|
|
17
16
|
enrich_assistant: bool = False,
|
|
18
|
-
enrich_token_usage: bool = False,
|
|
19
17
|
exception_logger=None,
|
|
20
18
|
get_common_metrics_attributes: Callable[[], dict] = lambda: {},
|
|
21
19
|
upload_base64_image: Optional[
|
|
22
20
|
Callable[[str, str, str, str], Coroutine[None, None, str]]
|
|
23
21
|
] = lambda *args: "",
|
|
24
22
|
enable_trace_context_propagation: bool = True,
|
|
23
|
+
use_legacy_attributes: bool = True,
|
|
25
24
|
):
|
|
26
25
|
super().__init__()
|
|
27
26
|
Config.enrich_assistant = enrich_assistant
|
|
28
|
-
Config.enrich_token_usage = enrich_token_usage
|
|
29
27
|
Config.exception_logger = exception_logger
|
|
30
28
|
Config.get_common_metrics_attributes = get_common_metrics_attributes
|
|
31
29
|
Config.upload_base64_image = upload_base64_image
|
|
32
30
|
Config.enable_trace_context_propagation = enable_trace_context_propagation
|
|
31
|
+
Config.use_legacy_attributes = use_legacy_attributes
|
|
33
32
|
|
|
34
33
|
def instrumentation_dependencies(self) -> Collection[str]:
|
|
35
34
|
return _instruments
|
|
@@ -1,25 +1,22 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import openai
|
|
3
1
|
import json
|
|
4
|
-
import types
|
|
5
2
|
import logging
|
|
6
|
-
|
|
3
|
+
import types
|
|
4
|
+
import openai
|
|
5
|
+
import pydantic
|
|
7
6
|
from importlib.metadata import version
|
|
8
7
|
|
|
9
|
-
from opentelemetry import context as context_api
|
|
10
|
-
from opentelemetry.trace.propagation import set_span_in_context
|
|
11
|
-
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
|
|
12
|
-
|
|
13
8
|
from opentelemetry.instrumentation.openai.shared.config import Config
|
|
14
|
-
from opentelemetry.semconv._incubating.attributes.gen_ai_attributes import (
|
|
15
|
-
GEN_AI_RESPONSE_ID,
|
|
16
|
-
)
|
|
17
|
-
from opentelemetry.semconv_ai import SpanAttributes
|
|
18
9
|
from opentelemetry.instrumentation.openai.utils import (
|
|
19
10
|
dont_throw,
|
|
20
11
|
is_openai_v1,
|
|
21
|
-
should_record_stream_token_usage,
|
|
22
12
|
)
|
|
13
|
+
from opentelemetry.semconv._incubating.attributes import (
|
|
14
|
+
gen_ai_attributes as GenAIAttributes,
|
|
15
|
+
openai_attributes as OpenAIAttributes,
|
|
16
|
+
)
|
|
17
|
+
from opentelemetry.semconv_ai import SpanAttributes
|
|
18
|
+
from opentelemetry.trace.propagation import set_span_in_context
|
|
19
|
+
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
|
|
23
20
|
|
|
24
21
|
OPENAI_LLM_USAGE_TOKEN_TYPES = ["prompt_tokens", "completion_tokens"]
|
|
25
22
|
PROMPT_FILTER_KEY = "prompt_filter_results"
|
|
@@ -27,18 +24,10 @@ PROMPT_ERROR = "prompt_error"
|
|
|
27
24
|
|
|
28
25
|
_PYDANTIC_VERSION = version("pydantic")
|
|
29
26
|
|
|
30
|
-
# tiktoken encodings map for different model, key is model_name, value is tiktoken encoding
|
|
31
|
-
tiktoken_encodings = {}
|
|
32
27
|
|
|
33
28
|
logger = logging.getLogger(__name__)
|
|
34
29
|
|
|
35
30
|
|
|
36
|
-
def should_send_prompts():
|
|
37
|
-
return (
|
|
38
|
-
os.getenv("TRACELOOP_TRACE_CONTENT") or "true"
|
|
39
|
-
).lower() == "true" or context_api.get_value("override_enable_content_tracing")
|
|
40
|
-
|
|
41
|
-
|
|
42
31
|
def _set_span_attribute(span, name, value):
|
|
43
32
|
if value is None or value == "":
|
|
44
33
|
return
|
|
@@ -113,20 +102,30 @@ def set_tools_attributes(span, tools):
|
|
|
113
102
|
)
|
|
114
103
|
|
|
115
104
|
|
|
116
|
-
def _set_request_attributes(span, kwargs):
|
|
105
|
+
def _set_request_attributes(span, kwargs, instance=None):
|
|
117
106
|
if not span.is_recording():
|
|
118
107
|
return
|
|
119
108
|
|
|
120
109
|
_set_api_attributes(span)
|
|
121
|
-
|
|
122
|
-
|
|
110
|
+
|
|
111
|
+
base_url = _get_openai_base_url(instance) if instance else ""
|
|
112
|
+
vendor = _get_vendor_from_url(base_url)
|
|
113
|
+
_set_span_attribute(span, GenAIAttributes.GEN_AI_SYSTEM, vendor)
|
|
114
|
+
|
|
115
|
+
model = kwargs.get("model")
|
|
116
|
+
if vendor == "AWS" and model and "." in model:
|
|
117
|
+
model = _cross_region_check(model)
|
|
118
|
+
elif vendor == "OpenRouter":
|
|
119
|
+
model = _extract_model_name_from_provider_format(model)
|
|
120
|
+
|
|
121
|
+
_set_span_attribute(span, GenAIAttributes.GEN_AI_REQUEST_MODEL, model)
|
|
123
122
|
_set_span_attribute(
|
|
124
|
-
span,
|
|
123
|
+
span, GenAIAttributes.GEN_AI_REQUEST_MAX_TOKENS, kwargs.get("max_tokens")
|
|
125
124
|
)
|
|
126
125
|
_set_span_attribute(
|
|
127
|
-
span,
|
|
126
|
+
span, GenAIAttributes.GEN_AI_REQUEST_TEMPERATURE, kwargs.get("temperature")
|
|
128
127
|
)
|
|
129
|
-
_set_span_attribute(span,
|
|
128
|
+
_set_span_attribute(span, GenAIAttributes.GEN_AI_REQUEST_TOP_P, kwargs.get("top_p"))
|
|
130
129
|
_set_span_attribute(
|
|
131
130
|
span, SpanAttributes.LLM_FREQUENCY_PENALTY, kwargs.get("frequency_penalty")
|
|
132
131
|
)
|
|
@@ -143,6 +142,52 @@ def _set_request_attributes(span, kwargs):
|
|
|
143
142
|
_set_span_attribute(
|
|
144
143
|
span, SpanAttributes.LLM_IS_STREAMING, kwargs.get("stream") or False
|
|
145
144
|
)
|
|
145
|
+
_set_span_attribute(
|
|
146
|
+
span, OpenAIAttributes.OPENAI_REQUEST_SERVICE_TIER, kwargs.get("service_tier")
|
|
147
|
+
)
|
|
148
|
+
if response_format := kwargs.get("response_format"):
|
|
149
|
+
# backward-compatible check for
|
|
150
|
+
# openai.types.shared_params.response_format_json_schema.ResponseFormatJSONSchema
|
|
151
|
+
if (
|
|
152
|
+
isinstance(response_format, dict)
|
|
153
|
+
and response_format.get("type") == "json_schema"
|
|
154
|
+
and response_format.get("json_schema")
|
|
155
|
+
):
|
|
156
|
+
schema = dict(response_format.get("json_schema")).get("schema")
|
|
157
|
+
if schema:
|
|
158
|
+
_set_span_attribute(
|
|
159
|
+
span,
|
|
160
|
+
SpanAttributes.LLM_REQUEST_STRUCTURED_OUTPUT_SCHEMA,
|
|
161
|
+
json.dumps(schema),
|
|
162
|
+
)
|
|
163
|
+
elif (
|
|
164
|
+
isinstance(response_format, pydantic.BaseModel)
|
|
165
|
+
or (
|
|
166
|
+
hasattr(response_format, "model_json_schema")
|
|
167
|
+
and callable(response_format.model_json_schema)
|
|
168
|
+
)
|
|
169
|
+
):
|
|
170
|
+
_set_span_attribute(
|
|
171
|
+
span,
|
|
172
|
+
SpanAttributes.LLM_REQUEST_STRUCTURED_OUTPUT_SCHEMA,
|
|
173
|
+
json.dumps(response_format.model_json_schema()),
|
|
174
|
+
)
|
|
175
|
+
else:
|
|
176
|
+
schema = None
|
|
177
|
+
try:
|
|
178
|
+
schema = json.dumps(pydantic.TypeAdapter(response_format).json_schema())
|
|
179
|
+
except Exception:
|
|
180
|
+
try:
|
|
181
|
+
schema = json.dumps(response_format)
|
|
182
|
+
except Exception:
|
|
183
|
+
pass
|
|
184
|
+
|
|
185
|
+
if schema:
|
|
186
|
+
_set_span_attribute(
|
|
187
|
+
span,
|
|
188
|
+
SpanAttributes.LLM_REQUEST_STRUCTURED_OUTPUT_SCHEMA,
|
|
189
|
+
schema,
|
|
190
|
+
)
|
|
146
191
|
|
|
147
192
|
|
|
148
193
|
@dont_throw
|
|
@@ -153,19 +198,27 @@ def _set_response_attributes(span, response):
|
|
|
153
198
|
if "error" in response:
|
|
154
199
|
_set_span_attribute(
|
|
155
200
|
span,
|
|
156
|
-
f"{
|
|
201
|
+
f"{GenAIAttributes.GEN_AI_PROMPT}.{PROMPT_ERROR}",
|
|
157
202
|
json.dumps(response.get("error")),
|
|
158
203
|
)
|
|
159
204
|
return
|
|
160
205
|
|
|
161
|
-
|
|
162
|
-
|
|
206
|
+
response_model = response.get("model")
|
|
207
|
+
if response_model:
|
|
208
|
+
response_model = _extract_model_name_from_provider_format(response_model)
|
|
209
|
+
_set_span_attribute(span, GenAIAttributes.GEN_AI_RESPONSE_MODEL, response_model)
|
|
210
|
+
_set_span_attribute(span, GenAIAttributes.GEN_AI_RESPONSE_ID, response.get("id"))
|
|
163
211
|
|
|
164
212
|
_set_span_attribute(
|
|
165
213
|
span,
|
|
166
214
|
SpanAttributes.LLM_OPENAI_RESPONSE_SYSTEM_FINGERPRINT,
|
|
167
215
|
response.get("system_fingerprint"),
|
|
168
216
|
)
|
|
217
|
+
_set_span_attribute(
|
|
218
|
+
span,
|
|
219
|
+
OpenAIAttributes.OPENAI_RESPONSE_SERVICE_TIER,
|
|
220
|
+
response.get("service_tier"),
|
|
221
|
+
)
|
|
169
222
|
_log_prompt_filter(span, response)
|
|
170
223
|
usage = response.get("usage")
|
|
171
224
|
if not usage:
|
|
@@ -179,11 +232,17 @@ def _set_response_attributes(span, response):
|
|
|
179
232
|
)
|
|
180
233
|
_set_span_attribute(
|
|
181
234
|
span,
|
|
182
|
-
|
|
235
|
+
GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS,
|
|
183
236
|
usage.get("completion_tokens"),
|
|
184
237
|
)
|
|
185
238
|
_set_span_attribute(
|
|
186
|
-
span,
|
|
239
|
+
span, GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS, usage.get("prompt_tokens")
|
|
240
|
+
)
|
|
241
|
+
prompt_tokens_details = dict(usage.get("prompt_tokens_details", {}))
|
|
242
|
+
_set_span_attribute(
|
|
243
|
+
span,
|
|
244
|
+
SpanAttributes.LLM_USAGE_CACHE_READ_INPUT_TOKENS,
|
|
245
|
+
prompt_tokens_details.get("cached_tokens", 0),
|
|
187
246
|
)
|
|
188
247
|
return
|
|
189
248
|
|
|
@@ -192,7 +251,7 @@ def _log_prompt_filter(span, response_dict):
|
|
|
192
251
|
if response_dict.get("prompt_filter_results"):
|
|
193
252
|
_set_span_attribute(
|
|
194
253
|
span,
|
|
195
|
-
f"{
|
|
254
|
+
f"{GenAIAttributes.GEN_AI_PROMPT}.{PROMPT_FILTER_KEY}",
|
|
196
255
|
json.dumps(response_dict.get("prompt_filter_results")),
|
|
197
256
|
)
|
|
198
257
|
|
|
@@ -202,17 +261,17 @@ def _set_span_stream_usage(span, prompt_tokens, completion_tokens):
|
|
|
202
261
|
if not span.is_recording():
|
|
203
262
|
return
|
|
204
263
|
|
|
205
|
-
if
|
|
264
|
+
if isinstance(completion_tokens, int) and completion_tokens >= 0:
|
|
206
265
|
_set_span_attribute(
|
|
207
|
-
span,
|
|
266
|
+
span, GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS, completion_tokens
|
|
208
267
|
)
|
|
209
268
|
|
|
210
|
-
if
|
|
211
|
-
_set_span_attribute(span,
|
|
269
|
+
if isinstance(prompt_tokens, int) and prompt_tokens >= 0:
|
|
270
|
+
_set_span_attribute(span, GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS, prompt_tokens)
|
|
212
271
|
|
|
213
272
|
if (
|
|
214
|
-
|
|
215
|
-
and
|
|
273
|
+
isinstance(prompt_tokens, int)
|
|
274
|
+
and isinstance(completion_tokens, int)
|
|
216
275
|
and completion_tokens + prompt_tokens >= 0
|
|
217
276
|
):
|
|
218
277
|
_set_span_attribute(
|
|
@@ -231,6 +290,53 @@ def _get_openai_base_url(instance):
|
|
|
231
290
|
return ""
|
|
232
291
|
|
|
233
292
|
|
|
293
|
+
def _get_vendor_from_url(base_url):
|
|
294
|
+
if not base_url:
|
|
295
|
+
return "openai"
|
|
296
|
+
|
|
297
|
+
if "openai.azure.com" in base_url:
|
|
298
|
+
return "Azure"
|
|
299
|
+
elif "amazonaws.com" in base_url or "bedrock" in base_url:
|
|
300
|
+
return "AWS"
|
|
301
|
+
elif "googleapis.com" in base_url or "vertex" in base_url:
|
|
302
|
+
return "Google"
|
|
303
|
+
elif "openrouter.ai" in base_url:
|
|
304
|
+
return "OpenRouter"
|
|
305
|
+
|
|
306
|
+
return "openai"
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def _cross_region_check(value):
|
|
310
|
+
if not value or "." not in value:
|
|
311
|
+
return value
|
|
312
|
+
|
|
313
|
+
prefixes = ["us", "us-gov", "eu", "apac"]
|
|
314
|
+
if any(value.startswith(prefix + ".") for prefix in prefixes):
|
|
315
|
+
parts = value.split(".")
|
|
316
|
+
if len(parts) > 2:
|
|
317
|
+
return parts[2]
|
|
318
|
+
else:
|
|
319
|
+
return value
|
|
320
|
+
else:
|
|
321
|
+
vendor, model = value.split(".", 1)
|
|
322
|
+
return model
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def _extract_model_name_from_provider_format(model_name):
|
|
326
|
+
"""
|
|
327
|
+
Extract model name from provider/model format.
|
|
328
|
+
E.g., 'openai/gpt-4o' -> 'gpt-4o', 'anthropic/claude-3-sonnet' -> 'claude-3-sonnet'
|
|
329
|
+
"""
|
|
330
|
+
if not model_name:
|
|
331
|
+
return model_name
|
|
332
|
+
|
|
333
|
+
if "/" in model_name:
|
|
334
|
+
parts = model_name.split("/")
|
|
335
|
+
return parts[-1] # Return the last part (actual model name)
|
|
336
|
+
|
|
337
|
+
return model_name
|
|
338
|
+
|
|
339
|
+
|
|
234
340
|
def is_streaming_response(response):
|
|
235
341
|
if is_openai_v1():
|
|
236
342
|
return isinstance(response, openai.Stream) or isinstance(
|
|
@@ -255,30 +361,6 @@ def model_as_dict(model):
|
|
|
255
361
|
return model
|
|
256
362
|
|
|
257
363
|
|
|
258
|
-
def get_token_count_from_string(string: str, model_name: str):
|
|
259
|
-
if not should_record_stream_token_usage():
|
|
260
|
-
return None
|
|
261
|
-
|
|
262
|
-
import tiktoken
|
|
263
|
-
|
|
264
|
-
if tiktoken_encodings.get(model_name) is None:
|
|
265
|
-
try:
|
|
266
|
-
encoding = tiktoken.encoding_for_model(model_name)
|
|
267
|
-
except KeyError as ex:
|
|
268
|
-
# no such model_name in tiktoken
|
|
269
|
-
logger.warning(
|
|
270
|
-
f"Failed to get tiktoken encoding for model_name {model_name}, error: {str(ex)}"
|
|
271
|
-
)
|
|
272
|
-
return None
|
|
273
|
-
|
|
274
|
-
tiktoken_encodings[model_name] = encoding
|
|
275
|
-
else:
|
|
276
|
-
encoding = tiktoken_encodings.get(model_name)
|
|
277
|
-
|
|
278
|
-
token_count = len(encoding.encode(string))
|
|
279
|
-
return token_count
|
|
280
|
-
|
|
281
|
-
|
|
282
364
|
def _token_type(token_type: str):
|
|
283
365
|
if token_type == "prompt_tokens":
|
|
284
366
|
return "input"
|
|
@@ -292,11 +374,12 @@ def metric_shared_attributes(
|
|
|
292
374
|
response_model: str, operation: str, server_address: str, is_streaming: bool = False
|
|
293
375
|
):
|
|
294
376
|
attributes = Config.get_common_metrics_attributes()
|
|
377
|
+
vendor = _get_vendor_from_url(server_address)
|
|
295
378
|
|
|
296
379
|
return {
|
|
297
380
|
**attributes,
|
|
298
|
-
|
|
299
|
-
|
|
381
|
+
GenAIAttributes.GEN_AI_SYSTEM: vendor,
|
|
382
|
+
GenAIAttributes.GEN_AI_RESPONSE_MODEL: response_model,
|
|
300
383
|
"gen_ai.operation.name": operation,
|
|
301
384
|
"server.address": server_address,
|
|
302
385
|
"stream": is_streaming,
|