modelfusion 0.23.0 → 0.24.0

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
@@ -35,6 +35,8 @@ You need to install `zod` and a matching version of `zod-to-json-schema` (peer d
35
35
  npm install zod zod-to-json-schema
36
36
  ```
37
37
 
38
+ Or use a template: [ModelFusion terminal app starter](https://github.com/lgrammel/modelfusion-terminal-app-starter)
39
+
38
40
  ## Usage Examples
39
41
 
40
42
  You can provide API keys for the different [integrations](https://modelfusion.dev/integration/model-provider/) using environment variables (e.g., `OPENAI_API_KEY`) or pass them into the model constructors as options.
@@ -4,7 +4,7 @@ import { Run } from "../../core/Run.js";
4
4
  import { RetryFunction } from "../../util/api/RetryFunction.js";
5
5
  import { ThrottleFunction } from "../../util/api/ThrottleFunction.js";
6
6
  import { CohereTextGenerationModelType } from "./CohereTextGenerationModel.js";
7
- import { CohereTextEmbeddingModelType } from "./index.js";
7
+ import { CohereTextEmbeddingModelType } from "./CohereTextEmbeddingModel.js";
8
8
  export type CohereTokenizerModelType = CohereTextGenerationModelType | CohereTextEmbeddingModelType;
9
9
  export interface CohereTokenizerSettings {
10
10
  model: CohereTokenizerModelType;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.OpenAITextResponseFormat = exports.OpenAITextGenerationModel = exports.calculateOpenAITextGenerationCostInMillicents = exports.isOpenAITextGenerationModel = exports.OPENAI_TEXT_GENERATION_MODELS = void 0;
6
+ exports.OpenAITextResponseFormat = exports.OpenAITextGenerationModel = exports.calculateOpenAITextGenerationCostInMillicents = exports.isOpenAITextGenerationModel = exports.getOpenAITextGenerationModelInformation = exports.OPENAI_TEXT_GENERATION_MODELS = void 0;
7
7
  const secure_json_parse_1 = __importDefault(require("secure-json-parse"));
8
8
  const zod_1 = __importDefault(require("zod"));
9
9
  const AbstractModel_js_1 = require("../../model-function/AbstractModel.cjs");
@@ -23,10 +23,12 @@ exports.OPENAI_TEXT_GENERATION_MODELS = {
23
23
  "davinci-002": {
24
24
  contextWindowSize: 16384,
25
25
  tokenCostInMillicents: 0.2,
26
+ fineTunedTokenCostInMillicents: 1.2,
26
27
  },
27
28
  "babbage-002": {
28
29
  contextWindowSize: 16384,
29
30
  tokenCostInMillicents: 0.04,
31
+ fineTunedTokenCostInMillicents: 0.16,
30
32
  },
31
33
  "text-davinci-003": {
32
34
  contextWindowSize: 4096,
@@ -69,10 +71,38 @@ exports.OPENAI_TEXT_GENERATION_MODELS = {
69
71
  tokenCostInMillicents: 0.04,
70
72
  },
71
73
  };
72
- const isOpenAITextGenerationModel = (model) => model in exports.OPENAI_TEXT_GENERATION_MODELS;
74
+ function getOpenAITextGenerationModelInformation(model) {
75
+ // Model is already a base model:
76
+ if (model in exports.OPENAI_TEXT_GENERATION_MODELS) {
77
+ const baseModelInformation = exports.OPENAI_TEXT_GENERATION_MODELS[model];
78
+ return {
79
+ baseModel: model,
80
+ isFineTuned: false,
81
+ contextWindowSize: baseModelInformation.contextWindowSize,
82
+ tokenCostInMillicents: baseModelInformation.tokenCostInMillicents,
83
+ };
84
+ }
85
+ // Extract the base model from the fine-tuned model:
86
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
87
+ const [_, baseModel, ___, ____, _____] = model.split(":");
88
+ if (["davinci-002", "babbage-002"].includes(baseModel)) {
89
+ const baseModelInformation = exports.OPENAI_TEXT_GENERATION_MODELS[baseModel];
90
+ return {
91
+ baseModel: baseModel,
92
+ isFineTuned: true,
93
+ contextWindowSize: baseModelInformation.contextWindowSize,
94
+ tokenCostInMillicents: baseModelInformation.fineTunedTokenCostInMillicents,
95
+ };
96
+ }
97
+ throw new Error(`Unknown OpenAI chat base model ${baseModel}.`);
98
+ }
99
+ exports.getOpenAITextGenerationModelInformation = getOpenAITextGenerationModelInformation;
100
+ const isOpenAITextGenerationModel = (model) => model in exports.OPENAI_TEXT_GENERATION_MODELS ||
101
+ model.startsWith("ft:davinci-002:") ||
102
+ model.startsWith("ft:babbage-002:");
73
103
  exports.isOpenAITextGenerationModel = isOpenAITextGenerationModel;
74
104
  const calculateOpenAITextGenerationCostInMillicents = ({ model, response, }) => response.usage.total_tokens *
75
- exports.OPENAI_TEXT_GENERATION_MODELS[model].tokenCostInMillicents;
105
+ getOpenAITextGenerationModelInformation(model).tokenCostInMillicents;
76
106
  exports.calculateOpenAITextGenerationCostInMillicents = calculateOpenAITextGenerationCostInMillicents;
77
107
  /**
78
108
  * Create a text generation model that calls the OpenAI text completion API.
@@ -113,9 +143,11 @@ class OpenAITextGenerationModel extends AbstractModel_js_1.AbstractModel {
113
143
  writable: true,
114
144
  value: void 0
115
145
  });
116
- this.tokenizer = new TikTokenTokenizer_js_1.TikTokenTokenizer({ model: settings.model });
117
- this.contextWindowSize =
118
- exports.OPENAI_TEXT_GENERATION_MODELS[settings.model].contextWindowSize;
146
+ const modelInformation = getOpenAITextGenerationModelInformation(this.settings.model);
147
+ this.tokenizer = new TikTokenTokenizer_js_1.TikTokenTokenizer({
148
+ model: modelInformation.baseModel,
149
+ });
150
+ this.contextWindowSize = modelInformation.contextWindowSize;
119
151
  }
120
152
  get modelName() {
121
153
  return this.settings.model;
@@ -19,10 +19,12 @@ export declare const OPENAI_TEXT_GENERATION_MODELS: {
19
19
  "davinci-002": {
20
20
  contextWindowSize: number;
21
21
  tokenCostInMillicents: number;
22
+ fineTunedTokenCostInMillicents: number;
22
23
  };
23
24
  "babbage-002": {
24
25
  contextWindowSize: number;
25
26
  tokenCostInMillicents: number;
27
+ fineTunedTokenCostInMillicents: number;
26
28
  };
27
29
  "text-davinci-003": {
28
30
  contextWindowSize: number;
@@ -65,8 +67,17 @@ export declare const OPENAI_TEXT_GENERATION_MODELS: {
65
67
  tokenCostInMillicents: number;
66
68
  };
67
69
  };
68
- export type OpenAITextGenerationModelType = keyof typeof OPENAI_TEXT_GENERATION_MODELS;
69
- export declare const isOpenAITextGenerationModel: (model: string) => model is "davinci-002" | "babbage-002" | "text-davinci-003" | "text-davinci-002" | "code-davinci-002" | "davinci" | "text-curie-001" | "curie" | "text-babbage-001" | "babbage" | "text-ada-001" | "ada";
70
+ export declare function getOpenAITextGenerationModelInformation(model: OpenAITextGenerationModelType): {
71
+ baseModel: OpenAITextGenerationBaseModelType;
72
+ isFineTuned: boolean;
73
+ contextWindowSize: number;
74
+ tokenCostInMillicents: number;
75
+ };
76
+ type FineTuneableOpenAITextGenerationModelType = "davinci-002" | "babbage-002";
77
+ type FineTunedOpenAITextGenerationModelType = `ft:${FineTuneableOpenAITextGenerationModelType}:${string}:${string}:${string}`;
78
+ export type OpenAITextGenerationBaseModelType = keyof typeof OPENAI_TEXT_GENERATION_MODELS;
79
+ export type OpenAITextGenerationModelType = OpenAITextGenerationBaseModelType | FineTunedOpenAITextGenerationModelType;
80
+ export declare const isOpenAITextGenerationModel: (model: string) => model is OpenAITextGenerationModelType;
70
81
  export declare const calculateOpenAITextGenerationCostInMillicents: ({ model, response, }: {
71
82
  model: OpenAITextGenerationModelType;
72
83
  response: OpenAITextGenerationResponse;
@@ -110,7 +121,7 @@ export interface OpenAITextGenerationModelSettings extends TextGenerationModelSe
110
121
  export declare class OpenAITextGenerationModel extends AbstractModel<OpenAITextGenerationModelSettings> implements TextGenerationModel<string, OpenAITextGenerationResponse, OpenAITextGenerationDelta, OpenAITextGenerationModelSettings> {
111
122
  constructor(settings: OpenAITextGenerationModelSettings);
112
123
  readonly provider: "openai";
113
- get modelName(): "davinci-002" | "babbage-002" | "text-davinci-003" | "text-davinci-002" | "code-davinci-002" | "davinci" | "text-curie-001" | "curie" | "text-babbage-001" | "babbage" | "text-ada-001" | "ada";
124
+ get modelName(): OpenAITextGenerationModelType;
114
125
  readonly contextWindowSize: number;
115
126
  readonly tokenizer: TikTokenTokenizer;
116
127
  private get apiKey();
@@ -126,8 +137,8 @@ export declare class OpenAITextGenerationModel extends AbstractModel<OpenAITextG
126
137
  model: string;
127
138
  usage: {
128
139
  prompt_tokens: number;
129
- total_tokens: number;
130
140
  completion_tokens: number;
141
+ total_tokens: number;
131
142
  };
132
143
  id: string;
133
144
  created: number;
@@ -176,20 +187,20 @@ declare const openAITextGenerationResponseSchema: z.ZodObject<{
176
187
  total_tokens: z.ZodNumber;
177
188
  }, "strip", z.ZodTypeAny, {
178
189
  prompt_tokens: number;
179
- total_tokens: number;
180
190
  completion_tokens: number;
191
+ total_tokens: number;
181
192
  }, {
182
193
  prompt_tokens: number;
183
- total_tokens: number;
184
194
  completion_tokens: number;
195
+ total_tokens: number;
185
196
  }>;
186
197
  }, "strip", z.ZodTypeAny, {
187
198
  object: "text_completion";
188
199
  model: string;
189
200
  usage: {
190
201
  prompt_tokens: number;
191
- total_tokens: number;
192
202
  completion_tokens: number;
203
+ total_tokens: number;
193
204
  };
194
205
  id: string;
195
206
  created: number;
@@ -204,8 +215,8 @@ declare const openAITextGenerationResponseSchema: z.ZodObject<{
204
215
  model: string;
205
216
  usage: {
206
217
  prompt_tokens: number;
207
- total_tokens: number;
208
218
  completion_tokens: number;
219
+ total_tokens: number;
209
220
  };
210
221
  id: string;
211
222
  created: number;
@@ -232,8 +243,8 @@ export declare const OpenAITextResponseFormat: {
232
243
  model: string;
233
244
  usage: {
234
245
  prompt_tokens: number;
235
- total_tokens: number;
236
246
  completion_tokens: number;
247
+ total_tokens: number;
237
248
  };
238
249
  id: string;
239
250
  created: number;
@@ -17,10 +17,12 @@ export const OPENAI_TEXT_GENERATION_MODELS = {
17
17
  "davinci-002": {
18
18
  contextWindowSize: 16384,
19
19
  tokenCostInMillicents: 0.2,
20
+ fineTunedTokenCostInMillicents: 1.2,
20
21
  },
21
22
  "babbage-002": {
22
23
  contextWindowSize: 16384,
23
24
  tokenCostInMillicents: 0.04,
25
+ fineTunedTokenCostInMillicents: 0.16,
24
26
  },
25
27
  "text-davinci-003": {
26
28
  contextWindowSize: 4096,
@@ -63,9 +65,36 @@ export const OPENAI_TEXT_GENERATION_MODELS = {
63
65
  tokenCostInMillicents: 0.04,
64
66
  },
65
67
  };
66
- export const isOpenAITextGenerationModel = (model) => model in OPENAI_TEXT_GENERATION_MODELS;
68
+ export function getOpenAITextGenerationModelInformation(model) {
69
+ // Model is already a base model:
70
+ if (model in OPENAI_TEXT_GENERATION_MODELS) {
71
+ const baseModelInformation = OPENAI_TEXT_GENERATION_MODELS[model];
72
+ return {
73
+ baseModel: model,
74
+ isFineTuned: false,
75
+ contextWindowSize: baseModelInformation.contextWindowSize,
76
+ tokenCostInMillicents: baseModelInformation.tokenCostInMillicents,
77
+ };
78
+ }
79
+ // Extract the base model from the fine-tuned model:
80
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
81
+ const [_, baseModel, ___, ____, _____] = model.split(":");
82
+ if (["davinci-002", "babbage-002"].includes(baseModel)) {
83
+ const baseModelInformation = OPENAI_TEXT_GENERATION_MODELS[baseModel];
84
+ return {
85
+ baseModel: baseModel,
86
+ isFineTuned: true,
87
+ contextWindowSize: baseModelInformation.contextWindowSize,
88
+ tokenCostInMillicents: baseModelInformation.fineTunedTokenCostInMillicents,
89
+ };
90
+ }
91
+ throw new Error(`Unknown OpenAI chat base model ${baseModel}.`);
92
+ }
93
+ export const isOpenAITextGenerationModel = (model) => model in OPENAI_TEXT_GENERATION_MODELS ||
94
+ model.startsWith("ft:davinci-002:") ||
95
+ model.startsWith("ft:babbage-002:");
67
96
  export const calculateOpenAITextGenerationCostInMillicents = ({ model, response, }) => response.usage.total_tokens *
68
- OPENAI_TEXT_GENERATION_MODELS[model].tokenCostInMillicents;
97
+ getOpenAITextGenerationModelInformation(model).tokenCostInMillicents;
69
98
  /**
70
99
  * Create a text generation model that calls the OpenAI text completion API.
71
100
  *
@@ -105,9 +134,11 @@ export class OpenAITextGenerationModel extends AbstractModel {
105
134
  writable: true,
106
135
  value: void 0
107
136
  });
108
- this.tokenizer = new TikTokenTokenizer({ model: settings.model });
109
- this.contextWindowSize =
110
- OPENAI_TEXT_GENERATION_MODELS[settings.model].contextWindowSize;
137
+ const modelInformation = getOpenAITextGenerationModelInformation(this.settings.model);
138
+ this.tokenizer = new TikTokenTokenizer({
139
+ model: modelInformation.baseModel,
140
+ });
141
+ this.contextWindowSize = modelInformation.contextWindowSize;
111
142
  }
112
143
  get modelName() {
113
144
  return this.settings.model;
@@ -1,6 +1,8 @@
1
1
  import { TiktokenEncoding } from "js-tiktoken";
2
2
  import { FullTokenizer } from "../../model-function/tokenize-text/Tokenizer.js";
3
- import { OpenAIChatModelType, OpenAITextEmbeddingModelType, OpenAITextGenerationModelType } from "./index.js";
3
+ import { OpenAITextEmbeddingModelType } from "./OpenAITextEmbeddingModel.js";
4
+ import { OpenAITextGenerationBaseModelType } from "./OpenAITextGenerationModel.js";
5
+ import { OpenAIChatBaseModelType } from "./chat/OpenAIChatModel.js";
4
6
  /**
5
7
  * TikToken tokenizer for OpenAI language models.
6
8
  *
@@ -21,7 +23,7 @@ export declare class TikTokenTokenizer implements FullTokenizer {
21
23
  * Get a TikToken tokenizer for a specific model or encoding.
22
24
  */
23
25
  constructor(options: {
24
- model: OpenAIChatModelType | OpenAITextEmbeddingModelType | OpenAITextGenerationModelType;
26
+ model: OpenAIChatBaseModelType | OpenAITextGenerationBaseModelType | OpenAITextEmbeddingModelType;
25
27
  } | {
26
28
  encoding: TiktokenEncoding;
27
29
  });
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.OpenAIChatResponseFormat = exports.OpenAIChatModel = exports.calculateOpenAIChatCostInMillicents = exports.isOpenAIChatModel = exports.OPENAI_CHAT_MODELS = void 0;
6
+ exports.OpenAIChatResponseFormat = exports.OpenAIChatModel = exports.calculateOpenAIChatCostInMillicents = exports.isOpenAIChatModel = exports.getOpenAIChatModelInformation = exports.OPENAI_CHAT_MODELS = void 0;
7
7
  const secure_json_parse_1 = __importDefault(require("secure-json-parse"));
8
8
  const zod_1 = __importDefault(require("zod"));
9
9
  const AbstractModel_js_1 = require("../../../model-function/AbstractModel.cjs");
@@ -55,6 +55,8 @@ exports.OPENAI_CHAT_MODELS = {
55
55
  contextWindowSize: 4096,
56
56
  promptTokenCostInMillicents: 0.15,
57
57
  completionTokenCostInMillicents: 0.2,
58
+ fineTunedPromptTokenCostInMillicents: 1.2,
59
+ fineTunedCompletionTokenCostInMillicents: 1.6,
58
60
  },
59
61
  "gpt-3.5-turbo-0301": {
60
62
  contextWindowSize: 4096,
@@ -65,6 +67,8 @@ exports.OPENAI_CHAT_MODELS = {
65
67
  contextWindowSize: 4096,
66
68
  promptTokenCostInMillicents: 0.15,
67
69
  completionTokenCostInMillicents: 0.2,
70
+ fineTunedPromptTokenCostInMillicents: 1.2,
71
+ fineTunedCompletionTokenCostInMillicents: 1.6,
68
72
  },
69
73
  "gpt-3.5-turbo-16k": {
70
74
  contextWindowSize: 16384,
@@ -77,12 +81,45 @@ exports.OPENAI_CHAT_MODELS = {
77
81
  completionTokenCostInMillicents: 0.4,
78
82
  },
79
83
  };
80
- const isOpenAIChatModel = (model) => model in exports.OPENAI_CHAT_MODELS;
84
+ function getOpenAIChatModelInformation(model) {
85
+ // Model is already a base model:
86
+ if (model in exports.OPENAI_CHAT_MODELS) {
87
+ const baseModelInformation = exports.OPENAI_CHAT_MODELS[model];
88
+ return {
89
+ baseModel: model,
90
+ isFineTuned: false,
91
+ contextWindowSize: baseModelInformation.contextWindowSize,
92
+ promptTokenCostInMillicents: baseModelInformation.promptTokenCostInMillicents,
93
+ completionTokenCostInMillicents: baseModelInformation.completionTokenCostInMillicents,
94
+ };
95
+ }
96
+ // Extract the base model from the fine-tuned model:
97
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
98
+ const [_, baseModel, ___, ____, _____] = model.split(":");
99
+ if (["gpt-3.5-turbo", "gpt-3.5-turbo-0613"].includes(baseModel)) {
100
+ const baseModelInformation = exports.OPENAI_CHAT_MODELS[baseModel];
101
+ return {
102
+ baseModel: baseModel,
103
+ isFineTuned: true,
104
+ contextWindowSize: baseModelInformation.contextWindowSize,
105
+ promptTokenCostInMillicents: baseModelInformation.fineTunedPromptTokenCostInMillicents,
106
+ completionTokenCostInMillicents: baseModelInformation.fineTunedCompletionTokenCostInMillicents,
107
+ };
108
+ }
109
+ throw new Error(`Unknown OpenAI chat base model ${baseModel}.`);
110
+ }
111
+ exports.getOpenAIChatModelInformation = getOpenAIChatModelInformation;
112
+ const isOpenAIChatModel = (model) => model in exports.OPENAI_CHAT_MODELS ||
113
+ model.startsWith("ft:gpt-3.5-turbo-0613:") ||
114
+ model.startsWith("ft:gpt-3.5-turbo:");
81
115
  exports.isOpenAIChatModel = isOpenAIChatModel;
82
- const calculateOpenAIChatCostInMillicents = ({ model, response, }) => response.usage.prompt_tokens *
83
- exports.OPENAI_CHAT_MODELS[model].promptTokenCostInMillicents +
84
- response.usage.completion_tokens *
85
- exports.OPENAI_CHAT_MODELS[model].completionTokenCostInMillicents;
116
+ const calculateOpenAIChatCostInMillicents = ({ model, response, }) => {
117
+ const modelInformation = getOpenAIChatModelInformation(model);
118
+ return (response.usage.prompt_tokens *
119
+ modelInformation.promptTokenCostInMillicents +
120
+ response.usage.completion_tokens *
121
+ modelInformation.completionTokenCostInMillicents);
122
+ };
86
123
  exports.calculateOpenAIChatCostInMillicents = calculateOpenAIChatCostInMillicents;
87
124
  /**
88
125
  * Create a text generation model that calls the OpenAI chat completion API.
@@ -124,9 +161,11 @@ class OpenAIChatModel extends AbstractModel_js_1.AbstractModel {
124
161
  writable: true,
125
162
  value: void 0
126
163
  });
127
- this.tokenizer = new TikTokenTokenizer_js_1.TikTokenTokenizer({ model: this.settings.model });
128
- this.contextWindowSize =
129
- exports.OPENAI_CHAT_MODELS[this.settings.model].contextWindowSize;
164
+ const modelInformation = getOpenAIChatModelInformation(this.settings.model);
165
+ this.tokenizer = new TikTokenTokenizer_js_1.TikTokenTokenizer({
166
+ model: modelInformation.baseModel,
167
+ });
168
+ this.contextWindowSize = modelInformation.contextWindowSize;
130
169
  }
131
170
  get modelName() {
132
171
  return this.settings.model;
@@ -48,6 +48,8 @@ export declare const OPENAI_CHAT_MODELS: {
48
48
  contextWindowSize: number;
49
49
  promptTokenCostInMillicents: number;
50
50
  completionTokenCostInMillicents: number;
51
+ fineTunedPromptTokenCostInMillicents: number;
52
+ fineTunedCompletionTokenCostInMillicents: number;
51
53
  };
52
54
  "gpt-3.5-turbo-0301": {
53
55
  contextWindowSize: number;
@@ -58,6 +60,8 @@ export declare const OPENAI_CHAT_MODELS: {
58
60
  contextWindowSize: number;
59
61
  promptTokenCostInMillicents: number;
60
62
  completionTokenCostInMillicents: number;
63
+ fineTunedPromptTokenCostInMillicents: number;
64
+ fineTunedCompletionTokenCostInMillicents: number;
61
65
  };
62
66
  "gpt-3.5-turbo-16k": {
63
67
  contextWindowSize: number;
@@ -70,8 +74,18 @@ export declare const OPENAI_CHAT_MODELS: {
70
74
  completionTokenCostInMillicents: number;
71
75
  };
72
76
  };
73
- export type OpenAIChatModelType = keyof typeof OPENAI_CHAT_MODELS;
74
- export declare const isOpenAIChatModel: (model: string) => model is "gpt-4" | "gpt-4-0314" | "gpt-4-0613" | "gpt-4-32k" | "gpt-4-32k-0314" | "gpt-4-32k-0613" | "gpt-3.5-turbo" | "gpt-3.5-turbo-0301" | "gpt-3.5-turbo-0613" | "gpt-3.5-turbo-16k" | "gpt-3.5-turbo-16k-0613";
77
+ export declare function getOpenAIChatModelInformation(model: OpenAIChatModelType): {
78
+ baseModel: OpenAIChatBaseModelType;
79
+ isFineTuned: boolean;
80
+ contextWindowSize: number;
81
+ promptTokenCostInMillicents: number;
82
+ completionTokenCostInMillicents: number;
83
+ };
84
+ type FineTuneableOpenAIChatModelType = `gpt-3.5-turbo` | `gpt-3.5-turbo-0613`;
85
+ type FineTunedOpenAIChatModelType = `ft:${FineTuneableOpenAIChatModelType}:${string}:${string}:${string}`;
86
+ export type OpenAIChatBaseModelType = keyof typeof OPENAI_CHAT_MODELS;
87
+ export type OpenAIChatModelType = OpenAIChatBaseModelType | FineTunedOpenAIChatModelType;
88
+ export declare const isOpenAIChatModel: (model: string) => model is OpenAIChatModelType;
75
89
  export declare const calculateOpenAIChatCostInMillicents: ({ model, response, }: {
76
90
  model: OpenAIChatModelType;
77
91
  response: OpenAIChatResponse;
@@ -120,7 +134,7 @@ export interface OpenAIChatSettings extends TextGenerationModelSettings, OpenAIM
120
134
  export declare class OpenAIChatModel extends AbstractModel<OpenAIChatSettings> implements TextGenerationModel<OpenAIChatMessage[], OpenAIChatResponse, OpenAIChatDelta, OpenAIChatSettings>, JsonGenerationModel<OpenAIChatSingleFunctionPrompt<unknown>, OpenAIChatResponse, OpenAIChatSettings>, JsonOrTextGenerationModel<OpenAIChatAutoFunctionPrompt<Array<OpenAIFunctionDescription<unknown>>>, OpenAIChatResponse, OpenAIChatSettings> {
121
135
  constructor(settings: OpenAIChatSettings);
122
136
  readonly provider: "openai";
123
- get modelName(): "gpt-4" | "gpt-4-0314" | "gpt-4-0613" | "gpt-4-32k" | "gpt-4-32k-0314" | "gpt-4-32k-0613" | "gpt-3.5-turbo" | "gpt-3.5-turbo-0301" | "gpt-3.5-turbo-0613" | "gpt-3.5-turbo-16k" | "gpt-3.5-turbo-16k-0613";
137
+ get modelName(): OpenAIChatModelType;
124
138
  readonly contextWindowSize: number;
125
139
  readonly tokenizer: TikTokenTokenizer;
126
140
  private get apiKey();
@@ -140,8 +154,8 @@ export declare class OpenAIChatModel extends AbstractModel<OpenAIChatSettings> i
140
154
  model: string;
141
155
  usage: {
142
156
  prompt_tokens: number;
143
- total_tokens: number;
144
157
  completion_tokens: number;
158
+ total_tokens: number;
145
159
  };
146
160
  id: string;
147
161
  created: number;
@@ -247,20 +261,20 @@ declare const openAIChatResponseSchema: z.ZodObject<{
247
261
  total_tokens: z.ZodNumber;
248
262
  }, "strip", z.ZodTypeAny, {
249
263
  prompt_tokens: number;
250
- total_tokens: number;
251
264
  completion_tokens: number;
265
+ total_tokens: number;
252
266
  }, {
253
267
  prompt_tokens: number;
254
- total_tokens: number;
255
268
  completion_tokens: number;
269
+ total_tokens: number;
256
270
  }>;
257
271
  }, "strip", z.ZodTypeAny, {
258
272
  object: "chat.completion";
259
273
  model: string;
260
274
  usage: {
261
275
  prompt_tokens: number;
262
- total_tokens: number;
263
276
  completion_tokens: number;
277
+ total_tokens: number;
264
278
  };
265
279
  id: string;
266
280
  created: number;
@@ -282,8 +296,8 @@ declare const openAIChatResponseSchema: z.ZodObject<{
282
296
  model: string;
283
297
  usage: {
284
298
  prompt_tokens: number;
285
- total_tokens: number;
286
299
  completion_tokens: number;
300
+ total_tokens: number;
287
301
  };
288
302
  id: string;
289
303
  created: number;
@@ -317,8 +331,8 @@ export declare const OpenAIChatResponseFormat: {
317
331
  model: string;
318
332
  usage: {
319
333
  prompt_tokens: number;
320
- total_tokens: number;
321
334
  completion_tokens: number;
335
+ total_tokens: number;
322
336
  };
323
337
  id: string;
324
338
  created: number;
@@ -49,6 +49,8 @@ export const OPENAI_CHAT_MODELS = {
49
49
  contextWindowSize: 4096,
50
50
  promptTokenCostInMillicents: 0.15,
51
51
  completionTokenCostInMillicents: 0.2,
52
+ fineTunedPromptTokenCostInMillicents: 1.2,
53
+ fineTunedCompletionTokenCostInMillicents: 1.6,
52
54
  },
53
55
  "gpt-3.5-turbo-0301": {
54
56
  contextWindowSize: 4096,
@@ -59,6 +61,8 @@ export const OPENAI_CHAT_MODELS = {
59
61
  contextWindowSize: 4096,
60
62
  promptTokenCostInMillicents: 0.15,
61
63
  completionTokenCostInMillicents: 0.2,
64
+ fineTunedPromptTokenCostInMillicents: 1.2,
65
+ fineTunedCompletionTokenCostInMillicents: 1.6,
62
66
  },
63
67
  "gpt-3.5-turbo-16k": {
64
68
  contextWindowSize: 16384,
@@ -71,11 +75,43 @@ export const OPENAI_CHAT_MODELS = {
71
75
  completionTokenCostInMillicents: 0.4,
72
76
  },
73
77
  };
74
- export const isOpenAIChatModel = (model) => model in OPENAI_CHAT_MODELS;
75
- export const calculateOpenAIChatCostInMillicents = ({ model, response, }) => response.usage.prompt_tokens *
76
- OPENAI_CHAT_MODELS[model].promptTokenCostInMillicents +
77
- response.usage.completion_tokens *
78
- OPENAI_CHAT_MODELS[model].completionTokenCostInMillicents;
78
+ export function getOpenAIChatModelInformation(model) {
79
+ // Model is already a base model:
80
+ if (model in OPENAI_CHAT_MODELS) {
81
+ const baseModelInformation = OPENAI_CHAT_MODELS[model];
82
+ return {
83
+ baseModel: model,
84
+ isFineTuned: false,
85
+ contextWindowSize: baseModelInformation.contextWindowSize,
86
+ promptTokenCostInMillicents: baseModelInformation.promptTokenCostInMillicents,
87
+ completionTokenCostInMillicents: baseModelInformation.completionTokenCostInMillicents,
88
+ };
89
+ }
90
+ // Extract the base model from the fine-tuned model:
91
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
92
+ const [_, baseModel, ___, ____, _____] = model.split(":");
93
+ if (["gpt-3.5-turbo", "gpt-3.5-turbo-0613"].includes(baseModel)) {
94
+ const baseModelInformation = OPENAI_CHAT_MODELS[baseModel];
95
+ return {
96
+ baseModel: baseModel,
97
+ isFineTuned: true,
98
+ contextWindowSize: baseModelInformation.contextWindowSize,
99
+ promptTokenCostInMillicents: baseModelInformation.fineTunedPromptTokenCostInMillicents,
100
+ completionTokenCostInMillicents: baseModelInformation.fineTunedCompletionTokenCostInMillicents,
101
+ };
102
+ }
103
+ throw new Error(`Unknown OpenAI chat base model ${baseModel}.`);
104
+ }
105
+ export const isOpenAIChatModel = (model) => model in OPENAI_CHAT_MODELS ||
106
+ model.startsWith("ft:gpt-3.5-turbo-0613:") ||
107
+ model.startsWith("ft:gpt-3.5-turbo:");
108
+ export const calculateOpenAIChatCostInMillicents = ({ model, response, }) => {
109
+ const modelInformation = getOpenAIChatModelInformation(model);
110
+ return (response.usage.prompt_tokens *
111
+ modelInformation.promptTokenCostInMillicents +
112
+ response.usage.completion_tokens *
113
+ modelInformation.completionTokenCostInMillicents);
114
+ };
79
115
  /**
80
116
  * Create a text generation model that calls the OpenAI chat completion API.
81
117
  *
@@ -116,9 +152,11 @@ export class OpenAIChatModel extends AbstractModel {
116
152
  writable: true,
117
153
  value: void 0
118
154
  });
119
- this.tokenizer = new TikTokenTokenizer({ model: this.settings.model });
120
- this.contextWindowSize =
121
- OPENAI_CHAT_MODELS[this.settings.model].contextWindowSize;
155
+ const modelInformation = getOpenAIChatModelInformation(this.settings.model);
156
+ this.tokenizer = new TikTokenTokenizer({
157
+ model: modelInformation.baseModel,
158
+ });
159
+ this.contextWindowSize = modelInformation.contextWindowSize;
122
160
  }
123
161
  get modelName() {
124
162
  return this.settings.model;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.countOpenAIChatPromptTokens = exports.countOpenAIChatMessageTokens = exports.OPENAI_CHAT_MESSAGE_BASE_TOKEN_COUNT = exports.OPENAI_CHAT_PROMPT_BASE_TOKEN_COUNT = void 0;
4
4
  const countTokens_js_1 = require("../../../model-function/tokenize-text/countTokens.cjs");
5
5
  const TikTokenTokenizer_js_1 = require("../TikTokenTokenizer.cjs");
6
+ const OpenAIChatModel_js_1 = require("./OpenAIChatModel.cjs");
6
7
  /**
7
8
  * Prompt tokens that are included automatically for every full
8
9
  * chat prompt (several messages) that is sent to OpenAI.
@@ -14,8 +15,10 @@ exports.OPENAI_CHAT_PROMPT_BASE_TOKEN_COUNT = 2;
14
15
  */
15
16
  exports.OPENAI_CHAT_MESSAGE_BASE_TOKEN_COUNT = 5;
16
17
  async function countOpenAIChatMessageTokens({ message, model, }) {
17
- return (exports.OPENAI_CHAT_MESSAGE_BASE_TOKEN_COUNT +
18
- (await (0, countTokens_js_1.countTokens)(new TikTokenTokenizer_js_1.TikTokenTokenizer({ model }), message.content ?? "")));
18
+ const contentTokenCount = await (0, countTokens_js_1.countTokens)(new TikTokenTokenizer_js_1.TikTokenTokenizer({
19
+ model: (0, OpenAIChatModel_js_1.getOpenAIChatModelInformation)(model).baseModel,
20
+ }), message.content ?? "");
21
+ return exports.OPENAI_CHAT_MESSAGE_BASE_TOKEN_COUNT + contentTokenCount;
19
22
  }
20
23
  exports.countOpenAIChatMessageTokens = countOpenAIChatMessageTokens;
21
24
  async function countOpenAIChatPromptTokens({ messages, model, }) {
@@ -1,5 +1,6 @@
1
1
  import { countTokens } from "../../../model-function/tokenize-text/countTokens.js";
2
2
  import { TikTokenTokenizer } from "../TikTokenTokenizer.js";
3
+ import { getOpenAIChatModelInformation, } from "./OpenAIChatModel.js";
3
4
  /**
4
5
  * Prompt tokens that are included automatically for every full
5
6
  * chat prompt (several messages) that is sent to OpenAI.
@@ -11,8 +12,10 @@ export const OPENAI_CHAT_PROMPT_BASE_TOKEN_COUNT = 2;
11
12
  */
12
13
  export const OPENAI_CHAT_MESSAGE_BASE_TOKEN_COUNT = 5;
13
14
  export async function countOpenAIChatMessageTokens({ message, model, }) {
14
- return (OPENAI_CHAT_MESSAGE_BASE_TOKEN_COUNT +
15
- (await countTokens(new TikTokenTokenizer({ model }), message.content ?? "")));
15
+ const contentTokenCount = await countTokens(new TikTokenTokenizer({
16
+ model: getOpenAIChatModelInformation(model).baseModel,
17
+ }), message.content ?? "");
18
+ return OPENAI_CHAT_MESSAGE_BASE_TOKEN_COUNT + contentTokenCount;
16
19
  }
17
20
  export async function countOpenAIChatPromptTokens({ messages, model, }) {
18
21
  let tokens = OPENAI_CHAT_PROMPT_BASE_TOKEN_COUNT;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "modelfusion",
3
3
  "description": "Build AI applications, chatbots, and agents with JavaScript and TypeScript.",
4
- "version": "0.23.0",
4
+ "version": "0.24.0",
5
5
  "author": "Lars Grammel",
6
6
  "license": "MIT",
7
7
  "keywords": [