@pydantic/genai-prices 0.0.7 → 0.0.8

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/README.md CHANGED
@@ -13,6 +13,12 @@ Library and CLI for calculating LLM API prices, supporting browser, Node.js and
13
13
 
14
14
  ## API Usage
15
15
 
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
+
16
22
  ### Node.js & Browser (Library)
17
23
 
18
24
  ```js
@@ -23,7 +29,11 @@ const usage = { input_tokens: 1000, output_tokens: 100 }
23
29
  // Sync (works everywhere, including browser)
24
30
  const result = calcPriceSync(usage, 'gpt-3.5-turbo', { providerId: 'openai' })
25
31
  if (result) {
26
- console.log(result.price, result.provider.name, result.model.name)
32
+ console.log(
33
+ `$${result.total_price} (input: $${result.input_price}, output: $${result.output_price})`,
34
+ result.provider.name,
35
+ result.model.name,
36
+ )
27
37
  } else {
28
38
  console.log('No price found for this model/provider combination')
29
39
  }
@@ -31,7 +41,11 @@ if (result) {
31
41
  // Async (works everywhere)
32
42
  const asyncResult = await calcPriceAsync(usage, 'gpt-3.5-turbo', { providerId: 'openai' })
33
43
  if (asyncResult) {
34
- console.log(asyncResult.price, asyncResult.provider.name, asyncResult.model.name)
44
+ console.log(
45
+ `$${asyncResult.total_price} (input: $${asyncResult.input_price}, output: $${asyncResult.output_price})`,
46
+ asyncResult.provider.name,
47
+ asyncResult.model.name,
48
+ )
35
49
  } else {
36
50
  console.log('No price found for this model/provider combination')
37
51
  }
@@ -44,7 +58,11 @@ import { calcPriceSync, calcPriceAsync } from './dist/index.js'
44
58
  const usage = { input_tokens: 1000, output_tokens: 100 }
45
59
  const result = calcPriceSync(usage, 'gpt-3.5-turbo', { providerId: 'openai' })
46
60
  if (result) {
47
- console.log(result.price, result.provider.name, result.model.name)
61
+ console.log(
62
+ `$${result.total_price} (input: $${result.input_price}, output: $${result.output_price})`,
63
+ result.provider.name,
64
+ result.model.name,
65
+ )
48
66
  }
49
67
  ```
50
68
 
@@ -110,7 +128,7 @@ const result = calcPriceSync(usage, 'non-existent-model')
110
128
  if (result === null) {
111
129
  console.log('No pricing information available for this model')
112
130
  } else {
113
- console.log(`Price: $${result.price}`)
131
+ console.log(`Total Price: $${result.total_price} (input: $${result.input_price}, output: $${result.output_price})`)
114
132
  }
115
133
 
116
134
  // Async version also returns null
@@ -118,7 +136,9 @@ const asyncResult = await calcPriceAsync(usage, 'non-existent-model', { provider
118
136
  if (asyncResult === null) {
119
137
  console.log('No pricing information available for this model/provider combination')
120
138
  } else {
121
- console.log(`Price: $${asyncResult.price}`)
139
+ console.log(
140
+ `Total Price: $${asyncResult.total_price} (input: $${asyncResult.input_price}, output: $${asyncResult.output_price})`,
141
+ )
122
142
  }
123
143
  ```
124
144
 
@@ -0,0 +1 @@
1
+ export {};
@@ -11,9 +11,11 @@ export async function calcPriceAsync(usage, modelRef, options = {}) {
11
11
  return null;
12
12
  const timestamp = options.timestamp || new Date();
13
13
  const model_price = getActiveModelPrice(model, timestamp);
14
- const price = calcModelPrice(usage, model_price);
14
+ const priceResult = calcModelPrice(usage, model_price);
15
15
  return {
16
- price,
16
+ input_price: priceResult.input_price,
17
+ output_price: priceResult.output_price,
18
+ total_price: priceResult.total_price,
17
19
  provider,
18
20
  model,
19
21
  model_price,
package/dist/cli.js CHANGED
@@ -126,7 +126,9 @@ async function main() {
126
126
  ['Model', result.model.name || result.model.id],
127
127
  ['Model Prices', JSON.stringify(result.model_price)],
128
128
  ['Context Window', w !== undefined ? w.toLocaleString() : undefined],
129
- ['Price', `$${result.price}`],
129
+ ['Total Price', `$${result.total_price}`],
130
+ ['Input Price', `$${result.input_price}`],
131
+ ['Output Price', `$${result.output_price}`],
130
132
  ];
131
133
  for (const [key, value] of output) {
132
134
  if (value !== undefined) {
package/dist/index.d.ts CHANGED
@@ -2,4 +2,4 @@ export { calcPriceSync } from './sync/calcPriceSync.js';
2
2
  export { calcPriceAsync } from './async/calcPriceAsync.js';
3
3
  export { getProvidersSync, getProvidersAsync, enableAutoUpdate, isLocalDataOutdated, prefetchAsync, getEnvironmentInfo, } from './dataLoader.js';
4
4
  export { matchProvider, matchModel } from './matcher.js';
5
- export type { Usage, PriceCalculation, PriceCalculationResult, Provider, ModelInfo } from './types.js';
5
+ export type { Usage, PriceCalculation, PriceCalculationResult, Provider, ModelInfo, CalcPrice } from './types.js';
@@ -10630,18 +10630,26 @@
10630
10630
  return calcTieredPrice(price, tokens);
10631
10631
  }
10632
10632
  function calcPrice(usage, modelPrice) {
10633
- let price = 0;
10634
- price += calcMtokPrice(modelPrice.input_mtok, usage.input_tokens);
10635
- price += calcMtokPrice(modelPrice.cache_write_mtok, usage.cache_write_tokens);
10636
- price += calcMtokPrice(modelPrice.cache_read_mtok, usage.cache_read_tokens);
10637
- price += calcMtokPrice(modelPrice.output_mtok, usage.output_tokens);
10638
- price += calcMtokPrice(modelPrice.input_audio_mtok, usage.input_audio_tokens);
10639
- price += calcMtokPrice(modelPrice.cache_audio_read_mtok, usage.cache_audio_read_tokens);
10640
- price += calcMtokPrice(modelPrice.output_audio_mtok, usage.output_audio_tokens);
10633
+ let input_price = 0;
10634
+ let output_price = 0;
10635
+ input_price += calcMtokPrice(modelPrice.input_mtok, usage.input_tokens);
10636
+ input_price += calcMtokPrice(modelPrice.cache_write_mtok, usage.cache_write_tokens);
10637
+ input_price += calcMtokPrice(modelPrice.cache_read_mtok, usage.cache_read_tokens);
10638
+ input_price += calcMtokPrice(modelPrice.input_audio_mtok, usage.input_audio_tokens);
10639
+ input_price += calcMtokPrice(
10640
+ modelPrice.cache_audio_read_mtok,
10641
+ usage.cache_audio_read_tokens);
10642
+ output_price += calcMtokPrice(modelPrice.output_mtok, usage.output_tokens);
10643
+ output_price += calcMtokPrice(modelPrice.output_audio_mtok, usage.output_audio_tokens);
10641
10644
  if (modelPrice.requests_kcount !== void 0) {
10642
- price += modelPrice.requests_kcount * ((usage.requests ?? 1) / 1e3);
10645
+ input_price += modelPrice.requests_kcount / 1e3;
10643
10646
  }
10644
- return price;
10647
+ const total_price = input_price + output_price;
10648
+ return {
10649
+ input_price,
10650
+ output_price,
10651
+ total_price
10652
+ };
10645
10653
  }
10646
10654
  function getActiveModelPrice(model, timestamp) {
10647
10655
  if (!Array.isArray(model.prices)) {
@@ -10655,9 +10663,17 @@
10655
10663
  return cond.prices;
10656
10664
  }
10657
10665
  } else if (cond.constraint.type === "time_of_date") {
10658
- const t = timestamp.toTimeString().slice(0, 8);
10659
- if (t >= cond.constraint.start_time && t < cond.constraint.end_time) {
10660
- return cond.prices;
10666
+ const t = timestamp.toISOString().slice(11, 19);
10667
+ const startTime = cond.constraint.start_time;
10668
+ const endTime = cond.constraint.end_time;
10669
+ if (endTime < startTime) {
10670
+ if (t >= startTime || t < endTime) {
10671
+ return cond.prices;
10672
+ }
10673
+ } else {
10674
+ if (t >= startTime && t < endTime) {
10675
+ return cond.prices;
10676
+ }
10661
10677
  }
10662
10678
  }
10663
10679
  }
@@ -10672,9 +10688,11 @@
10672
10688
  if (!model) return null;
10673
10689
  const timestamp = options.timestamp || /* @__PURE__ */ new Date();
10674
10690
  const model_price = getActiveModelPrice(model, timestamp);
10675
- const price = calcPrice(usage, model_price);
10691
+ const priceResult = calcPrice(usage, model_price);
10676
10692
  return {
10677
- price,
10693
+ input_price: priceResult.input_price,
10694
+ output_price: priceResult.output_price,
10695
+ total_price: priceResult.total_price,
10678
10696
  provider,
10679
10697
  model,
10680
10698
  model_price,
@@ -10690,9 +10708,11 @@
10690
10708
  if (!model) return null;
10691
10709
  const timestamp = options.timestamp || /* @__PURE__ */ new Date();
10692
10710
  const model_price = getActiveModelPrice(model, timestamp);
10693
- const price = calcPrice(usage, model_price);
10711
+ const priceResult = calcPrice(usage, model_price);
10694
10712
  return {
10695
- price,
10713
+ input_price: priceResult.input_price,
10714
+ output_price: priceResult.output_price,
10715
+ total_price: priceResult.total_price,
10696
10716
  provider,
10697
10717
  model,
10698
10718
  model_price,
@@ -1,3 +1,3 @@
1
- import { Usage, ModelPrice, ModelInfo } from './types.js';
2
- export declare function calcPrice(usage: Usage, modelPrice: ModelPrice): number;
1
+ import { Usage, ModelPrice, ModelInfo, CalcPrice } from './types.js';
2
+ export declare function calcPrice(usage: Usage, modelPrice: ModelPrice): CalcPrice;
3
3
  export declare function getActiveModelPrice(model: ModelInfo, timestamp: Date): ModelPrice;
package/dist/priceCalc.js CHANGED
@@ -29,18 +29,27 @@ function calcMtokPrice(price, tokens, _field) {
29
29
  return calcTieredPrice(price, tokens);
30
30
  }
31
31
  export function calcPrice(usage, modelPrice) {
32
- let price = 0;
33
- price += calcMtokPrice(modelPrice.input_mtok, usage.input_tokens, 'input_mtok');
34
- price += calcMtokPrice(modelPrice.cache_write_mtok, usage.cache_write_tokens, 'cache_write_mtok');
35
- price += calcMtokPrice(modelPrice.cache_read_mtok, usage.cache_read_tokens, 'cache_read_mtok');
36
- price += calcMtokPrice(modelPrice.output_mtok, usage.output_tokens, 'output_mtok');
37
- price += calcMtokPrice(modelPrice.input_audio_mtok, usage.input_audio_tokens, 'input_audio_mtok');
38
- price += calcMtokPrice(modelPrice.cache_audio_read_mtok, usage.cache_audio_read_tokens, 'cache_audio_read_mtok');
39
- price += calcMtokPrice(modelPrice.output_audio_mtok, usage.output_audio_tokens, 'output_audio_mtok');
32
+ let input_price = 0;
33
+ let output_price = 0;
34
+ // Input-related prices
35
+ input_price += calcMtokPrice(modelPrice.input_mtok, usage.input_tokens, 'input_mtok');
36
+ input_price += calcMtokPrice(modelPrice.cache_write_mtok, usage.cache_write_tokens, 'cache_write_mtok');
37
+ input_price += calcMtokPrice(modelPrice.cache_read_mtok, usage.cache_read_tokens, 'cache_read_mtok');
38
+ input_price += calcMtokPrice(modelPrice.input_audio_mtok, usage.input_audio_tokens, 'input_audio_mtok');
39
+ input_price += calcMtokPrice(modelPrice.cache_audio_read_mtok, usage.cache_audio_read_tokens, 'cache_audio_read_mtok');
40
+ // Output-related prices
41
+ output_price += calcMtokPrice(modelPrice.output_mtok, usage.output_tokens, 'output_mtok');
42
+ output_price += calcMtokPrice(modelPrice.output_audio_mtok, usage.output_audio_tokens, 'output_audio_mtok');
43
+ // Requests price (counted as input cost)
40
44
  if (modelPrice.requests_kcount !== undefined) {
41
- price += modelPrice.requests_kcount * ((usage.requests ?? 1) / 1000);
45
+ input_price += modelPrice.requests_kcount / 1000;
42
46
  }
43
- return price;
47
+ const total_price = input_price + output_price;
48
+ return {
49
+ input_price,
50
+ output_price,
51
+ total_price,
52
+ };
44
53
  }
45
54
  export function getActiveModelPrice(model, timestamp) {
46
55
  if (!Array.isArray(model.prices)) {
@@ -57,9 +66,22 @@ export function getActiveModelPrice(model, timestamp) {
57
66
  }
58
67
  }
59
68
  else if (cond.constraint.type === 'time_of_date') {
60
- const t = timestamp.toTimeString().slice(0, 8);
61
- if (t >= cond.constraint.start_time && t < cond.constraint.end_time) {
62
- return cond.prices;
69
+ // Extract UTC time to match constraint times which are in UTC (with 'Z' suffix)
70
+ const t = timestamp.toISOString().slice(11, 19); // Get "HH:MM:SS" from ISO string
71
+ const startTime = cond.constraint.start_time;
72
+ const endTime = cond.constraint.end_time;
73
+ // Handle time ranges that span midnight (end time < start time)
74
+ if (endTime < startTime) {
75
+ // Time is in range if it's >= start OR < end
76
+ if (t >= startTime || t < endTime) {
77
+ return cond.prices;
78
+ }
79
+ }
80
+ else {
81
+ // Normal time range (start <= time < end)
82
+ if (t >= startTime && t < endTime) {
83
+ return cond.prices;
84
+ }
63
85
  }
64
86
  }
65
87
  }
@@ -11,9 +11,11 @@ export function calcPriceSync(usage, modelRef, options = {}) {
11
11
  return null;
12
12
  const timestamp = options.timestamp || new Date();
13
13
  const model_price = getActiveModelPrice(model, timestamp);
14
- const price = calcModelPrice(usage, model_price);
14
+ const priceResult = calcModelPrice(usage, model_price);
15
15
  return {
16
- price,
16
+ input_price: priceResult.input_price,
17
+ output_price: priceResult.output_price,
18
+ total_price: priceResult.total_price,
17
19
  provider,
18
20
  model,
19
21
  model_price,
package/dist/types.d.ts CHANGED
@@ -6,7 +6,6 @@ export interface Usage {
6
6
  input_audio_tokens?: number;
7
7
  cache_audio_read_tokens?: number;
8
8
  output_audio_tokens?: number;
9
- requests?: number;
10
9
  }
11
10
  export interface Tier {
12
11
  start: number;
@@ -74,8 +73,15 @@ export interface Provider {
74
73
  provider_match?: MatchLogic;
75
74
  models: ModelInfo[];
76
75
  }
76
+ export interface CalcPrice {
77
+ input_price: number;
78
+ output_price: number;
79
+ total_price: number;
80
+ }
77
81
  export interface PriceCalculation {
78
- price: number;
82
+ input_price: number;
83
+ output_price: number;
84
+ total_price: number;
79
85
  provider: Provider;
80
86
  model: ModelInfo;
81
87
  model_price: ModelPrice;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pydantic/genai-prices",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "Calculate prices for calling LLM inference APIs (JS/TS version of genai-prices)",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",