paygent-sdk 1.0.0__py3-none-any.whl → 3.0.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.
@@ -0,0 +1,128 @@
1
+ """
2
+ Mistral wrapper for automatic usage tracking with Paygent.
3
+ This wrapper intercepts Mistral API calls and automatically sends usage data to Paygent.
4
+ """
5
+
6
+ import json
7
+ from typing import Any
8
+
9
+ try:
10
+ from mistralai import Mistral
11
+ except ImportError:
12
+ raise ImportError(
13
+ "mistralai package is a peer-dependency. To use the Paygent wrapper around mistralai "
14
+ "you're assumed to already have mistralai package installed."
15
+ )
16
+
17
+ from ..client import Client
18
+ from ..models import UsageData, UsageDataWithStrings
19
+
20
+
21
+ class PaygentMistral:
22
+ """Main wrapper class for Mistral that provides automatic usage tracking."""
23
+
24
+ def __init__(self, mistral_client: Mistral, paygent_client: Client):
25
+ """
26
+ Create a new PaygentMistral wrapper.
27
+
28
+ Args:
29
+ mistral_client: The Mistral client instance
30
+ paygent_client: The Paygent client instance for usage tracking
31
+ """
32
+ self.mistral = mistral_client
33
+ self.paygent_client = paygent_client
34
+
35
+ @property
36
+ def chat(self) -> 'ChatWrapper':
37
+ """Access to chat API with automatic usage tracking."""
38
+ return ChatWrapper(self.mistral, self.paygent_client)
39
+
40
+
41
+ class ChatWrapper:
42
+ """Wrapper for Mistral chat API."""
43
+
44
+ def __init__(self, mistral_client: Mistral, paygent_client: Client):
45
+ self.mistral = mistral_client
46
+ self.paygent_client = paygent_client
47
+
48
+ def complete(
49
+ self,
50
+ *,
51
+ model: str,
52
+ messages: list,
53
+ indicator: str,
54
+ external_agent_id: str,
55
+ external_customer_id: str,
56
+ **kwargs
57
+ ) -> Any:
58
+ """
59
+ Create a chat completion with automatic usage tracking.
60
+ Note: Streaming is not supported with automatic tracking.
61
+
62
+ Args:
63
+ model: The model to use
64
+ messages: The messages to send
65
+ indicator: Indicator for the usage event
66
+ external_agent_id: External agent identifier
67
+ external_customer_id: External customer identifier
68
+ **kwargs: Additional Mistral parameters
69
+
70
+ Returns:
71
+ The chat completion response from Mistral
72
+ """
73
+ # Make the Mistral API call
74
+ response = self.mistral.chat.complete(
75
+ model=model,
76
+ messages=messages,
77
+ **kwargs
78
+ )
79
+
80
+ # Extract usage data from response with robust fallback mechanism
81
+ has_valid_usage = (
82
+ hasattr(response, 'usage') and
83
+ response.usage and
84
+ response.usage.prompt_tokens > 0 and
85
+ response.usage.completion_tokens > 0
86
+ )
87
+
88
+ if has_valid_usage:
89
+ # Primary path: Use usage data from API response
90
+ usage_data = UsageData(
91
+ service_provider=model,
92
+ model=model,
93
+ prompt_tokens=response.usage.prompt_tokens,
94
+ completion_tokens=response.usage.completion_tokens,
95
+ total_tokens=response.usage.total_tokens
96
+ )
97
+
98
+ self.paygent_client.send_usage(
99
+ external_agent_id,
100
+ external_customer_id,
101
+ indicator,
102
+ usage_data
103
+ )
104
+ else:
105
+ # Fallback path: Calculate tokens from actual strings
106
+ prompt_string = json.dumps(messages)
107
+ output_string = ''
108
+ if hasattr(response, 'choices') and response.choices:
109
+ if len(response.choices) > 0:
110
+ choice = response.choices[0]
111
+ if hasattr(choice, 'message') and hasattr(choice.message, 'content'):
112
+ output_string = choice.message.content or ''
113
+
114
+ usage_data_with_strings = UsageDataWithStrings(
115
+ service_provider=model,
116
+ model=model,
117
+ prompt_string=prompt_string,
118
+ output_string=output_string
119
+ )
120
+
121
+ self.paygent_client.send_usage_with_token_string(
122
+ external_agent_id,
123
+ external_customer_id,
124
+ indicator,
125
+ usage_data_with_strings
126
+ )
127
+
128
+ return response
@@ -0,0 +1,316 @@
1
+ """
2
+ OpenAI wrapper for automatic usage tracking with Paygent.
3
+ This wrapper intercepts OpenAI API calls and automatically sends usage data to Paygent.
4
+ """
5
+
6
+ import json
7
+ from typing import Any, Optional
8
+
9
+ try:
10
+ from openai import OpenAI
11
+ except ImportError:
12
+ raise ImportError(
13
+ "openai package is a peer-dependency. To use the Paygent wrapper around openai "
14
+ "you're assumed to already have openai package installed."
15
+ )
16
+
17
+ from ..client import Client
18
+ from ..models import UsageData, UsageDataWithStrings
19
+
20
+
21
+ class PaygentOpenAI:
22
+ """Main wrapper class for OpenAI that provides automatic usage tracking."""
23
+
24
+ def __init__(self, openai_client: OpenAI, paygent_client: Client):
25
+ """
26
+ Create a new PaygentOpenAI wrapper.
27
+
28
+ Args:
29
+ openai_client: The OpenAI client instance
30
+ paygent_client: The Paygent client instance for usage tracking
31
+ """
32
+ self.openai = openai_client
33
+ self.paygent_client = paygent_client
34
+
35
+ @property
36
+ def chat(self) -> 'ChatWrapper':
37
+ """Access to chat API with automatic usage tracking."""
38
+ return ChatWrapper(self.openai, self.paygent_client)
39
+
40
+ @property
41
+ def embeddings(self) -> 'EmbeddingsWrapper':
42
+ """Access to embeddings API with automatic usage tracking."""
43
+ return EmbeddingsWrapper(self.openai, self.paygent_client)
44
+
45
+ @property
46
+ def images(self) -> 'ImagesWrapper':
47
+ """Access to images API with automatic usage tracking."""
48
+ return ImagesWrapper(self.openai, self.paygent_client)
49
+
50
+
51
+ class ChatWrapper:
52
+ """Wrapper for OpenAI chat API."""
53
+
54
+ def __init__(self, openai_client: OpenAI, paygent_client: Client):
55
+ self.openai = openai_client
56
+ self.paygent_client = paygent_client
57
+
58
+ @property
59
+ def completions(self) -> 'ChatCompletionsWrapper':
60
+ """Access to chat completions API with automatic usage tracking."""
61
+ return ChatCompletionsWrapper(self.openai, self.paygent_client)
62
+
63
+
64
+ class ChatCompletionsWrapper:
65
+ """Wrapper for OpenAI chat completions API."""
66
+
67
+ def __init__(self, openai_client: OpenAI, paygent_client: Client):
68
+ self.openai = openai_client
69
+ self.paygent_client = paygent_client
70
+
71
+ def create(
72
+ self,
73
+ *,
74
+ model: str,
75
+ messages: list,
76
+ indicator: str,
77
+ external_agent_id: str,
78
+ external_customer_id: str,
79
+ **kwargs
80
+ ) -> Any:
81
+ """
82
+ Create a chat completion with automatic usage tracking.
83
+ Note: Streaming is not supported with automatic tracking.
84
+
85
+ Args:
86
+ model: The model to use
87
+ messages: The messages to send
88
+ indicator: Indicator for the usage event
89
+ external_agent_id: External agent identifier
90
+ external_customer_id: External customer identifier
91
+ **kwargs: Additional OpenAI parameters
92
+
93
+ Returns:
94
+ The chat completion response from OpenAI
95
+ """
96
+ # Ensure streaming is disabled for automatic tracking
97
+ kwargs['stream'] = False
98
+
99
+ # Make the OpenAI API call (non-streaming)
100
+ response = self.openai.chat.completions.create(
101
+ model=model,
102
+ messages=messages,
103
+ **kwargs
104
+ )
105
+
106
+ # Extract usage data from response with robust fallback mechanism
107
+ has_valid_usage = (
108
+ hasattr(response, 'usage') and
109
+ response.usage and
110
+ response.usage.prompt_tokens > 0 and
111
+ response.usage.completion_tokens > 0
112
+ )
113
+
114
+ if has_valid_usage:
115
+ # Primary path: Use usage data from API response
116
+ # Extract cached tokens if available (OpenAI prompt caching feature)
117
+ cached_tokens = 0
118
+ if hasattr(response.usage, 'prompt_tokens_details'):
119
+ prompt_details = response.usage.prompt_tokens_details
120
+ if hasattr(prompt_details, 'cached_tokens') and prompt_details.cached_tokens:
121
+ cached_tokens = prompt_details.cached_tokens
122
+
123
+ usage_data = UsageData(
124
+ service_provider=model,
125
+ model=model,
126
+ prompt_tokens=response.usage.prompt_tokens,
127
+ completion_tokens=response.usage.completion_tokens,
128
+ total_tokens=response.usage.total_tokens,
129
+ cached_tokens=cached_tokens
130
+ )
131
+
132
+ self.paygent_client.send_usage(
133
+ external_agent_id,
134
+ external_customer_id,
135
+ indicator,
136
+ usage_data
137
+ )
138
+ else:
139
+ # Fallback path: Calculate tokens from actual strings
140
+ # This ensures we never lose billing data even if API response format changes
141
+ prompt_string = json.dumps(messages)
142
+ output_string = ''
143
+ if hasattr(response, 'choices') and response.choices:
144
+ if hasattr(response.choices[0], 'message') and hasattr(response.choices[0].message, 'content'):
145
+ output_string = response.choices[0].message.content or ''
146
+
147
+ usage_data_with_strings = UsageDataWithStrings(
148
+ service_provider=model,
149
+ model=model,
150
+ prompt_string=prompt_string,
151
+ output_string=output_string
152
+ )
153
+
154
+ self.paygent_client.send_usage_with_token_string(
155
+ external_agent_id,
156
+ external_customer_id,
157
+ indicator,
158
+ usage_data_with_strings
159
+ )
160
+
161
+ return response
162
+
163
+
164
+ class EmbeddingsWrapper:
165
+ """Wrapper for OpenAI embeddings API."""
166
+
167
+ def __init__(self, openai_client: OpenAI, paygent_client: Client):
168
+ self.openai = openai_client
169
+ self.paygent_client = paygent_client
170
+
171
+ def create(
172
+ self,
173
+ *,
174
+ model: str,
175
+ input: Any,
176
+ indicator: str,
177
+ external_agent_id: str,
178
+ external_customer_id: str,
179
+ **kwargs
180
+ ) -> Any:
181
+ """
182
+ Create embeddings with automatic usage tracking.
183
+
184
+ Args:
185
+ model: The model to use
186
+ input: The input text(s) to embed
187
+ indicator: Indicator for the usage event
188
+ external_agent_id: External agent identifier
189
+ external_customer_id: External customer identifier
190
+ **kwargs: Additional OpenAI parameters
191
+
192
+ Returns:
193
+ The embeddings response from OpenAI
194
+ """
195
+ # Make the OpenAI API call
196
+ response = self.openai.embeddings.create(
197
+ model=model,
198
+ input=input,
199
+ **kwargs
200
+ )
201
+
202
+ # Extract usage data from response with robust fallback mechanism
203
+ has_valid_usage = (
204
+ hasattr(response, 'usage') and
205
+ response.usage and
206
+ response.usage.prompt_tokens > 0
207
+ )
208
+
209
+ if has_valid_usage:
210
+ # Primary path: Use usage data from API response
211
+ usage_data = UsageData(
212
+ service_provider=model,
213
+ model=model,
214
+ prompt_tokens=response.usage.prompt_tokens,
215
+ completion_tokens=response.usage.prompt_tokens, # Embeddings don't have completion tokens
216
+ total_tokens=response.usage.total_tokens
217
+ )
218
+
219
+ self.paygent_client.send_usage(
220
+ external_agent_id,
221
+ external_customer_id,
222
+ indicator,
223
+ usage_data
224
+ )
225
+ else:
226
+ # Fallback path: Calculate tokens from input text
227
+ input_text = input
228
+ if isinstance(input, list):
229
+ input_text = ' '.join(str(i) for i in input)
230
+ else:
231
+ input_text = str(input)
232
+
233
+ usage_data_with_strings = UsageDataWithStrings(
234
+ service_provider=model,
235
+ model=model,
236
+ prompt_string=input_text,
237
+ output_string='' # Embeddings don't have output
238
+ )
239
+
240
+ self.paygent_client.send_usage_with_token_string(
241
+ external_agent_id,
242
+ external_customer_id,
243
+ indicator,
244
+ usage_data_with_strings
245
+ )
246
+
247
+ return response
248
+
249
+
250
+ class ImagesWrapper:
251
+ """Wrapper for OpenAI images API."""
252
+
253
+ def __init__(self, openai_client: OpenAI, paygent_client: Client):
254
+ self.openai = openai_client
255
+ self.paygent_client = paygent_client
256
+
257
+ def generate(
258
+ self,
259
+ *,
260
+ model: Optional[str] = None,
261
+ prompt: str,
262
+ indicator: str,
263
+ external_agent_id: str,
264
+ external_customer_id: str,
265
+ **kwargs
266
+ ) -> Any:
267
+ """
268
+ Generate images with automatic usage tracking.
269
+ Note: OpenAI's image generation API doesn't return token usage,
270
+ so we track the request parameters instead.
271
+
272
+ Args:
273
+ model: The model to use (optional, defaults to dall-e-2)
274
+ prompt: The prompt for image generation
275
+ indicator: Indicator for the usage event
276
+ external_agent_id: External agent identifier
277
+ external_customer_id: External customer identifier
278
+ **kwargs: Additional OpenAI parameters
279
+
280
+ Returns:
281
+ The images response from OpenAI
282
+ """
283
+ # Make the OpenAI API call
284
+ if model:
285
+ response = self.openai.images.generate(
286
+ model=model,
287
+ prompt=prompt,
288
+ **kwargs
289
+ )
290
+ else:
291
+ response = self.openai.images.generate(
292
+ prompt=prompt,
293
+ **kwargs
294
+ )
295
+ model = 'dall-e-2' # Default model
296
+
297
+ # For image generation, we'll use a simplified usage tracking
298
+ # since OpenAI doesn't provide token counts for images
299
+ usage_data = UsageData(
300
+ service_provider=model,
301
+ model=model,
302
+ prompt_tokens=0, # Images don't use traditional tokens
303
+ completion_tokens=0,
304
+ total_tokens=0
305
+ )
306
+
307
+ # Send usage data to Paygent
308
+ # Note: Cost calculation for images should be handled by the pricing module
309
+ self.paygent_client.send_usage(
310
+ external_agent_id,
311
+ external_customer_id,
312
+ indicator,
313
+ usage_data
314
+ )
315
+
316
+ return response
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: paygent-sdk
3
- Version: 1.0.0
3
+ Version: 3.0.0
4
4
  Summary: Official Python SDK for Paygent - Track AI usage and costs across multiple providers (OpenAI, Anthropic, Google, DeepSeek, etc.)
5
5
  Home-page: https://github.com/paygent/paygent-sdk-python
6
6
  Author: Paygent
@@ -0,0 +1,22 @@
1
+ examples/__init__.py,sha256=rkdmhcIN-xvRIaDWOWpUGQcdWZLopvjiK-4A2n40wQI,19
2
+ examples/advanced_usage.py,sha256=a8GlGg2mlbi0KccOJMXZihfJKJsZvOcjAa0vutoCTHQ,3619
3
+ examples/basic_usage.py,sha256=FvFR7t5Xs1eeV1-C6aAVQx2mhY8S8nJGGaJQd_Es0vg,1039
4
+ examples/constants_usage.py,sha256=fdmgbdAnVDlvdxuWIfpGX49NxuMGK3dwQ780D10ltmQ,4490
5
+ paygent_sdk/__init__.py,sha256=5dt2ogSTbPyM_JZ8lvafO9Fn0WsCnJgC1bCLtafzVEk,3064
6
+ paygent_sdk/client.py,sha256=PeusEcT8j8-bVWuCV_aJIdieNW1lQVTCT7jaxxIDVSw,16427
7
+ paygent_sdk/constants.py,sha256=ohvaHRfDcJ00DwBitHrYWH96k6FodO_uMvRYnOBZdJ8,10208
8
+ paygent_sdk/models.py,sha256=qlTSdogopr0TIdolkDHqn6MsNEJznPl4ie146fUbSRI,22666
9
+ paygent_sdk/voice_client.py,sha256=nGx2w2h7hW9cxi1oIDJNQMdLXdJPmHYlk3K8rNkwYTY,12680
10
+ paygent_sdk/wrappers/__init__.py,sha256=IPDrQZH9GmUlBCJp5UZfSgX8SJyh2Y09z2N811vcaKk,1542
11
+ paygent_sdk/wrappers/anthropic_wrapper.py,sha256=qw26SFCc0Nfsb7O9kqld9cV6D0DCFQjjVgfDHmUYEd8,4370
12
+ paygent_sdk/wrappers/gemini_wrapper.py,sha256=F6ZEfGwAXGyMisvPEh2M_5zTSFm2FiQvZKWRGS0y1Tg,11391
13
+ paygent_sdk/wrappers/langchain_wrapper.py,sha256=7GZs_7SjH6CRipc8EmqeZez2EPCie-IH9OyPSaBk7DQ,9674
14
+ paygent_sdk/wrappers/mistral_wrapper.py,sha256=TiXB5nGmk3O4PqfTqCa6aDX5ow0X07ol41N4bC-7kbE,4174
15
+ paygent_sdk/wrappers/openai_wrapper.py,sha256=eGwbiLcv3EFJQgGnU98JU-jfMxGxo7ziVZP4SPyfRp4,10439
16
+ paygent_sdk-3.0.0.dist-info/licenses/LICENSE,sha256=HXncQw9T-dF8ItNiDu_T-Mv_A3Fl73Is7a8K8ZDXgZI,1064
17
+ tests/__init__.py,sha256=Wk73Io62J15BtlLVIzxmASDWaaJkQLevS4BLK5LDAQg,16
18
+ tests/test_client.py,sha256=63es9cOeWyclR9yM0SLcV8rSfOtlqr6YRjWG4sCTbMg,10500
19
+ paygent_sdk-3.0.0.dist-info/METADATA,sha256=e_rkY8hz9WIUDT1_XeDvPgm40qNyy-UPvrrM4_W4_UI,12493
20
+ paygent_sdk-3.0.0.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
21
+ paygent_sdk-3.0.0.dist-info/top_level.txt,sha256=tWbxCRKTt8EeYPhYm8mE6QukqT6EVfai6RMaT9GnVkk,27
22
+ paygent_sdk-3.0.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,15 +0,0 @@
1
- examples/__init__.py,sha256=rkdmhcIN-xvRIaDWOWpUGQcdWZLopvjiK-4A2n40wQI,19
2
- examples/advanced_usage.py,sha256=a8GlGg2mlbi0KccOJMXZihfJKJsZvOcjAa0vutoCTHQ,3619
3
- examples/basic_usage.py,sha256=FvFR7t5Xs1eeV1-C6aAVQx2mhY8S8nJGGaJQd_Es0vg,1039
4
- examples/constants_usage.py,sha256=fdmgbdAnVDlvdxuWIfpGX49NxuMGK3dwQ780D10ltmQ,4490
5
- paygent_sdk/__init__.py,sha256=HUhtOr2BAyY16isDoVuNjUIv8Q-9dkmUT4hN-udWX2U,991
6
- paygent_sdk/client.py,sha256=ypaKKrKNvDb-OW9bh5ex2C1YEiZ0_QYcGQKszd0tpSo,15819
7
- paygent_sdk/constants.py,sha256=kTfLex00p8z8w7jBTfwMCYTks1BGYlmcWWGbPkXILc4,6355
8
- paygent_sdk/models.py,sha256=RMa0SKj1U8mFXNFpD9d7EVWB4PXx9qj4KLZe-qlMAtw,20237
9
- paygent_sdk-1.0.0.dist-info/licenses/LICENSE,sha256=HXncQw9T-dF8ItNiDu_T-Mv_A3Fl73Is7a8K8ZDXgZI,1064
10
- tests/__init__.py,sha256=Wk73Io62J15BtlLVIzxmASDWaaJkQLevS4BLK5LDAQg,16
11
- tests/test_client.py,sha256=63es9cOeWyclR9yM0SLcV8rSfOtlqr6YRjWG4sCTbMg,10500
12
- paygent_sdk-1.0.0.dist-info/METADATA,sha256=C3a9o9DoKGHXz0tojaTwjphQtGK2UqDSoq2wEC8yu8g,12493
13
- paygent_sdk-1.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
14
- paygent_sdk-1.0.0.dist-info/top_level.txt,sha256=tWbxCRKTt8EeYPhYm8mE6QukqT6EVfai6RMaT9GnVkk,27
15
- paygent_sdk-1.0.0.dist-info/RECORD,,