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.
- tokenator/anthropic/client_anthropic.py +0 -1
- tokenator/base_wrapper.py +1 -1
- tokenator/openai/client_openai.py +9 -3
- tokenator-0.1.12.dist-info/METADATA +240 -0
- {tokenator-0.1.10.dist-info → tokenator-0.1.12.dist-info}/RECORD +7 -7
- {tokenator-0.1.10.dist-info → tokenator-0.1.12.dist-info}/WHEEL +1 -1
- tokenator-0.1.10.dist-info/METADATA +0 -127
- {tokenator-0.1.10.dist-info → tokenator-0.1.12.dist-info}/LICENSE +0 -0
@@ -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
@@ -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=
|
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=
|
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=
|
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.
|
17
|
-
tokenator-0.1.
|
18
|
-
tokenator-0.1.
|
19
|
-
tokenator-0.1.
|
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,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
|
File without changes
|