@pydantic/genai-prices 0.0.7 → 0.0.12

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/data.js CHANGED
@@ -1973,6 +1973,30 @@ export const data = [
1973
1973
  output_mtok: 0.24,
1974
1974
  },
1975
1975
  },
1976
+ {
1977
+ id: 'openai/gpt-oss-120b',
1978
+ description: "GPT-OSS 120B is OpenAI's flagship open source model, built on a Mixture-of-Experts (MoE) architecture with\n120 billion parameters and 128 experts.\n",
1979
+ match: {
1980
+ equals: 'openai/gpt-oss-120b',
1981
+ },
1982
+ context_window: 131072,
1983
+ prices: {
1984
+ input_mtok: 0.15,
1985
+ output_mtok: 0.75,
1986
+ },
1987
+ },
1988
+ {
1989
+ id: 'openai/gpt-oss-20b',
1990
+ description: "GPT-OSS 20B is OpenAI's flagship open source model, built on a Mixture-of-Experts (MoE) architecture with\n20 billion parameters and 32 experts.\n",
1991
+ match: {
1992
+ equals: 'openai/gpt-oss-20b',
1993
+ },
1994
+ context_window: 131072,
1995
+ prices: {
1996
+ input_mtok: 0.1,
1997
+ output_mtok: 0.5,
1998
+ },
1999
+ },
1976
2000
  ],
1977
2001
  },
1978
2002
  {
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';
@@ -1978,6 +1978,30 @@
1978
1978
  input_mtok: 0.24,
1979
1979
  output_mtok: 0.24
1980
1980
  }
1981
+ },
1982
+ {
1983
+ id: "openai/gpt-oss-120b",
1984
+ description: "GPT-OSS 120B is OpenAI's flagship open source model, built on a Mixture-of-Experts (MoE) architecture with\n120 billion parameters and 128 experts.\n",
1985
+ match: {
1986
+ equals: "openai/gpt-oss-120b"
1987
+ },
1988
+ context_window: 131072,
1989
+ prices: {
1990
+ input_mtok: 0.15,
1991
+ output_mtok: 0.75
1992
+ }
1993
+ },
1994
+ {
1995
+ id: "openai/gpt-oss-20b",
1996
+ description: "GPT-OSS 20B is OpenAI's flagship open source model, built on a Mixture-of-Experts (MoE) architecture with\n20 billion parameters and 32 experts.\n",
1997
+ match: {
1998
+ equals: "openai/gpt-oss-20b"
1999
+ },
2000
+ context_window: 131072,
2001
+ prices: {
2002
+ input_mtok: 0.1,
2003
+ output_mtok: 0.5
2004
+ }
1981
2005
  }
1982
2006
  ]
1983
2007
  },
@@ -10630,18 +10654,26 @@
10630
10654
  return calcTieredPrice(price, tokens);
10631
10655
  }
10632
10656
  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);
10657
+ let input_price = 0;
10658
+ let output_price = 0;
10659
+ input_price += calcMtokPrice(modelPrice.input_mtok, usage.input_tokens);
10660
+ input_price += calcMtokPrice(modelPrice.cache_write_mtok, usage.cache_write_tokens);
10661
+ input_price += calcMtokPrice(modelPrice.cache_read_mtok, usage.cache_read_tokens);
10662
+ input_price += calcMtokPrice(modelPrice.input_audio_mtok, usage.input_audio_tokens);
10663
+ input_price += calcMtokPrice(
10664
+ modelPrice.cache_audio_read_mtok,
10665
+ usage.cache_audio_read_tokens);
10666
+ output_price += calcMtokPrice(modelPrice.output_mtok, usage.output_tokens);
10667
+ output_price += calcMtokPrice(modelPrice.output_audio_mtok, usage.output_audio_tokens);
10641
10668
  if (modelPrice.requests_kcount !== void 0) {
10642
- price += modelPrice.requests_kcount * ((usage.requests ?? 1) / 1e3);
10669
+ input_price += modelPrice.requests_kcount / 1e3;
10643
10670
  }
10644
- return price;
10671
+ const total_price = input_price + output_price;
10672
+ return {
10673
+ input_price,
10674
+ output_price,
10675
+ total_price
10676
+ };
10645
10677
  }
10646
10678
  function getActiveModelPrice(model, timestamp) {
10647
10679
  if (!Array.isArray(model.prices)) {
@@ -10655,9 +10687,17 @@
10655
10687
  return cond.prices;
10656
10688
  }
10657
10689
  } 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;
10690
+ const t = timestamp.toISOString().slice(11, 19);
10691
+ const startTime = cond.constraint.start_time;
10692
+ const endTime = cond.constraint.end_time;
10693
+ if (endTime < startTime) {
10694
+ if (t >= startTime || t < endTime) {
10695
+ return cond.prices;
10696
+ }
10697
+ } else {
10698
+ if (t >= startTime && t < endTime) {
10699
+ return cond.prices;
10700
+ }
10661
10701
  }
10662
10702
  }
10663
10703
  }
@@ -10672,9 +10712,11 @@
10672
10712
  if (!model) return null;
10673
10713
  const timestamp = options.timestamp || /* @__PURE__ */ new Date();
10674
10714
  const model_price = getActiveModelPrice(model, timestamp);
10675
- const price = calcPrice(usage, model_price);
10715
+ const priceResult = calcPrice(usage, model_price);
10676
10716
  return {
10677
- price,
10717
+ input_price: priceResult.input_price,
10718
+ output_price: priceResult.output_price,
10719
+ total_price: priceResult.total_price,
10678
10720
  provider,
10679
10721
  model,
10680
10722
  model_price,
@@ -10690,9 +10732,11 @@
10690
10732
  if (!model) return null;
10691
10733
  const timestamp = options.timestamp || /* @__PURE__ */ new Date();
10692
10734
  const model_price = getActiveModelPrice(model, timestamp);
10693
- const price = calcPrice(usage, model_price);
10735
+ const priceResult = calcPrice(usage, model_price);
10694
10736
  return {
10695
- price,
10737
+ input_price: priceResult.input_price,
10738
+ output_price: priceResult.output_price,
10739
+ total_price: priceResult.total_price,
10696
10740
  provider,
10697
10741
  model,
10698
10742
  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.12",
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",