paid-python 0.5.0__py3-none-any.whl → 1.0.0a0__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.
- paid/__init__.py +33 -0
- paid/client.py +1 -472
- paid/core/client_wrapper.py +3 -2
- paid/customers/__init__.py +3 -0
- paid/customers/client.py +428 -4
- paid/customers/raw_client.py +594 -2
- paid/customers/types/__init__.py +8 -0
- paid/customers/types/customers_check_entitlement_request_view.py +5 -0
- paid/customers/types/customers_check_entitlement_response.py +22 -0
- paid/orders/client.py +445 -0
- paid/orders/raw_client.py +705 -0
- paid/plans/client.py +142 -0
- paid/plans/raw_client.py +238 -0
- paid/types/__init__.py +30 -0
- paid/types/cancel_renewal_response.py +49 -0
- paid/types/contact_create_for_customer.py +37 -0
- paid/types/invoice.py +75 -0
- paid/types/invoice_status.py +5 -0
- paid/types/payment_method.py +58 -0
- paid/types/payment_method_card.py +49 -0
- paid/types/payment_method_type.py +5 -0
- paid/types/payment_method_us_bank_account.py +36 -0
- paid/types/payment_method_us_bank_account_account_type.py +5 -0
- paid/types/plan_group.py +60 -0
- paid/types/plan_plan_products_item.py +6 -0
- paid/types/plan_with_features.py +69 -0
- paid/types/plan_with_features_features_item.py +34 -0
- paid/types/proration_attribute_update.py +44 -0
- paid/types/proration_detail.py +49 -0
- paid/types/proration_upgrade_response.py +73 -0
- paid/types/signal_v_2.py +5 -5
- paid/usage/client.py +6 -6
- {paid_python-0.5.0.dist-info → paid_python-1.0.0a0.dist-info}/METADATA +6 -4
- {paid_python-0.5.0.dist-info → paid_python-1.0.0a0.dist-info}/RECORD +36 -36
- opentelemetry/instrumentation/openai/__init__.py +0 -54
- opentelemetry/instrumentation/openai/shared/__init__.py +0 -399
- opentelemetry/instrumentation/openai/shared/audio_wrappers.py +0 -247
- opentelemetry/instrumentation/openai/shared/chat_wrappers.py +0 -1192
- opentelemetry/instrumentation/openai/shared/completion_wrappers.py +0 -292
- opentelemetry/instrumentation/openai/shared/config.py +0 -15
- opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py +0 -311
- opentelemetry/instrumentation/openai/shared/event_emitter.py +0 -108
- opentelemetry/instrumentation/openai/shared/event_models.py +0 -41
- opentelemetry/instrumentation/openai/shared/image_gen_wrappers.py +0 -68
- opentelemetry/instrumentation/openai/shared/span_utils.py +0 -0
- opentelemetry/instrumentation/openai/utils.py +0 -213
- opentelemetry/instrumentation/openai/v0/__init__.py +0 -176
- opentelemetry/instrumentation/openai/v1/__init__.py +0 -394
- opentelemetry/instrumentation/openai/v1/assistant_wrappers.py +0 -329
- opentelemetry/instrumentation/openai/v1/event_handler_wrapper.py +0 -134
- opentelemetry/instrumentation/openai/v1/responses_wrappers.py +0 -1113
- opentelemetry/instrumentation/openai/version.py +0 -1
- {paid_python-0.5.0.dist-info → paid_python-1.0.0a0.dist-info}/LICENSE +0 -0
- {paid_python-0.5.0.dist-info → paid_python-1.0.0a0.dist-info}/WHEEL +0 -0
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
import time
|
|
3
|
-
|
|
4
|
-
from opentelemetry import context as context_api
|
|
5
|
-
from opentelemetry.instrumentation.openai.shared import (
|
|
6
|
-
_set_client_attributes,
|
|
7
|
-
_set_request_attributes,
|
|
8
|
-
_set_response_attributes,
|
|
9
|
-
_set_span_attribute,
|
|
10
|
-
metric_shared_attributes,
|
|
11
|
-
model_as_dict,
|
|
12
|
-
)
|
|
13
|
-
from opentelemetry.instrumentation.openai.utils import (
|
|
14
|
-
_with_audio_telemetry_wrapper,
|
|
15
|
-
dont_throw,
|
|
16
|
-
is_openai_v1,
|
|
17
|
-
start_as_current_span_async,
|
|
18
|
-
)
|
|
19
|
-
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
|
|
20
|
-
from opentelemetry.metrics import Counter, Histogram
|
|
21
|
-
from opentelemetry.semconv.attributes.error_attributes import ERROR_TYPE
|
|
22
|
-
from opentelemetry.semconv_ai import (
|
|
23
|
-
SUPPRESS_LANGUAGE_MODEL_INSTRUMENTATION_KEY,
|
|
24
|
-
SpanAttributes,
|
|
25
|
-
)
|
|
26
|
-
from opentelemetry.trace import SpanKind, Status, StatusCode
|
|
27
|
-
|
|
28
|
-
SPAN_NAME = "openai.audio.transcriptions"
|
|
29
|
-
|
|
30
|
-
logger = logging.getLogger(__name__)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def _get_audio_duration(file):
|
|
34
|
-
"""
|
|
35
|
-
Extract audio duration from file object.
|
|
36
|
-
Returns duration in seconds, or None if unable to determine.
|
|
37
|
-
"""
|
|
38
|
-
try:
|
|
39
|
-
# Try to get duration from common audio libraries
|
|
40
|
-
# First check if it's a file-like object with a name attribute
|
|
41
|
-
if hasattr(file, "name"):
|
|
42
|
-
file_path = file.name
|
|
43
|
-
elif isinstance(file, (str, bytes)):
|
|
44
|
-
# If it's a path string or bytes
|
|
45
|
-
return None
|
|
46
|
-
else:
|
|
47
|
-
# If it's a file-like object without name, we can't easily determine duration
|
|
48
|
-
return None
|
|
49
|
-
|
|
50
|
-
# Try mutagen (supports many formats)
|
|
51
|
-
try:
|
|
52
|
-
from mutagen import File as MutagenFile
|
|
53
|
-
|
|
54
|
-
audio = MutagenFile(file_path)
|
|
55
|
-
if audio and hasattr(audio.info, "length"):
|
|
56
|
-
return audio.info.length
|
|
57
|
-
except (ImportError, Exception):
|
|
58
|
-
pass
|
|
59
|
-
|
|
60
|
-
except Exception as e:
|
|
61
|
-
logger.debug(f"Unable to extract audio duration: {e}")
|
|
62
|
-
|
|
63
|
-
return None
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
@_with_audio_telemetry_wrapper
|
|
67
|
-
def transcription_wrapper(
|
|
68
|
-
tracer,
|
|
69
|
-
duration_histogram: Histogram,
|
|
70
|
-
exception_counter: Counter,
|
|
71
|
-
wrapped,
|
|
72
|
-
instance,
|
|
73
|
-
args,
|
|
74
|
-
kwargs,
|
|
75
|
-
):
|
|
76
|
-
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY) or context_api.get_value(
|
|
77
|
-
SUPPRESS_LANGUAGE_MODEL_INSTRUMENTATION_KEY
|
|
78
|
-
):
|
|
79
|
-
return wrapped(*args, **kwargs)
|
|
80
|
-
|
|
81
|
-
with tracer.start_as_current_span(
|
|
82
|
-
name=SPAN_NAME,
|
|
83
|
-
kind=SpanKind.CLIENT,
|
|
84
|
-
) as span:
|
|
85
|
-
_handle_request(span, kwargs, instance)
|
|
86
|
-
|
|
87
|
-
try:
|
|
88
|
-
# record time for duration
|
|
89
|
-
start_time = time.time()
|
|
90
|
-
response = wrapped(*args, **kwargs)
|
|
91
|
-
end_time = time.time()
|
|
92
|
-
except Exception as e: # pylint: disable=broad-except
|
|
93
|
-
end_time = time.time()
|
|
94
|
-
duration = end_time - start_time if "start_time" in locals() else 0
|
|
95
|
-
attributes = {
|
|
96
|
-
"error.type": e.__class__.__name__,
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
# if there are legal duration, record it
|
|
100
|
-
if duration > 0 and duration_histogram:
|
|
101
|
-
duration_histogram.record(duration, attributes=attributes)
|
|
102
|
-
if exception_counter:
|
|
103
|
-
exception_counter.add(1, attributes=attributes)
|
|
104
|
-
|
|
105
|
-
span.set_attribute(ERROR_TYPE, e.__class__.__name__)
|
|
106
|
-
span.record_exception(e)
|
|
107
|
-
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
108
|
-
span.end()
|
|
109
|
-
|
|
110
|
-
raise
|
|
111
|
-
|
|
112
|
-
duration = end_time - start_time
|
|
113
|
-
|
|
114
|
-
_handle_response(
|
|
115
|
-
response,
|
|
116
|
-
span,
|
|
117
|
-
instance,
|
|
118
|
-
duration_histogram,
|
|
119
|
-
duration,
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
return response
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
@_with_audio_telemetry_wrapper
|
|
126
|
-
async def atranscription_wrapper(
|
|
127
|
-
tracer,
|
|
128
|
-
duration_histogram: Histogram,
|
|
129
|
-
exception_counter: Counter,
|
|
130
|
-
wrapped,
|
|
131
|
-
instance,
|
|
132
|
-
args,
|
|
133
|
-
kwargs,
|
|
134
|
-
):
|
|
135
|
-
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY) or context_api.get_value(
|
|
136
|
-
SUPPRESS_LANGUAGE_MODEL_INSTRUMENTATION_KEY
|
|
137
|
-
):
|
|
138
|
-
return await wrapped(*args, **kwargs)
|
|
139
|
-
|
|
140
|
-
async with start_as_current_span_async(
|
|
141
|
-
tracer=tracer,
|
|
142
|
-
name=SPAN_NAME,
|
|
143
|
-
kind=SpanKind.CLIENT,
|
|
144
|
-
) as span:
|
|
145
|
-
_handle_request(span, kwargs, instance)
|
|
146
|
-
|
|
147
|
-
try:
|
|
148
|
-
# record time for duration
|
|
149
|
-
start_time = time.time()
|
|
150
|
-
response = await wrapped(*args, **kwargs)
|
|
151
|
-
end_time = time.time()
|
|
152
|
-
except Exception as e: # pylint: disable=broad-except
|
|
153
|
-
end_time = time.time()
|
|
154
|
-
duration = end_time - start_time if "start_time" in locals() else 0
|
|
155
|
-
attributes = {
|
|
156
|
-
"error.type": e.__class__.__name__,
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
# if there are legal duration, record it
|
|
160
|
-
if duration > 0 and duration_histogram:
|
|
161
|
-
duration_histogram.record(duration, attributes=attributes)
|
|
162
|
-
if exception_counter:
|
|
163
|
-
exception_counter.add(1, attributes=attributes)
|
|
164
|
-
|
|
165
|
-
span.set_attribute(ERROR_TYPE, e.__class__.__name__)
|
|
166
|
-
span.record_exception(e)
|
|
167
|
-
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
168
|
-
span.end()
|
|
169
|
-
|
|
170
|
-
raise
|
|
171
|
-
|
|
172
|
-
duration = end_time - start_time
|
|
173
|
-
|
|
174
|
-
_handle_response(
|
|
175
|
-
response,
|
|
176
|
-
span,
|
|
177
|
-
instance,
|
|
178
|
-
duration_histogram,
|
|
179
|
-
duration,
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
return response
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
@dont_throw
|
|
186
|
-
def _handle_request(span, kwargs, instance):
|
|
187
|
-
_set_request_attributes(span, kwargs, instance)
|
|
188
|
-
_set_client_attributes(span, instance)
|
|
189
|
-
|
|
190
|
-
# Extract and set audio duration
|
|
191
|
-
file_param = kwargs.get("file")
|
|
192
|
-
if file_param:
|
|
193
|
-
audio_duration = _get_audio_duration(file_param)
|
|
194
|
-
if audio_duration is not None:
|
|
195
|
-
# _set_span_attribute(
|
|
196
|
-
# span, SpanAttributes.LLM_OPENAI_AUDIO_INPUT_DURATION_SECONDS, audio_duration
|
|
197
|
-
# )
|
|
198
|
-
# TODO(Ata): come back here later when semconv is published
|
|
199
|
-
_set_span_attribute(
|
|
200
|
-
span, 'gen_ai.openai.audio.input.duration_seconds', audio_duration
|
|
201
|
-
)
|
|
202
|
-
else:
|
|
203
|
-
print("REMOVE ME : ATA-DBG : COULD NOT READ AUDIO FILE WITH MUTAGEN")
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
@dont_throw
|
|
207
|
-
def _handle_response(
|
|
208
|
-
response,
|
|
209
|
-
span,
|
|
210
|
-
instance=None,
|
|
211
|
-
duration_histogram=None,
|
|
212
|
-
duration=None,
|
|
213
|
-
):
|
|
214
|
-
if is_openai_v1():
|
|
215
|
-
response_dict = model_as_dict(response)
|
|
216
|
-
else:
|
|
217
|
-
response_dict = response
|
|
218
|
-
|
|
219
|
-
# metrics record
|
|
220
|
-
_set_transcription_metrics(
|
|
221
|
-
instance,
|
|
222
|
-
duration_histogram,
|
|
223
|
-
response_dict,
|
|
224
|
-
duration,
|
|
225
|
-
)
|
|
226
|
-
|
|
227
|
-
# span attributes
|
|
228
|
-
_set_response_attributes(span, response_dict)
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
def _set_transcription_metrics(
|
|
232
|
-
instance,
|
|
233
|
-
duration_histogram,
|
|
234
|
-
response_dict,
|
|
235
|
-
duration,
|
|
236
|
-
):
|
|
237
|
-
from opentelemetry.instrumentation.openai.shared import _get_openai_base_url
|
|
238
|
-
|
|
239
|
-
shared_attributes = metric_shared_attributes(
|
|
240
|
-
response_model=response_dict.get("model") or None,
|
|
241
|
-
operation="audio.transcriptions",
|
|
242
|
-
server_address=_get_openai_base_url(instance),
|
|
243
|
-
)
|
|
244
|
-
|
|
245
|
-
# duration metrics
|
|
246
|
-
if duration and isinstance(duration, (float, int)) and duration_histogram:
|
|
247
|
-
duration_histogram.record(duration, attributes=shared_attributes)
|