tokenator 0.1.10__py3-none-any.whl → 0.1.12__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.
@@ -71,7 +71,6 @@ def _create_usage_callback(execution_id, log_usage_fn):
71
71
  usage_data.usage.prompt_tokens += chunk.message.usage.input_tokens
72
72
  usage_data.usage.completion_tokens += chunk.message.usage.output_tokens
73
73
  elif isinstance(chunk, RawMessageDeltaEvent):
74
- usage_data.usage.prompt_tokens += chunk.usage.input_tokens
75
74
  usage_data.usage.completion_tokens += chunk.usage.output_tokens
76
75
 
77
76
  usage_data.usage.total_tokens = usage_data.usage.prompt_tokens + usage_data.usage.completion_tokens
tokenator/base_wrapper.py CHANGED
@@ -47,7 +47,7 @@ class BaseWrapper:
47
47
  total_tokens=token_usage_stats.usage.total_tokens,
48
48
  )
49
49
  session.add(token_usage)
50
- logger.info(
50
+ logger.debug(
51
51
  "Logged token usage: model=%s, total_tokens=%d",
52
52
  token_usage_stats.model,
53
53
  token_usage_stats.usage.total_tokens,
@@ -14,7 +14,9 @@ logger = logging.getLogger(__name__)
14
14
 
15
15
 
16
16
  class BaseOpenAIWrapper(BaseWrapper):
17
- provider = "openai"
17
+ def __init__(self, client, db_path=None, provider: str = "openai"):
18
+ super().__init__(client, db_path)
19
+ self.provider = provider
18
20
 
19
21
  def _process_response_usage(
20
22
  self, response: ResponseType
@@ -134,6 +136,7 @@ class AsyncOpenAIWrapper(BaseOpenAIWrapper):
134
136
  def tokenator_openai(
135
137
  client: OpenAI,
136
138
  db_path: Optional[str] = None,
139
+ provider: str = "openai",
137
140
  ) -> OpenAIWrapper: ...
138
141
 
139
142
 
@@ -141,23 +144,26 @@ def tokenator_openai(
141
144
  def tokenator_openai(
142
145
  client: AsyncOpenAI,
143
146
  db_path: Optional[str] = None,
147
+ provider: str = "openai",
144
148
  ) -> AsyncOpenAIWrapper: ...
145
149
 
146
150
 
147
151
  def tokenator_openai(
148
152
  client: Union[OpenAI, AsyncOpenAI],
149
153
  db_path: Optional[str] = None,
154
+ provider: str = "openai",
150
155
  ) -> Union[OpenAIWrapper, AsyncOpenAIWrapper]:
151
156
  """Create a token-tracking wrapper for an OpenAI client.
152
157
 
153
158
  Args:
154
159
  client: OpenAI or AsyncOpenAI client instance
155
160
  db_path: Optional path to SQLite database for token tracking
161
+ provider: Provider name, defaults to "openai"
156
162
  """
157
163
  if isinstance(client, OpenAI):
158
- return OpenAIWrapper(client=client, db_path=db_path)
164
+ return OpenAIWrapper(client=client, db_path=db_path, provider=provider)
159
165
 
160
166
  if isinstance(client, AsyncOpenAI):
161
- return AsyncOpenAIWrapper(client=client, db_path=db_path)
167
+ return AsyncOpenAIWrapper(client=client, db_path=db_path, provider=provider)
162
168
 
163
169
  raise ValueError("Client must be an instance of OpenAI or AsyncOpenAI")
@@ -0,0 +1,240 @@
1
+ Metadata-Version: 2.3
2
+ Name: tokenator
3
+ Version: 0.1.12
4
+ Summary: Token usage tracking wrapper for LLMs
5
+ License: MIT
6
+ Author: Ujjwal Maheshwari
7
+ Author-email: your.email@example.com
8
+ Requires-Python: >=3.9,<4.0
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Requires-Dist: alembic (>=1.13.0,<2.0.0)
17
+ Requires-Dist: anthropic (>=0.40.0,<0.41.0)
18
+ Requires-Dist: openai (>=1.57.0,<2.0.0)
19
+ Requires-Dist: requests (>=2.32.3,<3.0.0)
20
+ Requires-Dist: sqlalchemy (>=2.0.0,<3.0.0)
21
+ Description-Content-Type: text/markdown
22
+
23
+ # Tokenator : Track and analyze LLM token usage and cost
24
+
25
+ Have you ever wondered about :
26
+ - How many tokens does your AI agent consume?
27
+ - How much does it cost to do run a complex AI workflow with multiple LLM providers?
28
+ - How much money/tokens did you spend today on developing with LLMs?
29
+
30
+ Afraid not, tokenator is here! With tokenator's easy to use API, you can start tracking LLM usage in a matter of minutes.
31
+
32
+ Get started with just 3 lines of code!
33
+
34
+ ## Installation
35
+
36
+ ```bash
37
+ pip install tokenator
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ ### OpenAI
43
+
44
+ ```python
45
+ from openai import OpenAI
46
+ from tokenator import tokenator_openai
47
+
48
+ openai_client = OpenAI(api_key="your-api-key")
49
+
50
+ # Wrap it with Tokenator
51
+ client = tokenator_openai(openai_client)
52
+
53
+ # Use it exactly like the OpenAI client
54
+ response = client.chat.completions.create(
55
+ model="gpt-4o",
56
+ messages=[{"role": "user", "content": "Hello!"}]
57
+ )
58
+ ```
59
+
60
+ Works with AsyncOpenAI and `streaming=True` as well!
61
+ Note : When streaming, don't forget to add `stream_options={"include_usage": True}` to the `create()` call!
62
+
63
+ ### Cost Analysis
64
+
65
+ ```python
66
+ from tokenator import usage
67
+
68
+ # Get usage for different time periods
69
+ usage.last_hour()
70
+ usage.last_day()
71
+ usage.last_week()
72
+ usage.last_month()
73
+
74
+ # Custom date range
75
+ usage.between("2024-03-01", "2024-03-15")
76
+
77
+ # Get usage for different LLM providers
78
+ usage.last_day("openai")
79
+ usage.last_day("anthropic")
80
+ usage.last_day("google")
81
+ ```
82
+
83
+ ### Example `usage` object
84
+
85
+ ```python
86
+ print(cost.last_hour().model_dump_json(indent=4))
87
+ ```
88
+
89
+ ```json
90
+ {
91
+ "total_cost": 0.0004,
92
+ "total_tokens": 79,
93
+ "prompt_tokens": 52,
94
+ "completion_tokens": 27,
95
+ "providers": [
96
+ {
97
+ "total_cost": 0.0004,
98
+ "total_tokens": 79,
99
+ "prompt_tokens": 52,
100
+ "completion_tokens": 27,
101
+ "provider": "openai",
102
+ "models": [
103
+ {
104
+ "total_cost": 0.0004,
105
+ "total_tokens": 79,
106
+ "prompt_tokens": 52,
107
+ "completion_tokens": 27,
108
+ "model": "gpt-4o-2024-08-06"
109
+ }
110
+ ]
111
+ }
112
+ ]
113
+ }
114
+ ```
115
+
116
+ ## Features
117
+
118
+ - Drop-in replacement for OpenAI, Anthropic client
119
+ - Automatic token usage tracking
120
+ - Cost analysis for different time periods
121
+ - SQLite storage with zero configuration
122
+ - Thread-safe operations
123
+ - Minimal memory footprint
124
+ - Minimal latency footprint
125
+
126
+ ### Anthropic
127
+
128
+ ```python
129
+ from anthropic import Anthropic, AsyncAnthropic
130
+ from tokenator import tokenator_anthropic
131
+
132
+ anthropic_client = AsyncAnthropic(api_key="your-api-key")
133
+
134
+ # Wrap it with Tokenator
135
+ client = tokenator_anthropic(anthropic_client)
136
+
137
+ # Use it exactly like the Anthropic client
138
+ response = await client.messages.create(
139
+ model="claude-3-5-haiku-20241022",
140
+ messages=[{"role": "user", "content": "hello how are you"}],
141
+ max_tokens=20,
142
+ )
143
+
144
+ print(response)
145
+
146
+ print(usage.last_execution().model_dump_json(indent=4))
147
+ """
148
+ {
149
+ "total_cost": 0.0001,
150
+ "total_tokens": 23,
151
+ "prompt_tokens": 10,
152
+ "completion_tokens": 13,
153
+ "providers": [
154
+ {
155
+ "total_cost": 0.0001,
156
+ "total_tokens": 23,
157
+ "prompt_tokens": 10,
158
+ "completion_tokens": 13,
159
+ "provider": "anthropic",
160
+ "models": [
161
+ {
162
+ "total_cost": 0.0004,
163
+ "total_tokens": 79,
164
+ "prompt_tokens": 52,
165
+ "completion_tokens": 27,
166
+ "model": "claude-3-5-haiku-20241022"
167
+ }
168
+ ]
169
+ }
170
+ ]
171
+ }
172
+ """
173
+ ```
174
+
175
+ ### xAI
176
+
177
+ You can use xAI models through the `openai` SDK and track usage using `provider` parameter in `tokenator`.
178
+
179
+ ```python
180
+ from openai import OpenAI
181
+ from tokenator import tokenator_openai
182
+
183
+ xai_client = OpenAI(
184
+ api_key=os.getenv("XAI_API_KEY"),
185
+ base_url="https://api.x.ai/v1"
186
+ )
187
+
188
+ # Wrap it with Tokenator
189
+ client = tokenator_openai(client, db_path=temp_db, provider="xai")
190
+
191
+ # Use it exactly like the OpenAI client but with xAI models
192
+ response = client.chat.completions.create(
193
+ model="grok-2-latest",
194
+ messages=[{"role": "user", "content": "Hello!"}]
195
+ )
196
+
197
+ print(response)
198
+
199
+ print(usage.last_execution())
200
+ ```
201
+
202
+ ### Other AI model providers through openai SDKs
203
+
204
+ Today, a variety of AI companies have made their APIs compatible to the `openai` SDK.
205
+ You can track usage of any such AI models using `tokenator`'s `provider` parameter.
206
+
207
+ For example, let's see how we can track usage of `perplexity` tokens.
208
+
209
+ ```python
210
+ from openai import OpenAI
211
+ from tokenator import tokenator_openai
212
+
213
+ xai_client = OpenAI(
214
+ api_key=os.getenv("PERPLEXITY_API_KEY"),
215
+ base_url="https://api.perplexity.ai"
216
+ )
217
+
218
+ # Wrap it with Tokenator
219
+ client = tokenator_openai(client, db_path=temp_db, provider="perplexity")
220
+
221
+ # Use it exactly like the OpenAI client but with xAI models
222
+ response = client.chat.completions.create(
223
+ model="grok-2-latest",
224
+ messages=[{"role": "user", "content": "Hello!"}]
225
+ )
226
+
227
+ print(response)
228
+
229
+ print(usage.last_execution())
230
+
231
+ print(usage.provider("perplexity"))
232
+ ```
233
+
234
+ ---
235
+
236
+ Most importantly, none of your data is ever sent to any server.
237
+
238
+ ## License
239
+
240
+ MIT
@@ -1,19 +1,19 @@
1
1
  tokenator/__init__.py,sha256=bIAPyGAvWreS2i_5tzxJEyX9JlZgAUNxzVk1iHNUhvU,593
2
- tokenator/anthropic/client_anthropic.py,sha256=fcKxGsLex99II-WD9SVNI5QVzH0IEWRmVLjyvZd9wKs,5936
2
+ tokenator/anthropic/client_anthropic.py,sha256=fnjWz_Kf8D0GUTudkZNeSmH9ueCGFLDSBDz1U8Jri3Y,5861
3
3
  tokenator/anthropic/stream_interceptors.py,sha256=4VHC_-WkG3Pa10YizmFLrHcbz0Tm2MR_YB5-uohKp5A,5221
4
- tokenator/base_wrapper.py,sha256=VYSkQB1MEudgzBX60T-VAMsNg4fFx7IRzpadzjm4klE,2466
4
+ tokenator/base_wrapper.py,sha256=IO344KWbRswQy4vG_pBxWPR7Wp7K-4mlgmS3SCYGep8,2467
5
5
  tokenator/create_migrations.py,sha256=k9IHiGK21dLTA8MYNsuhO0-kUVIcMSViMFYtY4WU2Rw,730
6
6
  tokenator/migrations/env.py,sha256=JoF5MJ4ae0wJW5kdBHuFlG3ZqeCCDvbMcU8fNA_a6hM,1396
7
7
  tokenator/migrations/script.py.mako,sha256=nJL-tbLQE0Qy4P9S4r4ntNAcikPtoFUlvXe6xvm9ot8,635
8
8
  tokenator/migrations/versions/f6f1f2437513_initial_migration.py,sha256=4cveHkwSxs-hxOPCm81YfvGZTkJJ2ClAFmyL98-1VCo,1910
9
9
  tokenator/migrations.py,sha256=YAf9gZmDzAq36PWWXPtdUQoJFYPXtIDzflC79H6gcJg,1114
10
10
  tokenator/models.py,sha256=MhYwCvmqposUNDRxFZNAVnzCqBTHxNL3Hp0MNFXM5ck,1201
11
- tokenator/openai/client_openai.py,sha256=Umfxha3BhBFU_JebPjyuaUZEZuPqJWQo1xTCuAy3R24,5691
11
+ tokenator/openai/client_openai.py,sha256=Ffa3ujLh5PuPe1W8KSISGH3NonZ_AC6ZpKhO6kTupTU,5996
12
12
  tokenator/openai/stream_interceptors.py,sha256=ez1MnjRZW_rEalv2SIPAvrU9oMD6OJoD9vht-057fDM,5243
13
13
  tokenator/schemas.py,sha256=Ye8hqZlrm3Gh2FyvOVX-hWCpKynWxS58QQRQMfDtIAQ,2114
14
14
  tokenator/usage.py,sha256=eTWfcRrTLop-30FmwHpi7_GwCJxU6Qfji374hG1Qptw,8476
15
15
  tokenator/utils.py,sha256=xg9l2GV1yJL1BlxKL1r8CboABWDslf3G5rGQEJSjFrE,1973
16
- tokenator-0.1.10.dist-info/LICENSE,sha256=wdG-B6-ODk8RQ4jq5uXSn0w1UWTzCH_MMyvh7AwtGns,1074
17
- tokenator-0.1.10.dist-info/METADATA,sha256=ryILkOYlq8V8219sVmK0xUeEEw51msw_FCoF_3VJ_k8,3108
18
- tokenator-0.1.10.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
19
- tokenator-0.1.10.dist-info/RECORD,,
16
+ tokenator-0.1.12.dist-info/LICENSE,sha256=wdG-B6-ODk8RQ4jq5uXSn0w1UWTzCH_MMyvh7AwtGns,1074
17
+ tokenator-0.1.12.dist-info/METADATA,sha256=VdJVlwESY2_QbiterwI1lH9dng4r4WwWYd6MwXlT9V4,5969
18
+ tokenator-0.1.12.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
19
+ tokenator-0.1.12.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.1
2
+ Generator: poetry-core 2.0.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,127 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: tokenator
3
- Version: 0.1.10
4
- Summary: Token usage tracking wrapper for LLMs
5
- License: MIT
6
- Author: Ujjwal Maheshwari
7
- Author-email: your.email@example.com
8
- Requires-Python: >=3.9,<4.0
9
- Classifier: License :: OSI Approved :: MIT License
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.9
12
- Classifier: Programming Language :: Python :: 3.10
13
- Classifier: Programming Language :: Python :: 3.11
14
- Classifier: Programming Language :: Python :: 3.12
15
- Classifier: Programming Language :: Python :: 3.13
16
- Requires-Dist: alembic (>=1.13.0,<2.0.0)
17
- Requires-Dist: anthropic (>=0.40.0,<0.41.0)
18
- Requires-Dist: openai (>=1.57.0,<2.0.0)
19
- Requires-Dist: requests (>=2.32.3,<3.0.0)
20
- Requires-Dist: sqlalchemy (>=2.0.0,<3.0.0)
21
- Description-Content-Type: text/markdown
22
-
23
- # Tokenator : Easiest way to track and analyze LLM token usage and cost
24
-
25
- Have you ever wondered about :
26
- - How many tokens does your AI agent consume?
27
- - How much does it cost to do run a complex AI workflow with multiple LLM providers?
28
- - How much money did I spent today on development?
29
-
30
- Afraid not, tokenator is here! With tokenator's easy to use API, you can start tracking LLM usage in a matter of minutes.
31
-
32
- Get started with just 3 lines of code!
33
-
34
- ## Installation
35
-
36
- ```bash
37
- pip install tokenator
38
- ```
39
-
40
- ## Usage
41
-
42
- ### OpenAI
43
-
44
- ```python
45
- from openai import OpenAI
46
- from tokenator import tokenator_openai
47
-
48
- openai_client = OpenAI(api_key="your-api-key")
49
-
50
- # Wrap it with Tokenator
51
- client = tokenator_openai(openai_client)
52
-
53
- # Use it exactly like the OpenAI client
54
- response = client.chat.completions.create(
55
- model="gpt-4o",
56
- messages=[{"role": "user", "content": "Hello!"}]
57
- )
58
- ```
59
-
60
- ### Cost Analysis
61
-
62
- ```python
63
- from tokenator import usage
64
-
65
- # Get usage for different time periods
66
- usage.last_hour()
67
- usage.last_day()
68
- usage.last_week()
69
- usage.last_month()
70
-
71
- # Custom date range
72
- usage.between("2024-03-01", "2024-03-15")
73
-
74
- # Get usage for different LLM providers
75
- usage.last_day("openai")
76
- usage.last_day("anthropic")
77
- usage.last_day("google")
78
- ```
79
-
80
- ### Example `usage` object
81
-
82
- ```python
83
- print(cost.last_hour().model_dump_json(indent=4))
84
- ```
85
-
86
- ```json
87
- {
88
- "total_cost": 0.0004,
89
- "total_tokens": 79,
90
- "prompt_tokens": 52,
91
- "completion_tokens": 27,
92
- "providers": [
93
- {
94
- "total_cost": 0.0004,
95
- "total_tokens": 79,
96
- "prompt_tokens": 52,
97
- "completion_tokens": 27,
98
- "provider": "openai",
99
- "models": [
100
- {
101
- "total_cost": 0.0004,
102
- "total_tokens": 79,
103
- "prompt_tokens": 52,
104
- "completion_tokens": 27,
105
- "model": "gpt-4o-2024-08-06"
106
- }
107
- ]
108
- }
109
- ]
110
- }
111
- ```
112
-
113
- ## Features
114
-
115
- - Drop-in replacement for OpenAI, Anthropic client
116
- - Automatic token usage tracking
117
- - Cost analysis for different time periods
118
- - SQLite storage with zero configuration
119
- - Thread-safe operations
120
- - Minimal memory footprint
121
- - Minimal latency footprint
122
-
123
- Most importantly, none of your data is ever sent to any server.
124
-
125
- ## License
126
-
127
- MIT