spent 0.1.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.
- spent-0.1.0/.gitignore +14 -0
- spent-0.1.0/CONTRIBUTING.md +39 -0
- spent-0.1.0/LICENSE +21 -0
- spent-0.1.0/PKG-INFO +241 -0
- spent-0.1.0/README.md +203 -0
- spent-0.1.0/pyproject.toml +67 -0
- spent-0.1.0/spent/__init__.py +66 -0
- spent-0.1.0/spent/cli.py +209 -0
- spent-0.1.0/spent/dashboard.py +208 -0
- spent-0.1.0/spent/patches/__init__.py +19 -0
- spent-0.1.0/spent/patches/anthropic_patch.py +75 -0
- spent-0.1.0/spent/patches/openai_patch.py +100 -0
- spent-0.1.0/spent/pricing.py +131 -0
- spent-0.1.0/spent/storage.py +131 -0
- spent-0.1.0/spent/tracker.py +163 -0
- spent-0.1.0/tests/__init__.py +0 -0
- spent-0.1.0/tests/test_pricing.py +95 -0
- spent-0.1.0/tests/test_storage.py +89 -0
- spent-0.1.0/tests/test_tracker.py +110 -0
spent-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Contributing to spent
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing!
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/loplop-h/spent.git
|
|
9
|
+
cd spent
|
|
10
|
+
pip install -e ".[dev]"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Running Tests
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pytest
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Code Style
|
|
20
|
+
|
|
21
|
+
We use [ruff](https://github.com/astral-sh/ruff) for linting:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
ruff check .
|
|
25
|
+
ruff format .
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Adding a New Provider
|
|
29
|
+
|
|
30
|
+
1. Create a new patch file in `spent/patches/` (see `openai_patch.py` for reference)
|
|
31
|
+
2. Add the provider's model pricing to `spent/pricing.py`
|
|
32
|
+
3. Import and call the patch in `spent/patches/__init__.py`
|
|
33
|
+
4. Add tests
|
|
34
|
+
|
|
35
|
+
## Pull Requests
|
|
36
|
+
|
|
37
|
+
- Keep PRs focused on a single change
|
|
38
|
+
- Include tests for new functionality
|
|
39
|
+
- Update README if adding user-facing features
|
spent-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 maxhu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
spent-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spent
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: See what your AI really costs. Zero code changes.
|
|
5
|
+
Project-URL: Homepage, https://github.com/loplop-h/spent
|
|
6
|
+
Project-URL: Repository, https://github.com/loplop-h/spent
|
|
7
|
+
Project-URL: Issues, https://github.com/loplop-h/spent/issues
|
|
8
|
+
Author: maxhu
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ai,anthropic,budget,cost,llm,monitoring,openai,optimization,tokens,tracking
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
22
|
+
Classifier: Topic :: System :: Monitoring
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Requires-Dist: click>=8.0
|
|
25
|
+
Requires-Dist: rich>=13.0
|
|
26
|
+
Provides-Extra: all
|
|
27
|
+
Requires-Dist: anthropic>=0.20; extra == 'all'
|
|
28
|
+
Requires-Dist: openai>=1.0; extra == 'all'
|
|
29
|
+
Provides-Extra: anthropic
|
|
30
|
+
Requires-Dist: anthropic>=0.20; extra == 'anthropic'
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
35
|
+
Provides-Extra: openai
|
|
36
|
+
Requires-Dist: openai>=1.0; extra == 'openai'
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
<p align="center">
|
|
40
|
+
<h1 align="center">spent</h1>
|
|
41
|
+
<p align="center"><strong>See what your AI really costs. Zero code changes.</strong></p>
|
|
42
|
+
</p>
|
|
43
|
+
|
|
44
|
+
<p align="center">
|
|
45
|
+
<a href="https://pypi.org/project/spent/"><img src="https://img.shields.io/pypi/v/spent?style=flat-square" alt="PyPI"></a>
|
|
46
|
+
<a href="https://pypi.org/project/spent/"><img src="https://img.shields.io/pypi/pyversions/spent?style=flat-square" alt="Python"></a>
|
|
47
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="License"></a>
|
|
48
|
+
<a href="https://github.com/loplop-h/spent/stargazers"><img src="https://img.shields.io/github/stars/maxhu/spent?style=flat-square" alt="Stars"></a>
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
You're spending hundreds on LLM APIs every month. Do you know which calls cost what?
|
|
54
|
+
|
|
55
|
+
**spent** tracks every token, every model, every dollar -- automatically. One command. No code changes. Beautiful reports.
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
$ spent run python app.py
|
|
59
|
+
|
|
60
|
+
┌──────────────────────────────────────────┐
|
|
61
|
+
│ spent session a1b2c3 │
|
|
62
|
+
│ │
|
|
63
|
+
│ Total Cost: $4.2731 │
|
|
64
|
+
│ Tokens: 125,430 (98k in / 27k out)
|
|
65
|
+
│ API Calls: 47 │
|
|
66
|
+
│ Duration: 2m 34s │
|
|
67
|
+
└──────────────────────────────────────────┘
|
|
68
|
+
|
|
69
|
+
Model Calls Tokens Cost Share
|
|
70
|
+
gpt-4o 12 84,200 $3.8100 ████████░░ 89%
|
|
71
|
+
gpt-4o-mini 31 38,100 $0.4200 █░░░░░░░░░ 10%
|
|
72
|
+
claude-sonnet-4-6 4 3,130 $0.0431 ░░░░░░░░░░ 1%
|
|
73
|
+
|
|
74
|
+
Savings Opportunities: ~$2.1000
|
|
75
|
+
gpt-4o -> gpt-4o-mini: save $2.10 (55%) on 12 calls
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Quick Start
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pip install spent
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Option 1: Zero code changes (recommended)
|
|
85
|
+
|
|
86
|
+
Just prefix your command:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
spent run python app.py
|
|
90
|
+
spent run python -m pytest
|
|
91
|
+
spent run --budget 5.00 python train.py
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Option 2: One line of code
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from spent import track
|
|
98
|
+
from openai import OpenAI
|
|
99
|
+
|
|
100
|
+
client = track(OpenAI())
|
|
101
|
+
|
|
102
|
+
# Use normally -- costs tracked automatically
|
|
103
|
+
response = client.chat.completions.create(
|
|
104
|
+
model="gpt-4o",
|
|
105
|
+
messages=[{"role": "user", "content": "Hello!"}],
|
|
106
|
+
)
|
|
107
|
+
# Exit summary printed automatically
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Works with Anthropic too:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from spent import track
|
|
114
|
+
from anthropic import Anthropic
|
|
115
|
+
|
|
116
|
+
client = track(Anthropic())
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Features
|
|
120
|
+
|
|
121
|
+
| Feature | Status |
|
|
122
|
+
|---------|--------|
|
|
123
|
+
| OpenAI cost tracking | Done |
|
|
124
|
+
| Anthropic cost tracking | Done |
|
|
125
|
+
| Beautiful terminal dashboard | Done |
|
|
126
|
+
| Per-model cost breakdown | Done |
|
|
127
|
+
| Savings recommendations | Done |
|
|
128
|
+
| Budget alerts | Done |
|
|
129
|
+
| Session history | Done |
|
|
130
|
+
| JSON/CSV export | Done |
|
|
131
|
+
| Google AI tracking | Roadmap |
|
|
132
|
+
| Auto model routing | Roadmap |
|
|
133
|
+
| Team cost sharing | Roadmap |
|
|
134
|
+
| CI/CD cost reports | Roadmap |
|
|
135
|
+
|
|
136
|
+
## Commands
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# Track costs (zero code changes)
|
|
140
|
+
spent run python app.py
|
|
141
|
+
|
|
142
|
+
# Set a budget alert
|
|
143
|
+
spent run --budget 10.00 python app.py
|
|
144
|
+
|
|
145
|
+
# Live dashboard (watches costs in real-time)
|
|
146
|
+
spent dashboard
|
|
147
|
+
|
|
148
|
+
# View cost reports
|
|
149
|
+
spent report # Recent sessions
|
|
150
|
+
spent report --today # Today's costs
|
|
151
|
+
spent report --json # Machine-readable
|
|
152
|
+
spent report --csv # Spreadsheet-ready
|
|
153
|
+
|
|
154
|
+
# Clear all data
|
|
155
|
+
spent reset
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## How It Works
|
|
159
|
+
|
|
160
|
+
**spent** transparently patches the OpenAI and Anthropic Python SDKs at import time. When your code calls `client.chat.completions.create(...)`, spent:
|
|
161
|
+
|
|
162
|
+
1. Intercepts the call (before and after)
|
|
163
|
+
2. Extracts token usage from the response
|
|
164
|
+
3. Calculates cost using up-to-date pricing
|
|
165
|
+
4. Stores the record in a local SQLite database
|
|
166
|
+
5. Returns the original response unchanged
|
|
167
|
+
|
|
168
|
+
Your code runs exactly the same. No API proxies. No network changes. No latency added to API calls themselves.
|
|
169
|
+
|
|
170
|
+
Data stays on your machine at `~/.spent/data.db`.
|
|
171
|
+
|
|
172
|
+
## Supported Models
|
|
173
|
+
|
|
174
|
+
40+ models with up-to-date pricing:
|
|
175
|
+
|
|
176
|
+
| Provider | Models |
|
|
177
|
+
|----------|--------|
|
|
178
|
+
| **OpenAI** | GPT-4o, GPT-4o-mini, GPT-4-Turbo, GPT-4, GPT-3.5-Turbo, o1, o3, o3-mini, o4-mini |
|
|
179
|
+
| **Anthropic** | Claude Opus 4, Claude Sonnet 4, Claude Haiku 4, Claude 3.5/3 family |
|
|
180
|
+
| **Google** | Gemini 2.5 Pro/Flash, 2.0 Flash, 1.5 Pro/Flash |
|
|
181
|
+
| **DeepSeek** | DeepSeek Chat, DeepSeek Reasoner |
|
|
182
|
+
| **Mistral** | Mistral Large, Mistral Small, Codestral |
|
|
183
|
+
| **Groq** | Llama 3.3 70B, Llama 3.1 8B, Mixtral 8x7B |
|
|
184
|
+
|
|
185
|
+
Unknown models are tracked with $0 cost (tokens still recorded).
|
|
186
|
+
|
|
187
|
+
## Budget Alerts
|
|
188
|
+
|
|
189
|
+
Set a budget and get warned when you exceed it:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
# CLI
|
|
193
|
+
spent run --budget 5.00 python app.py
|
|
194
|
+
|
|
195
|
+
# Python
|
|
196
|
+
from spent import track, configure
|
|
197
|
+
configure(budget=5.00)
|
|
198
|
+
client = track(OpenAI())
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
When the budget is exceeded:
|
|
202
|
+
```
|
|
203
|
+
[spent] BUDGET ALERT: $5.0231 spent (budget: $5.00)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Why spent?
|
|
207
|
+
|
|
208
|
+
| | spent | Manual tracking | LLM framework built-in |
|
|
209
|
+
|---|---|---|---|
|
|
210
|
+
| Code changes needed | 0 | Lots | Framework-specific |
|
|
211
|
+
| Works across providers | Yes | Manual per-provider | Usually one provider |
|
|
212
|
+
| Historical data | SQLite | Spreadsheets | In-memory only |
|
|
213
|
+
| Savings recommendations | Automatic | You do the math | No |
|
|
214
|
+
| Export formats | JSON, CSV | Copy-paste | Varies |
|
|
215
|
+
| Privacy | 100% local | Depends | Often cloud |
|
|
216
|
+
|
|
217
|
+
## Roadmap
|
|
218
|
+
|
|
219
|
+
- [ ] **Google AI / Vertex tracking** -- Gemini model support
|
|
220
|
+
- [ ] **Auto model routing** -- automatically use cheaper models for simple tasks
|
|
221
|
+
- [ ] **Team dashboards** -- aggregate costs across team members
|
|
222
|
+
- [ ] **CI/CD integration** -- cost reports in GitHub Actions / PR comments
|
|
223
|
+
- [ ] **Ollama / local model tracking** -- track local inference costs (compute time)
|
|
224
|
+
- [ ] **Web dashboard** -- browser-based cost explorer
|
|
225
|
+
- [ ] **Slack / Discord alerts** -- budget notifications in team channels
|
|
226
|
+
- [ ] **Cost anomaly detection** -- alert on unusual spending patterns
|
|
227
|
+
|
|
228
|
+
## Contributing
|
|
229
|
+
|
|
230
|
+
Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
git clone https://github.com/loplop-h/spent.git
|
|
234
|
+
cd spent
|
|
235
|
+
pip install -e ".[dev]"
|
|
236
|
+
pytest
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## License
|
|
240
|
+
|
|
241
|
+
MIT
|
spent-0.1.0/README.md
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center">spent</h1>
|
|
3
|
+
<p align="center"><strong>See what your AI really costs. Zero code changes.</strong></p>
|
|
4
|
+
</p>
|
|
5
|
+
|
|
6
|
+
<p align="center">
|
|
7
|
+
<a href="https://pypi.org/project/spent/"><img src="https://img.shields.io/pypi/v/spent?style=flat-square" alt="PyPI"></a>
|
|
8
|
+
<a href="https://pypi.org/project/spent/"><img src="https://img.shields.io/pypi/pyversions/spent?style=flat-square" alt="Python"></a>
|
|
9
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="License"></a>
|
|
10
|
+
<a href="https://github.com/loplop-h/spent/stargazers"><img src="https://img.shields.io/github/stars/maxhu/spent?style=flat-square" alt="Stars"></a>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
You're spending hundreds on LLM APIs every month. Do you know which calls cost what?
|
|
16
|
+
|
|
17
|
+
**spent** tracks every token, every model, every dollar -- automatically. One command. No code changes. Beautiful reports.
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
$ spent run python app.py
|
|
21
|
+
|
|
22
|
+
┌──────────────────────────────────────────┐
|
|
23
|
+
│ spent session a1b2c3 │
|
|
24
|
+
│ │
|
|
25
|
+
│ Total Cost: $4.2731 │
|
|
26
|
+
│ Tokens: 125,430 (98k in / 27k out)
|
|
27
|
+
│ API Calls: 47 │
|
|
28
|
+
│ Duration: 2m 34s │
|
|
29
|
+
└──────────────────────────────────────────┘
|
|
30
|
+
|
|
31
|
+
Model Calls Tokens Cost Share
|
|
32
|
+
gpt-4o 12 84,200 $3.8100 ████████░░ 89%
|
|
33
|
+
gpt-4o-mini 31 38,100 $0.4200 █░░░░░░░░░ 10%
|
|
34
|
+
claude-sonnet-4-6 4 3,130 $0.0431 ░░░░░░░░░░ 1%
|
|
35
|
+
|
|
36
|
+
Savings Opportunities: ~$2.1000
|
|
37
|
+
gpt-4o -> gpt-4o-mini: save $2.10 (55%) on 12 calls
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install spent
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Option 1: Zero code changes (recommended)
|
|
47
|
+
|
|
48
|
+
Just prefix your command:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
spent run python app.py
|
|
52
|
+
spent run python -m pytest
|
|
53
|
+
spent run --budget 5.00 python train.py
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Option 2: One line of code
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from spent import track
|
|
60
|
+
from openai import OpenAI
|
|
61
|
+
|
|
62
|
+
client = track(OpenAI())
|
|
63
|
+
|
|
64
|
+
# Use normally -- costs tracked automatically
|
|
65
|
+
response = client.chat.completions.create(
|
|
66
|
+
model="gpt-4o",
|
|
67
|
+
messages=[{"role": "user", "content": "Hello!"}],
|
|
68
|
+
)
|
|
69
|
+
# Exit summary printed automatically
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Works with Anthropic too:
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from spent import track
|
|
76
|
+
from anthropic import Anthropic
|
|
77
|
+
|
|
78
|
+
client = track(Anthropic())
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Features
|
|
82
|
+
|
|
83
|
+
| Feature | Status |
|
|
84
|
+
|---------|--------|
|
|
85
|
+
| OpenAI cost tracking | Done |
|
|
86
|
+
| Anthropic cost tracking | Done |
|
|
87
|
+
| Beautiful terminal dashboard | Done |
|
|
88
|
+
| Per-model cost breakdown | Done |
|
|
89
|
+
| Savings recommendations | Done |
|
|
90
|
+
| Budget alerts | Done |
|
|
91
|
+
| Session history | Done |
|
|
92
|
+
| JSON/CSV export | Done |
|
|
93
|
+
| Google AI tracking | Roadmap |
|
|
94
|
+
| Auto model routing | Roadmap |
|
|
95
|
+
| Team cost sharing | Roadmap |
|
|
96
|
+
| CI/CD cost reports | Roadmap |
|
|
97
|
+
|
|
98
|
+
## Commands
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Track costs (zero code changes)
|
|
102
|
+
spent run python app.py
|
|
103
|
+
|
|
104
|
+
# Set a budget alert
|
|
105
|
+
spent run --budget 10.00 python app.py
|
|
106
|
+
|
|
107
|
+
# Live dashboard (watches costs in real-time)
|
|
108
|
+
spent dashboard
|
|
109
|
+
|
|
110
|
+
# View cost reports
|
|
111
|
+
spent report # Recent sessions
|
|
112
|
+
spent report --today # Today's costs
|
|
113
|
+
spent report --json # Machine-readable
|
|
114
|
+
spent report --csv # Spreadsheet-ready
|
|
115
|
+
|
|
116
|
+
# Clear all data
|
|
117
|
+
spent reset
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## How It Works
|
|
121
|
+
|
|
122
|
+
**spent** transparently patches the OpenAI and Anthropic Python SDKs at import time. When your code calls `client.chat.completions.create(...)`, spent:
|
|
123
|
+
|
|
124
|
+
1. Intercepts the call (before and after)
|
|
125
|
+
2. Extracts token usage from the response
|
|
126
|
+
3. Calculates cost using up-to-date pricing
|
|
127
|
+
4. Stores the record in a local SQLite database
|
|
128
|
+
5. Returns the original response unchanged
|
|
129
|
+
|
|
130
|
+
Your code runs exactly the same. No API proxies. No network changes. No latency added to API calls themselves.
|
|
131
|
+
|
|
132
|
+
Data stays on your machine at `~/.spent/data.db`.
|
|
133
|
+
|
|
134
|
+
## Supported Models
|
|
135
|
+
|
|
136
|
+
40+ models with up-to-date pricing:
|
|
137
|
+
|
|
138
|
+
| Provider | Models |
|
|
139
|
+
|----------|--------|
|
|
140
|
+
| **OpenAI** | GPT-4o, GPT-4o-mini, GPT-4-Turbo, GPT-4, GPT-3.5-Turbo, o1, o3, o3-mini, o4-mini |
|
|
141
|
+
| **Anthropic** | Claude Opus 4, Claude Sonnet 4, Claude Haiku 4, Claude 3.5/3 family |
|
|
142
|
+
| **Google** | Gemini 2.5 Pro/Flash, 2.0 Flash, 1.5 Pro/Flash |
|
|
143
|
+
| **DeepSeek** | DeepSeek Chat, DeepSeek Reasoner |
|
|
144
|
+
| **Mistral** | Mistral Large, Mistral Small, Codestral |
|
|
145
|
+
| **Groq** | Llama 3.3 70B, Llama 3.1 8B, Mixtral 8x7B |
|
|
146
|
+
|
|
147
|
+
Unknown models are tracked with $0 cost (tokens still recorded).
|
|
148
|
+
|
|
149
|
+
## Budget Alerts
|
|
150
|
+
|
|
151
|
+
Set a budget and get warned when you exceed it:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# CLI
|
|
155
|
+
spent run --budget 5.00 python app.py
|
|
156
|
+
|
|
157
|
+
# Python
|
|
158
|
+
from spent import track, configure
|
|
159
|
+
configure(budget=5.00)
|
|
160
|
+
client = track(OpenAI())
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
When the budget is exceeded:
|
|
164
|
+
```
|
|
165
|
+
[spent] BUDGET ALERT: $5.0231 spent (budget: $5.00)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Why spent?
|
|
169
|
+
|
|
170
|
+
| | spent | Manual tracking | LLM framework built-in |
|
|
171
|
+
|---|---|---|---|
|
|
172
|
+
| Code changes needed | 0 | Lots | Framework-specific |
|
|
173
|
+
| Works across providers | Yes | Manual per-provider | Usually one provider |
|
|
174
|
+
| Historical data | SQLite | Spreadsheets | In-memory only |
|
|
175
|
+
| Savings recommendations | Automatic | You do the math | No |
|
|
176
|
+
| Export formats | JSON, CSV | Copy-paste | Varies |
|
|
177
|
+
| Privacy | 100% local | Depends | Often cloud |
|
|
178
|
+
|
|
179
|
+
## Roadmap
|
|
180
|
+
|
|
181
|
+
- [ ] **Google AI / Vertex tracking** -- Gemini model support
|
|
182
|
+
- [ ] **Auto model routing** -- automatically use cheaper models for simple tasks
|
|
183
|
+
- [ ] **Team dashboards** -- aggregate costs across team members
|
|
184
|
+
- [ ] **CI/CD integration** -- cost reports in GitHub Actions / PR comments
|
|
185
|
+
- [ ] **Ollama / local model tracking** -- track local inference costs (compute time)
|
|
186
|
+
- [ ] **Web dashboard** -- browser-based cost explorer
|
|
187
|
+
- [ ] **Slack / Discord alerts** -- budget notifications in team channels
|
|
188
|
+
- [ ] **Cost anomaly detection** -- alert on unusual spending patterns
|
|
189
|
+
|
|
190
|
+
## Contributing
|
|
191
|
+
|
|
192
|
+
Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
git clone https://github.com/loplop-h/spent.git
|
|
196
|
+
cd spent
|
|
197
|
+
pip install -e ".[dev]"
|
|
198
|
+
pytest
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## License
|
|
202
|
+
|
|
203
|
+
MIT
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "spent"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "See what your AI really costs. Zero code changes."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "maxhu" },
|
|
14
|
+
]
|
|
15
|
+
keywords = [
|
|
16
|
+
"llm", "ai", "cost", "tracking", "openai", "anthropic",
|
|
17
|
+
"tokens", "monitoring", "budget", "optimization",
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 4 - Beta",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"License :: OSI Approved :: MIT License",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3.9",
|
|
25
|
+
"Programming Language :: Python :: 3.10",
|
|
26
|
+
"Programming Language :: Python :: 3.11",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Programming Language :: Python :: 3.13",
|
|
29
|
+
"Topic :: Software Development :: Libraries",
|
|
30
|
+
"Topic :: System :: Monitoring",
|
|
31
|
+
]
|
|
32
|
+
dependencies = [
|
|
33
|
+
"click>=8.0",
|
|
34
|
+
"rich>=13.0",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[project.optional-dependencies]
|
|
38
|
+
openai = ["openai>=1.0"]
|
|
39
|
+
anthropic = ["anthropic>=0.20"]
|
|
40
|
+
all = ["openai>=1.0", "anthropic>=0.20"]
|
|
41
|
+
dev = [
|
|
42
|
+
"pytest>=7.0",
|
|
43
|
+
"pytest-cov>=4.0",
|
|
44
|
+
"ruff>=0.4",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[project.scripts]
|
|
48
|
+
spent = "spent.cli:main"
|
|
49
|
+
|
|
50
|
+
[project.urls]
|
|
51
|
+
Homepage = "https://github.com/loplop-h/spent"
|
|
52
|
+
Repository = "https://github.com/loplop-h/spent"
|
|
53
|
+
Issues = "https://github.com/loplop-h/spent/issues"
|
|
54
|
+
|
|
55
|
+
[tool.ruff]
|
|
56
|
+
target-version = "py39"
|
|
57
|
+
line-length = 100
|
|
58
|
+
|
|
59
|
+
[tool.ruff.lint]
|
|
60
|
+
select = ["E", "F", "I", "W"]
|
|
61
|
+
|
|
62
|
+
[tool.pytest.ini_options]
|
|
63
|
+
testpaths = ["tests"]
|
|
64
|
+
addopts = "-v --tb=short"
|
|
65
|
+
|
|
66
|
+
[tool.hatch.build.targets.wheel]
|
|
67
|
+
packages = ["spent"]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""spent -- see what your AI really costs.
|
|
2
|
+
|
|
3
|
+
Usage (zero code changes):
|
|
4
|
+
$ spent run python app.py
|
|
5
|
+
|
|
6
|
+
Usage (programmatic):
|
|
7
|
+
from spent import track
|
|
8
|
+
from openai import OpenAI
|
|
9
|
+
|
|
10
|
+
client = track(OpenAI())
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
__version__ = "0.1.0"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def track(client, *, budget: float | None = None):
|
|
19
|
+
"""Wrap an LLM client to track all API costs.
|
|
20
|
+
|
|
21
|
+
Supports OpenAI and Anthropic clients. Returns the same client
|
|
22
|
+
with transparent cost tracking enabled.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
client: An OpenAI() or Anthropic() client instance.
|
|
26
|
+
budget: Optional budget alert threshold in USD.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
The same client, now tracked.
|
|
30
|
+
|
|
31
|
+
Example:
|
|
32
|
+
from openai import OpenAI
|
|
33
|
+
from spent import track
|
|
34
|
+
|
|
35
|
+
client = track(OpenAI())
|
|
36
|
+
# Use client normally -- costs are tracked automatically.
|
|
37
|
+
"""
|
|
38
|
+
from .tracker import Tracker
|
|
39
|
+
from .patches import apply_all
|
|
40
|
+
|
|
41
|
+
tracker = Tracker.get()
|
|
42
|
+
if budget is not None:
|
|
43
|
+
tracker.set_budget(budget)
|
|
44
|
+
|
|
45
|
+
apply_all()
|
|
46
|
+
return client
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def configure(*, budget: float | None = None, quiet: bool = False) -> None:
|
|
50
|
+
"""Configure the global tracker.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
budget: Budget alert threshold in USD.
|
|
54
|
+
quiet: Suppress the exit summary.
|
|
55
|
+
"""
|
|
56
|
+
from .tracker import Tracker
|
|
57
|
+
tracker = Tracker.get()
|
|
58
|
+
if budget is not None:
|
|
59
|
+
tracker.set_budget(budget)
|
|
60
|
+
tracker.quiet = quiet
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def summary() -> dict:
|
|
64
|
+
"""Get the current session cost summary as a dict."""
|
|
65
|
+
from .tracker import Tracker
|
|
66
|
+
return Tracker.get().summary()
|