voice-prices 0.0.1__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.
- voice_prices-0.0.1/LICENSE +21 -0
- voice_prices-0.0.1/PKG-INFO +218 -0
- voice_prices-0.0.1/README.md +180 -0
- voice_prices-0.0.1/pyproject.toml +56 -0
- voice_prices-0.0.1/voice_prices/__init__.py +94 -0
- voice_prices-0.0.1/voice_prices/__main__.py +6 -0
- voice_prices-0.0.1/voice_prices/_cli.py +735 -0
- voice_prices-0.0.1/voice_prices/data.py +10522 -0
- voice_prices-0.0.1/voice_prices/data_snapshot.py +162 -0
- voice_prices-0.0.1/voice_prices/py.typed +0 -0
- voice_prices-0.0.1/voice_prices/types.py +1087 -0
- voice_prices-0.0.1/voice_prices/update_prices.py +166 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) Pydantic Services Inc. 2025 to present
|
|
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.
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: voice-prices
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Calculate prices for calling LLM, STT and TTS inference APIs. Fork of pydantic/genai-prices with voice-modality support.
|
|
5
|
+
Author: Mahimai Raja J
|
|
6
|
+
Author-email: Mahimai Raja J <mahimairaja3@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Programming Language :: Python
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: Intended Audience :: Information Technology
|
|
19
|
+
Classifier: Intended Audience :: System Administrators
|
|
20
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
21
|
+
Classifier: Operating System :: Unix
|
|
22
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
23
|
+
Classifier: Environment :: Console
|
|
24
|
+
Classifier: Environment :: MacOS X
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
|
+
Classifier: Topic :: Internet
|
|
27
|
+
Requires-Dist: httpx2>=2.0
|
|
28
|
+
Requires-Dist: pydantic>=2.10
|
|
29
|
+
Requires-Dist: pydantic-settings>=2.11 ; extra == 'cli'
|
|
30
|
+
Requires-Dist: rich>=14.3.2 ; extra == 'cli'
|
|
31
|
+
Requires-Dist: rich-argparse>=1.7.2 ; extra == 'cli'
|
|
32
|
+
Requires-Python: >=3.10
|
|
33
|
+
Project-URL: Homepage, https://github.com/mahimailabs/voice-prices
|
|
34
|
+
Project-URL: Source, https://github.com/mahimailabs/voice-prices
|
|
35
|
+
Project-URL: Changelog, https://github.com/mahimailabs/voice-prices/releases
|
|
36
|
+
Provides-Extra: cli
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
<div align="center">
|
|
40
|
+
<h1>voice-prices</h1>
|
|
41
|
+
</div>
|
|
42
|
+
<div align="center">
|
|
43
|
+
<a href="https://github.com/mahimailabs/voice-prices/actions/workflows/ci.yml?query=branch%3Amain"><img src="https://github.com/mahimailabs/voice-prices/actions/workflows/ci.yml/badge.svg?event=push" alt="CI"></a>
|
|
44
|
+
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/mahimailabs/voice-prices"><img src="https://coverage-badge.samuelcolvin.workers.dev/mahimailabs/voice-prices.svg" alt="Coverage"></a>
|
|
45
|
+
<a href="https://pypi.python.org/pypi/voice-prices"><img src="https://img.shields.io/pypi/v/voice-prices.svg" alt="PyPI"></a>
|
|
46
|
+
<a href="https://github.com/mahimailabs/voice-prices"><img src="https://img.shields.io/pypi/pyversions/voice-prices.svg" alt="versions"></a>
|
|
47
|
+
<a href="https://github.com/mahimailabs/voice-prices/blob/main/LICENSE"><img src="https://img.shields.io/github/license/mahimailabs/voice-prices.svg" alt="license"></a>
|
|
48
|
+
<a href="https://logfire.pydantic.dev/docs/join-slack/"><img src="https://img.shields.io/badge/Slack-Join%20Slack-4A154B?logo=slack" alt="Join Slack" /></a>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<br/>
|
|
52
|
+
<div align="center">
|
|
53
|
+
Python package for <a href="https://github.com/mahimailabs/voice-prices">github.com/mahimailabs/voice-prices</a>.
|
|
54
|
+
</div>
|
|
55
|
+
<br/>
|
|
56
|
+
|
|
57
|
+
## Installation
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
uv add voice-prices
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
(or `pip install voice-prices` if you're old school)
|
|
64
|
+
|
|
65
|
+
To use the CLI with Rich output/help, install the optional CLI dependencies:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
uv add "voice-prices[cli]"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
(or `pip install "voice-prices[cli]"`)
|
|
72
|
+
|
|
73
|
+
## Warning: these prices will not be 100% accurate
|
|
74
|
+
|
|
75
|
+
See [the project README](https://github.com/mahimailabs/voice-prices?tab=readme-ov-file#warning) for more information.
|
|
76
|
+
|
|
77
|
+
## Usage
|
|
78
|
+
|
|
79
|
+
### `calc_price`
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from voice_prices import Usage, calc_price
|
|
83
|
+
|
|
84
|
+
price_data = calc_price(
|
|
85
|
+
Usage(input_tokens=1000, output_tokens=100),
|
|
86
|
+
model_ref='gpt-4o',
|
|
87
|
+
provider_id='openai',
|
|
88
|
+
)
|
|
89
|
+
print(f"Total Price: ${price_data.total_price} (input: ${price_data.input_price}, output: ${price_data.output_price})")
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### `extract_usage`
|
|
93
|
+
|
|
94
|
+
`extract_usage` can be used to extract usage data and the `model_ref` from response data,
|
|
95
|
+
which in turn can be used to calculate prices:
|
|
96
|
+
|
|
97
|
+
```py
|
|
98
|
+
from voice_prices import extract_usage
|
|
99
|
+
|
|
100
|
+
response_data = {
|
|
101
|
+
'model': 'claude-sonnet-4-20250514',
|
|
102
|
+
'usage': {
|
|
103
|
+
'input_tokens': 504,
|
|
104
|
+
'cache_creation_input_tokens': 123,
|
|
105
|
+
'cache_read_input_tokens': 0,
|
|
106
|
+
'output_tokens': 97,
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
extracted_usage = extract_usage(response_data, provider_id='anthropic')
|
|
110
|
+
price = extracted_usage.calc_price()
|
|
111
|
+
print(price.total_price)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
or with OpenAI where there are two API flavors:
|
|
115
|
+
|
|
116
|
+
```py
|
|
117
|
+
from voice_prices import extract_usage
|
|
118
|
+
|
|
119
|
+
response_data = {
|
|
120
|
+
'model': 'gpt-5',
|
|
121
|
+
'usage': {'prompt_tokens': 100, 'completion_tokens': 200},
|
|
122
|
+
}
|
|
123
|
+
extracted_usage = extract_usage(response_data, provider_id='openai', api_flavor='chat')
|
|
124
|
+
price = extracted_usage.calc_price()
|
|
125
|
+
print(price.total_price)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### `UpdatePrices`
|
|
129
|
+
|
|
130
|
+
`UpdatePrices` can be used to periodically update the price data by downloading it from GitHub
|
|
131
|
+
|
|
132
|
+
Please note:
|
|
133
|
+
|
|
134
|
+
- this functionality is explicitly opt-in
|
|
135
|
+
- we download data directly from GitHub (`https://raw.githubusercontent.com/mahimailabs/voice-prices/refs/heads/main/prices/data.json`) so we don't and can't monitor requests or gather telemetry
|
|
136
|
+
|
|
137
|
+
At the time of writing, the `data.json` file
|
|
138
|
+
downloaded by `UpdatePrices` is around 26KB when compressed, so is generally very quick to download.
|
|
139
|
+
|
|
140
|
+
By default `UpdatePrices` downloads price data immediately after it's started in the background, then every hour after that.
|
|
141
|
+
|
|
142
|
+
Usage with `UpdatePrices` as as context manager:
|
|
143
|
+
|
|
144
|
+
```py
|
|
145
|
+
from voice_prices import UpdatePrices, Usage, calc_price
|
|
146
|
+
|
|
147
|
+
with UpdatePrices() as update_prices:
|
|
148
|
+
update_prices.wait() # optionally wait for prices to have updated
|
|
149
|
+
p = calc_price(Usage(input_tokens=123, output_tokens=456), 'gpt-5')
|
|
150
|
+
print(p)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Usage with `UpdatePrices` as a simple class:
|
|
154
|
+
|
|
155
|
+
```py
|
|
156
|
+
from voice_prices import UpdatePrices, Usage, calc_price
|
|
157
|
+
|
|
158
|
+
update_prices = UpdatePrices()
|
|
159
|
+
update_prices.start(wait=True) # start updating prices, optionally wait for prices to have updated
|
|
160
|
+
p = calc_price(Usage(input_tokens=123, output_tokens=456), 'gpt-5')
|
|
161
|
+
print(p)
|
|
162
|
+
update_prices.stop() # stop updating prices
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Only one `UpdatePrices` instance can be running at a time.
|
|
166
|
+
|
|
167
|
+
If you'd like to wait for prices to be updated without access to the `UpdatePrices` instance, you can use the `wait_prices_updated_sync` function:
|
|
168
|
+
|
|
169
|
+
```py
|
|
170
|
+
from voice_prices import wait_prices_updated_sync
|
|
171
|
+
|
|
172
|
+
wait_prices_updated_sync()
|
|
173
|
+
...
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Or it's async variant, `wait_prices_updated_async`.
|
|
177
|
+
|
|
178
|
+
### CLI Usage
|
|
179
|
+
|
|
180
|
+
Run the CLI with:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
uvx voice-prices --help
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Or, if installed locally, make sure CLI extras are present:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
pip install "voice-prices[cli]"
|
|
190
|
+
voice-prices --help
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
If local CLI extras are not installed, the command will print an install hint for `voice-prices[cli]`.
|
|
194
|
+
|
|
195
|
+
To list providers and models, run:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
uvx voice-prices list
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
To calculate the price of models, run for example:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
uvx voice-prices calc --input-tokens 100000 --output-tokens 3000 o1 o3 claude-opus-4
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
CLI output notes:
|
|
208
|
+
|
|
209
|
+
- Rich output is the default.
|
|
210
|
+
- Use `--plain` (`-p`) for legacy/plain output.
|
|
211
|
+
- Use `--no-color` to keep rich formatting without colors.
|
|
212
|
+
- Use `-T` / `--table` for wide table output.
|
|
213
|
+
|
|
214
|
+
## Further Documentation
|
|
215
|
+
|
|
216
|
+
We do not yet build API documentation for this package, but the source code is relatively simple and well documented.
|
|
217
|
+
|
|
218
|
+
If you need further information on the API, we encourage you to read the source code.
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1>voice-prices</h1>
|
|
3
|
+
</div>
|
|
4
|
+
<div align="center">
|
|
5
|
+
<a href="https://github.com/mahimailabs/voice-prices/actions/workflows/ci.yml?query=branch%3Amain"><img src="https://github.com/mahimailabs/voice-prices/actions/workflows/ci.yml/badge.svg?event=push" alt="CI"></a>
|
|
6
|
+
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/mahimailabs/voice-prices"><img src="https://coverage-badge.samuelcolvin.workers.dev/mahimailabs/voice-prices.svg" alt="Coverage"></a>
|
|
7
|
+
<a href="https://pypi.python.org/pypi/voice-prices"><img src="https://img.shields.io/pypi/v/voice-prices.svg" alt="PyPI"></a>
|
|
8
|
+
<a href="https://github.com/mahimailabs/voice-prices"><img src="https://img.shields.io/pypi/pyversions/voice-prices.svg" alt="versions"></a>
|
|
9
|
+
<a href="https://github.com/mahimailabs/voice-prices/blob/main/LICENSE"><img src="https://img.shields.io/github/license/mahimailabs/voice-prices.svg" alt="license"></a>
|
|
10
|
+
<a href="https://logfire.pydantic.dev/docs/join-slack/"><img src="https://img.shields.io/badge/Slack-Join%20Slack-4A154B?logo=slack" alt="Join Slack" /></a>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
<div align="center">
|
|
15
|
+
Python package for <a href="https://github.com/mahimailabs/voice-prices">github.com/mahimailabs/voice-prices</a>.
|
|
16
|
+
</div>
|
|
17
|
+
<br/>
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
uv add voice-prices
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
(or `pip install voice-prices` if you're old school)
|
|
26
|
+
|
|
27
|
+
To use the CLI with Rich output/help, install the optional CLI dependencies:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
uv add "voice-prices[cli]"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
(or `pip install "voice-prices[cli]"`)
|
|
34
|
+
|
|
35
|
+
## Warning: these prices will not be 100% accurate
|
|
36
|
+
|
|
37
|
+
See [the project README](https://github.com/mahimailabs/voice-prices?tab=readme-ov-file#warning) for more information.
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
### `calc_price`
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from voice_prices import Usage, calc_price
|
|
45
|
+
|
|
46
|
+
price_data = calc_price(
|
|
47
|
+
Usage(input_tokens=1000, output_tokens=100),
|
|
48
|
+
model_ref='gpt-4o',
|
|
49
|
+
provider_id='openai',
|
|
50
|
+
)
|
|
51
|
+
print(f"Total Price: ${price_data.total_price} (input: ${price_data.input_price}, output: ${price_data.output_price})")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### `extract_usage`
|
|
55
|
+
|
|
56
|
+
`extract_usage` can be used to extract usage data and the `model_ref` from response data,
|
|
57
|
+
which in turn can be used to calculate prices:
|
|
58
|
+
|
|
59
|
+
```py
|
|
60
|
+
from voice_prices import extract_usage
|
|
61
|
+
|
|
62
|
+
response_data = {
|
|
63
|
+
'model': 'claude-sonnet-4-20250514',
|
|
64
|
+
'usage': {
|
|
65
|
+
'input_tokens': 504,
|
|
66
|
+
'cache_creation_input_tokens': 123,
|
|
67
|
+
'cache_read_input_tokens': 0,
|
|
68
|
+
'output_tokens': 97,
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
extracted_usage = extract_usage(response_data, provider_id='anthropic')
|
|
72
|
+
price = extracted_usage.calc_price()
|
|
73
|
+
print(price.total_price)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
or with OpenAI where there are two API flavors:
|
|
77
|
+
|
|
78
|
+
```py
|
|
79
|
+
from voice_prices import extract_usage
|
|
80
|
+
|
|
81
|
+
response_data = {
|
|
82
|
+
'model': 'gpt-5',
|
|
83
|
+
'usage': {'prompt_tokens': 100, 'completion_tokens': 200},
|
|
84
|
+
}
|
|
85
|
+
extracted_usage = extract_usage(response_data, provider_id='openai', api_flavor='chat')
|
|
86
|
+
price = extracted_usage.calc_price()
|
|
87
|
+
print(price.total_price)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### `UpdatePrices`
|
|
91
|
+
|
|
92
|
+
`UpdatePrices` can be used to periodically update the price data by downloading it from GitHub
|
|
93
|
+
|
|
94
|
+
Please note:
|
|
95
|
+
|
|
96
|
+
- this functionality is explicitly opt-in
|
|
97
|
+
- we download data directly from GitHub (`https://raw.githubusercontent.com/mahimailabs/voice-prices/refs/heads/main/prices/data.json`) so we don't and can't monitor requests or gather telemetry
|
|
98
|
+
|
|
99
|
+
At the time of writing, the `data.json` file
|
|
100
|
+
downloaded by `UpdatePrices` is around 26KB when compressed, so is generally very quick to download.
|
|
101
|
+
|
|
102
|
+
By default `UpdatePrices` downloads price data immediately after it's started in the background, then every hour after that.
|
|
103
|
+
|
|
104
|
+
Usage with `UpdatePrices` as as context manager:
|
|
105
|
+
|
|
106
|
+
```py
|
|
107
|
+
from voice_prices import UpdatePrices, Usage, calc_price
|
|
108
|
+
|
|
109
|
+
with UpdatePrices() as update_prices:
|
|
110
|
+
update_prices.wait() # optionally wait for prices to have updated
|
|
111
|
+
p = calc_price(Usage(input_tokens=123, output_tokens=456), 'gpt-5')
|
|
112
|
+
print(p)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Usage with `UpdatePrices` as a simple class:
|
|
116
|
+
|
|
117
|
+
```py
|
|
118
|
+
from voice_prices import UpdatePrices, Usage, calc_price
|
|
119
|
+
|
|
120
|
+
update_prices = UpdatePrices()
|
|
121
|
+
update_prices.start(wait=True) # start updating prices, optionally wait for prices to have updated
|
|
122
|
+
p = calc_price(Usage(input_tokens=123, output_tokens=456), 'gpt-5')
|
|
123
|
+
print(p)
|
|
124
|
+
update_prices.stop() # stop updating prices
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Only one `UpdatePrices` instance can be running at a time.
|
|
128
|
+
|
|
129
|
+
If you'd like to wait for prices to be updated without access to the `UpdatePrices` instance, you can use the `wait_prices_updated_sync` function:
|
|
130
|
+
|
|
131
|
+
```py
|
|
132
|
+
from voice_prices import wait_prices_updated_sync
|
|
133
|
+
|
|
134
|
+
wait_prices_updated_sync()
|
|
135
|
+
...
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Or it's async variant, `wait_prices_updated_async`.
|
|
139
|
+
|
|
140
|
+
### CLI Usage
|
|
141
|
+
|
|
142
|
+
Run the CLI with:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
uvx voice-prices --help
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Or, if installed locally, make sure CLI extras are present:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
pip install "voice-prices[cli]"
|
|
152
|
+
voice-prices --help
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
If local CLI extras are not installed, the command will print an install hint for `voice-prices[cli]`.
|
|
156
|
+
|
|
157
|
+
To list providers and models, run:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
uvx voice-prices list
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
To calculate the price of models, run for example:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
uvx voice-prices calc --input-tokens 100000 --output-tokens 3000 o1 o3 claude-opus-4
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
CLI output notes:
|
|
170
|
+
|
|
171
|
+
- Rich output is the default.
|
|
172
|
+
- Use `--plain` (`-p`) for legacy/plain output.
|
|
173
|
+
- Use `--no-color` to keep rich formatting without colors.
|
|
174
|
+
- Use `-T` / `--table` for wide table output.
|
|
175
|
+
|
|
176
|
+
## Further Documentation
|
|
177
|
+
|
|
178
|
+
We do not yet build API documentation for this package, but the source code is relatively simple and well documented.
|
|
179
|
+
|
|
180
|
+
If you need further information on the API, we encourage you to read the source code.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["uv_build>=0.8.10"]
|
|
3
|
+
build-backend = "uv_build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "voice-prices"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
description = "Calculate prices for calling LLM, STT and TTS inference APIs. Fork of pydantic/genai-prices with voice-modality support."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [{ name = "Mahimai Raja J", email = "mahimairaja3@gmail.com" }]
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
license = "MIT"
|
|
13
|
+
license-files = ["LICENSE"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Programming Language :: Python",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Intended Audience :: Developers",
|
|
24
|
+
"Intended Audience :: Information Technology",
|
|
25
|
+
"Intended Audience :: System Administrators",
|
|
26
|
+
"License :: OSI Approved :: MIT License",
|
|
27
|
+
"Operating System :: Unix",
|
|
28
|
+
"Operating System :: POSIX :: Linux",
|
|
29
|
+
"Environment :: Console",
|
|
30
|
+
"Environment :: MacOS X",
|
|
31
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
32
|
+
"Topic :: Internet",
|
|
33
|
+
]
|
|
34
|
+
dependencies = [
|
|
35
|
+
"httpx2>=2.0",
|
|
36
|
+
"pydantic>=2.10",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[project.optional-dependencies]
|
|
40
|
+
cli = [
|
|
41
|
+
"pydantic-settings>=2.11",
|
|
42
|
+
"rich>=14.3.2",
|
|
43
|
+
"rich-argparse>=1.7.2",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[project.scripts]
|
|
47
|
+
voice-prices = "voice_prices._cli:cli"
|
|
48
|
+
|
|
49
|
+
[project.urls]
|
|
50
|
+
Homepage = "https://github.com/mahimailabs/voice-prices"
|
|
51
|
+
Source = "https://github.com/mahimailabs/voice-prices"
|
|
52
|
+
Changelog = "https://github.com/mahimailabs/voice-prices/releases"
|
|
53
|
+
|
|
54
|
+
[tool.uv.build-backend]
|
|
55
|
+
module-name = "voice_prices"
|
|
56
|
+
module-root = ""
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from __future__ import annotations as _annotations
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from importlib.metadata import version as _metadata_version
|
|
5
|
+
from typing import Any, overload
|
|
6
|
+
|
|
7
|
+
from . import data_snapshot, types
|
|
8
|
+
from .types import Usage
|
|
9
|
+
from .update_prices import UpdatePrices, wait_prices_updated_async, wait_prices_updated_sync
|
|
10
|
+
|
|
11
|
+
__version__ = _metadata_version('voice_prices')
|
|
12
|
+
__all__ = 'Usage', 'calc_price', 'UpdatePrices', 'wait_prices_updated_sync', 'wait_prices_updated_async', '__version__'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@overload
|
|
16
|
+
def calc_price(
|
|
17
|
+
usage: types.AbstractUsage,
|
|
18
|
+
model_ref: str,
|
|
19
|
+
*,
|
|
20
|
+
provider_id: types.ProviderID | str | None = None,
|
|
21
|
+
genai_request_timestamp: datetime | None = None,
|
|
22
|
+
) -> types.PriceCalculation: ...
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@overload
|
|
26
|
+
def calc_price(
|
|
27
|
+
usage: types.AbstractUsage,
|
|
28
|
+
model_ref: str,
|
|
29
|
+
*,
|
|
30
|
+
provider_api_url: str | None = None,
|
|
31
|
+
genai_request_timestamp: datetime | None = None,
|
|
32
|
+
) -> types.PriceCalculation: ...
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def calc_price(
|
|
36
|
+
usage: types.AbstractUsage,
|
|
37
|
+
model_ref: str,
|
|
38
|
+
*,
|
|
39
|
+
provider_id: types.ProviderID | str | None = None,
|
|
40
|
+
provider_api_url: str | None = None,
|
|
41
|
+
genai_request_timestamp: datetime | None = None,
|
|
42
|
+
) -> types.PriceCalculation:
|
|
43
|
+
"""Calculate the price of an LLM API call.
|
|
44
|
+
|
|
45
|
+
Either `provider_id` or `provider_api_url` should be provided, but not both. If neither are provided,
|
|
46
|
+
we try to find the most suitable provider based on the model reference.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
usage: The usage to calculate the price for.
|
|
50
|
+
model_ref: A reference to the model used, this method will try to match this to a specific model.
|
|
51
|
+
provider_id: The ID of the provider to calculate the price for.
|
|
52
|
+
provider_api_url: The API URL of the provider to calculate the price for.
|
|
53
|
+
genai_request_timestamp: The timestamp of the request to the GenAI service, use `None` to use the current time.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
The price calculation details.
|
|
57
|
+
"""
|
|
58
|
+
return data_snapshot.get_snapshot().calc(usage, model_ref, provider_id, provider_api_url, genai_request_timestamp)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@overload
|
|
62
|
+
def extract_usage(
|
|
63
|
+
response_data: Any, *, provider_id: types.ProviderID | str, api_flavor: str = 'default'
|
|
64
|
+
) -> types.ExtractedUsage: ...
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@overload
|
|
68
|
+
def extract_usage(
|
|
69
|
+
response_data: Any, *, provider_api_url: str, api_flavor: str = 'default'
|
|
70
|
+
) -> types.ExtractedUsage: ...
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def extract_usage(
|
|
74
|
+
response_data: Any,
|
|
75
|
+
*,
|
|
76
|
+
provider_id: types.ProviderID | str | None = None,
|
|
77
|
+
provider_api_url: str | None = None,
|
|
78
|
+
api_flavor: str = 'default',
|
|
79
|
+
) -> types.ExtractedUsage:
|
|
80
|
+
"""Extract usage information from a response.
|
|
81
|
+
|
|
82
|
+
One of `provider_id` or `provider_api_url` is required.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
response_data: The response data to extract usage information from.
|
|
86
|
+
provider: The provider to extract usage information for.
|
|
87
|
+
provider_id: The ID of the provider to extract usage information for.
|
|
88
|
+
provider_api_url: The API URL of the provider to extract usage information for.
|
|
89
|
+
api_flavor: The API flavor of the provider to extract usage information for.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
The extracted usage information, model ref and provider used.
|
|
93
|
+
"""
|
|
94
|
+
return data_snapshot.get_snapshot().extract_usage(response_data, provider_id, provider_api_url, api_flavor)
|