paygent-sdk 1.0.0__tar.gz → 2.0.0__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 (31) hide show
  1. {paygent_sdk-1.0.0/paygent_sdk.egg-info → paygent_sdk-2.0.0}/PKG-INFO +1 -1
  2. paygent_sdk-2.0.0/paygent_sdk/__init__.py +100 -0
  3. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/paygent_sdk/client.py +16 -41
  4. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/paygent_sdk/constants.py +84 -0
  5. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/paygent_sdk/models.py +28 -0
  6. paygent_sdk-2.0.0/paygent_sdk/voice_client.py +263 -0
  7. paygent_sdk-2.0.0/paygent_sdk/wrappers/__init__.py +30 -0
  8. paygent_sdk-2.0.0/paygent_sdk/wrappers/anthropic_wrapper.py +132 -0
  9. paygent_sdk-2.0.0/paygent_sdk/wrappers/gemini_wrapper.py +334 -0
  10. paygent_sdk-2.0.0/paygent_sdk/wrappers/langchain_wrapper.py +257 -0
  11. paygent_sdk-2.0.0/paygent_sdk/wrappers/mistral_wrapper.py +128 -0
  12. paygent_sdk-2.0.0/paygent_sdk/wrappers/openai_wrapper.py +308 -0
  13. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0/paygent_sdk.egg-info}/PKG-INFO +1 -1
  14. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/paygent_sdk.egg-info/SOURCES.txt +7 -0
  15. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/pyproject.toml +1 -1
  16. paygent_sdk-1.0.0/paygent_sdk/__init__.py +0 -47
  17. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/LICENSE +0 -0
  18. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/MANIFEST.in +0 -0
  19. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/README.md +0 -0
  20. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/examples/__init__.py +0 -0
  21. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/examples/advanced_usage.py +0 -0
  22. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/examples/basic_usage.py +0 -0
  23. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/examples/constants_usage.py +0 -0
  24. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/paygent_sdk.egg-info/dependency_links.txt +0 -0
  25. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/paygent_sdk.egg-info/requires.txt +0 -0
  26. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/paygent_sdk.egg-info/top_level.txt +0 -0
  27. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/requirements.txt +0 -0
  28. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/setup.cfg +0 -0
  29. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/setup.py +0 -0
  30. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/tests/__init__.py +0 -0
  31. {paygent_sdk-1.0.0 → paygent_sdk-2.0.0}/tests/test_client.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: paygent-sdk
3
- Version: 1.0.0
3
+ Version: 2.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,100 @@
1
+ """
2
+ Paygent SDK for Python
3
+
4
+ A Python SDK for integrating with the Paygent API to track usage and costs for AI models.
5
+
6
+ For the Go SDK equivalent, see: https://github.com/paygent/paygent-sdk-go
7
+ """
8
+
9
+ from .client import Client
10
+ from .models import (
11
+ UsageData, UsageDataWithStrings, APIRequest, ModelPricing, MODEL_PRICING,
12
+ SttUsageData, TtsUsageData, SttModelPricing, TtsModelPricing
13
+ )
14
+ from .voice_client import send_stt_usage, send_tts_usage # Import to attach methods to Client
15
+
16
+ # Import wrappers with optional LangChain support
17
+ try:
18
+ from .wrappers import (
19
+ PaygentOpenAI,
20
+ PaygentAnthropic,
21
+ PaygentMistral,
22
+ PaygentGemini,
23
+ PaygentLangChainCallback
24
+ )
25
+ _has_langchain = True
26
+ except ImportError:
27
+ from .wrappers import (
28
+ PaygentOpenAI,
29
+ PaygentAnthropic,
30
+ PaygentMistral,
31
+ PaygentGemini
32
+ )
33
+ _has_langchain = False
34
+ from .constants import (
35
+ ServiceProvider,
36
+ OpenAIModels,
37
+ AnthropicModels,
38
+ GoogleDeepMindModels,
39
+ MetaModels,
40
+ AWSModels,
41
+ MistralAIModels,
42
+ CohereModels,
43
+ DeepSeekModels,
44
+ DeepgramSTTModels,
45
+ MicrosoftAzureSpeechSTTModels,
46
+ GoogleCloudSpeechSTTModels,
47
+ AssemblyAISTTModels,
48
+ AmazonPollyTTSModels,
49
+ MicrosoftAzureSpeechTTSModels,
50
+ GoogleCloudTextToSpeechTTSModels,
51
+ DeepgramTTSModels,
52
+ is_model_supported
53
+ )
54
+
55
+ __version__ = "1.0.0"
56
+ __all__ = [
57
+ # Core classes
58
+ "Client",
59
+ "UsageData",
60
+ "UsageDataWithStrings",
61
+ "APIRequest",
62
+ "ModelPricing",
63
+ "MODEL_PRICING",
64
+
65
+ # Voice data models
66
+ "SttUsageData",
67
+ "TtsUsageData",
68
+ "SttModelPricing",
69
+ "TtsModelPricing",
70
+
71
+ # Wrappers
72
+ "PaygentOpenAI",
73
+ "PaygentAnthropic",
74
+ "PaygentMistral",
75
+ "PaygentGemini",
76
+
77
+ # Constants
78
+ "ServiceProvider",
79
+ "OpenAIModels",
80
+ "AnthropicModels",
81
+ "GoogleDeepMindModels",
82
+ "MetaModels",
83
+ "AWSModels",
84
+ "MistralAIModels",
85
+ "CohereModels",
86
+ "DeepSeekModels",
87
+
88
+ # STT/TTS Model constants
89
+ "DeepgramSTTModels",
90
+ "MicrosoftAzureSpeechSTTModels",
91
+ "GoogleCloudSpeechSTTModels",
92
+ "AssemblyAISTTModels",
93
+ "AmazonPollyTTSModels",
94
+ "MicrosoftAzureSpeechTTSModels",
95
+ "GoogleCloudTextToSpeechTTSModels",
96
+ "DeepgramTTSModels",
97
+
98
+ # Utility functions
99
+ "is_model_supported"
100
+ ]
@@ -23,20 +23,22 @@ from .models import UsageData, UsageDataWithStrings, APIRequest, ModelPricing, M
23
23
  class Client:
24
24
  """Paygent SDK client for tracking usage and costs for AI models."""
25
25
 
26
- def __init__(self, api_key: str, base_url: str = "http://13.201.118.45:8080"):
26
+ def __init__(self, api_key: str):
27
27
  """
28
28
  Initialize the Paygent SDK client.
29
29
 
30
30
  Args:
31
31
  api_key: Your Paygent API key
32
- base_url: Base URL for the Paygent API (default: http://13.201.118.45:8080)
33
32
  """
34
33
  self.api_key = api_key
35
- self.base_url = base_url.rstrip('/')
34
+ # Locked configuration - cannot be changed by users
35
+ self.base_url = "https://cp-api.withpaygent.com"
36
+ # self.base_url = "http://localhost:8082"
37
+ self.timeout = 3000
36
38
 
37
- # Setup logging
39
+ # Setup logging with ERROR level by default (minimal logging)
38
40
  self.logger = logging.getLogger(f"paygent_sdk.{id(self)}")
39
- self.logger.setLevel(logging.INFO)
41
+ self.logger.setLevel(logging.ERROR)
40
42
 
41
43
  # Add console handler if no handlers exist
42
44
  if not self.logger.handlers:
@@ -61,13 +63,13 @@ class Client:
61
63
  self.session.mount("http://", adapter)
62
64
  self.session.mount("https://", adapter)
63
65
 
64
- # Set default timeout
65
- self.session.timeout = 30
66
+ # Set timeout from locked configuration
67
+ self.session.timeout = self.timeout
66
68
 
67
69
  @classmethod
68
70
  def new_client(cls, api_key: str) -> 'Client':
69
71
  """
70
- Create a new Paygent SDK client with the default API URL.
72
+ Create a new Paygent SDK client.
71
73
 
72
74
  Args:
73
75
  api_key: Your Paygent API key
@@ -77,20 +79,6 @@ class Client:
77
79
  """
78
80
  return cls(api_key)
79
81
 
80
- @classmethod
81
- def new_client_with_url(cls, api_key: str, base_url: str) -> 'Client':
82
- """
83
- Create a new Paygent SDK client with a custom base URL.
84
-
85
- Args:
86
- api_key: Your Paygent API key
87
- base_url: Custom base URL for the Paygent API
88
-
89
- Returns:
90
- Client instance
91
- """
92
- return cls(api_key, base_url)
93
-
94
82
  def _calculate_cost(self, model: str, usage_data: UsageData) -> float:
95
83
  """
96
84
  Calculate the cost based on model and usage data.
@@ -145,10 +133,7 @@ class Client:
145
133
  requests.RequestException: If the HTTP request fails
146
134
  ValueError: If the usage data is invalid
147
135
  """
148
- self.logger.info(
149
- f"Starting sendUsage for agentID={agent_id}, customerID={customer_id}, "
150
- f"indicator={indicator}, model={usage_data.model}"
151
- )
136
+ # Removed verbose logging - only log errors
152
137
 
153
138
  # Calculate cost
154
139
  try:
@@ -157,7 +142,7 @@ class Client:
157
142
  self.logger.error(f"Failed to calculate cost: {e}")
158
143
  raise ValueError(f"Failed to calculate cost: {e}") from e
159
144
 
160
- self.logger.info(f"Calculated cost: {cost:.6f} for model {usage_data.model}")
145
+ # Cost calculated (no logging for performance)
161
146
 
162
147
  # Prepare API request
163
148
  api_request = APIRequest(
@@ -207,10 +192,7 @@ class Client:
207
192
 
208
193
  # Check response status
209
194
  if 200 <= response.status_code < 300:
210
- self.logger.info(
211
- f"Successfully sent usage data for agentID={agent_id}, "
212
- f"customerID={customer_id}, cost={cost:.6f}"
213
- )
195
+ # Success - no logging to minimize verbosity
214
196
  return
215
197
 
216
198
  # Handle error response
@@ -381,11 +363,7 @@ class Client:
381
363
  requests.RequestException: If the HTTP request fails
382
364
  ValueError: If the usage data is invalid
383
365
  """
384
- self.logger.info(
385
- f"Starting sendUsageWithTokenString for agentID={agent_id}, customerID={customer_id}, "
386
- f"indicator={indicator}, serviceProvider={usage_data.service_provider}, model={usage_data.model}"
387
- )
388
-
366
+ # Removed verbose logging - only log errors
389
367
  # Calculate cost from strings
390
368
  try:
391
369
  cost = self._calculate_cost_from_strings(usage_data.model, usage_data)
@@ -393,7 +371,7 @@ class Client:
393
371
  self.logger.error(f"Failed to calculate cost from strings: {e}")
394
372
  raise ValueError(f"Failed to calculate cost from strings: {e}") from e
395
373
 
396
- self.logger.info(f"Calculated cost: {cost:.6f} for model {usage_data.model} from strings")
374
+ # Cost calculated from strings (no logging for performance)
397
375
 
398
376
  # Calculate token counts for API request
399
377
  prompt_tokens = self._get_token_count(usage_data.model, usage_data.prompt_string)
@@ -447,10 +425,7 @@ class Client:
447
425
 
448
426
  # Check response status
449
427
  if 200 <= response.status_code < 300:
450
- self.logger.info(
451
- f"Successfully sent usage data from strings for agentID={agent_id}, "
452
- f"customerID={customer_id}, cost={cost:.6f}"
453
- )
428
+ # Success - no logging to minimize verbosity
454
429
  return
455
430
 
456
431
  # Handle error response
@@ -19,6 +19,18 @@ class ServiceProvider:
19
19
  COHERE = "Cohere"
20
20
  DEEPSEEK = "DeepSeek"
21
21
  CUSTOM = "Custom"
22
+
23
+ # STT Service Providers
24
+ DEEPGRAM = "Deepgram"
25
+ MICROSOFT_AZURE_SPEECH = "Microsoft Azure Speech Service"
26
+ GOOGLE_CLOUD_SPEECH = "Google Cloud Speech-to-Text"
27
+ ASSEMBLY_AI = "AssemblyAI"
28
+
29
+ # TTS Service Providers
30
+ AMAZON_POLLY = "Amazon Polly"
31
+ MICROSOFT_AZURE_SPEECH_TTS = "Microsoft Azure Speech Service"
32
+ GOOGLE_CLOUD_TEXT_TO_SPEECH = "Google Cloud Text-to-Speech"
33
+ DEEPGRAM_TTS = "Deepgram"
22
34
 
23
35
 
24
36
  # OpenAI Models
@@ -202,6 +214,78 @@ class DeepSeekModels:
202
214
 
203
215
 
204
216
 
217
+ # Deepgram STT Models
218
+ class DeepgramSTTModels:
219
+ """Deepgram STT model constants."""
220
+ FLUX = "Flux"
221
+ NOVA_3_MONOLINGUAL = "Nova-3 (Monolingual)"
222
+ NOVA_3_MULTILINGUAL = "Nova-3 (Multilingual)"
223
+ NOVA_1 = "Nova-1"
224
+ NOVA_2 = "Nova-2"
225
+ ENHANCED = "Enhanced"
226
+ BASE = "Base"
227
+ REDACTION = "Redaction (Add-on)"
228
+ KEYTERM_PROMPTING = "Keyterm Prompting (Add-on)"
229
+ SPEAKER_DIARIZATION = "Speaker Diarization (Add-on)"
230
+
231
+
232
+ # Microsoft Azure Speech Service STT Models
233
+ class MicrosoftAzureSpeechSTTModels:
234
+ """Microsoft Azure Speech Service STT model constants."""
235
+ STANDARD = "Azure Speech Standard"
236
+ CUSTOM = "Azure Speech Custom"
237
+
238
+
239
+ # Google Cloud Speech-to-Text STT Models
240
+ class GoogleCloudSpeechSTTModels:
241
+ """Google Cloud Speech-to-Text STT model constants."""
242
+ STANDARD = "Google Cloud Speech Standard"
243
+
244
+
245
+ # AssemblyAI STT Models
246
+ class AssemblyAISTTModels:
247
+ """AssemblyAI STT model constants."""
248
+ UNIVERSAL_STREAMING = "Universal-Streaming"
249
+ UNIVERSAL_STREAMING_MULTILANG = "Universal-Streaming Multilingual"
250
+ KEYTERMS_PROMPTING = "Keyterms Prompting"
251
+
252
+
253
+ # Amazon Polly TTS Models
254
+ class AmazonPollyTTSModels:
255
+ """Amazon Polly TTS model constants."""
256
+ STANDARD = "Amazon Polly Standard"
257
+ NEURAL = "Amazon Polly Neural"
258
+ LONG_FORM = "Amazon Polly Long-form"
259
+ GENERATIVE = "Amazon Polly Generative"
260
+
261
+
262
+ # Microsoft Azure Speech Service TTS Models
263
+ class MicrosoftAzureSpeechTTSModels:
264
+ """Microsoft Azure Speech Service TTS model constants."""
265
+ STANDARD = "Azure TTS Standard"
266
+ CUSTOM = "Azure TTS Custom"
267
+ CUSTOM_NEURAL_HD = "Azure TTS Custom Neural HD"
268
+
269
+
270
+ # Google Cloud Text-to-Speech TTS Models
271
+ class GoogleCloudTextToSpeechTTSModels:
272
+ """Google Cloud Text-to-Speech TTS model constants."""
273
+ CHIRP_3_HD = "Google Cloud TTS Chirp 3: HD"
274
+ INSTANT_CUSTOM = "Google Cloud TTS Instant custom"
275
+ WAVENET = "Google Cloud TTS WaveNet"
276
+ STUDIO = "Google Cloud TTS Studio"
277
+ STANDARD = "Google Cloud TTS Standard"
278
+ NEURAL2 = "Google Cloud TTS Neural2"
279
+ POLYGLOT_PREVIEW = "Google Cloud TTS Polyglot (Preview)"
280
+
281
+
282
+ # Deepgram TTS Models
283
+ class DeepgramTTSModels:
284
+ """Deepgram TTS model constants."""
285
+ AURA_2 = "Deepgram Aura-2"
286
+ AURA_1 = "Deepgram Aura-1"
287
+
288
+
205
289
  def is_model_supported(model: str) -> bool:
206
290
  """
207
291
  Check if a model is supported by the SDK.
@@ -53,6 +53,34 @@ class ModelPricing:
53
53
  completion_tokens_cost: float
54
54
 
55
55
 
56
+ @dataclass
57
+ class SttUsageData:
58
+ """Represents the STT usage data structure."""
59
+ service_provider: str
60
+ model: str
61
+ audio_duration: int # Duration in seconds
62
+
63
+
64
+ @dataclass
65
+ class TtsUsageData:
66
+ """Represents the TTS usage data structure."""
67
+ service_provider: str
68
+ model: str
69
+ character_count: int # Number of characters
70
+
71
+
72
+ @dataclass
73
+ class SttModelPricing:
74
+ """Represents pricing information for STT models (cost per hour in USD)."""
75
+ cost_per_hour: float # Cost per hour in USD
76
+
77
+
78
+ @dataclass
79
+ class TtsModelPricing:
80
+ """Represents pricing information for TTS models (cost per 1 million characters in USD)."""
81
+ cost_per_million_characters: float # Cost per 1 million characters in USD
82
+
83
+
56
84
  # Default model pricing (cost per 1000 tokens in USD)
57
85
  MODEL_PRICING: Dict[str, ModelPricing] = {
58
86
  # OpenAI Models (pricing per 1000 tokens)
@@ -0,0 +1,263 @@
1
+ """
2
+ Voice client implementation for STT and TTS usage tracking.
3
+ """
4
+
5
+ import logging
6
+ from typing import Dict
7
+ from urllib.parse import urljoin
8
+
9
+ import requests
10
+
11
+ from .constants import (
12
+ DeepgramSTTModels,
13
+ MicrosoftAzureSpeechSTTModels,
14
+ GoogleCloudSpeechSTTModels,
15
+ AssemblyAISTTModels,
16
+ AmazonPollyTTSModels,
17
+ MicrosoftAzureSpeechTTSModels,
18
+ GoogleCloudTextToSpeechTTSModels,
19
+ DeepgramTTSModels,
20
+ )
21
+ from .models import SttModelPricing, TtsModelPricing
22
+
23
+
24
+ # STT model pricing (cost per hour in USD)
25
+ STT_MODEL_PRICING: Dict[str, SttModelPricing] = {
26
+ # Deepgram Models
27
+ DeepgramSTTModels.FLUX: SttModelPricing(cost_per_hour=0.462), # $0.462 per hour
28
+ DeepgramSTTModels.NOVA_3_MONOLINGUAL: SttModelPricing(cost_per_hour=0.462), # $0.462 per hour
29
+ DeepgramSTTModels.NOVA_3_MULTILINGUAL: SttModelPricing(cost_per_hour=0.552), # $0.552 per hour
30
+ DeepgramSTTModels.NOVA_1: SttModelPricing(cost_per_hour=0.348), # $0.348 per hour
31
+ DeepgramSTTModels.NOVA_2: SttModelPricing(cost_per_hour=0.348), # $0.348 per hour
32
+ DeepgramSTTModels.ENHANCED: SttModelPricing(cost_per_hour=0.99), # $0.99 per hour
33
+ DeepgramSTTModels.BASE: SttModelPricing(cost_per_hour=0.87), # $0.87 per hour
34
+ DeepgramSTTModels.REDACTION: SttModelPricing(cost_per_hour=0.12), # $0.12 per hour (add-on)
35
+ DeepgramSTTModels.KEYTERM_PROMPTING: SttModelPricing(cost_per_hour=0.072), # $0.072 per hour (add-on)
36
+ DeepgramSTTModels.SPEAKER_DIARIZATION: SttModelPricing(cost_per_hour=0.12), # $0.12 per hour (add-on)
37
+
38
+ # Microsoft Azure Speech Service Models
39
+ MicrosoftAzureSpeechSTTModels.STANDARD: SttModelPricing(cost_per_hour=1.0), # $1.0 per hour
40
+ MicrosoftAzureSpeechSTTModels.CUSTOM: SttModelPricing(cost_per_hour=1.2), # $1.2 per hour
41
+
42
+ # Google Cloud Speech-to-Text Models
43
+ GoogleCloudSpeechSTTModels.STANDARD: SttModelPricing(cost_per_hour=0.96), # $0.96 per hour
44
+
45
+ # AssemblyAI Models
46
+ AssemblyAISTTModels.UNIVERSAL_STREAMING: SttModelPricing(cost_per_hour=0.15), # $0.15 per hour
47
+ AssemblyAISTTModels.UNIVERSAL_STREAMING_MULTILANG: SttModelPricing(cost_per_hour=0.15), # $0.15 per hour
48
+ AssemblyAISTTModels.KEYTERMS_PROMPTING: SttModelPricing(cost_per_hour=0.04), # $0.04 per hour
49
+ }
50
+
51
+
52
+ # TTS model pricing (cost per 1 million characters in USD)
53
+ TTS_MODEL_PRICING: Dict[str, TtsModelPricing] = {
54
+ # Amazon Polly Models
55
+ AmazonPollyTTSModels.STANDARD: TtsModelPricing(cost_per_million_characters=0.4), # $0.4 per 1 million characters
56
+ AmazonPollyTTSModels.NEURAL: TtsModelPricing(cost_per_million_characters=16.0), # $16 per 1 million characters
57
+ AmazonPollyTTSModels.LONG_FORM: TtsModelPricing(cost_per_million_characters=100.0), # $100 per 1 million characters
58
+ AmazonPollyTTSModels.GENERATIVE: TtsModelPricing(cost_per_million_characters=30.0), # $30 per 1 million characters
59
+
60
+ # Microsoft Azure Speech Service TTS Models
61
+ MicrosoftAzureSpeechTTSModels.STANDARD: TtsModelPricing(cost_per_million_characters=15.0), # $15 per 1 million characters
62
+ MicrosoftAzureSpeechTTSModels.CUSTOM: TtsModelPricing(cost_per_million_characters=24.0), # $24 per 1 million characters
63
+ MicrosoftAzureSpeechTTSModels.CUSTOM_NEURAL_HD: TtsModelPricing(cost_per_million_characters=48.0), # $48 per 1 million characters
64
+
65
+ # Google Cloud Text-to-Speech TTS Models
66
+ GoogleCloudTextToSpeechTTSModels.CHIRP_3_HD: TtsModelPricing(cost_per_million_characters=30.0), # $30 per 1 million characters
67
+ GoogleCloudTextToSpeechTTSModels.INSTANT_CUSTOM: TtsModelPricing(cost_per_million_characters=60.0), # $60 per 1 million characters
68
+ GoogleCloudTextToSpeechTTSModels.WAVENET: TtsModelPricing(cost_per_million_characters=4.0), # $4 per 1 million characters
69
+ GoogleCloudTextToSpeechTTSModels.STUDIO: TtsModelPricing(cost_per_million_characters=160.0), # $160 per 1 million characters
70
+ GoogleCloudTextToSpeechTTSModels.STANDARD: TtsModelPricing(cost_per_million_characters=4.0), # $4 per 1 million characters
71
+ GoogleCloudTextToSpeechTTSModels.NEURAL2: TtsModelPricing(cost_per_million_characters=16.0), # $16 per 1 million characters
72
+ GoogleCloudTextToSpeechTTSModels.POLYGLOT_PREVIEW: TtsModelPricing(cost_per_million_characters=16.0), # $16 per 1 million characters
73
+
74
+ # Deepgram TTS Models
75
+ DeepgramTTSModels.AURA_2: TtsModelPricing(cost_per_million_characters=30.0), # $30 per 1 million characters
76
+ DeepgramTTSModels.AURA_1: TtsModelPricing(cost_per_million_characters=15.0), # $15 per 1 million characters
77
+ }
78
+
79
+
80
+ def _calculate_stt_cost(client_instance, model: str, audio_duration_seconds: int) -> float:
81
+ """
82
+ Calculate the cost based on STT model and audio duration.
83
+
84
+ Args:
85
+ client_instance: The Client instance
86
+ model: The STT model name
87
+ audio_duration_seconds: Audio duration in seconds
88
+
89
+ Returns:
90
+ Calculated cost in USD
91
+ """
92
+ pricing = STT_MODEL_PRICING.get(model)
93
+
94
+ if not pricing:
95
+ client_instance.logger.warning(f"Unknown STT model '{model}', using default pricing")
96
+ # Use default pricing for unknown models (per hour)
97
+ pricing = SttModelPricing(cost_per_hour=0.5) # $0.50 per hour default
98
+
99
+ # Calculate cost: (duration in seconds / 3600) * cost per hour
100
+ # Convert seconds to hours and multiply by cost per hour
101
+ duration_hours = audio_duration_seconds / 3600.0
102
+ total_cost = duration_hours * pricing.cost_per_hour
103
+
104
+ client_instance.logger.debug(
105
+ f"STT cost calculation for model '{model}': "
106
+ f"duration={audio_duration_seconds} seconds ({duration_hours:.6f} hours), "
107
+ f"cost_per_hour={pricing.cost_per_hour:.6f}, total={total_cost:.6f}"
108
+ )
109
+
110
+ return total_cost
111
+
112
+
113
+ def _calculate_tts_cost(client_instance, model: str, character_count: int) -> float:
114
+ """
115
+ Calculate the cost based on TTS model and character count.
116
+
117
+ Args:
118
+ client_instance: The Client instance
119
+ model: The TTS model name
120
+ character_count: Number of characters
121
+
122
+ Returns:
123
+ Calculated cost in USD
124
+ """
125
+ pricing = TTS_MODEL_PRICING.get(model)
126
+
127
+ if not pricing:
128
+ client_instance.logger.warning(f"Unknown TTS model '{model}', using default pricing")
129
+ # Use default pricing for unknown models (per 1 million characters)
130
+ pricing = TtsModelPricing(cost_per_million_characters=10.0) # $10 per 1 million characters default
131
+
132
+ # Calculate cost: (character count / 1,000,000) * cost per 1 million characters
133
+ # Convert character count to millions and multiply by cost per million
134
+ characters_in_millions = character_count / 1000000.0
135
+ total_cost = characters_in_millions * pricing.cost_per_million_characters
136
+
137
+ client_instance.logger.debug(
138
+ f"TTS cost calculation for model '{model}': "
139
+ f"characters={character_count} ({characters_in_millions:.6f} millions), "
140
+ f"cost_per_million={pricing.cost_per_million_characters:.6f}, total={total_cost:.6f}"
141
+ )
142
+
143
+ return total_cost
144
+
145
+
146
+ def send_stt_usage(client_instance, agent_id: str, customer_id: str, stt_usage_data) -> None:
147
+ """
148
+ Send STT usage data to the Paygent API.
149
+
150
+ Args:
151
+ client_instance: The Client instance
152
+ agent_id: Unique identifier for the agent
153
+ customer_id: Unique identifier for the customer
154
+ stt_usage_data: SttUsageData containing model and audio duration information
155
+
156
+ Raises:
157
+ requests.RequestException: If the request fails
158
+ """
159
+ client_instance.logger.info(
160
+ f"Starting send_stt_usage for agentID={agent_id}, customerID={customer_id}, "
161
+ f"model={stt_usage_data.model}, duration={stt_usage_data.audio_duration} seconds"
162
+ )
163
+
164
+ try:
165
+ # Calculate cost
166
+ cost = _calculate_stt_cost(client_instance, stt_usage_data.model, stt_usage_data.audio_duration)
167
+ client_instance.logger.info(f"Calculated STT cost: {cost:.6f} for model {stt_usage_data.model}")
168
+
169
+ # Prepare API request
170
+ api_request = {
171
+ "agentId": agent_id,
172
+ "customerId": customer_id,
173
+ "indicator": "stt-usage", # Default indicator for STT usage
174
+ "amount": cost,
175
+ "audioDuration": stt_usage_data.audio_duration,
176
+ "model": stt_usage_data.model,
177
+ "serviceProvider": stt_usage_data.service_provider,
178
+ }
179
+
180
+ # Make HTTP request
181
+ url = urljoin(client_instance.base_url, "/api/v1/usage")
182
+ headers = {
183
+ "Content-Type": "application/json",
184
+ "paygent-api-key": client_instance.api_key,
185
+ }
186
+
187
+ response = client_instance.session.post(url, json=api_request, headers=headers)
188
+ response.raise_for_status()
189
+
190
+ client_instance.logger.info(
191
+ f"Successfully sent STT usage data for agentID={agent_id}, "
192
+ f"customerID={customer_id}, cost={cost:.6f}"
193
+ )
194
+ except requests.RequestException as e:
195
+ client_instance.logger.error(f"Failed to send STT usage data: {str(e)}")
196
+ raise
197
+
198
+
199
+ def send_tts_usage(client_instance, agent_id: str, customer_id: str, tts_usage_data) -> None:
200
+ """
201
+ Send TTS usage data to the Paygent API.
202
+
203
+ Args:
204
+ client_instance: The Client instance
205
+ agent_id: Unique identifier for the agent
206
+ customer_id: Unique identifier for the customer
207
+ tts_usage_data: TtsUsageData containing model and character count information
208
+
209
+ Raises:
210
+ requests.RequestException: If the request fails
211
+ """
212
+ client_instance.logger.info(
213
+ f"Starting send_tts_usage for agentID={agent_id}, customerID={customer_id}, "
214
+ f"model={tts_usage_data.model}, characters={tts_usage_data.character_count}"
215
+ )
216
+
217
+ try:
218
+ # Calculate cost
219
+ cost = _calculate_tts_cost(client_instance, tts_usage_data.model, tts_usage_data.character_count)
220
+ client_instance.logger.info(f"Calculated TTS cost: {cost:.6f} for model {tts_usage_data.model}")
221
+
222
+ # Prepare API request
223
+ api_request = {
224
+ "agentId": agent_id,
225
+ "customerId": customer_id,
226
+ "indicator": "tts-usage", # Default indicator for TTS usage
227
+ "amount": cost,
228
+ "characterCount": tts_usage_data.character_count,
229
+ "model": tts_usage_data.model,
230
+ "serviceProvider": tts_usage_data.service_provider,
231
+ }
232
+
233
+ # Make HTTP request
234
+ url = urljoin(client_instance.base_url, "/api/v1/usage")
235
+ headers = {
236
+ "Content-Type": "application/json",
237
+ "paygent-api-key": client_instance.api_key,
238
+ }
239
+
240
+ response = client_instance.session.post(url, json=api_request, headers=headers)
241
+ response.raise_for_status()
242
+
243
+ client_instance.logger.info(
244
+ f"Successfully sent TTS usage data for agentID={agent_id}, "
245
+ f"customerID={customer_id}, cost={cost:.6f}"
246
+ )
247
+ except requests.RequestException as e:
248
+ client_instance.logger.error(f"Failed to send TTS usage data: {str(e)}")
249
+ raise
250
+
251
+
252
+ # Add methods to Client class
253
+ def _add_voice_methods_to_client():
254
+ """Dynamically add voice methods to the Client class."""
255
+ from .client import Client
256
+
257
+ Client.send_stt_usage = send_stt_usage
258
+ Client.send_tts_usage = send_tts_usage
259
+
260
+
261
+ # Call this function to attach methods when module is imported
262
+ _add_voice_methods_to_client()
263
+
@@ -0,0 +1,30 @@
1
+ """
2
+ Wrappers for automatic usage tracking with AI provider SDKs.
3
+
4
+ This module provides wrapper classes that intercept API calls to various AI providers
5
+ and automatically send usage data to Paygent for tracking and billing.
6
+ """
7
+
8
+ from .openai_wrapper import PaygentOpenAI
9
+ from .anthropic_wrapper import PaygentAnthropic
10
+ from .mistral_wrapper import PaygentMistral
11
+ from .gemini_wrapper import PaygentGemini
12
+
13
+ # LangChain integration (optional dependency)
14
+ try:
15
+ from .langchain_wrapper import PaygentLangChainCallback
16
+ __all__ = [
17
+ "PaygentOpenAI",
18
+ "PaygentAnthropic",
19
+ "PaygentMistral",
20
+ "PaygentGemini",
21
+ "PaygentLangChainCallback",
22
+ ]
23
+ except ImportError:
24
+ # LangChain not installed
25
+ __all__ = [
26
+ "PaygentOpenAI",
27
+ "PaygentAnthropic",
28
+ "PaygentMistral",
29
+ "PaygentGemini",
30
+ ]