@pydantic/genai-prices 0.0.20 → 0.0.21

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.
package/LICENSE ADDED
@@ -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.
package/README.md CHANGED
@@ -1,103 +1,54 @@
1
- # genai-prices package (JS/TS)
1
+ # @pydantic/genai-prices
2
2
 
3
- Library and CLI for calculating LLM API prices, supporting browser, Node.js and other environments.
3
+ JavaScript package and command-line tool for calculating LLM API prices.
4
4
 
5
- ## Features
5
+ ## Basic usage
6
6
 
7
- - **Sync API**: Fast, local price calculation using embedded data. Works in browser, Node.js, Cloudflare, Deno, etc.
8
- - **Async API**: Fetches and caches price data from GitHub, works in browser, Node.js, Cloudflare, Deno, etc.
9
- - **Environment-agnostic design**: Sync/async distinction is about API style, not environment.
10
- - **Smart provider and model matching** with flexible options.
11
- - **CLI** for quick price calculations with auto-update support.
12
- - **Browser support** with a single bundle and test page.
7
+ ### `calcPrice`
13
8
 
14
- ## API Usage
9
+ The package exports a function for price calculation that, by default, uses the bundled price data.
15
10
 
16
- The library provides separated input and output pricing, giving you detailed breakdown of costs:
17
-
18
- - `result.total_price` - Total cost for the request
19
- - `result.input_price` - Cost for input/prompt tokens
20
- - `result.output_price` - Cost for output/completion tokens
21
-
22
- ### Node.js & Browser (Library)
23
-
24
- ```js
25
- import { calcPriceSync, calcPriceAsync } from '@pydantic/genai-prices'
11
+ ```ts
12
+ import { calcPrice } from '@pydantic/genai-prices'
26
13
 
27
14
  const usage = { input_tokens: 1000, output_tokens: 100 }
28
15
 
29
- // Sync (works everywhere, including browser)
30
- const result = calcPriceSync(usage, 'gpt-3.5-turbo', { providerId: 'openai' })
16
+ const result = calcPrice(usage, 'gpt-3.5-turbo', { providerId: 'openai' })
17
+
31
18
  if (result) {
32
19
  console.log(
33
20
  `$${result.total_price} (input: $${result.input_price}, output: $${result.output_price})`,
34
21
  result.provider.name,
35
- result.model.name,
36
- )
37
- } else {
38
- console.log('No price found for this model/provider combination')
39
- }
40
-
41
- // Async (works everywhere)
42
- const asyncResult = await calcPriceAsync(usage, 'gpt-3.5-turbo', { providerId: 'openai' })
43
- if (asyncResult) {
44
- console.log(
45
- `$${asyncResult.total_price} (input: $${asyncResult.input_price}, output: $${asyncResult.output_price})`,
46
- asyncResult.provider.name,
47
- asyncResult.model.name,
22
+ result.model.name
48
23
  )
49
24
  } else {
50
25
  console.log('No price found for this model/provider combination')
51
26
  }
52
27
  ```
53
28
 
54
- ### Browser (Direct Bundle)
55
-
56
- ```js
57
- import { calcPriceSync, calcPriceAsync } from './dist/index.js'
58
- const usage = { input_tokens: 1000, output_tokens: 100 }
59
- const result = calcPriceSync(usage, 'gpt-3.5-turbo', { providerId: 'openai' })
60
- if (result) {
61
- console.log(
62
- `$${result.total_price} (input: $${result.input_price}, output: $${result.output_price})`,
63
- result.provider.name,
64
- result.model.name,
65
- )
66
- }
67
- ```
68
-
69
- ### Global CLI Installation
70
-
71
- You can install the CLI globally to use the `genai-prices` command from anywhere:
72
-
73
- ```bash
74
- npm install -g @pydantic/genai-prices
75
- ```
76
-
77
- After installing globally, you can run:
29
+ ### `updatePrices`
78
30
 
79
- ```bash
80
- genai-prices calc gpt-4 --input-tokens 1000 --output-tokens 500
81
- genai-prices list
82
- ```
31
+ You can optionally use `updatePrices` to implement logic that can periodically update the data used by `calcPrice`.
32
+ See the `src/examples/browser` directory for an example that implements a local storage-backed auto-update and `src/examples/node-script.ts` for an example of a file-based asynchronous auto-update implementation.
83
33
 
84
- ### CLI
34
+ `calcPrice` is a synchronous function that uses the currently available data - either the bundled one, or the last data fetched from the `updatePrices` setup. To force `calcPrice` to await potential in-progress data updates that can happen in `enableAutoUpdate`, await the `waitForUpdate()` return value before calling `calcPrice`
85
35
 
86
- After global installation, you can use the CLI as follows:
36
+ ```ts
37
+ import { calcPrice, updatePrices } from '@pydantic/genai-prices'
87
38
 
88
- ```bash
89
- # Basic usage
90
- genai-prices gpt-3.5-turbo --input-tokens 1000 --output-tokens 100
39
+ enableAutoUpdate(/** auto-update logic */)
91
40
 
92
- # With auto-update (fetches latest prices from GitHub)
93
- genai-prices gpt-3.5-turbo --input-tokens 1000 --output-tokens 100 --auto-update
41
+ // ...
94
42
 
95
- # Specify provider explicitly
96
- genai-prices openai:gpt-3.5-turbo --input-tokens 1000 --output-tokens 100
43
+ // this guarantees that the latest data is used
44
+ await waitForUpdate()
45
+ const result = calcPrice(usage, 'gpt-5', { providerId: 'openai' })
97
46
 
98
- # List available providers and models
99
- genai-prices list
100
- genai-prices list openai
47
+ console.log(
48
+ `$${result.total_price} (input: $${result.input_price}, output: $${result.output_price})`,
49
+ result.provider.name,
50
+ result.model.name
51
+ )
101
52
  ```
102
53
 
103
54
  ### Provider Matching
@@ -105,7 +56,7 @@ genai-prices list openai
105
56
  The library uses intelligent provider matching:
106
57
 
107
58
  1. **Explicit provider**: Use `providerId` parameter or `provider:model` format
108
- 2. **Model-based matching**: Uses provider's `model_match` logic (e.g., OpenAI matches models starting with "gpt-")
59
+ 2. **Model-based matching**: Uses the provider's `model_match` logic (e.g., OpenAI matches models starting with "gpt-")
109
60
  3. **Fallback**: Tries to match based on model name patterns
110
61
 
111
62
  **Best practices:**
@@ -116,15 +67,15 @@ The library uses intelligent provider matching:
116
67
 
117
68
  ### Error Handling
118
69
 
119
- The library returns `null` when a model or provider is not found, rather than throwing errors. This makes it easier to handle cases where pricing information might not be available:
70
+ When a model or provider is not found, the library returns `null`. This makes it easier to handle cases where pricing information might not be available.
120
71
 
121
72
  ```js
122
- import { calcPriceSync, calcPriceAsync } from '@pydantic/genai-prices'
73
+ import { calcPrice } from '@pydantic/genai-prices'
123
74
 
124
75
  const usage = { input_tokens: 1000, output_tokens: 100 }
125
76
 
126
77
  // Returns null if model/provider not found
127
- const result = calcPriceSync(usage, 'non-existent-model')
78
+ const result = calcPrice(usage, 'non-existent-model')
128
79
  if (result === null) {
129
80
  console.log('No pricing information available for this model')
130
81
  } else {
@@ -132,63 +83,14 @@ if (result === null) {
132
83
  }
133
84
 
134
85
  // Async version also returns null
135
- const asyncResult = await calcPriceAsync(usage, 'non-existent-model', { providerId: 'unknown-provider' })
86
+ const asyncResult = await calcPrice(usage, 'non-existent-model', { awaitAutoUpdate: true, providerId: 'unknown-provider' })
136
87
  if (asyncResult === null) {
137
88
  console.log('No pricing information available for this model/provider combination')
138
89
  } else {
139
- console.log(
140
- `Total Price: $${asyncResult.total_price} (input: $${asyncResult.input_price}, output: $${asyncResult.output_price})`,
141
- )
90
+ console.log(`Total Price: $${asyncResult.total_price} (input: $${asyncResult.input_price}, output: $${asyncResult.output_price})`)
142
91
  }
143
92
  ```
144
93
 
145
- **TypeScript users**: The return type is `PriceCalculation | null` (exported as `PriceCalculationResult`).
146
-
147
- ## Testing
148
-
149
- ### Node.js Test
150
-
151
- Run:
152
-
153
- ```bash
154
- node tests/test-error-handling.js
155
- ```
156
-
157
- This tests error handling, sync/async API, and providerId usage.
158
-
159
- ### Browser Test
160
-
161
- 1. Build the package: `npm run build`
162
- 2. Serve the directory: `npx serve .` or `python3 -m http.server`
163
- 3. Open `tests/test-browser.html` in your browser.
164
- 4. Enter a provider (e.g., `openai`) and model (e.g., `gpt-3.5-turbo`) and run the test.
165
-
166
- ## Architecture
167
-
168
- ### Folder Structure
169
-
170
- ```
171
- src/
172
- ├── sync/
173
- │ └── calcPriceSync.ts # Sync API implementation
174
- ├── async/
175
- │ └── calcPriceAsync.ts # Async API implementation
176
- ├── dataLoader.ts # Data loader (sync + async)
177
- ├── index.ts # Entry point (exports both sync + async)
178
- ├── cli.ts # CLI tool
179
- ├── types.ts # Shared types (snake_case, matches JSON)
180
- ├── matcher.ts # Shared matching logic
181
- ├── priceCalc.ts # Shared price calculation
182
- └── __tests__/ # Tests
183
- ```
184
-
185
- ### Design Principles
186
-
187
- - **Environment-agnostic APIs**: Sync/async is about API style, not environment
188
- - **Single data loader**: Handles all environments with embedded data for sync and remote fetch for async
189
- - **Cross-environment compatibility**: Both sync and async APIs can be used in Node.js, browser, Cloudflare, etc.
190
- - **No mapping needed**: All types and data use snake_case, matching the JSON schema
191
-
192
94
  ## Troubleshooting
193
95
 
194
96
  ### Common Issues
@@ -198,26 +100,36 @@ src/
198
100
  - Try using `provider:model` format in CLI
199
101
  - Use `--auto-update` flag to fetch latest data
200
102
  - Check that the model name is correct and supported by the provider
201
- - **Build errors**: Ensure you have run the build and that your data is up to date.
202
103
 
203
- ### Provider Matching Examples
104
+ ## CLI
105
+
106
+ The easiest way to run the latest version of the package as a CLI tool is through npx:
107
+
108
+ ```bash
109
+ npx @pydantic/genai-prices@latest
110
+ ```
111
+
112
+ For example:
113
+
114
+ ```bash
115
+ npx @pydantic/genai-prices@latest calc gpt-4 --input-tokens 1000 --output-tokens 500
116
+ npx @pydantic/genai-prices@latest list
117
+ ```
118
+
119
+ You can also install it globally and then use the `genai-prices` command:
204
120
 
205
121
  ```bash
206
- # These should work with auto-update
207
- genai-prices gpt-3.5-turbo --auto-update
208
- genai-prices claude-3-5-sonnet --auto-update
209
- genai-prices gemini-1.5-pro --auto-update
210
-
211
- # Explicit provider specification
212
- genai-prices openai:gpt-3.5-turbo
213
- genai-prices anthropic:claude-3-5-sonnet
214
- genai-prices google:gemini-1.5-pro
122
+ npm i -g @pydantic/genai-prices
215
123
  ```
216
124
 
217
- ## Maintainers
125
+ ```bash
126
+ # Basic usage
127
+ genai-prices gpt-5 --input-tokens 1000 --output-tokens 100
128
+
129
+ # Specify provider explicitly
130
+ genai-prices openai:gpt-5 --input-tokens 1000 --output-tokens 100
218
131
 
219
- - When adding new features, keep sync and async logic in separate files
220
- - Only import Node.js built-ins in Node-only files if absolutely necessary
221
- - Use the main entry for all environments
222
- - All types and data should use snake_case to match the JSON schema
223
- - Provider matching logic is in `matcher.ts` and should be environment-agnostic
132
+ # List available providers and models
133
+ genai-prices list
134
+ genai-prices list openai
135
+ ```