paid-python 0.0.5a40__py3-none-any.whl → 0.1.0__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/client.py +339 -233
- paid/logger.py +21 -0
- paid/tracing/__init__.py +4 -4
- paid/tracing/autoinstrumentation.py +6 -3
- paid/tracing/context_manager.py +243 -0
- paid/tracing/distributed_tracing.py +113 -0
- paid/tracing/signal.py +58 -28
- paid/tracing/tracing.py +103 -439
- paid/tracing/wrappers/anthropic/anthropicWrapper.py +11 -72
- paid/tracing/wrappers/bedrock/bedrockWrapper.py +3 -32
- paid/tracing/wrappers/gemini/geminiWrapper.py +10 -46
- paid/tracing/wrappers/langchain/paidLangChainCallback.py +3 -38
- paid/tracing/wrappers/llamaindex/llamaIndexWrapper.py +4 -38
- paid/tracing/wrappers/mistral/mistralWrapper.py +7 -118
- paid/tracing/wrappers/openai/openAiWrapper.py +56 -323
- paid/tracing/wrappers/openai_agents/openaiAgentsHook.py +8 -76
- {paid_python-0.0.5a40.dist-info → paid_python-0.1.0.dist-info}/METADATA +39 -192
- {paid_python-0.0.5a40.dist-info → paid_python-0.1.0.dist-info}/RECORD +20 -17
- {paid_python-0.0.5a40.dist-info → paid_python-0.1.0.dist-info}/LICENSE +0 -0
- {paid_python-0.0.5a40.dist-info → paid_python-0.1.0.dist-info}/WHEEL +0 -0
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
|
|
3
|
-
from opentelemetry import trace
|
|
4
3
|
from opentelemetry.trace import Status, StatusCode
|
|
5
4
|
|
|
6
5
|
from paid.tracing.tracing import (
|
|
7
6
|
get_paid_tracer,
|
|
8
|
-
logger,
|
|
9
|
-
paid_external_agent_id_var,
|
|
10
|
-
paid_external_customer_id_var,
|
|
11
|
-
paid_token_var,
|
|
12
7
|
)
|
|
13
8
|
from paid.tracing.wrappers.utils import get_audio_duration
|
|
14
9
|
|
|
@@ -22,80 +17,51 @@ except ImportError:
|
|
|
22
17
|
|
|
23
18
|
|
|
24
19
|
class PaidOpenAI:
|
|
25
|
-
def __init__(self, openai_client: OpenAI
|
|
20
|
+
def __init__(self, openai_client: OpenAI):
|
|
26
21
|
self.openai = openai_client
|
|
27
|
-
self.tracer = get_paid_tracer()
|
|
28
|
-
self.optional_tracing = optional_tracing
|
|
29
22
|
|
|
30
23
|
@property
|
|
31
24
|
def chat(self):
|
|
32
|
-
return ChatWrapper(self.openai
|
|
25
|
+
return ChatWrapper(self.openai)
|
|
33
26
|
|
|
34
27
|
@property
|
|
35
28
|
def responses(self):
|
|
36
|
-
return ResponsesWrapper(self.openai
|
|
29
|
+
return ResponsesWrapper(self.openai)
|
|
37
30
|
|
|
38
31
|
@property
|
|
39
32
|
def embeddings(self):
|
|
40
|
-
return EmbeddingsWrapper(self.openai
|
|
33
|
+
return EmbeddingsWrapper(self.openai)
|
|
41
34
|
|
|
42
35
|
@property
|
|
43
36
|
def images(self):
|
|
44
|
-
return ImagesWrapper(self.openai
|
|
37
|
+
return ImagesWrapper(self.openai)
|
|
45
38
|
|
|
46
39
|
@property
|
|
47
40
|
def audio(self):
|
|
48
|
-
return AudioWrapper(self.openai
|
|
41
|
+
return AudioWrapper(self.openai)
|
|
49
42
|
|
|
50
43
|
|
|
51
44
|
class ChatWrapper:
|
|
52
|
-
def __init__(self, openai_client: OpenAI
|
|
45
|
+
def __init__(self, openai_client: OpenAI):
|
|
53
46
|
self.openai = openai_client
|
|
54
|
-
self.tracer = tracer
|
|
55
|
-
self.optional_tracing = optional_tracing
|
|
56
47
|
|
|
57
48
|
@property
|
|
58
49
|
def completions(self):
|
|
59
|
-
return ChatCompletionsWrapper(self.openai
|
|
50
|
+
return ChatCompletionsWrapper(self.openai)
|
|
60
51
|
|
|
61
52
|
|
|
62
53
|
class ChatCompletionsWrapper:
|
|
63
|
-
def __init__(self, openai_client: OpenAI
|
|
54
|
+
def __init__(self, openai_client: OpenAI):
|
|
64
55
|
self.openai = openai_client
|
|
65
|
-
self.tracer = tracer
|
|
66
|
-
self.optional_tracing = optional_tracing
|
|
67
56
|
|
|
68
57
|
def create(self, *, model: str, messages: list, **kwargs) -> Any:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if self.optional_tracing:
|
|
73
|
-
logger.info(f"{self.__class__.__name__} No tracing, calling OpenAI directly.")
|
|
74
|
-
return self.openai.chat.completions.create(model=model, messages=messages, **kwargs)
|
|
75
|
-
raise RuntimeError("No OTEL span found. Make sure to call this method from Paid.trace().")
|
|
76
|
-
|
|
77
|
-
external_customer_id = paid_external_customer_id_var.get()
|
|
78
|
-
external_agent_id = paid_external_agent_id_var.get()
|
|
79
|
-
token = paid_token_var.get()
|
|
80
|
-
|
|
81
|
-
if not (external_customer_id and token):
|
|
82
|
-
if self.optional_tracing:
|
|
83
|
-
logger.info(f"{self.__class__.__name__} No external_customer_id or token, calling OpenAI directly")
|
|
84
|
-
return self.openai.chat.completions.create(model=model, messages=messages, **kwargs)
|
|
85
|
-
raise RuntimeError(
|
|
86
|
-
"Missing required tracing information: external_customer_id or token."
|
|
87
|
-
" Make sure to call this method from Paid.trace()."
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
with self.tracer.start_as_current_span("openai.chat.completions.create") as span:
|
|
58
|
+
tracer = get_paid_tracer()
|
|
59
|
+
|
|
60
|
+
with tracer.start_as_current_span("openai.chat.completions.create") as span:
|
|
91
61
|
attributes = {
|
|
92
62
|
"gen_ai.system": "openai",
|
|
93
63
|
"gen_ai.operation.name": "chat",
|
|
94
64
|
}
|
|
95
|
-
attributes["external_customer_id"] = external_customer_id
|
|
96
|
-
attributes["token"] = token
|
|
97
|
-
if external_agent_id:
|
|
98
|
-
attributes["external_agent_id"] = external_agent_id
|
|
99
65
|
span.set_attributes(attributes)
|
|
100
66
|
|
|
101
67
|
try:
|
|
@@ -149,45 +115,20 @@ class ChatCompletionsWrapper:
|
|
|
149
115
|
|
|
150
116
|
|
|
151
117
|
class EmbeddingsWrapper:
|
|
152
|
-
def __init__(self, openai_client: OpenAI
|
|
118
|
+
def __init__(self, openai_client: OpenAI):
|
|
153
119
|
self.openai = openai_client
|
|
154
|
-
self.tracer = tracer
|
|
155
|
-
self.optional_tracing = optional_tracing
|
|
156
120
|
|
|
157
121
|
def create(
|
|
158
122
|
self,
|
|
159
123
|
**kwargs, # Accept all parameters as-is to match the actual API
|
|
160
124
|
) -> Any:
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if self.optional_tracing:
|
|
165
|
-
logger.info(f"{self.__class__.__name__} No tracing, calling OpenAI directly.")
|
|
166
|
-
return self.openai.embeddings.create(**kwargs)
|
|
167
|
-
raise RuntimeError("No OTEL span found. Make sure to call this method from Paid.trace().")
|
|
168
|
-
|
|
169
|
-
external_customer_id = paid_external_customer_id_var.get()
|
|
170
|
-
external_agent_id = paid_external_agent_id_var.get()
|
|
171
|
-
token = paid_token_var.get()
|
|
172
|
-
|
|
173
|
-
if not (external_customer_id and token):
|
|
174
|
-
if self.optional_tracing:
|
|
175
|
-
logger.info(f"{self.__class__.__name__} No external_customer_id or token, calling OpenAI directly")
|
|
176
|
-
return self.openai.embeddings.create(**kwargs)
|
|
177
|
-
raise RuntimeError(
|
|
178
|
-
"Missing required tracing information: external_customer_id or token."
|
|
179
|
-
" Make sure to call this method from Paid.trace()."
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
with self.tracer.start_as_current_span("openai.embeddings.create") as span:
|
|
125
|
+
tracer = get_paid_tracer()
|
|
126
|
+
|
|
127
|
+
with tracer.start_as_current_span("openai.embeddings.create") as span:
|
|
183
128
|
attributes = {
|
|
184
129
|
"gen_ai.system": "openai",
|
|
185
130
|
"gen_ai.operation.name": "embeddings",
|
|
186
131
|
}
|
|
187
|
-
attributes["external_customer_id"] = external_customer_id
|
|
188
|
-
attributes["token"] = token
|
|
189
|
-
if external_agent_id:
|
|
190
|
-
attributes["external_agent_id"] = external_agent_id
|
|
191
132
|
span.set_attributes(attributes)
|
|
192
133
|
|
|
193
134
|
try:
|
|
@@ -216,49 +157,24 @@ class EmbeddingsWrapper:
|
|
|
216
157
|
|
|
217
158
|
|
|
218
159
|
class ImagesWrapper:
|
|
219
|
-
def __init__(self, openai_client: OpenAI
|
|
160
|
+
def __init__(self, openai_client: OpenAI):
|
|
220
161
|
self.openai = openai_client
|
|
221
|
-
self.tracer = tracer
|
|
222
|
-
self.optional_tracing = optional_tracing
|
|
223
162
|
|
|
224
163
|
def generate(
|
|
225
164
|
self,
|
|
226
165
|
**kwargs, # Accept all parameters as-is to match the actual API
|
|
227
166
|
) -> Any:
|
|
228
|
-
|
|
229
|
-
current_span = trace.get_current_span()
|
|
230
|
-
if current_span == trace.INVALID_SPAN:
|
|
231
|
-
if self.optional_tracing:
|
|
232
|
-
logger.info(f"{self.__class__.__name__} No tracing, calling OpenAI directly.")
|
|
233
|
-
return self.openai.images.generate(**kwargs)
|
|
234
|
-
raise RuntimeError("No OTEL span found. Make sure to call this method from Paid.trace().")
|
|
235
|
-
|
|
236
|
-
external_customer_id = paid_external_customer_id_var.get()
|
|
237
|
-
external_agent_id = paid_external_agent_id_var.get()
|
|
238
|
-
token = paid_token_var.get()
|
|
239
|
-
|
|
240
|
-
if not (external_customer_id and token):
|
|
241
|
-
if self.optional_tracing:
|
|
242
|
-
logger.info(f"{self.__class__.__name__} No external_customer_id or token, calling OpenAI directly")
|
|
243
|
-
return self.openai.images.generate(**kwargs)
|
|
244
|
-
raise RuntimeError(
|
|
245
|
-
"Missing required tracing information: external_customer_id or token."
|
|
246
|
-
" Make sure to call this method from Paid.trace()."
|
|
247
|
-
)
|
|
167
|
+
tracer = get_paid_tracer()
|
|
248
168
|
|
|
249
169
|
# Extract model for span naming with proper defaults
|
|
250
170
|
model = kwargs.get("model", "")
|
|
251
171
|
|
|
252
|
-
with
|
|
172
|
+
with tracer.start_as_current_span("openai.images.generate") as span:
|
|
253
173
|
attributes = {
|
|
254
174
|
"gen_ai.request.model": model, # there's no model in response, so extract from request
|
|
255
175
|
"gen_ai.system": "openai",
|
|
256
176
|
"gen_ai.operation.name": "image_generation",
|
|
257
177
|
}
|
|
258
|
-
attributes["external_customer_id"] = external_customer_id
|
|
259
|
-
attributes["token"] = token
|
|
260
|
-
if external_agent_id:
|
|
261
|
-
attributes["external_agent_id"] = external_agent_id
|
|
262
178
|
span.set_attributes(attributes)
|
|
263
179
|
|
|
264
180
|
try:
|
|
@@ -287,45 +203,20 @@ class ImagesWrapper:
|
|
|
287
203
|
|
|
288
204
|
|
|
289
205
|
class ResponsesWrapper:
|
|
290
|
-
def __init__(self, openai_client: OpenAI
|
|
206
|
+
def __init__(self, openai_client: OpenAI):
|
|
291
207
|
self.openai = openai_client
|
|
292
|
-
self.tracer = tracer
|
|
293
|
-
self.optional_tracing = optional_tracing
|
|
294
208
|
|
|
295
209
|
def create(
|
|
296
210
|
self,
|
|
297
211
|
**kwargs, # Accept all parameters as-is to match the actual API
|
|
298
212
|
) -> Any:
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
if self.optional_tracing:
|
|
303
|
-
logger.info(f"{self.__class__.__name__} No tracing, calling OpenAI directly.")
|
|
304
|
-
return self.openai.responses.create(**kwargs)
|
|
305
|
-
raise RuntimeError("No OTEL span found. Make sure to call this method from Paid.trace().")
|
|
306
|
-
|
|
307
|
-
external_customer_id = paid_external_customer_id_var.get()
|
|
308
|
-
external_agent_id = paid_external_agent_id_var.get()
|
|
309
|
-
token = paid_token_var.get()
|
|
310
|
-
|
|
311
|
-
if not (external_customer_id and token):
|
|
312
|
-
if self.optional_tracing:
|
|
313
|
-
logger.info(f"{self.__class__.__name__} No external_customer_id or token, calling OpenAI directly")
|
|
314
|
-
return self.openai.responses.create(**kwargs)
|
|
315
|
-
raise RuntimeError(
|
|
316
|
-
"Missing required tracing information: external_customer_id or token."
|
|
317
|
-
" Make sure to call this method from Paid.trace()."
|
|
318
|
-
)
|
|
319
|
-
|
|
320
|
-
with self.tracer.start_as_current_span("openai.responses.create") as span:
|
|
213
|
+
tracer = get_paid_tracer()
|
|
214
|
+
|
|
215
|
+
with tracer.start_as_current_span("openai.responses.create") as span:
|
|
321
216
|
attributes = {
|
|
322
217
|
"gen_ai.system": "openai",
|
|
323
218
|
"gen_ai.operation.name": "chat",
|
|
324
219
|
}
|
|
325
|
-
attributes["external_customer_id"] = external_customer_id
|
|
326
|
-
attributes["token"] = token
|
|
327
|
-
if external_agent_id:
|
|
328
|
-
attributes["external_agent_id"] = external_agent_id
|
|
329
220
|
span.set_attributes(attributes)
|
|
330
221
|
|
|
331
222
|
try:
|
|
@@ -376,46 +267,23 @@ class ResponsesWrapper:
|
|
|
376
267
|
|
|
377
268
|
|
|
378
269
|
class AudioWrapper:
|
|
379
|
-
def __init__(self, openai_client: OpenAI
|
|
270
|
+
def __init__(self, openai_client: OpenAI):
|
|
380
271
|
self.openai = openai_client
|
|
381
|
-
self.tracer = tracer
|
|
382
|
-
self.optional_tracing = optional_tracing
|
|
383
272
|
|
|
384
273
|
@property
|
|
385
274
|
def transcriptions(self):
|
|
386
|
-
return AudioTranscriptionsWrapper(self.openai
|
|
275
|
+
return AudioTranscriptionsWrapper(self.openai)
|
|
387
276
|
|
|
388
277
|
|
|
389
278
|
class AudioTranscriptionsWrapper:
|
|
390
|
-
def __init__(self, openai_client: OpenAI
|
|
279
|
+
def __init__(self, openai_client: OpenAI):
|
|
391
280
|
self.openai = openai_client
|
|
392
|
-
self.tracer = tracer
|
|
393
|
-
self.optional_tracing = optional_tracing
|
|
394
281
|
|
|
395
282
|
def create(
|
|
396
283
|
self,
|
|
397
284
|
**kwargs, # Accept all parameters as-is to match the actual API
|
|
398
285
|
) -> Any:
|
|
399
|
-
|
|
400
|
-
current_span = trace.get_current_span()
|
|
401
|
-
if current_span == trace.INVALID_SPAN:
|
|
402
|
-
if self.optional_tracing:
|
|
403
|
-
logger.info(f"{self.__class__.__name__} No tracing, calling OpenAI directly.")
|
|
404
|
-
return self.openai.audio.transcriptions.create(**kwargs)
|
|
405
|
-
raise RuntimeError("No OTEL span found. Make sure to call this method from Paid.trace().")
|
|
406
|
-
|
|
407
|
-
external_customer_id = paid_external_customer_id_var.get()
|
|
408
|
-
external_agent_id = paid_external_agent_id_var.get()
|
|
409
|
-
token = paid_token_var.get()
|
|
410
|
-
|
|
411
|
-
if not (external_customer_id and token):
|
|
412
|
-
if self.optional_tracing:
|
|
413
|
-
logger.info(f"{self.__class__.__name__} No external_customer_id or token, calling OpenAI directly")
|
|
414
|
-
return self.openai.audio.transcriptions.create(**kwargs)
|
|
415
|
-
raise RuntimeError(
|
|
416
|
-
"Missing required tracing information: external_customer_id or token."
|
|
417
|
-
" Make sure to call this method from Paid.trace()."
|
|
418
|
-
)
|
|
286
|
+
tracer = get_paid_tracer()
|
|
419
287
|
|
|
420
288
|
# Extract model and file for span attributes
|
|
421
289
|
model = kwargs.get("model", "")
|
|
@@ -423,16 +291,12 @@ class AudioTranscriptionsWrapper:
|
|
|
423
291
|
|
|
424
292
|
audio_duration = get_audio_duration(file_input) if file_input else None
|
|
425
293
|
|
|
426
|
-
with
|
|
294
|
+
with tracer.start_as_current_span("openai.audio.transcriptions.create") as span:
|
|
427
295
|
attributes = {
|
|
428
296
|
"gen_ai.request.model": model,
|
|
429
297
|
"gen_ai.system": "openai",
|
|
430
298
|
"gen_ai.operation.name": "transcription",
|
|
431
299
|
}
|
|
432
|
-
attributes["external_customer_id"] = external_customer_id
|
|
433
|
-
attributes["token"] = token
|
|
434
|
-
if external_agent_id:
|
|
435
|
-
attributes["external_agent_id"] = external_agent_id
|
|
436
300
|
if audio_duration:
|
|
437
301
|
attributes["gen_ai.audio.input_duration_seconds"] = audio_duration
|
|
438
302
|
span.set_attributes(attributes)
|
|
@@ -454,80 +318,51 @@ class AudioTranscriptionsWrapper:
|
|
|
454
318
|
|
|
455
319
|
|
|
456
320
|
class PaidAsyncOpenAI:
|
|
457
|
-
def __init__(self, openai_client: AsyncOpenAI
|
|
321
|
+
def __init__(self, openai_client: AsyncOpenAI):
|
|
458
322
|
self.openai = openai_client
|
|
459
|
-
self.tracer = get_paid_tracer()
|
|
460
|
-
self.optional_tracing = optional_tracing
|
|
461
323
|
|
|
462
324
|
@property
|
|
463
325
|
def chat(self):
|
|
464
|
-
return AsyncChatWrapper(self.openai
|
|
326
|
+
return AsyncChatWrapper(self.openai)
|
|
465
327
|
|
|
466
328
|
@property
|
|
467
329
|
def responses(self):
|
|
468
|
-
return AsyncResponsesWrapper(self.openai
|
|
330
|
+
return AsyncResponsesWrapper(self.openai)
|
|
469
331
|
|
|
470
332
|
@property
|
|
471
333
|
def embeddings(self):
|
|
472
|
-
return AsyncEmbeddingsWrapper(self.openai
|
|
334
|
+
return AsyncEmbeddingsWrapper(self.openai)
|
|
473
335
|
|
|
474
336
|
@property
|
|
475
337
|
def images(self):
|
|
476
|
-
return AsyncImagesWrapper(self.openai
|
|
338
|
+
return AsyncImagesWrapper(self.openai)
|
|
477
339
|
|
|
478
340
|
@property
|
|
479
341
|
def audio(self):
|
|
480
|
-
return AsyncAudioWrapper(self.openai
|
|
342
|
+
return AsyncAudioWrapper(self.openai)
|
|
481
343
|
|
|
482
344
|
|
|
483
345
|
class AsyncChatWrapper:
|
|
484
|
-
def __init__(self, openai_client: AsyncOpenAI
|
|
346
|
+
def __init__(self, openai_client: AsyncOpenAI):
|
|
485
347
|
self.openai = openai_client
|
|
486
|
-
self.tracer = tracer
|
|
487
|
-
self.optional_tracing = optional_tracing
|
|
488
348
|
|
|
489
349
|
@property
|
|
490
350
|
def completions(self):
|
|
491
|
-
return AsyncChatCompletionsWrapper(self.openai
|
|
351
|
+
return AsyncChatCompletionsWrapper(self.openai)
|
|
492
352
|
|
|
493
353
|
|
|
494
354
|
class AsyncChatCompletionsWrapper:
|
|
495
|
-
def __init__(self, openai_client: AsyncOpenAI
|
|
355
|
+
def __init__(self, openai_client: AsyncOpenAI):
|
|
496
356
|
self.openai = openai_client
|
|
497
|
-
self.tracer = tracer
|
|
498
|
-
self.optional_tracing = optional_tracing
|
|
499
357
|
|
|
500
358
|
async def create(self, *, model: str, messages: list, **kwargs) -> Any:
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
if self.optional_tracing:
|
|
505
|
-
logger.info(f"{self.__class__.__name__} No tracing, calling OpenAI directly.")
|
|
506
|
-
return await self.openai.chat.completions.create(model=model, messages=messages, **kwargs)
|
|
507
|
-
raise RuntimeError("No OTEL span found. Make sure to call this method from Paid.trace().")
|
|
508
|
-
|
|
509
|
-
external_customer_id = paid_external_customer_id_var.get()
|
|
510
|
-
external_agent_id = paid_external_agent_id_var.get()
|
|
511
|
-
token = paid_token_var.get()
|
|
512
|
-
|
|
513
|
-
if not (external_customer_id and token):
|
|
514
|
-
if self.optional_tracing:
|
|
515
|
-
logger.info(f"{self.__class__.__name__} No external_customer_id or token, calling OpenAI directly")
|
|
516
|
-
return await self.openai.chat.completions.create(model=model, messages=messages, **kwargs)
|
|
517
|
-
raise RuntimeError(
|
|
518
|
-
"Missing required tracing information: external_customer_id or token."
|
|
519
|
-
" Make sure to call this method from Paid.trace()."
|
|
520
|
-
)
|
|
521
|
-
|
|
522
|
-
with self.tracer.start_as_current_span("openai.chat.completions.create") as span:
|
|
359
|
+
tracer = get_paid_tracer()
|
|
360
|
+
|
|
361
|
+
with tracer.start_as_current_span("openai.chat.completions.create") as span:
|
|
523
362
|
attributes = {
|
|
524
363
|
"gen_ai.system": "openai",
|
|
525
364
|
"gen_ai.operation.name": "chat",
|
|
526
365
|
}
|
|
527
|
-
attributes["external_customer_id"] = external_customer_id
|
|
528
|
-
attributes["token"] = token
|
|
529
|
-
if external_agent_id:
|
|
530
|
-
attributes["external_agent_id"] = external_agent_id
|
|
531
366
|
span.set_attributes(attributes)
|
|
532
367
|
|
|
533
368
|
try:
|
|
@@ -581,45 +416,20 @@ class AsyncChatCompletionsWrapper:
|
|
|
581
416
|
|
|
582
417
|
|
|
583
418
|
class AsyncEmbeddingsWrapper:
|
|
584
|
-
def __init__(self, openai_client: AsyncOpenAI
|
|
419
|
+
def __init__(self, openai_client: AsyncOpenAI):
|
|
585
420
|
self.openai = openai_client
|
|
586
|
-
self.tracer = tracer
|
|
587
|
-
self.optional_tracing = optional_tracing
|
|
588
421
|
|
|
589
422
|
async def create(
|
|
590
423
|
self,
|
|
591
424
|
**kwargs, # Accept all parameters as-is to match the actual API
|
|
592
425
|
) -> Any:
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
if self.optional_tracing:
|
|
597
|
-
logger.info(f"{self.__class__.__name__} No tracing, calling OpenAI directly.")
|
|
598
|
-
return await self.openai.embeddings.create(**kwargs)
|
|
599
|
-
raise RuntimeError("No OTEL span found. Make sure to call this method from Paid.trace().")
|
|
600
|
-
|
|
601
|
-
external_customer_id = paid_external_customer_id_var.get()
|
|
602
|
-
external_agent_id = paid_external_agent_id_var.get()
|
|
603
|
-
token = paid_token_var.get()
|
|
604
|
-
|
|
605
|
-
if not (external_customer_id and token):
|
|
606
|
-
if self.optional_tracing:
|
|
607
|
-
logger.info(f"{self.__class__.__name__} No external_customer_id or token, calling OpenAI directly")
|
|
608
|
-
return await self.openai.embeddings.create(**kwargs)
|
|
609
|
-
raise RuntimeError(
|
|
610
|
-
"Missing required tracing information: external_customer_id or token."
|
|
611
|
-
" Make sure to call this method from Paid.trace()."
|
|
612
|
-
)
|
|
613
|
-
|
|
614
|
-
with self.tracer.start_as_current_span("openai.embeddings.create") as span:
|
|
426
|
+
tracer = get_paid_tracer()
|
|
427
|
+
|
|
428
|
+
with tracer.start_as_current_span("openai.embeddings.create") as span:
|
|
615
429
|
attributes = {
|
|
616
430
|
"gen_ai.system": "openai",
|
|
617
431
|
"gen_ai.operation.name": "embeddings",
|
|
618
432
|
}
|
|
619
|
-
attributes["external_customer_id"] = external_customer_id
|
|
620
|
-
attributes["token"] = token
|
|
621
|
-
if external_agent_id:
|
|
622
|
-
attributes["external_agent_id"] = external_agent_id
|
|
623
433
|
span.set_attributes(attributes)
|
|
624
434
|
|
|
625
435
|
try:
|
|
@@ -648,49 +458,24 @@ class AsyncEmbeddingsWrapper:
|
|
|
648
458
|
|
|
649
459
|
|
|
650
460
|
class AsyncImagesWrapper:
|
|
651
|
-
def __init__(self, openai_client: AsyncOpenAI
|
|
461
|
+
def __init__(self, openai_client: AsyncOpenAI):
|
|
652
462
|
self.openai = openai_client
|
|
653
|
-
self.tracer = tracer
|
|
654
|
-
self.optional_tracing = optional_tracing
|
|
655
463
|
|
|
656
464
|
async def generate(
|
|
657
465
|
self,
|
|
658
466
|
**kwargs, # Accept all parameters as-is to match the actual API
|
|
659
467
|
) -> Any:
|
|
660
|
-
|
|
661
|
-
current_span = trace.get_current_span()
|
|
662
|
-
if current_span == trace.INVALID_SPAN:
|
|
663
|
-
if self.optional_tracing:
|
|
664
|
-
logger.info(f"{self.__class__.__name__} No tracing, calling OpenAI directly.")
|
|
665
|
-
return await self.openai.images.generate(**kwargs)
|
|
666
|
-
raise RuntimeError("No OTEL span found. Make sure to call this method from Paid.trace().")
|
|
667
|
-
|
|
668
|
-
external_customer_id = paid_external_customer_id_var.get()
|
|
669
|
-
external_agent_id = paid_external_agent_id_var.get()
|
|
670
|
-
token = paid_token_var.get()
|
|
671
|
-
|
|
672
|
-
if not (external_customer_id and token):
|
|
673
|
-
if self.optional_tracing:
|
|
674
|
-
logger.info(f"{self.__class__.__name__} No external_customer_id or token, calling OpenAI directly")
|
|
675
|
-
return await self.openai.images.generate(**kwargs)
|
|
676
|
-
raise RuntimeError(
|
|
677
|
-
"Missing required tracing information: external_customer_id or token."
|
|
678
|
-
" Make sure to call this method from Paid.trace()."
|
|
679
|
-
)
|
|
468
|
+
tracer = get_paid_tracer()
|
|
680
469
|
|
|
681
470
|
# Extract model for span naming with proper defaults
|
|
682
471
|
model = kwargs.get("model", "")
|
|
683
472
|
|
|
684
|
-
with
|
|
473
|
+
with tracer.start_as_current_span("openai.images.generate") as span:
|
|
685
474
|
attributes = {
|
|
686
475
|
"gen_ai.request.model": model, # there's no model in response, so extract from request
|
|
687
476
|
"gen_ai.system": "openai",
|
|
688
477
|
"gen_ai.operation.name": "image_generation",
|
|
689
478
|
}
|
|
690
|
-
attributes["external_customer_id"] = external_customer_id
|
|
691
|
-
attributes["token"] = token
|
|
692
|
-
if external_agent_id:
|
|
693
|
-
attributes["external_agent_id"] = external_agent_id
|
|
694
479
|
span.set_attributes(attributes)
|
|
695
480
|
|
|
696
481
|
try:
|
|
@@ -719,45 +504,20 @@ class AsyncImagesWrapper:
|
|
|
719
504
|
|
|
720
505
|
|
|
721
506
|
class AsyncResponsesWrapper:
|
|
722
|
-
def __init__(self, openai_client: AsyncOpenAI
|
|
507
|
+
def __init__(self, openai_client: AsyncOpenAI):
|
|
723
508
|
self.openai = openai_client
|
|
724
|
-
self.tracer = tracer
|
|
725
|
-
self.optional_tracing = optional_tracing
|
|
726
509
|
|
|
727
510
|
async def create(
|
|
728
511
|
self,
|
|
729
512
|
**kwargs, # Accept all parameters as-is to match the actual API
|
|
730
513
|
) -> Any:
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
if self.optional_tracing:
|
|
735
|
-
logger.info(f"{self.__class__.__name__} No tracing, calling OpenAI directly.")
|
|
736
|
-
return await self.openai.responses.create(**kwargs)
|
|
737
|
-
raise RuntimeError("No OTEL span found. Make sure to call this method from Paid.trace().")
|
|
738
|
-
|
|
739
|
-
external_customer_id = paid_external_customer_id_var.get()
|
|
740
|
-
external_agent_id = paid_external_agent_id_var.get()
|
|
741
|
-
token = paid_token_var.get()
|
|
742
|
-
|
|
743
|
-
if not (external_customer_id and token):
|
|
744
|
-
if self.optional_tracing:
|
|
745
|
-
logger.info(f"{self.__class__.__name__} No external_customer_id or token, calling OpenAI directly")
|
|
746
|
-
return await self.openai.responses.create(**kwargs)
|
|
747
|
-
raise RuntimeError(
|
|
748
|
-
"Missing required tracing information: external_customer_id or token."
|
|
749
|
-
" Make sure to call this method from Paid.trace()."
|
|
750
|
-
)
|
|
751
|
-
|
|
752
|
-
with self.tracer.start_as_current_span("openai.responses.create") as span:
|
|
514
|
+
tracer = get_paid_tracer()
|
|
515
|
+
|
|
516
|
+
with tracer.start_as_current_span("openai.responses.create") as span:
|
|
753
517
|
attributes = {
|
|
754
518
|
"gen_ai.system": "openai",
|
|
755
519
|
"gen_ai.operation.name": "chat",
|
|
756
520
|
}
|
|
757
|
-
attributes["external_customer_id"] = external_customer_id
|
|
758
|
-
attributes["token"] = token
|
|
759
|
-
if external_agent_id:
|
|
760
|
-
attributes["external_agent_id"] = external_agent_id
|
|
761
521
|
span.set_attributes(attributes)
|
|
762
522
|
|
|
763
523
|
try:
|
|
@@ -808,46 +568,23 @@ class AsyncResponsesWrapper:
|
|
|
808
568
|
|
|
809
569
|
|
|
810
570
|
class AsyncAudioWrapper:
|
|
811
|
-
def __init__(self, openai_client: AsyncOpenAI
|
|
571
|
+
def __init__(self, openai_client: AsyncOpenAI):
|
|
812
572
|
self.openai = openai_client
|
|
813
|
-
self.tracer = tracer
|
|
814
|
-
self.optional_tracing = optional_tracing
|
|
815
573
|
|
|
816
574
|
@property
|
|
817
575
|
def transcriptions(self):
|
|
818
|
-
return AsyncAudioTranscriptionsWrapper(self.openai
|
|
576
|
+
return AsyncAudioTranscriptionsWrapper(self.openai)
|
|
819
577
|
|
|
820
578
|
|
|
821
579
|
class AsyncAudioTranscriptionsWrapper:
|
|
822
|
-
def __init__(self, openai_client: AsyncOpenAI
|
|
580
|
+
def __init__(self, openai_client: AsyncOpenAI):
|
|
823
581
|
self.openai = openai_client
|
|
824
|
-
self.tracer = tracer
|
|
825
|
-
self.optional_tracing = optional_tracing
|
|
826
582
|
|
|
827
583
|
async def create(
|
|
828
584
|
self,
|
|
829
585
|
**kwargs, # Accept all parameters as-is to match the actual API
|
|
830
586
|
) -> Any:
|
|
831
|
-
|
|
832
|
-
current_span = trace.get_current_span()
|
|
833
|
-
if current_span == trace.INVALID_SPAN:
|
|
834
|
-
if self.optional_tracing:
|
|
835
|
-
logger.info(f"{self.__class__.__name__} No tracing, calling OpenAI directly.")
|
|
836
|
-
return await self.openai.audio.transcriptions.create(**kwargs)
|
|
837
|
-
raise RuntimeError("No OTEL span found. Make sure to call this method from Paid.trace().")
|
|
838
|
-
|
|
839
|
-
external_customer_id = paid_external_customer_id_var.get()
|
|
840
|
-
external_agent_id = paid_external_agent_id_var.get()
|
|
841
|
-
token = paid_token_var.get()
|
|
842
|
-
|
|
843
|
-
if not (external_customer_id and token):
|
|
844
|
-
if self.optional_tracing:
|
|
845
|
-
logger.info(f"{self.__class__.__name__} No external_customer_id or token, calling OpenAI directly")
|
|
846
|
-
return await self.openai.audio.transcriptions.create(**kwargs)
|
|
847
|
-
raise RuntimeError(
|
|
848
|
-
"Missing required tracing information: external_customer_id or token."
|
|
849
|
-
" Make sure to call this method from Paid.trace()."
|
|
850
|
-
)
|
|
587
|
+
tracer = get_paid_tracer()
|
|
851
588
|
|
|
852
589
|
# Extract model and file for span attributes
|
|
853
590
|
model = kwargs.get("model", "")
|
|
@@ -856,16 +593,12 @@ class AsyncAudioTranscriptionsWrapper:
|
|
|
856
593
|
# Get audio duration if possible
|
|
857
594
|
audio_duration = get_audio_duration(file_input) if file_input else None
|
|
858
595
|
|
|
859
|
-
with
|
|
596
|
+
with tracer.start_as_current_span("openai.audio.transcriptions.create") as span:
|
|
860
597
|
attributes = {
|
|
861
598
|
"gen_ai.request.model": model,
|
|
862
599
|
"gen_ai.system": "openai",
|
|
863
600
|
"gen_ai.operation.name": "transcription",
|
|
864
601
|
}
|
|
865
|
-
attributes["external_customer_id"] = external_customer_id
|
|
866
|
-
attributes["token"] = token
|
|
867
|
-
if external_agent_id:
|
|
868
|
-
attributes["external_agent_id"] = external_agent_id
|
|
869
602
|
if audio_duration:
|
|
870
603
|
attributes["gen_ai.audio.input_duration_seconds"] = audio_duration
|
|
871
604
|
span.set_attributes(attributes)
|