opentelemetry-instrumentation-openai 0.18.0__py3-none-any.whl → 0.18.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.
Potentially problematic release.
This version of opentelemetry-instrumentation-openai might be problematic. Click here for more details.
- opentelemetry/instrumentation/openai/shared/__init__.py +7 -1
- opentelemetry/instrumentation/openai/shared/chat_wrappers.py +234 -26
- opentelemetry/instrumentation/openai/version.py +1 -1
- {opentelemetry_instrumentation_openai-0.18.0.dist-info → opentelemetry_instrumentation_openai-0.18.2.dist-info}/METADATA +1 -1
- {opentelemetry_instrumentation_openai-0.18.0.dist-info → opentelemetry_instrumentation_openai-0.18.2.dist-info}/RECORD +7 -7
- {opentelemetry_instrumentation_openai-0.18.0.dist-info → opentelemetry_instrumentation_openai-0.18.2.dist-info}/WHEEL +0 -0
- {opentelemetry_instrumentation_openai-0.18.0.dist-info → opentelemetry_instrumentation_openai-0.18.2.dist-info}/entry_points.txt +0 -0
|
@@ -112,7 +112,9 @@ def _set_request_attributes(span, kwargs):
|
|
|
112
112
|
_set_span_attribute(
|
|
113
113
|
span, SpanAttributes.LLM_REQUEST_MAX_TOKENS, kwargs.get("max_tokens")
|
|
114
114
|
)
|
|
115
|
-
_set_span_attribute(
|
|
115
|
+
_set_span_attribute(
|
|
116
|
+
span, SpanAttributes.LLM_REQUEST_TEMPERATURE, kwargs.get("temperature")
|
|
117
|
+
)
|
|
116
118
|
_set_span_attribute(span, SpanAttributes.LLM_REQUEST_TOP_P, kwargs.get("top_p"))
|
|
117
119
|
_set_span_attribute(
|
|
118
120
|
span, SpanAttributes.LLM_FREQUENCY_PENALTY, kwargs.get("frequency_penalty")
|
|
@@ -139,6 +141,10 @@ def _set_response_attributes(span, response):
|
|
|
139
141
|
|
|
140
142
|
_set_span_attribute(span, SpanAttributes.LLM_RESPONSE_MODEL, response.get("model"))
|
|
141
143
|
|
|
144
|
+
_set_span_attribute(
|
|
145
|
+
span, "gen_ai.openai.system_fingerprint", response.get("system_fingerprint")
|
|
146
|
+
)
|
|
147
|
+
|
|
142
148
|
usage = response.get("usage")
|
|
143
149
|
if not usage:
|
|
144
150
|
return
|
|
@@ -87,18 +87,32 @@ def chat_wrapper(
|
|
|
87
87
|
|
|
88
88
|
if is_streaming_response(response):
|
|
89
89
|
# span will be closed after the generator is done
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
90
|
+
if is_openai_v1():
|
|
91
|
+
return ChatStream(
|
|
92
|
+
span,
|
|
93
|
+
response,
|
|
94
|
+
instance,
|
|
95
|
+
token_counter,
|
|
96
|
+
choice_counter,
|
|
97
|
+
duration_histogram,
|
|
98
|
+
streaming_time_to_first_token,
|
|
99
|
+
streaming_time_to_generate,
|
|
100
|
+
start_time,
|
|
101
|
+
kwargs,
|
|
102
|
+
)
|
|
103
|
+
else:
|
|
104
|
+
return _build_from_streaming_response(
|
|
105
|
+
span,
|
|
106
|
+
response,
|
|
107
|
+
instance,
|
|
108
|
+
token_counter,
|
|
109
|
+
choice_counter,
|
|
110
|
+
duration_histogram,
|
|
111
|
+
streaming_time_to_first_token,
|
|
112
|
+
streaming_time_to_generate,
|
|
113
|
+
start_time,
|
|
114
|
+
kwargs,
|
|
115
|
+
)
|
|
102
116
|
|
|
103
117
|
duration = end_time - start_time
|
|
104
118
|
|
|
@@ -161,18 +175,32 @@ async def achat_wrapper(
|
|
|
161
175
|
|
|
162
176
|
if is_streaming_response(response):
|
|
163
177
|
# span will be closed after the generator is done
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
178
|
+
if is_openai_v1():
|
|
179
|
+
return ChatStream(
|
|
180
|
+
span,
|
|
181
|
+
response,
|
|
182
|
+
instance,
|
|
183
|
+
token_counter,
|
|
184
|
+
choice_counter,
|
|
185
|
+
duration_histogram,
|
|
186
|
+
streaming_time_to_first_token,
|
|
187
|
+
streaming_time_to_generate,
|
|
188
|
+
start_time,
|
|
189
|
+
kwargs,
|
|
190
|
+
)
|
|
191
|
+
else:
|
|
192
|
+
return _abuild_from_streaming_response(
|
|
193
|
+
span,
|
|
194
|
+
response,
|
|
195
|
+
instance,
|
|
196
|
+
token_counter,
|
|
197
|
+
choice_counter,
|
|
198
|
+
duration_histogram,
|
|
199
|
+
streaming_time_to_first_token,
|
|
200
|
+
streaming_time_to_generate,
|
|
201
|
+
start_time,
|
|
202
|
+
kwargs,
|
|
203
|
+
)
|
|
176
204
|
|
|
177
205
|
duration = end_time - start_time
|
|
178
206
|
|
|
@@ -242,6 +270,7 @@ def _set_chat_metrics(
|
|
|
242
270
|
shared_attributes = {
|
|
243
271
|
"gen_ai.response.model": response_dict.get("model") or None,
|
|
244
272
|
"server.address": _get_openai_base_url(instance),
|
|
273
|
+
"stream": False,
|
|
245
274
|
}
|
|
246
275
|
|
|
247
276
|
# token metrics
|
|
@@ -356,7 +385,11 @@ def _set_streaming_token_metrics(
|
|
|
356
385
|
# prompt_usage
|
|
357
386
|
if request_kwargs and request_kwargs.get("messages"):
|
|
358
387
|
prompt_content = ""
|
|
359
|
-
model_name
|
|
388
|
+
# setting the default model_name as gpt-4. As this uses the embedding "cl100k_base" that
|
|
389
|
+
# is used by most of the other model.
|
|
390
|
+
model_name = (
|
|
391
|
+
request_kwargs.get("model") or complete_response.get("model") or "gpt-4"
|
|
392
|
+
)
|
|
360
393
|
for msg in request_kwargs.get("messages"):
|
|
361
394
|
if msg.get("content"):
|
|
362
395
|
prompt_content += msg.get("content")
|
|
@@ -366,7 +399,9 @@ def _set_streaming_token_metrics(
|
|
|
366
399
|
# completion_usage
|
|
367
400
|
if complete_response.get("choices"):
|
|
368
401
|
completion_content = ""
|
|
369
|
-
model_name
|
|
402
|
+
# setting the default model_name as gpt-4. As this uses the embedding "cl100k_base" that
|
|
403
|
+
# is used by most of the other model.
|
|
404
|
+
model_name = complete_response.get("model") or "gpt-4"
|
|
370
405
|
|
|
371
406
|
for choice in complete_response.get("choices"):
|
|
372
407
|
if choice.get("message") and choice.get("message").get("content"):
|
|
@@ -398,6 +433,16 @@ def _set_streaming_token_metrics(
|
|
|
398
433
|
|
|
399
434
|
|
|
400
435
|
class ChatStream(ObjectProxy):
|
|
436
|
+
_span = None
|
|
437
|
+
_instance = None
|
|
438
|
+
_token_counter = None
|
|
439
|
+
_choice_counter = None
|
|
440
|
+
_duration_histogram = None
|
|
441
|
+
_streaming_time_to_first_token = None
|
|
442
|
+
_streaming_time_to_generate = None
|
|
443
|
+
_start_time = None
|
|
444
|
+
_request_kwargs = None
|
|
445
|
+
|
|
401
446
|
def __init__(
|
|
402
447
|
self,
|
|
403
448
|
span,
|
|
@@ -534,3 +579,166 @@ class ChatStream(ObjectProxy):
|
|
|
534
579
|
|
|
535
580
|
self._span.set_status(Status(StatusCode.OK))
|
|
536
581
|
self._span.end()
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
# Backward compatibility with OpenAI v0
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
@dont_throw
|
|
588
|
+
def _build_from_streaming_response(
|
|
589
|
+
span,
|
|
590
|
+
response,
|
|
591
|
+
instance=None,
|
|
592
|
+
token_counter=None,
|
|
593
|
+
choice_counter=None,
|
|
594
|
+
duration_histogram=None,
|
|
595
|
+
streaming_time_to_first_token=None,
|
|
596
|
+
streaming_time_to_generate=None,
|
|
597
|
+
start_time=None,
|
|
598
|
+
request_kwargs=None,
|
|
599
|
+
):
|
|
600
|
+
complete_response = {"choices": [], "model": ""}
|
|
601
|
+
|
|
602
|
+
first_token = True
|
|
603
|
+
time_of_first_token = start_time # will be updated when first token is received
|
|
604
|
+
|
|
605
|
+
for item in response:
|
|
606
|
+
span.add_event(name="llm.content.completion.chunk")
|
|
607
|
+
|
|
608
|
+
item_to_yield = item
|
|
609
|
+
|
|
610
|
+
if first_token and streaming_time_to_first_token:
|
|
611
|
+
time_of_first_token = time.time()
|
|
612
|
+
streaming_time_to_first_token.record(time_of_first_token - start_time)
|
|
613
|
+
first_token = False
|
|
614
|
+
|
|
615
|
+
_accumulate_stream_items(item, complete_response)
|
|
616
|
+
|
|
617
|
+
yield item_to_yield
|
|
618
|
+
|
|
619
|
+
shared_attributes = {
|
|
620
|
+
"gen_ai.response.model": complete_response.get("model") or None,
|
|
621
|
+
"server.address": _get_openai_base_url(instance),
|
|
622
|
+
"stream": True,
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
if not is_azure_openai(instance):
|
|
626
|
+
_set_streaming_token_metrics(
|
|
627
|
+
request_kwargs, complete_response, span, token_counter, shared_attributes
|
|
628
|
+
)
|
|
629
|
+
|
|
630
|
+
# choice metrics
|
|
631
|
+
if choice_counter and complete_response.get("choices"):
|
|
632
|
+
_set_choice_counter_metrics(
|
|
633
|
+
choice_counter, complete_response.get("choices"), shared_attributes
|
|
634
|
+
)
|
|
635
|
+
|
|
636
|
+
# duration metrics
|
|
637
|
+
if start_time and isinstance(start_time, (float, int)):
|
|
638
|
+
duration = time.time() - start_time
|
|
639
|
+
else:
|
|
640
|
+
duration = None
|
|
641
|
+
if duration and isinstance(duration, (float, int)) and duration_histogram:
|
|
642
|
+
duration_histogram.record(duration, attributes=shared_attributes)
|
|
643
|
+
if streaming_time_to_generate and time_of_first_token:
|
|
644
|
+
streaming_time_to_generate.record(time.time() - time_of_first_token)
|
|
645
|
+
|
|
646
|
+
_set_response_attributes(span, complete_response)
|
|
647
|
+
|
|
648
|
+
if should_send_prompts():
|
|
649
|
+
_set_completions(span, complete_response.get("choices"))
|
|
650
|
+
|
|
651
|
+
span.set_status(Status(StatusCode.OK))
|
|
652
|
+
span.end()
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
@dont_throw
|
|
656
|
+
async def _abuild_from_streaming_response(
|
|
657
|
+
span,
|
|
658
|
+
response,
|
|
659
|
+
instance=None,
|
|
660
|
+
token_counter=None,
|
|
661
|
+
choice_counter=None,
|
|
662
|
+
duration_histogram=None,
|
|
663
|
+
streaming_time_to_first_token=None,
|
|
664
|
+
streaming_time_to_generate=None,
|
|
665
|
+
start_time=None,
|
|
666
|
+
request_kwargs=None,
|
|
667
|
+
):
|
|
668
|
+
complete_response = {"choices": [], "model": ""}
|
|
669
|
+
|
|
670
|
+
first_token = True
|
|
671
|
+
time_of_first_token = start_time # will be updated when first token is received
|
|
672
|
+
|
|
673
|
+
async for item in response:
|
|
674
|
+
span.add_event(name="llm.content.completion.chunk")
|
|
675
|
+
|
|
676
|
+
item_to_yield = item
|
|
677
|
+
|
|
678
|
+
if first_token and streaming_time_to_first_token:
|
|
679
|
+
time_of_first_token = time.time()
|
|
680
|
+
streaming_time_to_first_token.record(time_of_first_token - start_time)
|
|
681
|
+
first_token = False
|
|
682
|
+
|
|
683
|
+
_accumulate_stream_items(item, complete_response)
|
|
684
|
+
|
|
685
|
+
yield item_to_yield
|
|
686
|
+
|
|
687
|
+
shared_attributes = {
|
|
688
|
+
"gen_ai.response.model": complete_response.get("model") or None,
|
|
689
|
+
"server.address": _get_openai_base_url(instance),
|
|
690
|
+
"stream": True,
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
if not is_azure_openai(instance):
|
|
694
|
+
_set_streaming_token_metrics(
|
|
695
|
+
request_kwargs, complete_response, span, token_counter, shared_attributes
|
|
696
|
+
)
|
|
697
|
+
|
|
698
|
+
# choice metrics
|
|
699
|
+
if choice_counter and complete_response.get("choices"):
|
|
700
|
+
_set_choice_counter_metrics(
|
|
701
|
+
choice_counter, complete_response.get("choices"), shared_attributes
|
|
702
|
+
)
|
|
703
|
+
|
|
704
|
+
# duration metrics
|
|
705
|
+
if start_time and isinstance(start_time, (float, int)):
|
|
706
|
+
duration = time.time() - start_time
|
|
707
|
+
else:
|
|
708
|
+
duration = None
|
|
709
|
+
if duration and isinstance(duration, (float, int)) and duration_histogram:
|
|
710
|
+
duration_histogram.record(duration, attributes=shared_attributes)
|
|
711
|
+
if streaming_time_to_generate and time_of_first_token:
|
|
712
|
+
streaming_time_to_generate.record(time.time() - time_of_first_token)
|
|
713
|
+
|
|
714
|
+
_set_response_attributes(span, complete_response)
|
|
715
|
+
|
|
716
|
+
if should_send_prompts():
|
|
717
|
+
_set_completions(span, complete_response.get("choices"))
|
|
718
|
+
|
|
719
|
+
span.set_status(Status(StatusCode.OK))
|
|
720
|
+
span.end()
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
def _accumulate_stream_items(item, complete_response):
|
|
724
|
+
if is_openai_v1():
|
|
725
|
+
item = model_as_dict(item)
|
|
726
|
+
|
|
727
|
+
complete_response["model"] = item.get("model")
|
|
728
|
+
|
|
729
|
+
for choice in item.get("choices"):
|
|
730
|
+
index = choice.get("index")
|
|
731
|
+
if len(complete_response.get("choices")) <= index:
|
|
732
|
+
complete_response["choices"].append(
|
|
733
|
+
{"index": index, "message": {"content": "", "role": ""}}
|
|
734
|
+
)
|
|
735
|
+
complete_choice = complete_response.get("choices")[index]
|
|
736
|
+
if choice.get("finish_reason"):
|
|
737
|
+
complete_choice["finish_reason"] = choice.get("finish_reason")
|
|
738
|
+
|
|
739
|
+
delta = choice.get("delta")
|
|
740
|
+
|
|
741
|
+
if delta and delta.get("content"):
|
|
742
|
+
complete_choice["message"]["content"] += delta.get("content")
|
|
743
|
+
if delta and delta.get("role"):
|
|
744
|
+
complete_choice["message"]["role"] = delta.get("role")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.18.
|
|
1
|
+
__version__ = "0.18.2"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: opentelemetry-instrumentation-openai
|
|
3
|
-
Version: 0.18.
|
|
3
|
+
Version: 0.18.2
|
|
4
4
|
Summary: OpenTelemetry OpenAI instrumentation
|
|
5
5
|
Home-page: https://github.com/traceloop/openllmetry/tree/main/packages/opentelemetry-instrumentation-openai
|
|
6
6
|
License: Apache-2.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
opentelemetry/instrumentation/openai/__init__.py,sha256=xl3Kvqry9glVhu8VtdknfUE9FpXQ7KWAFqtVlpjE-40,1344
|
|
2
|
-
opentelemetry/instrumentation/openai/shared/__init__.py,sha256=
|
|
3
|
-
opentelemetry/instrumentation/openai/shared/chat_wrappers.py,sha256=
|
|
2
|
+
opentelemetry/instrumentation/openai/shared/__init__.py,sha256=5kEyVhz2YDHvuq2SDQOsDhtjbG7R7GCn793oLq2_J_k,7490
|
|
3
|
+
opentelemetry/instrumentation/openai/shared/chat_wrappers.py,sha256=6gJUpjp1tq3eYviTVTRNq5RcF4yduhI6yAKJBSEGToI,23344
|
|
4
4
|
opentelemetry/instrumentation/openai/shared/completion_wrappers.py,sha256=-JHfgyxic5I3Wr3Uc_L-U7ztDVFcyovtF37tNLtaW3s,6604
|
|
5
5
|
opentelemetry/instrumentation/openai/shared/config.py,sha256=5uekQEnmYo1o6tsTD2IGc-cVmHUo5KmUC4pOVdrFFNk,102
|
|
6
6
|
opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py,sha256=6I6I98T1a5Np0ZjcGZQbId4ZyEmMI6o9wVm8qoRpO9o,6595
|
|
@@ -10,8 +10,8 @@ opentelemetry/instrumentation/openai/v0/__init__.py,sha256=ngmmYyfTwRQSjTZAvNpBI
|
|
|
10
10
|
opentelemetry/instrumentation/openai/v1/__init__.py,sha256=6XHk11JhkpZixgMDsjb0b-efd8LlBTG0jjMCyf0fOSo,8652
|
|
11
11
|
opentelemetry/instrumentation/openai/v1/assistant_wrappers.py,sha256=T6Vtdp1fAZdcYjGiTMZwkn4F4DgsltD4p4xLEFW-GhI,5874
|
|
12
12
|
opentelemetry/instrumentation/openai/v1/event_handler_wrapper.py,sha256=SAzYoun2yyOloofyOWtxpm8E2M9TL3Nm8TgKdNyXHuY,2779
|
|
13
|
-
opentelemetry/instrumentation/openai/version.py,sha256=
|
|
14
|
-
opentelemetry_instrumentation_openai-0.18.
|
|
15
|
-
opentelemetry_instrumentation_openai-0.18.
|
|
16
|
-
opentelemetry_instrumentation_openai-0.18.
|
|
17
|
-
opentelemetry_instrumentation_openai-0.18.
|
|
13
|
+
opentelemetry/instrumentation/openai/version.py,sha256=GYySpgpz2Cs3F3nz_H9h8KIG60jkP6f1a--08qCTJCQ,23
|
|
14
|
+
opentelemetry_instrumentation_openai-0.18.2.dist-info/METADATA,sha256=8_mfPUYiS7Wxf5kBberCnJ4KEm4VjYtk7ESz_tXiSZ0,2255
|
|
15
|
+
opentelemetry_instrumentation_openai-0.18.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
16
|
+
opentelemetry_instrumentation_openai-0.18.2.dist-info/entry_points.txt,sha256=vTBfiX5yXji5YHikuJHEOoBZ1TFdPQ1EI4ctd2pZSeE,93
|
|
17
|
+
opentelemetry_instrumentation_openai-0.18.2.dist-info/RECORD,,
|
|
File without changes
|