paid-python 0.4.0__tar.gz → 0.4.1__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.
Files changed (127) hide show
  1. {paid_python-0.4.0 → paid_python-0.4.1}/PKG-INFO +1 -1
  2. {paid_python-0.4.0 → paid_python-0.4.1}/pyproject.toml +12 -5
  3. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/client.py +23 -2
  4. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/__init__.py +1 -1
  5. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/autoinstrumentation.py +1 -2
  6. {paid_python-0.4.0/src/paid/_vendor → paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai}/opentelemetry/instrumentation/openai/__init__.py +6 -6
  7. {paid_python-0.4.0/src/paid/_vendor → paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai}/opentelemetry/instrumentation/openai/shared/__init__.py +2 -2
  8. paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai/opentelemetry/instrumentation/openai/shared/audio_wrappers.py +247 -0
  9. {paid_python-0.4.0/src/paid/_vendor → paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai}/opentelemetry/instrumentation/openai/shared/chat_wrappers.py +5 -5
  10. {paid_python-0.4.0/src/paid/_vendor → paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai}/opentelemetry/instrumentation/openai/shared/completion_wrappers.py +5 -5
  11. {paid_python-0.4.0/src/paid/_vendor → paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai}/opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py +5 -5
  12. {paid_python-0.4.0/src/paid/_vendor → paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai}/opentelemetry/instrumentation/openai/shared/event_emitter.py +2 -2
  13. {paid_python-0.4.0/src/paid/_vendor → paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai}/opentelemetry/instrumentation/openai/shared/image_gen_wrappers.py +3 -3
  14. {paid_python-0.4.0/src/paid/_vendor → paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai}/opentelemetry/instrumentation/openai/utils.py +24 -1
  15. {paid_python-0.4.0/src/paid/_vendor → paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai}/opentelemetry/instrumentation/openai/v0/__init__.py +6 -6
  16. {paid_python-0.4.0/src/paid/_vendor → paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai}/opentelemetry/instrumentation/openai/v1/__init__.py +45 -9
  17. {paid_python-0.4.0/src/paid/_vendor → paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai}/opentelemetry/instrumentation/openai/v1/assistant_wrappers.py +6 -6
  18. {paid_python-0.4.0/src/paid/_vendor → paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai}/opentelemetry/instrumentation/openai/v1/event_handler_wrapper.py +4 -4
  19. {paid_python-0.4.0/src/paid/_vendor → paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai}/opentelemetry/instrumentation/openai/v1/responses_wrappers.py +186 -69
  20. paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai/opentelemetry/instrumentation/openai/version.py +1 -0
  21. paid_python-0.4.0/src/paid/_vendor/__init__.py +0 -0
  22. paid_python-0.4.0/src/paid/_vendor/opentelemetry/__init__.py +0 -0
  23. paid_python-0.4.0/src/paid/_vendor/opentelemetry/instrumentation/__init__.py +0 -0
  24. paid_python-0.4.0/src/paid/_vendor/opentelemetry/instrumentation/openai/version.py +0 -1
  25. {paid_python-0.4.0 → paid_python-0.4.1}/LICENSE +0 -0
  26. {paid_python-0.4.0 → paid_python-0.4.1}/README.md +0 -0
  27. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/__init__.py +0 -0
  28. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/agents/__init__.py +0 -0
  29. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/agents/client.py +0 -0
  30. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/agents/raw_client.py +0 -0
  31. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/contacts/__init__.py +0 -0
  32. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/contacts/client.py +0 -0
  33. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/contacts/raw_client.py +0 -0
  34. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/core/__init__.py +0 -0
  35. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/core/api_error.py +0 -0
  36. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/core/client_wrapper.py +0 -0
  37. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/core/datetime_utils.py +0 -0
  38. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/core/file.py +0 -0
  39. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/core/force_multipart.py +0 -0
  40. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/core/http_client.py +0 -0
  41. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/core/http_response.py +0 -0
  42. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/core/jsonable_encoder.py +0 -0
  43. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/core/pydantic_utilities.py +0 -0
  44. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/core/query_encoder.py +0 -0
  45. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/core/remove_none_from_dict.py +0 -0
  46. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/core/request_options.py +0 -0
  47. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/core/serialization.py +0 -0
  48. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/customers/__init__.py +0 -0
  49. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/customers/client.py +0 -0
  50. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/customers/raw_client.py +0 -0
  51. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/environment.py +0 -0
  52. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/errors/__init__.py +0 -0
  53. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/errors/bad_request_error.py +0 -0
  54. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/errors/forbidden_error.py +0 -0
  55. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/errors/not_found_error.py +0 -0
  56. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/logger.py +0 -0
  57. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/orders/__init__.py +0 -0
  58. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/orders/client.py +0 -0
  59. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/orders/lines/__init__.py +0 -0
  60. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/orders/lines/client.py +0 -0
  61. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/orders/lines/raw_client.py +0 -0
  62. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/orders/raw_client.py +0 -0
  63. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/py.typed +0 -0
  64. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/context_data.py +0 -0
  65. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/context_manager.py +0 -0
  66. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/distributed_tracing.py +0 -0
  67. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/signal.py +0 -0
  68. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/tracing.py +0 -0
  69. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/__init__.py +0 -0
  70. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/anthropic/__init__.py +0 -0
  71. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/anthropic/anthropicWrapper.py +0 -0
  72. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/bedrock/__init__.py +0 -0
  73. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/bedrock/bedrockWrapper.py +0 -0
  74. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/gemini/__init__.py +0 -0
  75. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/gemini/geminiWrapper.py +0 -0
  76. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/langchain/__init__.py +0 -0
  77. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/langchain/paidLangChainCallback.py +0 -0
  78. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/llamaindex/__init__.py +0 -0
  79. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/llamaindex/llamaIndexWrapper.py +0 -0
  80. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/mistral/__init__.py +0 -0
  81. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/mistral/mistralWrapper.py +0 -0
  82. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/openai/__init__.py +0 -0
  83. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/openai/openAiWrapper.py +0 -0
  84. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/openai_agents/__init__.py +0 -0
  85. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/openai_agents/openaiAgentsHook.py +0 -0
  86. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/tracing/wrappers/utils.py +0 -0
  87. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/__init__.py +0 -0
  88. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/address.py +0 -0
  89. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/agent.py +0 -0
  90. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/agent_attribute.py +0 -0
  91. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/agent_price_point.py +0 -0
  92. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/agent_price_point_tiers.py +0 -0
  93. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/agent_update.py +0 -0
  94. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/api_error.py +0 -0
  95. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/billing_frequency.py +0 -0
  96. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/charge_type.py +0 -0
  97. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/contact.py +0 -0
  98. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/cost_amount.py +0 -0
  99. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/cost_trace.py +0 -0
  100. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/cost_traces_response.py +0 -0
  101. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/creation_source.py +0 -0
  102. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/creation_state.py +0 -0
  103. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/customer.py +0 -0
  104. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/customer_update.py +0 -0
  105. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/entitlement_usage.py +0 -0
  106. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/error.py +0 -0
  107. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/order.py +0 -0
  108. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/order_line.py +0 -0
  109. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/order_line_attribute.py +0 -0
  110. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/order_line_attribute_create.py +0 -0
  111. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/order_line_attribute_pricing.py +0 -0
  112. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/order_line_create.py +0 -0
  113. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/pagination_meta.py +0 -0
  114. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/price_point.py +0 -0
  115. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/pricing.py +0 -0
  116. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/pricing_model_type.py +0 -0
  117. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/salutation.py +0 -0
  118. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/signal.py +0 -0
  119. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/tax_exempt_status.py +0 -0
  120. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/types/tier.py +0 -0
  121. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/usage/__init__.py +0 -0
  122. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/usage/client.py +0 -0
  123. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/usage/raw_client.py +0 -0
  124. {paid_python-0.4.0 → paid_python-0.4.1}/src/paid/version.py +0 -0
  125. {paid_python-0.4.0/src/paid/_vendor → paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai}/opentelemetry/instrumentation/openai/shared/config.py +0 -0
  126. {paid_python-0.4.0/src/paid/_vendor → paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai}/opentelemetry/instrumentation/openai/shared/event_models.py +0 -0
  127. {paid_python-0.4.0/src/paid/_vendor → paid_python-0.4.1/vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai}/opentelemetry/instrumentation/openai/shared/span_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: paid-python
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary:
5
5
  Requires-Python: >=3.9,<3.14
6
6
  Classifier: Intended Audience :: Developers
@@ -3,7 +3,7 @@ name = "paid-python"
3
3
 
4
4
  [tool.poetry]
5
5
  name = "paid-python"
6
- version = "0.4.0"
6
+ version = "0.4.1"
7
7
  description = ""
8
8
  readme = "README.md"
9
9
  authors = []
@@ -26,7 +26,8 @@ classifiers = [
26
26
  "Typing :: Typed"
27
27
  ]
28
28
  packages = [
29
- { include = "paid", from = "src"}
29
+ { include = "paid", from = "src"},
30
+ { include = "opentelemetry", from = "vendor/patched-instrumentation-openllmetry/packages/opentelemetry-instrumentation-openai" },
30
31
  ]
31
32
 
32
33
  [project.urls]
@@ -44,7 +45,7 @@ opentelemetry-exporter-otlp-proto-http = ">=1.23.0"
44
45
  mutagen = ">=1.47.0"
45
46
  python-dotenv = ">=0.15.0"
46
47
  opentelemetry-instrumentation-anthropic = ">=0.47.0"
47
- # opentelemetry-instrumentation-openai is vendored from https://github.com/paid-ai/openllmetry-instrumentation-patch (patched version)
48
+ # opentelemetry-instrumentation-openai is vendored from git a submodule under vendor/patched-instrumentation-openllmetry
48
49
  openinference-instrumentation-langchain = ">=0.1.55"
49
50
  openinference-instrumentation-openai-agents = ">=1.0.0"
50
51
  openinference-instrumentation-bedrock = ">=0.1.0"
@@ -71,9 +72,15 @@ openai = ">=1.12.0"
71
72
  [tool.pytest.ini_options]
72
73
  testpaths = [ "tests" ]
73
74
  asyncio_mode = "auto"
75
+ # TODO(Ata): remove this once the openai instrumentation isn't vendored anymore
76
+ norecursedirs = ["vendor/patched-instrumentation-openllmetry"]
74
77
 
75
78
  [tool.mypy]
76
79
  plugins = ["pydantic.mypy"]
80
+ exclude = [
81
+ # TODO(Ata): remove this once the openai instrumentation isn't vendored anymore
82
+ "^vendor/patched-instrumentation-openllmetry/",
83
+ ]
77
84
 
78
85
  [[tool.mypy.overrides]]
79
86
  module = [
@@ -87,8 +94,8 @@ module = [
87
94
  "agents",
88
95
  "agents.*",
89
96
  "langchain_core.*",
90
- "paid._vendor", # remove once openai instrumentor is upstream
91
- "paid._vendor.*", # remove once openai instrumentor is upstream
97
+ "opentelemetry.instrumentation.openai", # TODO(Ata): remove this once the openai instrumentation isn't vendored anymore
98
+ "opentelemetry.instrumentation.openai.*",
92
99
  ]
93
100
  ignore_missing_imports = true
94
101
  ignore_errors = true # remove once openai instrumentor is upstream
@@ -1,8 +1,13 @@
1
1
  # This file was auto-generated by Fern from our API Definition.
2
+ import os
2
3
  import typing
3
4
  import warnings
4
5
 
5
6
  import httpx
7
+ from dotenv import load_dotenv
8
+
9
+ # Load environment variables from .env file
10
+ load_dotenv()
6
11
  from .agents.client import AgentsClient, AsyncAgentsClient
7
12
  from .contacts.client import AsyncContactsClient, ContactsClient
8
13
  from .core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
@@ -60,11 +65,19 @@ class Paid:
60
65
  *,
61
66
  base_url: typing.Optional[str] = None,
62
67
  environment: PaidEnvironment = PaidEnvironment.PRODUCTION,
63
- token: typing.Union[str, typing.Callable[[], str]],
68
+ token: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None,
64
69
  timeout: typing.Optional[float] = None,
65
70
  follow_redirects: typing.Optional[bool] = True,
66
71
  httpx_client: typing.Optional[httpx.Client] = None,
67
72
  ):
73
+ # If token is not provided, try to get it from environment variable
74
+ if token is None:
75
+ token = os.environ.get("PAID_API_KEY")
76
+ if token is None:
77
+ raise ValueError(
78
+ "API token must be provided either via the 'token' parameter or the 'PAID_API_KEY' environment variable"
79
+ )
80
+
68
81
  _defaulted_timeout = (
69
82
  timeout if timeout is not None else 60 if httpx_client is None else httpx_client.timeout.read
70
83
  )
@@ -338,11 +351,19 @@ class AsyncPaid:
338
351
  *,
339
352
  base_url: typing.Optional[str] = None,
340
353
  environment: PaidEnvironment = PaidEnvironment.PRODUCTION,
341
- token: typing.Union[str, typing.Callable[[], str]],
354
+ token: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None,
342
355
  timeout: typing.Optional[float] = None,
343
356
  follow_redirects: typing.Optional[bool] = True,
344
357
  httpx_client: typing.Optional[httpx.AsyncClient] = None,
345
358
  ):
359
+ # If token is not provided, try to get it from environment variable
360
+ if token is None:
361
+ token = os.environ.get("PAID_API_KEY")
362
+ if token is None:
363
+ raise ValueError(
364
+ "API token must be provided either via the 'token' parameter or the 'PAID_API_KEY' environment variable"
365
+ )
366
+
346
367
  _defaulted_timeout = (
347
368
  timeout if timeout is not None else 60 if httpx_client is None else httpx_client.timeout.read
348
369
  )
@@ -7,7 +7,7 @@ from .distributed_tracing import (
7
7
  unset_tracing_token,
8
8
  )
9
9
  from .signal import signal
10
- from .tracing import initialize_tracing, get_paid_tracer_provider
10
+ from .tracing import get_paid_tracer_provider, initialize_tracing
11
11
 
12
12
  __all__ = [
13
13
  "generate_tracing_token",
@@ -22,8 +22,7 @@ except ImportError:
22
22
  ANTHROPIC_AVAILABLE = False
23
23
 
24
24
  try:
25
- # from opentelemetry.instrumentation.openai import OpenAIInstrumentor
26
- from paid._vendor.opentelemetry.instrumentation.openai import OpenAIInstrumentor # remove once openai instrumentor is upstream
25
+ from opentelemetry.instrumentation.openai import OpenAIInstrumentor
27
26
 
28
27
  OPENAI_AVAILABLE = True
29
28
  except ImportError:
@@ -1,8 +1,8 @@
1
1
  from typing import Callable, Collection, Optional
2
2
 
3
3
  from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
4
- from paid._vendor.opentelemetry.instrumentation.openai.shared.config import Config
5
- from paid._vendor.opentelemetry.instrumentation.openai.utils import is_openai_v1
4
+ from opentelemetry.instrumentation.openai.shared.config import Config
5
+ from opentelemetry.instrumentation.openai.utils import is_openai_v1
6
6
  from typing_extensions import Coroutine
7
7
 
8
8
  _instruments = ("openai >= 0.27.0",)
@@ -35,20 +35,20 @@ class OpenAIInstrumentor(BaseInstrumentor):
35
35
 
36
36
  def _instrument(self, **kwargs):
37
37
  if is_openai_v1():
38
- from paid._vendor.opentelemetry.instrumentation.openai.v1 import OpenAIV1Instrumentor
38
+ from opentelemetry.instrumentation.openai.v1 import OpenAIV1Instrumentor
39
39
 
40
40
  OpenAIV1Instrumentor().instrument(**kwargs)
41
41
  else:
42
- from paid._vendor.opentelemetry.instrumentation.openai.v0 import OpenAIV0Instrumentor
42
+ from opentelemetry.instrumentation.openai.v0 import OpenAIV0Instrumentor
43
43
 
44
44
  OpenAIV0Instrumentor().instrument(**kwargs)
45
45
 
46
46
  def _uninstrument(self, **kwargs):
47
47
  if is_openai_v1():
48
- from paid._vendor.opentelemetry.instrumentation.openai.v1 import OpenAIV1Instrumentor
48
+ from opentelemetry.instrumentation.openai.v1 import OpenAIV1Instrumentor
49
49
 
50
50
  OpenAIV1Instrumentor().uninstrument(**kwargs)
51
51
  else:
52
- from paid._vendor.opentelemetry.instrumentation.openai.v0 import OpenAIV0Instrumentor
52
+ from opentelemetry.instrumentation.openai.v0 import OpenAIV0Instrumentor
53
53
 
54
54
  OpenAIV0Instrumentor().uninstrument(**kwargs)
@@ -5,8 +5,8 @@ import openai
5
5
  import pydantic
6
6
  from importlib.metadata import version
7
7
 
8
- from paid._vendor.opentelemetry.instrumentation.openai.shared.config import Config
9
- from paid._vendor.opentelemetry.instrumentation.openai.utils import (
8
+ from opentelemetry.instrumentation.openai.shared.config import Config
9
+ from opentelemetry.instrumentation.openai.utils import (
10
10
  dont_throw,
11
11
  is_openai_v1,
12
12
  )
@@ -0,0 +1,247 @@
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)
@@ -8,7 +8,7 @@ from typing import List, Optional, Union
8
8
 
9
9
  from opentelemetry import context as context_api
10
10
  import pydantic
11
- from paid._vendor.opentelemetry.instrumentation.openai.shared import (
11
+ from opentelemetry.instrumentation.openai.shared import (
12
12
  OPENAI_LLM_USAGE_TOKEN_TYPES,
13
13
  _get_openai_base_url,
14
14
  _set_client_attributes,
@@ -24,14 +24,14 @@ from paid._vendor.opentelemetry.instrumentation.openai.shared import (
24
24
  propagate_trace_context,
25
25
  set_tools_attributes,
26
26
  )
27
- from paid._vendor.opentelemetry.instrumentation.openai.shared.config import Config
28
- from paid._vendor.opentelemetry.instrumentation.openai.shared.event_emitter import emit_event
29
- from paid._vendor.opentelemetry.instrumentation.openai.shared.event_models import (
27
+ from opentelemetry.instrumentation.openai.shared.config import Config
28
+ from opentelemetry.instrumentation.openai.shared.event_emitter import emit_event
29
+ from opentelemetry.instrumentation.openai.shared.event_models import (
30
30
  ChoiceEvent,
31
31
  MessageEvent,
32
32
  ToolCall,
33
33
  )
34
- from paid._vendor.opentelemetry.instrumentation.openai.utils import (
34
+ from opentelemetry.instrumentation.openai.utils import (
35
35
  _with_chat_telemetry_wrapper,
36
36
  dont_throw,
37
37
  is_openai_v1,
@@ -2,7 +2,7 @@ import logging
2
2
 
3
3
  from opentelemetry import context as context_api
4
4
  from opentelemetry import trace
5
- from paid._vendor.opentelemetry.instrumentation.openai.shared import (
5
+ from opentelemetry.instrumentation.openai.shared import (
6
6
  _set_client_attributes,
7
7
  _set_functions_attributes,
8
8
  _set_request_attributes,
@@ -13,14 +13,14 @@ from paid._vendor.opentelemetry.instrumentation.openai.shared import (
13
13
  model_as_dict,
14
14
  propagate_trace_context,
15
15
  )
16
- from paid._vendor.opentelemetry.instrumentation.openai.shared.config import Config
16
+ from opentelemetry.instrumentation.openai.shared.config import Config
17
17
  from opentelemetry.semconv.attributes.error_attributes import ERROR_TYPE
18
- from paid._vendor.opentelemetry.instrumentation.openai.shared.event_emitter import emit_event
19
- from paid._vendor.opentelemetry.instrumentation.openai.shared.event_models import (
18
+ from opentelemetry.instrumentation.openai.shared.event_emitter import emit_event
19
+ from opentelemetry.instrumentation.openai.shared.event_models import (
20
20
  ChoiceEvent,
21
21
  MessageEvent,
22
22
  )
23
- from paid._vendor.opentelemetry.instrumentation.openai.utils import (
23
+ from opentelemetry.instrumentation.openai.utils import (
24
24
  _with_tracer_wrapper,
25
25
  dont_throw,
26
26
  is_openai_v1,
@@ -3,7 +3,7 @@ import time
3
3
  from collections.abc import Iterable
4
4
 
5
5
  from opentelemetry import context as context_api
6
- from paid._vendor.opentelemetry.instrumentation.openai.shared import (
6
+ from opentelemetry.instrumentation.openai.shared import (
7
7
  OPENAI_LLM_USAGE_TOKEN_TYPES,
8
8
  _get_openai_base_url,
9
9
  _set_client_attributes,
@@ -15,13 +15,13 @@ from paid._vendor.opentelemetry.instrumentation.openai.shared import (
15
15
  model_as_dict,
16
16
  propagate_trace_context,
17
17
  )
18
- from paid._vendor.opentelemetry.instrumentation.openai.shared.config import Config
19
- from paid._vendor.opentelemetry.instrumentation.openai.shared.event_emitter import emit_event
20
- from paid._vendor.opentelemetry.instrumentation.openai.shared.event_models import (
18
+ from opentelemetry.instrumentation.openai.shared.config import Config
19
+ from opentelemetry.instrumentation.openai.shared.event_emitter import emit_event
20
+ from opentelemetry.instrumentation.openai.shared.event_models import (
21
21
  ChoiceEvent,
22
22
  MessageEvent,
23
23
  )
24
- from paid._vendor.opentelemetry.instrumentation.openai.utils import (
24
+ from opentelemetry.instrumentation.openai.utils import (
25
25
  _with_embeddings_telemetry_wrapper,
26
26
  dont_throw,
27
27
  is_openai_v1,
@@ -3,11 +3,11 @@ from enum import Enum
3
3
  from typing import Union
4
4
 
5
5
  from opentelemetry._logs import LogRecord
6
- from paid._vendor.opentelemetry.instrumentation.openai.shared.event_models import (
6
+ from opentelemetry.instrumentation.openai.shared.event_models import (
7
7
  ChoiceEvent,
8
8
  MessageEvent,
9
9
  )
10
- from paid._vendor.opentelemetry.instrumentation.openai.utils import (
10
+ from opentelemetry.instrumentation.openai.utils import (
11
11
  should_emit_events,
12
12
  should_send_prompts,
13
13
  )
@@ -1,13 +1,13 @@
1
1
  import time
2
2
 
3
3
  from opentelemetry import context as context_api
4
- from paid._vendor.opentelemetry.instrumentation.openai import is_openai_v1
5
- from paid._vendor.opentelemetry.instrumentation.openai.shared import (
4
+ from opentelemetry.instrumentation.openai import is_openai_v1
5
+ from opentelemetry.instrumentation.openai.shared import (
6
6
  _get_openai_base_url,
7
7
  metric_shared_attributes,
8
8
  model_as_dict,
9
9
  )
10
- from paid._vendor.opentelemetry.instrumentation.openai.utils import (
10
+ from opentelemetry.instrumentation.openai.utils import (
11
11
  _with_image_gen_metric_wrapper,
12
12
  )
13
13
  from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
@@ -9,7 +9,7 @@ from packaging import version as pkg_version
9
9
 
10
10
  from opentelemetry import context as context_api
11
11
  from opentelemetry._logs import Logger
12
- from paid._vendor.opentelemetry.instrumentation.openai.shared.config import Config
12
+ from opentelemetry.instrumentation.openai.shared.config import Config
13
13
 
14
14
  import openai
15
15
 
@@ -83,6 +83,29 @@ def _with_embeddings_telemetry_wrapper(func):
83
83
  return _with_embeddings_telemetry
84
84
 
85
85
 
86
+ def _with_audio_telemetry_wrapper(func):
87
+ """Wrapper to convert the audio wrapper function into the expected format for wrapt."""
88
+ def _with_audio_telemetry(
89
+ tracer,
90
+ duration_histogram,
91
+ exception_counter,
92
+ ):
93
+ def wrapper(wrapped, instance, args, kwargs):
94
+ return func(
95
+ tracer,
96
+ duration_histogram,
97
+ exception_counter,
98
+ wrapped,
99
+ instance,
100
+ args,
101
+ kwargs,
102
+ )
103
+
104
+ return wrapper
105
+
106
+ return _with_audio_telemetry
107
+
108
+
86
109
  def _with_chat_telemetry_wrapper(func):
87
110
  def _with_chat_telemetry(
88
111
  tracer,
@@ -2,21 +2,21 @@ from typing import Collection
2
2
 
3
3
  from opentelemetry._logs import get_logger
4
4
  from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
5
- from paid._vendor.opentelemetry.instrumentation.openai.shared.chat_wrappers import (
5
+ from opentelemetry.instrumentation.openai.shared.chat_wrappers import (
6
6
  achat_wrapper,
7
7
  chat_wrapper,
8
8
  )
9
- from paid._vendor.opentelemetry.instrumentation.openai.shared.completion_wrappers import (
9
+ from opentelemetry.instrumentation.openai.shared.completion_wrappers import (
10
10
  acompletion_wrapper,
11
11
  completion_wrapper,
12
12
  )
13
- from paid._vendor.opentelemetry.instrumentation.openai.shared.config import Config
14
- from paid._vendor.opentelemetry.instrumentation.openai.shared.embeddings_wrappers import (
13
+ from opentelemetry.instrumentation.openai.shared.config import Config
14
+ from opentelemetry.instrumentation.openai.shared.embeddings_wrappers import (
15
15
  aembeddings_wrapper,
16
16
  embeddings_wrapper,
17
17
  )
18
- from paid._vendor.opentelemetry.instrumentation.openai.utils import is_metrics_enabled
19
- from paid._vendor.opentelemetry.instrumentation.openai.version import __version__
18
+ from opentelemetry.instrumentation.openai.utils import is_metrics_enabled
19
+ from opentelemetry.instrumentation.openai.version import __version__
20
20
  from opentelemetry.instrumentation.utils import unwrap
21
21
  from opentelemetry.metrics import get_meter
22
22
  from opentelemetry.semconv._incubating.metrics import gen_ai_metrics as GenAIMetrics