langtrace-python-sdk 2.3.3__py3-none-any.whl → 2.3.4__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.
- examples/anthropic_example/completion.py +1 -1
- examples/openai_example/__init__.py +1 -0
- langtrace_python_sdk/instrumentation/anthropic/instrumentation.py +10 -9
- langtrace_python_sdk/instrumentation/anthropic/patch.py +33 -29
- langtrace_python_sdk/instrumentation/anthropic/types.py +105 -0
- langtrace_python_sdk/instrumentation/cohere/patch.py +1 -4
- langtrace_python_sdk/instrumentation/crewai/patch.py +16 -15
- langtrace_python_sdk/instrumentation/gemini/patch.py +2 -5
- langtrace_python_sdk/instrumentation/groq/patch.py +7 -19
- langtrace_python_sdk/instrumentation/openai/instrumentation.py +14 -19
- langtrace_python_sdk/instrumentation/openai/patch.py +93 -101
- langtrace_python_sdk/instrumentation/openai/types.py +170 -0
- langtrace_python_sdk/instrumentation/vertexai/patch.py +2 -5
- langtrace_python_sdk/instrumentation/weaviate/patch.py +3 -13
- langtrace_python_sdk/utils/llm.py +12 -7
- langtrace_python_sdk/utils/silently_fail.py +19 -3
- langtrace_python_sdk/version.py +1 -1
- {langtrace_python_sdk-2.3.3.dist-info → langtrace_python_sdk-2.3.4.dist-info}/METADATA +1 -1
- {langtrace_python_sdk-2.3.3.dist-info → langtrace_python_sdk-2.3.4.dist-info}/RECORD +22 -20
- {langtrace_python_sdk-2.3.3.dist-info → langtrace_python_sdk-2.3.4.dist-info}/WHEEL +0 -0
- {langtrace_python_sdk-2.3.3.dist-info → langtrace_python_sdk-2.3.4.dist-info}/entry_points.txt +0 -0
- {langtrace_python_sdk-2.3.3.dist-info → langtrace_python_sdk-2.3.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -16,38 +16,39 @@ limitations under the License.
|
|
|
16
16
|
|
|
17
17
|
import importlib.metadata
|
|
18
18
|
import logging
|
|
19
|
-
from typing import Collection
|
|
19
|
+
from typing import Collection, Any
|
|
20
20
|
|
|
21
21
|
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
|
22
|
+
from opentelemetry.trace import TracerProvider
|
|
22
23
|
from opentelemetry.trace import get_tracer
|
|
23
24
|
from wrapt import wrap_function_wrapper
|
|
24
|
-
|
|
25
|
+
from typing import Any
|
|
25
26
|
from langtrace_python_sdk.instrumentation.anthropic.patch import messages_create
|
|
26
27
|
|
|
27
28
|
logging.basicConfig(level=logging.FATAL)
|
|
28
29
|
|
|
29
30
|
|
|
30
|
-
class AnthropicInstrumentation(BaseInstrumentor):
|
|
31
|
+
class AnthropicInstrumentation(BaseInstrumentor): # type: ignore[misc]
|
|
31
32
|
"""
|
|
32
|
-
The AnthropicInstrumentation class represents the Anthropic instrumentation
|
|
33
|
+
The AnthropicInstrumentation class represents the Anthropic instrumentation.
|
|
33
34
|
"""
|
|
34
35
|
|
|
35
36
|
def instrumentation_dependencies(self) -> Collection[str]:
|
|
36
37
|
return ["anthropic >= 0.19.1"]
|
|
37
38
|
|
|
38
|
-
def _instrument(self, **kwargs):
|
|
39
|
-
tracer_provider = kwargs.get("tracer_provider")
|
|
39
|
+
def _instrument(self, **kwargs: dict[str, Any]) -> None:
|
|
40
|
+
tracer_provider: TracerProvider = kwargs.get("tracer_provider") # type: ignore
|
|
40
41
|
tracer = get_tracer(__name__, "", tracer_provider)
|
|
41
42
|
version = importlib.metadata.version("anthropic")
|
|
42
43
|
|
|
43
44
|
wrap_function_wrapper(
|
|
44
45
|
"anthropic.resources.messages",
|
|
45
46
|
"Messages.create",
|
|
46
|
-
messages_create(
|
|
47
|
+
messages_create(version, tracer),
|
|
47
48
|
)
|
|
48
49
|
|
|
49
|
-
def _instrument_module(self, module_name):
|
|
50
|
+
def _instrument_module(self, module_name: str) -> None:
|
|
50
51
|
pass
|
|
51
52
|
|
|
52
|
-
def _uninstrument(self, **kwargs):
|
|
53
|
+
def _uninstrument(self, **kwargs: dict[str, Any]) -> None:
|
|
53
54
|
pass
|
|
@@ -14,9 +14,8 @@ See the License for the specific language governing permissions and
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
-
import
|
|
18
|
-
|
|
19
|
-
from langtrace.trace_attributes import Event, LLMSpanAttributes
|
|
17
|
+
from typing import Any, Callable, Dict, List, Optional, Iterator, TypedDict, Union
|
|
18
|
+
from langtrace.trace_attributes import Event, SpanAttributes, LLMSpanAttributes
|
|
20
19
|
from langtrace_python_sdk.utils import set_span_attribute
|
|
21
20
|
from langtrace_python_sdk.utils.silently_fail import silently_fail
|
|
22
21
|
|
|
@@ -27,41 +26,48 @@ from langtrace_python_sdk.utils.llm import (
|
|
|
27
26
|
get_llm_request_attributes,
|
|
28
27
|
get_llm_url,
|
|
29
28
|
get_span_name,
|
|
30
|
-
is_streaming,
|
|
31
29
|
set_event_completion,
|
|
32
30
|
set_usage_attributes,
|
|
31
|
+
set_span_attribute,
|
|
33
32
|
)
|
|
34
|
-
from opentelemetry.trace import SpanKind
|
|
35
|
-
from opentelemetry.trace.status import
|
|
36
|
-
from langtrace.trace_attributes import SpanAttributes
|
|
37
|
-
|
|
33
|
+
from opentelemetry.trace import Span, Tracer, SpanKind
|
|
34
|
+
from opentelemetry.trace.status import StatusCode
|
|
38
35
|
from langtrace_python_sdk.constants.instrumentation.anthropic import APIS
|
|
39
|
-
from langtrace_python_sdk.constants.instrumentation.common import
|
|
40
|
-
|
|
36
|
+
from langtrace_python_sdk.constants.instrumentation.common import SERVICE_PROVIDERS
|
|
37
|
+
from langtrace_python_sdk.instrumentation.anthropic.types import (
|
|
38
|
+
StreamingResult,
|
|
39
|
+
ResultType,
|
|
40
|
+
MessagesCreateKwargs,
|
|
41
|
+
ContentItem,
|
|
42
|
+
Usage,
|
|
41
43
|
)
|
|
42
44
|
|
|
43
45
|
|
|
44
|
-
def messages_create(
|
|
46
|
+
def messages_create(version: str, tracer: Tracer) -> Callable[..., Any]:
|
|
45
47
|
"""Wrap the `messages_create` method."""
|
|
46
48
|
|
|
47
|
-
def traced_method(
|
|
49
|
+
def traced_method(
|
|
50
|
+
wrapped: Callable[..., Any],
|
|
51
|
+
instance: Any,
|
|
52
|
+
args: List[Any],
|
|
53
|
+
kwargs: MessagesCreateKwargs,
|
|
54
|
+
) -> Any:
|
|
48
55
|
service_provider = SERVICE_PROVIDERS["ANTHROPIC"]
|
|
49
56
|
|
|
50
|
-
#
|
|
51
|
-
# we do this to keep it consistent with the openai
|
|
57
|
+
# Extract system from kwargs and attach as a role to the prompts
|
|
52
58
|
prompts = kwargs.get("messages", [])
|
|
53
59
|
system = kwargs.get("system")
|
|
54
60
|
if system:
|
|
55
61
|
prompts = [{"role": "system", "content": system}] + kwargs.get(
|
|
56
62
|
"messages", []
|
|
57
63
|
)
|
|
58
|
-
|
|
64
|
+
extraAttributes = get_extra_attributes()
|
|
59
65
|
span_attributes = {
|
|
60
66
|
**get_langtrace_attributes(version, service_provider),
|
|
61
67
|
**get_llm_request_attributes(kwargs, prompts=prompts),
|
|
62
68
|
**get_llm_url(instance),
|
|
63
69
|
SpanAttributes.LLM_PATH: APIS["MESSAGES_CREATE"]["ENDPOINT"],
|
|
64
|
-
**
|
|
70
|
+
**extraAttributes, # type: ignore
|
|
65
71
|
}
|
|
66
72
|
|
|
67
73
|
attributes = LLMSpanAttributes(**span_attributes)
|
|
@@ -74,37 +80,35 @@ def messages_create(original_method, version, tracer):
|
|
|
74
80
|
try:
|
|
75
81
|
# Attempt to call the original method
|
|
76
82
|
result = wrapped(*args, **kwargs)
|
|
77
|
-
return set_response_attributes(result, span
|
|
83
|
+
return set_response_attributes(result, span)
|
|
78
84
|
|
|
79
85
|
except Exception as err:
|
|
80
86
|
# Record the exception in the span
|
|
81
87
|
span.record_exception(err)
|
|
82
88
|
# Set the span status to indicate an error
|
|
83
|
-
span.set_status(
|
|
89
|
+
span.set_status(StatusCode.ERROR, str(err))
|
|
84
90
|
# Reraise the exception to ensure it's not swallowed
|
|
85
91
|
span.end()
|
|
86
92
|
raise
|
|
87
93
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
94
|
+
def set_response_attributes(
|
|
95
|
+
result: Union[ResultType, StreamingResult], span: Span
|
|
96
|
+
) -> Any:
|
|
97
|
+
if not isinstance(result, Iterator):
|
|
91
98
|
if hasattr(result, "content") and result.content is not None:
|
|
92
99
|
set_span_attribute(
|
|
93
100
|
span, SpanAttributes.LLM_RESPONSE_MODEL, result.model
|
|
94
101
|
)
|
|
102
|
+
content_item = result.content[0]
|
|
95
103
|
completion = [
|
|
96
104
|
{
|
|
97
|
-
"role": result.role
|
|
98
|
-
"content":
|
|
99
|
-
"type":
|
|
105
|
+
"role": result.role or "assistant",
|
|
106
|
+
"content": content_item.text,
|
|
107
|
+
"type": content_item.type,
|
|
100
108
|
}
|
|
101
109
|
]
|
|
102
110
|
set_event_completion(span, completion)
|
|
103
111
|
|
|
104
|
-
else:
|
|
105
|
-
responses = []
|
|
106
|
-
set_event_completion(span, responses)
|
|
107
|
-
|
|
108
112
|
if (
|
|
109
113
|
hasattr(result, "system_fingerprint")
|
|
110
114
|
and result.system_fingerprint is not None
|
|
@@ -116,7 +120,7 @@ def messages_create(original_method, version, tracer):
|
|
|
116
120
|
# Get the usage
|
|
117
121
|
if hasattr(result, "usage") and result.usage is not None:
|
|
118
122
|
usage = result.usage
|
|
119
|
-
set_usage_attributes(span,
|
|
123
|
+
set_usage_attributes(span, vars(usage))
|
|
120
124
|
|
|
121
125
|
span.set_status(StatusCode.OK)
|
|
122
126
|
span.end()
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Copyright (c) 2024 Scale3 Labs
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License.
|
|
5
|
+
You may obtain a copy of the License at
|
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software
|
|
8
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
9
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
10
|
+
See the License for the specific language governing permissions and
|
|
11
|
+
limitations under the License.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from typing import Dict, List, Optional, Iterator, TypedDict
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MessagesCreateKwargs(TypedDict, total=False):
|
|
18
|
+
system: Optional[str]
|
|
19
|
+
messages: List[Dict[str, str]]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Usage:
|
|
23
|
+
input_tokens: int
|
|
24
|
+
output_tokens: int
|
|
25
|
+
|
|
26
|
+
def __init__(self, input_tokens: int, output_tokens: int):
|
|
27
|
+
self.input_tokens = input_tokens
|
|
28
|
+
self.output_tokens = output_tokens
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class Message:
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
id: str,
|
|
35
|
+
model: Optional[str],
|
|
36
|
+
usage: Optional[Usage],
|
|
37
|
+
):
|
|
38
|
+
self.id = id
|
|
39
|
+
self.model = model
|
|
40
|
+
self.usage = usage
|
|
41
|
+
|
|
42
|
+
model: Optional[str]
|
|
43
|
+
usage: Optional[Usage]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class Delta:
|
|
47
|
+
text: Optional[str]
|
|
48
|
+
|
|
49
|
+
def __init__(
|
|
50
|
+
self,
|
|
51
|
+
text: Optional[str],
|
|
52
|
+
):
|
|
53
|
+
self.text = text
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class Chunk:
|
|
57
|
+
message: Message
|
|
58
|
+
delta: Delta
|
|
59
|
+
|
|
60
|
+
def __init__(
|
|
61
|
+
self,
|
|
62
|
+
message: Message,
|
|
63
|
+
delta: Delta,
|
|
64
|
+
):
|
|
65
|
+
self.message = message
|
|
66
|
+
self.delta = delta
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class ContentItem:
|
|
70
|
+
role: str
|
|
71
|
+
content: str
|
|
72
|
+
text: str
|
|
73
|
+
type: str
|
|
74
|
+
|
|
75
|
+
def __init__(self, role: str, content: str, text: str, type: str):
|
|
76
|
+
self.role = role
|
|
77
|
+
self.content = content
|
|
78
|
+
self.text = text
|
|
79
|
+
self.type = type
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class ResultType:
|
|
83
|
+
model: Optional[str]
|
|
84
|
+
role: Optional[str]
|
|
85
|
+
content: List[ContentItem]
|
|
86
|
+
system_fingerprint: Optional[str]
|
|
87
|
+
usage: Optional[Usage]
|
|
88
|
+
|
|
89
|
+
def __init__(
|
|
90
|
+
self,
|
|
91
|
+
model: Optional[str],
|
|
92
|
+
role: Optional[str],
|
|
93
|
+
content: Optional[List[ContentItem]],
|
|
94
|
+
system_fingerprint: Optional[str],
|
|
95
|
+
usage: Optional[Usage],
|
|
96
|
+
):
|
|
97
|
+
self.model = model
|
|
98
|
+
self.role = role
|
|
99
|
+
self.content = content if content is not None else []
|
|
100
|
+
self.system_fingerprint = system_fingerprint
|
|
101
|
+
self.usage = usage
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# The result would be an iterator that yields these Chunk objects
|
|
105
|
+
StreamingResult = Iterator[Chunk]
|
|
@@ -367,10 +367,7 @@ def chat_stream(original_method, version, tracer):
|
|
|
367
367
|
}
|
|
368
368
|
for item in chat_history
|
|
369
369
|
]
|
|
370
|
-
|
|
371
|
-
prompts = history + prompts
|
|
372
|
-
if len(system_prompts) > 0:
|
|
373
|
-
prompts = system_prompts + prompts
|
|
370
|
+
prompts = system_prompts + history + prompts
|
|
374
371
|
|
|
375
372
|
span_attributes = {
|
|
376
373
|
**get_langtrace_attributes(version, service_provider),
|
|
@@ -8,7 +8,9 @@ from opentelemetry.trace.status import Status, StatusCode
|
|
|
8
8
|
|
|
9
9
|
from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME
|
|
10
10
|
from langtrace_python_sdk.constants.instrumentation.common import (
|
|
11
|
-
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY,
|
|
11
|
+
LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY,
|
|
12
|
+
SERVICE_PROVIDERS,
|
|
13
|
+
)
|
|
12
14
|
from langtrace_python_sdk.utils import set_span_attribute
|
|
13
15
|
from langtrace_python_sdk.utils.llm import get_span_name, set_span_attributes
|
|
14
16
|
from langtrace_python_sdk.utils.misc import serialize_args, serialize_kwargs
|
|
@@ -44,7 +46,9 @@ def patch_memory(operation_name, version, tracer: Tracer):
|
|
|
44
46
|
set_span_attributes(span, attributes)
|
|
45
47
|
result = wrapped(*args, **kwargs)
|
|
46
48
|
if result is not None and len(result) > 0:
|
|
47
|
-
set_span_attribute(
|
|
49
|
+
set_span_attribute(
|
|
50
|
+
span, "crewai.memory.storage.rag_storage.outputs", str(result)
|
|
51
|
+
)
|
|
48
52
|
if result:
|
|
49
53
|
span.set_status(Status(StatusCode.OK))
|
|
50
54
|
span.end()
|
|
@@ -87,20 +91,17 @@ def patch_crew(operation_name, version, tracer: Tracer):
|
|
|
87
91
|
CrewAISpanAttributes(span=span, instance=instance)
|
|
88
92
|
result = wrapped(*args, **kwargs)
|
|
89
93
|
if result:
|
|
94
|
+
class_name = instance.__class__.__name__
|
|
95
|
+
span.set_attribute(
|
|
96
|
+
f"crewai.{class_name.lower()}.result", str(result)
|
|
97
|
+
)
|
|
90
98
|
span.set_status(Status(StatusCode.OK))
|
|
91
|
-
if
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if hasattr(result, "usage_metrics") and result.usage_metrics is not None:
|
|
98
|
-
span.set_attribute("crewai.crew.usage_metrics", str((result.usage_metrics)))
|
|
99
|
-
elif instance.__class__.__name__ == "Agent":
|
|
100
|
-
span.set_attribute("crewai.agent.result", str(result))
|
|
101
|
-
elif instance.__class__.__name__ == "Task":
|
|
102
|
-
span.set_attribute("crewai.task.result", str(result))
|
|
103
|
-
|
|
99
|
+
if class_name == "Crew":
|
|
100
|
+
for attr in ["tasks_output", "token_usage", "usage_metrics"]:
|
|
101
|
+
if hasattr(result, attr):
|
|
102
|
+
span.set_attribute(
|
|
103
|
+
f"crewai.crew.{attr}", str(getattr(result, attr))
|
|
104
|
+
)
|
|
104
105
|
span.end()
|
|
105
106
|
return result
|
|
106
107
|
|
|
@@ -100,12 +100,9 @@ def apatch_gemini(name, version, tracer: Tracer):
|
|
|
100
100
|
|
|
101
101
|
|
|
102
102
|
def get_llm_model(instance):
|
|
103
|
-
llm_model = "unknown"
|
|
104
|
-
if hasattr(instance, "_model_id"):
|
|
105
|
-
llm_model = instance._model_id
|
|
106
103
|
if hasattr(instance, "_model_name"):
|
|
107
|
-
|
|
108
|
-
return
|
|
104
|
+
return instance._model_name.replace("models/", "")
|
|
105
|
+
return getattr(instance, "_model_id", "unknown")
|
|
109
106
|
|
|
110
107
|
|
|
111
108
|
def serialize_prompts(args, kwargs, instance):
|
|
@@ -158,7 +158,7 @@ def chat_completions_create(original_method, version, tracer):
|
|
|
158
158
|
usage = result.usage
|
|
159
159
|
set_usage_attributes(span, dict(usage))
|
|
160
160
|
|
|
161
|
-
span.set_status(StatusCode.OK)
|
|
161
|
+
span.set_status(Status(StatusCode.OK))
|
|
162
162
|
span.end()
|
|
163
163
|
return result
|
|
164
164
|
else:
|
|
@@ -257,7 +257,7 @@ def chat_completions_create(original_method, version, tracer):
|
|
|
257
257
|
span, [{"role": "assistant", "content": "".join(result_content)}]
|
|
258
258
|
)
|
|
259
259
|
|
|
260
|
-
span.set_status(StatusCode.OK)
|
|
260
|
+
span.set_status(Status(StatusCode.OK))
|
|
261
261
|
span.end()
|
|
262
262
|
|
|
263
263
|
# return the wrapped method
|
|
@@ -282,21 +282,13 @@ def async_chat_completions_create(original_method, version, tracer):
|
|
|
282
282
|
tool_calls = []
|
|
283
283
|
for tool_call in item.tool_calls:
|
|
284
284
|
tool_call_dict = {
|
|
285
|
-
"id":
|
|
286
|
-
"type":
|
|
285
|
+
"id": getattr(tool_call, "id", ""),
|
|
286
|
+
"type": getattr(tool_call, "type", ""),
|
|
287
287
|
}
|
|
288
288
|
if hasattr(tool_call, "function"):
|
|
289
289
|
tool_call_dict["function"] = {
|
|
290
|
-
"name": (
|
|
291
|
-
|
|
292
|
-
if hasattr(tool_call.function, "name")
|
|
293
|
-
else ""
|
|
294
|
-
),
|
|
295
|
-
"arguments": (
|
|
296
|
-
tool_call.function.arguments
|
|
297
|
-
if hasattr(tool_call.function, "arguments")
|
|
298
|
-
else ""
|
|
299
|
-
),
|
|
290
|
+
"name": getattr(tool_call.function, "name", ""),
|
|
291
|
+
"arguments": getattr(tool_call.function, "arguments", ""),
|
|
300
292
|
}
|
|
301
293
|
tool_calls.append(tool_call_dict)
|
|
302
294
|
llm_prompts.append(tool_calls)
|
|
@@ -459,11 +451,7 @@ def async_chat_completions_create(original_method, version, tracer):
|
|
|
459
451
|
tool_call.function.arguments
|
|
460
452
|
)
|
|
461
453
|
completion_tokens += token_counts
|
|
462
|
-
content
|
|
463
|
-
tool_call.function.arguments
|
|
464
|
-
]
|
|
465
|
-
else:
|
|
466
|
-
content = content + []
|
|
454
|
+
content += [tool_call.function.arguments]
|
|
467
455
|
else:
|
|
468
456
|
content = []
|
|
469
457
|
span.add_event(
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Copyright (c) 2024 Scale3 Labs
|
|
3
|
-
|
|
4
3
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
4
|
you may not use this file except in compliance with the License.
|
|
6
5
|
You may obtain a copy of the License at
|
|
7
|
-
|
|
8
6
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
|
|
10
7
|
Unless required by applicable law or agreed to in writing, software
|
|
11
8
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
9
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
@@ -14,12 +11,12 @@ See the License for the specific language governing permissions and
|
|
|
14
11
|
limitations under the License.
|
|
15
12
|
"""
|
|
16
13
|
|
|
14
|
+
from typing import Collection, Optional, Any
|
|
17
15
|
import importlib.metadata
|
|
18
16
|
import logging
|
|
19
|
-
from typing import Collection
|
|
20
17
|
|
|
21
18
|
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
|
22
|
-
from opentelemetry.trace import get_tracer
|
|
19
|
+
from opentelemetry.trace import get_tracer, TracerProvider
|
|
23
20
|
from wrapt import wrap_function_wrapper
|
|
24
21
|
|
|
25
22
|
from langtrace_python_sdk.instrumentation.openai.patch import (
|
|
@@ -35,59 +32,57 @@ from langtrace_python_sdk.instrumentation.openai.patch import (
|
|
|
35
32
|
logging.basicConfig(level=logging.FATAL)
|
|
36
33
|
|
|
37
34
|
|
|
38
|
-
class OpenAIInstrumentation(BaseInstrumentor):
|
|
35
|
+
class OpenAIInstrumentation(BaseInstrumentor): # type: ignore
|
|
39
36
|
|
|
40
37
|
def instrumentation_dependencies(self) -> Collection[str]:
|
|
41
38
|
return ["openai >= 0.27.0", "trace-attributes >= 4.0.5"]
|
|
42
39
|
|
|
43
|
-
def _instrument(self, **kwargs):
|
|
44
|
-
tracer_provider = kwargs.get("tracer_provider")
|
|
40
|
+
def _instrument(self, **kwargs: Any) -> None:
|
|
41
|
+
tracer_provider: Optional[TracerProvider] = kwargs.get("tracer_provider")
|
|
45
42
|
tracer = get_tracer(__name__, "", tracer_provider)
|
|
46
|
-
version = importlib.metadata.version("openai")
|
|
43
|
+
version: str = importlib.metadata.version("openai")
|
|
47
44
|
|
|
48
45
|
wrap_function_wrapper(
|
|
49
46
|
"openai.resources.chat.completions",
|
|
50
47
|
"Completions.create",
|
|
51
|
-
chat_completions_create(
|
|
48
|
+
chat_completions_create(version, tracer),
|
|
52
49
|
)
|
|
53
50
|
|
|
54
51
|
wrap_function_wrapper(
|
|
55
52
|
"openai.resources.chat.completions",
|
|
56
53
|
"AsyncCompletions.create",
|
|
57
|
-
async_chat_completions_create(
|
|
58
|
-
"openai.chat.completions.create_stream", version, tracer
|
|
59
|
-
),
|
|
54
|
+
async_chat_completions_create(version, tracer),
|
|
60
55
|
)
|
|
61
56
|
|
|
62
57
|
wrap_function_wrapper(
|
|
63
58
|
"openai.resources.images",
|
|
64
59
|
"Images.generate",
|
|
65
|
-
images_generate(
|
|
60
|
+
images_generate(version, tracer),
|
|
66
61
|
)
|
|
67
62
|
|
|
68
63
|
wrap_function_wrapper(
|
|
69
64
|
"openai.resources.images",
|
|
70
65
|
"AsyncImages.generate",
|
|
71
|
-
async_images_generate(
|
|
66
|
+
async_images_generate(version, tracer),
|
|
72
67
|
)
|
|
73
68
|
|
|
74
69
|
wrap_function_wrapper(
|
|
75
70
|
"openai.resources.images",
|
|
76
71
|
"Images.edit",
|
|
77
|
-
images_edit(
|
|
72
|
+
images_edit(version, tracer),
|
|
78
73
|
)
|
|
79
74
|
|
|
80
75
|
wrap_function_wrapper(
|
|
81
76
|
"openai.resources.embeddings",
|
|
82
77
|
"Embeddings.create",
|
|
83
|
-
embeddings_create(
|
|
78
|
+
embeddings_create(version, tracer),
|
|
84
79
|
)
|
|
85
80
|
|
|
86
81
|
wrap_function_wrapper(
|
|
87
82
|
"openai.resources.embeddings",
|
|
88
83
|
"AsyncEmbeddings.create",
|
|
89
|
-
async_embeddings_create(
|
|
84
|
+
async_embeddings_create(version, tracer),
|
|
90
85
|
)
|
|
91
86
|
|
|
92
|
-
def _uninstrument(self, **kwargs):
|
|
87
|
+
def _uninstrument(self, **kwargs: Any) -> None:
|
|
93
88
|
pass
|