modelfusion 0.23.0 → 0.24.1
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 +2 -0
- package/model-provider/cohere/CohereTokenizer.d.ts +1 -1
- package/model-provider/openai/OpenAITextGenerationModel.cjs +41 -7
- package/model-provider/openai/OpenAITextGenerationModel.d.ts +27 -17
- package/model-provider/openai/OpenAITextGenerationModel.js +39 -6
- package/model-provider/openai/TikTokenTokenizer.d.ts +4 -2
- package/model-provider/openai/chat/OpenAIChatModel.cjs +53 -10
- package/model-provider/openai/chat/OpenAIChatModel.d.ts +26 -11
- package/model-provider/openai/chat/OpenAIChatModel.js +51 -9
- package/model-provider/openai/chat/countOpenAIChatMessageTokens.cjs +5 -2
- package/model-provider/openai/chat/countOpenAIChatMessageTokens.js +5 -2
- package/package.json +1 -1
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 "./
|
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
|
-
|
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
|
-
|
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
|
-
|
117
|
-
this.
|
118
|
-
|
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;
|
@@ -169,6 +201,7 @@ class OpenAITextGenerationModel extends AbstractModel_js_1.AbstractModel {
|
|
169
201
|
"presencePenalty",
|
170
202
|
"frequencyPenalty",
|
171
203
|
"bestOf",
|
204
|
+
"logitBias",
|
172
205
|
];
|
173
206
|
return Object.fromEntries(Object.entries(this.settings).filter(([key]) => eventSettingProperties.includes(key)));
|
174
207
|
}
|
@@ -243,7 +276,7 @@ const openAITextGenerationResponseSchema = zod_1.default.object({
|
|
243
276
|
*
|
244
277
|
* console.log(response.choices[0].text);
|
245
278
|
*/
|
246
|
-
async function callOpenAITextGenerationAPI({ baseUrl = "https://api.openai.com/v1", headers, abortSignal, responseFormat, apiKey, model, prompt, suffix, maxTokens, temperature, topP, n, logprobs, echo, stop, presencePenalty, frequencyPenalty, bestOf, user, }) {
|
279
|
+
async function callOpenAITextGenerationAPI({ baseUrl = "https://api.openai.com/v1", headers, abortSignal, responseFormat, apiKey, model, prompt, suffix, maxTokens, temperature, topP, n, logprobs, echo, stop, presencePenalty, frequencyPenalty, bestOf, logitBias, user, }) {
|
247
280
|
return (0, postToApi_js_1.postJsonToApi)({
|
248
281
|
url: `${baseUrl}/completions`,
|
249
282
|
headers: {
|
@@ -265,6 +298,7 @@ async function callOpenAITextGenerationAPI({ baseUrl = "https://api.openai.com/v
|
|
265
298
|
presence_penalty: presencePenalty,
|
266
299
|
frequency_penalty: frequencyPenalty,
|
267
300
|
best_of: bestOf,
|
301
|
+
logit_bias: logitBias,
|
268
302
|
user,
|
269
303
|
},
|
270
304
|
failedResponseHandler: OpenAIError_js_1.failedOpenAICallResponseHandler,
|
@@ -5,8 +5,6 @@ import { DeltaEvent } from "../../model-function/generate-text/DeltaEvent.js";
|
|
5
5
|
import { TextGenerationModel, TextGenerationModelSettings } from "../../model-function/generate-text/TextGenerationModel.js";
|
6
6
|
import { PromptFormat } from "../../prompt/PromptFormat.js";
|
7
7
|
import { PromptFormatTextGenerationModel } from "../../prompt/PromptFormatTextGenerationModel.js";
|
8
|
-
import { RetryFunction } from "../../util/api/RetryFunction.js";
|
9
|
-
import { ThrottleFunction } from "../../util/api/ThrottleFunction.js";
|
10
8
|
import { ResponseHandler } from "../../util/api/postToApi.js";
|
11
9
|
import { OpenAIImageGenerationCallSettings } from "./OpenAIImageGenerationModel.js";
|
12
10
|
import { OpenAIModelSettings } from "./OpenAIModelSettings.js";
|
@@ -19,10 +17,12 @@ export declare const OPENAI_TEXT_GENERATION_MODELS: {
|
|
19
17
|
"davinci-002": {
|
20
18
|
contextWindowSize: number;
|
21
19
|
tokenCostInMillicents: number;
|
20
|
+
fineTunedTokenCostInMillicents: number;
|
22
21
|
};
|
23
22
|
"babbage-002": {
|
24
23
|
contextWindowSize: number;
|
25
24
|
tokenCostInMillicents: number;
|
25
|
+
fineTunedTokenCostInMillicents: number;
|
26
26
|
};
|
27
27
|
"text-davinci-003": {
|
28
28
|
contextWindowSize: number;
|
@@ -65,29 +65,39 @@ export declare const OPENAI_TEXT_GENERATION_MODELS: {
|
|
65
65
|
tokenCostInMillicents: number;
|
66
66
|
};
|
67
67
|
};
|
68
|
-
export
|
69
|
-
|
68
|
+
export declare function getOpenAITextGenerationModelInformation(model: OpenAITextGenerationModelType): {
|
69
|
+
baseModel: OpenAITextGenerationBaseModelType;
|
70
|
+
isFineTuned: boolean;
|
71
|
+
contextWindowSize: number;
|
72
|
+
tokenCostInMillicents: number;
|
73
|
+
};
|
74
|
+
type FineTuneableOpenAITextGenerationModelType = "davinci-002" | "babbage-002";
|
75
|
+
type FineTunedOpenAITextGenerationModelType = `ft:${FineTuneableOpenAITextGenerationModelType}:${string}:${string}:${string}`;
|
76
|
+
export type OpenAITextGenerationBaseModelType = keyof typeof OPENAI_TEXT_GENERATION_MODELS;
|
77
|
+
export type OpenAITextGenerationModelType = OpenAITextGenerationBaseModelType | FineTunedOpenAITextGenerationModelType;
|
78
|
+
export declare const isOpenAITextGenerationModel: (model: string) => model is OpenAITextGenerationModelType;
|
70
79
|
export declare const calculateOpenAITextGenerationCostInMillicents: ({ model, response, }: {
|
71
80
|
model: OpenAITextGenerationModelType;
|
72
81
|
response: OpenAITextGenerationResponse;
|
73
82
|
}) => number;
|
74
|
-
export interface
|
83
|
+
export interface OpenAITextGenerationCallSettings {
|
75
84
|
model: OpenAITextGenerationModelType;
|
76
85
|
headers?: Record<string, string>;
|
77
|
-
baseUrl?: string;
|
78
|
-
apiKey?: string;
|
79
|
-
retry?: RetryFunction;
|
80
|
-
throttle?: ThrottleFunction;
|
81
|
-
isUserIdForwardingEnabled?: boolean;
|
82
86
|
suffix?: string;
|
87
|
+
maxTokens?: number;
|
83
88
|
temperature?: number;
|
84
89
|
topP?: number;
|
85
90
|
n?: number;
|
86
91
|
logprobs?: number;
|
87
92
|
echo?: boolean;
|
93
|
+
stop?: string | string[];
|
88
94
|
presencePenalty?: number;
|
89
95
|
frequencyPenalty?: number;
|
90
96
|
bestOf?: number;
|
97
|
+
logitBias?: Record<number, number>;
|
98
|
+
}
|
99
|
+
export interface OpenAITextGenerationModelSettings extends TextGenerationModelSettings, OpenAIModelSettings, Omit<OpenAITextGenerationCallSettings, "stop" | "maxTokens"> {
|
100
|
+
isUserIdForwardingEnabled?: boolean;
|
91
101
|
}
|
92
102
|
/**
|
93
103
|
* Create a text generation model that calls the OpenAI text completion API.
|
@@ -110,7 +120,7 @@ export interface OpenAITextGenerationModelSettings extends TextGenerationModelSe
|
|
110
120
|
export declare class OpenAITextGenerationModel extends AbstractModel<OpenAITextGenerationModelSettings> implements TextGenerationModel<string, OpenAITextGenerationResponse, OpenAITextGenerationDelta, OpenAITextGenerationModelSettings> {
|
111
121
|
constructor(settings: OpenAITextGenerationModelSettings);
|
112
122
|
readonly provider: "openai";
|
113
|
-
get modelName():
|
123
|
+
get modelName(): OpenAITextGenerationModelType;
|
114
124
|
readonly contextWindowSize: number;
|
115
125
|
readonly tokenizer: TikTokenTokenizer;
|
116
126
|
private get apiKey();
|
@@ -126,8 +136,8 @@ export declare class OpenAITextGenerationModel extends AbstractModel<OpenAITextG
|
|
126
136
|
model: string;
|
127
137
|
usage: {
|
128
138
|
prompt_tokens: number;
|
129
|
-
total_tokens: number;
|
130
139
|
completion_tokens: number;
|
140
|
+
total_tokens: number;
|
131
141
|
};
|
132
142
|
id: string;
|
133
143
|
created: number;
|
@@ -176,20 +186,20 @@ declare const openAITextGenerationResponseSchema: z.ZodObject<{
|
|
176
186
|
total_tokens: z.ZodNumber;
|
177
187
|
}, "strip", z.ZodTypeAny, {
|
178
188
|
prompt_tokens: number;
|
179
|
-
total_tokens: number;
|
180
189
|
completion_tokens: number;
|
190
|
+
total_tokens: number;
|
181
191
|
}, {
|
182
192
|
prompt_tokens: number;
|
183
|
-
total_tokens: number;
|
184
193
|
completion_tokens: number;
|
194
|
+
total_tokens: number;
|
185
195
|
}>;
|
186
196
|
}, "strip", z.ZodTypeAny, {
|
187
197
|
object: "text_completion";
|
188
198
|
model: string;
|
189
199
|
usage: {
|
190
200
|
prompt_tokens: number;
|
191
|
-
total_tokens: number;
|
192
201
|
completion_tokens: number;
|
202
|
+
total_tokens: number;
|
193
203
|
};
|
194
204
|
id: string;
|
195
205
|
created: number;
|
@@ -204,8 +214,8 @@ declare const openAITextGenerationResponseSchema: z.ZodObject<{
|
|
204
214
|
model: string;
|
205
215
|
usage: {
|
206
216
|
prompt_tokens: number;
|
207
|
-
total_tokens: number;
|
208
217
|
completion_tokens: number;
|
218
|
+
total_tokens: number;
|
209
219
|
};
|
210
220
|
id: string;
|
211
221
|
created: number;
|
@@ -232,8 +242,8 @@ export declare const OpenAITextResponseFormat: {
|
|
232
242
|
model: string;
|
233
243
|
usage: {
|
234
244
|
prompt_tokens: number;
|
235
|
-
total_tokens: number;
|
236
245
|
completion_tokens: number;
|
246
|
+
total_tokens: number;
|
237
247
|
};
|
238
248
|
id: string;
|
239
249
|
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
|
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
|
-
|
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
|
-
|
109
|
-
this.
|
110
|
-
|
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;
|
@@ -161,6 +192,7 @@ export class OpenAITextGenerationModel extends AbstractModel {
|
|
161
192
|
"presencePenalty",
|
162
193
|
"frequencyPenalty",
|
163
194
|
"bestOf",
|
195
|
+
"logitBias",
|
164
196
|
];
|
165
197
|
return Object.fromEntries(Object.entries(this.settings).filter(([key]) => eventSettingProperties.includes(key)));
|
166
198
|
}
|
@@ -234,7 +266,7 @@ const openAITextGenerationResponseSchema = z.object({
|
|
234
266
|
*
|
235
267
|
* console.log(response.choices[0].text);
|
236
268
|
*/
|
237
|
-
async function callOpenAITextGenerationAPI({ baseUrl = "https://api.openai.com/v1", headers, abortSignal, responseFormat, apiKey, model, prompt, suffix, maxTokens, temperature, topP, n, logprobs, echo, stop, presencePenalty, frequencyPenalty, bestOf, user, }) {
|
269
|
+
async function callOpenAITextGenerationAPI({ baseUrl = "https://api.openai.com/v1", headers, abortSignal, responseFormat, apiKey, model, prompt, suffix, maxTokens, temperature, topP, n, logprobs, echo, stop, presencePenalty, frequencyPenalty, bestOf, logitBias, user, }) {
|
238
270
|
return postJsonToApi({
|
239
271
|
url: `${baseUrl}/completions`,
|
240
272
|
headers: {
|
@@ -256,6 +288,7 @@ async function callOpenAITextGenerationAPI({ baseUrl = "https://api.openai.com/v
|
|
256
288
|
presence_penalty: presencePenalty,
|
257
289
|
frequency_penalty: frequencyPenalty,
|
258
290
|
best_of: bestOf,
|
291
|
+
logit_bias: logitBias,
|
259
292
|
user,
|
260
293
|
},
|
261
294
|
failedResponseHandler: failedOpenAICallResponseHandler,
|
@@ -1,6 +1,8 @@
|
|
1
1
|
import { TiktokenEncoding } from "js-tiktoken";
|
2
2
|
import { FullTokenizer } from "../../model-function/tokenize-text/Tokenizer.js";
|
3
|
-
import {
|
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:
|
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
|
-
|
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, }) =>
|
83
|
-
|
84
|
-
response.usage.
|
85
|
-
|
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
|
-
|
128
|
-
this.
|
129
|
-
|
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;
|
@@ -180,6 +219,9 @@ class OpenAIChatModel extends AbstractModel_js_1.AbstractModel {
|
|
180
219
|
"temperature",
|
181
220
|
"topP",
|
182
221
|
"n",
|
222
|
+
"presencePenalty",
|
223
|
+
"frequencyPenalty",
|
224
|
+
"logitBias",
|
183
225
|
];
|
184
226
|
return Object.fromEntries(Object.entries(this.settings).filter(([key]) => eventSettingProperties.includes(key)));
|
185
227
|
}
|
@@ -268,7 +310,7 @@ const openAIChatResponseSchema = zod_1.default.object({
|
|
268
310
|
total_tokens: zod_1.default.number(),
|
269
311
|
}),
|
270
312
|
});
|
271
|
-
async function callOpenAIChatCompletionAPI({ baseUrl = "https://api.openai.com/v1", headers, abortSignal, responseFormat, apiKey, model, messages, functions, functionCall, temperature, topP, n, stop, maxTokens, presencePenalty, frequencyPenalty, user, }) {
|
313
|
+
async function callOpenAIChatCompletionAPI({ baseUrl = "https://api.openai.com/v1", headers, abortSignal, responseFormat, apiKey, model, messages, functions, functionCall, temperature, topP, n, stop, maxTokens, presencePenalty, frequencyPenalty, logitBias, user, }) {
|
272
314
|
return (0, postToApi_js_1.postJsonToApi)({
|
273
315
|
url: `${baseUrl}/chat/completions`,
|
274
316
|
headers: {
|
@@ -288,6 +330,7 @@ async function callOpenAIChatCompletionAPI({ baseUrl = "https://api.openai.com/v
|
|
288
330
|
max_tokens: maxTokens,
|
289
331
|
presence_penalty: presencePenalty,
|
290
332
|
frequency_penalty: frequencyPenalty,
|
333
|
+
logit_bias: logitBias,
|
291
334
|
user,
|
292
335
|
},
|
293
336
|
failedResponseHandler: OpenAIError_js_1.failedOpenAICallResponseHandler,
|
@@ -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
|
74
|
-
|
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;
|
@@ -87,13 +101,14 @@ export interface OpenAIChatCallSettings {
|
|
87
101
|
functionCall?: "none" | "auto" | {
|
88
102
|
name: string;
|
89
103
|
};
|
104
|
+
stop?: string | string[];
|
105
|
+
maxTokens?: number;
|
90
106
|
temperature?: number;
|
91
107
|
topP?: number;
|
92
108
|
n?: number;
|
93
|
-
stop?: string | string[];
|
94
|
-
maxTokens?: number;
|
95
109
|
presencePenalty?: number;
|
96
110
|
frequencyPenalty?: number;
|
111
|
+
logitBias?: Record<number, number>;
|
97
112
|
}
|
98
113
|
export interface OpenAIChatSettings extends TextGenerationModelSettings, OpenAIModelSettings, Omit<OpenAIChatCallSettings, "stop" | "maxTokens"> {
|
99
114
|
isUserIdForwardingEnabled?: boolean;
|
@@ -120,7 +135,7 @@ export interface OpenAIChatSettings extends TextGenerationModelSettings, OpenAIM
|
|
120
135
|
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
136
|
constructor(settings: OpenAIChatSettings);
|
122
137
|
readonly provider: "openai";
|
123
|
-
get modelName():
|
138
|
+
get modelName(): OpenAIChatModelType;
|
124
139
|
readonly contextWindowSize: number;
|
125
140
|
readonly tokenizer: TikTokenTokenizer;
|
126
141
|
private get apiKey();
|
@@ -140,8 +155,8 @@ export declare class OpenAIChatModel extends AbstractModel<OpenAIChatSettings> i
|
|
140
155
|
model: string;
|
141
156
|
usage: {
|
142
157
|
prompt_tokens: number;
|
143
|
-
total_tokens: number;
|
144
158
|
completion_tokens: number;
|
159
|
+
total_tokens: number;
|
145
160
|
};
|
146
161
|
id: string;
|
147
162
|
created: number;
|
@@ -247,20 +262,20 @@ declare const openAIChatResponseSchema: z.ZodObject<{
|
|
247
262
|
total_tokens: z.ZodNumber;
|
248
263
|
}, "strip", z.ZodTypeAny, {
|
249
264
|
prompt_tokens: number;
|
250
|
-
total_tokens: number;
|
251
265
|
completion_tokens: number;
|
266
|
+
total_tokens: number;
|
252
267
|
}, {
|
253
268
|
prompt_tokens: number;
|
254
|
-
total_tokens: number;
|
255
269
|
completion_tokens: number;
|
270
|
+
total_tokens: number;
|
256
271
|
}>;
|
257
272
|
}, "strip", z.ZodTypeAny, {
|
258
273
|
object: "chat.completion";
|
259
274
|
model: string;
|
260
275
|
usage: {
|
261
276
|
prompt_tokens: number;
|
262
|
-
total_tokens: number;
|
263
277
|
completion_tokens: number;
|
278
|
+
total_tokens: number;
|
264
279
|
};
|
265
280
|
id: string;
|
266
281
|
created: number;
|
@@ -282,8 +297,8 @@ declare const openAIChatResponseSchema: z.ZodObject<{
|
|
282
297
|
model: string;
|
283
298
|
usage: {
|
284
299
|
prompt_tokens: number;
|
285
|
-
total_tokens: number;
|
286
300
|
completion_tokens: number;
|
301
|
+
total_tokens: number;
|
287
302
|
};
|
288
303
|
id: string;
|
289
304
|
created: number;
|
@@ -317,8 +332,8 @@ export declare const OpenAIChatResponseFormat: {
|
|
317
332
|
model: string;
|
318
333
|
usage: {
|
319
334
|
prompt_tokens: number;
|
320
|
-
total_tokens: number;
|
321
335
|
completion_tokens: number;
|
336
|
+
total_tokens: number;
|
322
337
|
};
|
323
338
|
id: string;
|
324
339
|
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
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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
|
-
|
120
|
-
this.
|
121
|
-
|
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;
|
@@ -172,6 +210,9 @@ export class OpenAIChatModel extends AbstractModel {
|
|
172
210
|
"temperature",
|
173
211
|
"topP",
|
174
212
|
"n",
|
213
|
+
"presencePenalty",
|
214
|
+
"frequencyPenalty",
|
215
|
+
"logitBias",
|
175
216
|
];
|
176
217
|
return Object.fromEntries(Object.entries(this.settings).filter(([key]) => eventSettingProperties.includes(key)));
|
177
218
|
}
|
@@ -259,7 +300,7 @@ const openAIChatResponseSchema = z.object({
|
|
259
300
|
total_tokens: z.number(),
|
260
301
|
}),
|
261
302
|
});
|
262
|
-
async function callOpenAIChatCompletionAPI({ baseUrl = "https://api.openai.com/v1", headers, abortSignal, responseFormat, apiKey, model, messages, functions, functionCall, temperature, topP, n, stop, maxTokens, presencePenalty, frequencyPenalty, user, }) {
|
303
|
+
async function callOpenAIChatCompletionAPI({ baseUrl = "https://api.openai.com/v1", headers, abortSignal, responseFormat, apiKey, model, messages, functions, functionCall, temperature, topP, n, stop, maxTokens, presencePenalty, frequencyPenalty, logitBias, user, }) {
|
263
304
|
return postJsonToApi({
|
264
305
|
url: `${baseUrl}/chat/completions`,
|
265
306
|
headers: {
|
@@ -279,6 +320,7 @@ async function callOpenAIChatCompletionAPI({ baseUrl = "https://api.openai.com/v
|
|
279
320
|
max_tokens: maxTokens,
|
280
321
|
presence_penalty: presencePenalty,
|
281
322
|
frequency_penalty: frequencyPenalty,
|
323
|
+
logit_bias: logitBias,
|
282
324
|
user,
|
283
325
|
},
|
284
326
|
failedResponseHandler: failedOpenAICallResponseHandler,
|
@@ -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
|
-
|
18
|
-
|
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
|
-
|
15
|
-
|
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;
|