modelfusion 0.2.0 → 0.4.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 +23 -21
- package/model-provider/cohere/CohereError.cjs +11 -0
- package/model-provider/cohere/CohereError.js +11 -0
- package/model-provider/cohere/CohereTextEmbeddingModel.cjs +3 -1
- package/model-provider/cohere/CohereTextEmbeddingModel.js +3 -1
- package/model-provider/cohere/CohereTextGenerationModel.cjs +3 -1
- package/model-provider/cohere/CohereTextGenerationModel.js +3 -1
- package/model-provider/cohere/CohereTokenizer.cjs +6 -2
- package/model-provider/cohere/CohereTokenizer.js +6 -2
- package/model-provider/huggingface/HuggingFaceTextEmbeddingModel.cjs +138 -0
- package/model-provider/huggingface/HuggingFaceTextEmbeddingModel.d.ts +57 -0
- package/model-provider/huggingface/HuggingFaceTextEmbeddingModel.js +131 -0
- package/model-provider/huggingface/HuggingFaceTextGenerationModel.cjs +3 -1
- package/model-provider/huggingface/HuggingFaceTextGenerationModel.js +3 -1
- package/model-provider/huggingface/index.cjs +1 -0
- package/model-provider/huggingface/index.d.ts +1 -0
- package/model-provider/huggingface/index.js +1 -0
- package/model-provider/llamacpp/LlamaCppTextEmbeddingModel.cjs +2 -1
- package/model-provider/llamacpp/LlamaCppTextEmbeddingModel.d.ts +8 -7
- package/model-provider/llamacpp/LlamaCppTextEmbeddingModel.js +2 -1
- package/model-provider/openai/OpenAIError.cjs +21 -9
- package/model-provider/openai/OpenAIError.d.ts +3 -3
- package/model-provider/openai/OpenAIError.js +21 -9
- package/model-provider/openai/OpenAIImageGenerationModel.cjs +3 -1
- package/model-provider/openai/OpenAIImageGenerationModel.js +3 -1
- package/model-provider/openai/OpenAITextEmbeddingModel.cjs +3 -1
- package/model-provider/openai/OpenAITextEmbeddingModel.js +3 -1
- package/model-provider/openai/OpenAITextGenerationModel.cjs +5 -2
- package/model-provider/openai/OpenAITextGenerationModel.d.ts +1 -0
- package/model-provider/openai/OpenAITextGenerationModel.js +5 -2
- package/model-provider/openai/OpenAITranscriptionModel.cjs +3 -2
- package/model-provider/openai/OpenAITranscriptionModel.js +3 -2
- package/model-provider/openai/chat/OpenAIChatModel.cjs +5 -2
- package/model-provider/openai/chat/OpenAIChatModel.d.ts +1 -0
- package/model-provider/openai/chat/OpenAIChatModel.js +5 -2
- package/model-provider/stability/StabilityImageGenerationModel.cjs +3 -1
- package/model-provider/stability/StabilityImageGenerationModel.js +3 -1
- package/package.json +1 -1
- package/prompt/chat/trimChatPrompt.cjs +2 -0
- package/prompt/chat/trimChatPrompt.d.ts +2 -0
- package/prompt/chat/trimChatPrompt.js +2 -0
- package/util/api/postToApi.cjs +6 -11
- package/util/api/postToApi.d.ts +4 -5
- package/util/api/postToApi.js +6 -11
- package/util/api/retryWithExponentialBackoff.cjs +1 -1
- package/util/api/retryWithExponentialBackoff.js +1 -1
package/README.md
CHANGED
@@ -366,7 +366,7 @@ const { chunks } = await retrieveTextChunks(
|
|
366
366
|
| [Stream text](https://modelfusion.dev/guide/function/generate-text) | ✅ | ✅ | ✅ | | | |
|
367
367
|
| [Generate JSON](https://modelfusion.dev/guide/function/generate-json) | chat models | | | | | |
|
368
368
|
| [Generate JSON or Text](https://modelfusion.dev/guide/function/generate-json-or-text) | chat models | | | | | |
|
369
|
-
| [Embed text](https://modelfusion.dev/guide/function/embed-text) | ✅ | ✅ | ✅ |
|
369
|
+
| [Embed text](https://modelfusion.dev/guide/function/embed-text) | ✅ | ✅ | ✅ | ✅ | | |
|
370
370
|
| [Tokenize text](https://modelfusion.dev/guide/function/tokenize-text) | full | full | basic | | | |
|
371
371
|
| [Generate image](https://modelfusion.dev/guide/function/generate-image) | ✅ | | | | ✅ | ✅ |
|
372
372
|
| [Transcribe audio](https://modelfusion.dev/guide/function/transcribe-audio) | ✅ | | | | | |
|
@@ -377,17 +377,21 @@ const { chunks } = await retrieveTextChunks(
|
|
377
377
|
- [Memory](https://modelfusion.dev/integration/vector-index/memory)
|
378
378
|
- [Pinecone](https://modelfusion.dev/integration/vector-index/pinecone)
|
379
379
|
|
380
|
-
###
|
380
|
+
### Observability
|
381
381
|
|
382
|
-
|
382
|
+
- [Helicone](https://modelfusion.dev/integration/observability/helicone)
|
383
383
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
384
|
+
### Prompt Formats
|
385
|
+
|
386
|
+
Use higher level prompts that are mapped into model specific prompt formats.
|
387
|
+
|
388
|
+
| Prompt Format | Instruction Prompt | Chat Prompt |
|
389
|
+
| ------------- | ------------------ | ----------- |
|
390
|
+
| OpenAI Chat | ✅ | ✅ |
|
391
|
+
| Llama 2 | ✅ | ✅ |
|
392
|
+
| Alpaca | ✅ | ❌ |
|
393
|
+
| Vicuna | ❌ | ✅ |
|
394
|
+
| Generic Text | ✅ | ✅ |
|
391
395
|
|
392
396
|
## Documentation
|
393
397
|
|
@@ -402,17 +406,15 @@ Use higher level prompts that are mapped into model specific prompts.
|
|
402
406
|
|
403
407
|
Examples for the individual functions and objects.
|
404
408
|
|
405
|
-
### [
|
406
|
-
|
407
|
-
> _terminal app_, _PDF parsing_, _recursive information extraction_, _in memory vector index, \_style example retrieval_, _OpenAI GPT-4_, _cost calculation_
|
409
|
+
### [Chatbot (Terminal)](https://github.com/lgrammel/modelfusion/tree/main/examples/chatbot-terminal)
|
408
410
|
|
409
|
-
|
411
|
+
> _Terminal app_, _chat_, _llama.cpp_
|
410
412
|
|
411
|
-
### [
|
413
|
+
### [Chatbot (Next.JS)](https://github.com/lgrammel/modelfusion/tree/main/examples/chatbot-next-js)
|
412
414
|
|
413
415
|
> _Next.js app_, _OpenAI GPT-3.5-turbo_, _streaming_, _abort handling_
|
414
416
|
|
415
|
-
A
|
417
|
+
A web chat with an AI assistant, implemented as a Next.js app.
|
416
418
|
|
417
419
|
### [Image generator (Next.js)](https://github.com/lgrammel/modelfusion/tree/main/examples/image-generator-next-js)
|
418
420
|
|
@@ -426,20 +428,20 @@ Create an 19th century painting image for your input.
|
|
426
428
|
|
427
429
|
Record audio with push-to-talk and transcribe it using Whisper, implemented as a Next.js app. The app shows a list of the transcriptions.
|
428
430
|
|
429
|
-
### [BabyAGI
|
431
|
+
### [BabyAGI Agent](https://github.com/lgrammel/modelfusion/tree/main/examples/babyagi-agent)
|
430
432
|
|
431
433
|
> _terminal app_, _agent_, _BabyAGI_, _OpenAI text-davinci-003_
|
432
434
|
|
433
435
|
TypeScript implementation of the classic [BabyAGI](https://github.com/yoheinakajima/babyagi/blob/main/classic/babyagi.py) by [@yoheinakajima](https://twitter.com/yoheinakajima) without embeddings.
|
434
436
|
|
435
|
-
### [Middle school math](https://github.com/lgrammel/modelfusion/tree/main/examples/middle-school-math)
|
437
|
+
### [Middle school math agent](https://github.com/lgrammel/modelfusion/tree/main/examples/middle-school-math-agent)
|
436
438
|
|
437
439
|
> _terminal app_, _agent_, _tools_, _GPT-4_
|
438
440
|
|
439
441
|
Small agent that solves middle school math problems. It uses a calculator tool to solve the problems.
|
440
442
|
|
441
|
-
### [
|
443
|
+
### [PDF to Tweet](https://github.com/lgrammel/modelfusion/tree/main/examples/pdf-to-tweet)
|
442
444
|
|
443
|
-
>
|
445
|
+
> _terminal app_, _PDF parsing_, _recursive information extraction_, _in memory vector index, \_style example retrieval_, _OpenAI GPT-4_, _cost calculation_
|
444
446
|
|
445
|
-
|
447
|
+
Extracts information about a topic from a PDF and writes a tweet in your own style about it.
|
@@ -25,6 +25,17 @@ class CohereError extends ApiCallError_js_1.ApiCallError {
|
|
25
25
|
exports.CohereError = CohereError;
|
26
26
|
const failedCohereCallResponseHandler = async ({ response, url, requestBodyValues }) => {
|
27
27
|
const responseBody = await response.text();
|
28
|
+
// For some errors, the body of Cohere responses is empty:
|
29
|
+
if (responseBody.trim() === "") {
|
30
|
+
return new CohereError({
|
31
|
+
url,
|
32
|
+
requestBodyValues,
|
33
|
+
statusCode: response.status,
|
34
|
+
data: {
|
35
|
+
message: response.statusText,
|
36
|
+
},
|
37
|
+
});
|
38
|
+
}
|
28
39
|
const parsedError = exports.cohereErrorDataSchema.parse(secure_json_parse_1.default.parse(responseBody));
|
29
40
|
return new CohereError({
|
30
41
|
url,
|
@@ -18,6 +18,17 @@ export class CohereError extends ApiCallError {
|
|
18
18
|
}
|
19
19
|
export const failedCohereCallResponseHandler = async ({ response, url, requestBodyValues }) => {
|
20
20
|
const responseBody = await response.text();
|
21
|
+
// For some errors, the body of Cohere responses is empty:
|
22
|
+
if (responseBody.trim() === "") {
|
23
|
+
return new CohereError({
|
24
|
+
url,
|
25
|
+
requestBodyValues,
|
26
|
+
statusCode: response.status,
|
27
|
+
data: {
|
28
|
+
message: response.statusText,
|
29
|
+
},
|
30
|
+
});
|
31
|
+
}
|
21
32
|
const parsedError = cohereErrorDataSchema.parse(SecureJSON.parse(responseBody));
|
22
33
|
return new CohereError({
|
23
34
|
url,
|
@@ -159,7 +159,9 @@ const cohereTextEmbeddingResponseSchema = zod_1.default.object({
|
|
159
159
|
async function callCohereEmbeddingAPI({ baseUrl = "https://api.cohere.ai/v1", abortSignal, apiKey, model, texts, truncate, }) {
|
160
160
|
return (0, postToApi_js_1.postJsonToApi)({
|
161
161
|
url: `${baseUrl}/embed`,
|
162
|
-
|
162
|
+
headers: {
|
163
|
+
Authorization: `Bearer ${apiKey}`,
|
164
|
+
},
|
163
165
|
body: {
|
164
166
|
model,
|
165
167
|
texts,
|
@@ -152,7 +152,9 @@ const cohereTextEmbeddingResponseSchema = z.object({
|
|
152
152
|
async function callCohereEmbeddingAPI({ baseUrl = "https://api.cohere.ai/v1", abortSignal, apiKey, model, texts, truncate, }) {
|
153
153
|
return postJsonToApi({
|
154
154
|
url: `${baseUrl}/embed`,
|
155
|
-
|
155
|
+
headers: {
|
156
|
+
Authorization: `Bearer ${apiKey}`,
|
157
|
+
},
|
156
158
|
body: {
|
157
159
|
model,
|
158
160
|
texts,
|
@@ -179,7 +179,9 @@ const cohereTextGenerationResponseSchema = zod_1.z.object({
|
|
179
179
|
async function callCohereTextGenerationAPI({ baseUrl = "https://api.cohere.ai/v1", abortSignal, responseFormat, apiKey, model, prompt, numGenerations, maxTokens, temperature, k, p, frequencyPenalty, presencePenalty, endSequences, stopSequences, returnLikelihoods, logitBias, truncate, }) {
|
180
180
|
return (0, postToApi_js_1.postJsonToApi)({
|
181
181
|
url: `${baseUrl}/generate`,
|
182
|
-
|
182
|
+
headers: {
|
183
|
+
Authorization: `Bearer ${apiKey}`,
|
184
|
+
},
|
183
185
|
body: {
|
184
186
|
stream: responseFormat.stream,
|
185
187
|
model,
|
@@ -172,7 +172,9 @@ const cohereTextGenerationResponseSchema = z.object({
|
|
172
172
|
async function callCohereTextGenerationAPI({ baseUrl = "https://api.cohere.ai/v1", abortSignal, responseFormat, apiKey, model, prompt, numGenerations, maxTokens, temperature, k, p, frequencyPenalty, presencePenalty, endSequences, stopSequences, returnLikelihoods, logitBias, truncate, }) {
|
173
173
|
return postJsonToApi({
|
174
174
|
url: `${baseUrl}/generate`,
|
175
|
-
|
175
|
+
headers: {
|
176
|
+
Authorization: `Bearer ${apiKey}`,
|
177
|
+
},
|
176
178
|
body: {
|
177
179
|
stream: responseFormat.stream,
|
178
180
|
model,
|
@@ -97,7 +97,9 @@ const cohereDetokenizationResponseSchema = zod_1.default.object({
|
|
97
97
|
async function callCohereDetokenizeAPI({ baseUrl = "https://api.cohere.ai/v1", abortSignal, apiKey, model, tokens, }) {
|
98
98
|
return (0, postToApi_js_1.postJsonToApi)({
|
99
99
|
url: `${baseUrl}/detokenize`,
|
100
|
-
|
100
|
+
headers: {
|
101
|
+
Authorization: `Bearer ${apiKey}`,
|
102
|
+
},
|
101
103
|
body: {
|
102
104
|
model,
|
103
105
|
tokens,
|
@@ -124,7 +126,9 @@ const cohereTokenizationResponseSchema = zod_1.default.object({
|
|
124
126
|
async function callCohereTokenizeAPI({ baseUrl = "https://api.cohere.ai/v1", abortSignal, apiKey, model, text, }) {
|
125
127
|
return (0, postToApi_js_1.postJsonToApi)({
|
126
128
|
url: `${baseUrl}/tokenize`,
|
127
|
-
|
129
|
+
headers: {
|
130
|
+
Authorization: `Bearer ${apiKey}`,
|
131
|
+
},
|
128
132
|
body: {
|
129
133
|
model,
|
130
134
|
text,
|
@@ -90,7 +90,9 @@ const cohereDetokenizationResponseSchema = z.object({
|
|
90
90
|
async function callCohereDetokenizeAPI({ baseUrl = "https://api.cohere.ai/v1", abortSignal, apiKey, model, tokens, }) {
|
91
91
|
return postJsonToApi({
|
92
92
|
url: `${baseUrl}/detokenize`,
|
93
|
-
|
93
|
+
headers: {
|
94
|
+
Authorization: `Bearer ${apiKey}`,
|
95
|
+
},
|
94
96
|
body: {
|
95
97
|
model,
|
96
98
|
tokens,
|
@@ -117,7 +119,9 @@ const cohereTokenizationResponseSchema = z.object({
|
|
117
119
|
async function callCohereTokenizeAPI({ baseUrl = "https://api.cohere.ai/v1", abortSignal, apiKey, model, text, }) {
|
118
120
|
return postJsonToApi({
|
119
121
|
url: `${baseUrl}/tokenize`,
|
120
|
-
|
122
|
+
headers: {
|
123
|
+
Authorization: `Bearer ${apiKey}`,
|
124
|
+
},
|
121
125
|
body: {
|
122
126
|
model,
|
123
127
|
text,
|
@@ -0,0 +1,138 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.HuggingFaceTextEmbeddingModel = void 0;
|
7
|
+
const zod_1 = __importDefault(require("zod"));
|
8
|
+
const AbstractModel_js_1 = require("../../model-function/AbstractModel.cjs");
|
9
|
+
const callWithRetryAndThrottle_js_1 = require("../../util/api/callWithRetryAndThrottle.cjs");
|
10
|
+
const postToApi_js_1 = require("../../util/api/postToApi.cjs");
|
11
|
+
const HuggingFaceError_js_1 = require("./HuggingFaceError.cjs");
|
12
|
+
/**
|
13
|
+
* Create a text embeddinng model that calls a Hugging Face Inference API Feature Extraction Task.
|
14
|
+
*
|
15
|
+
* @see https://huggingface.co/docs/api-inference/detailed_parameters#feature-extraction-task
|
16
|
+
*
|
17
|
+
* @example
|
18
|
+
* const model = new HuggingFaceTextGenerationModel({
|
19
|
+
* model: "intfloat/e5-base-v2",
|
20
|
+
* maxTexstsPerCall: 5,
|
21
|
+
* retry: retryWithExponentialBackoff({ maxTries: 5 }),
|
22
|
+
* });
|
23
|
+
*
|
24
|
+
* const { embeddings } = await embedTexts(
|
25
|
+
* model,
|
26
|
+
* [
|
27
|
+
* "At first, Nox didn't know what to do with the pup.",
|
28
|
+
* "He keenly observed and absorbed everything around him, from the birds in the sky to the trees in the forest.",
|
29
|
+
* ]
|
30
|
+
* );
|
31
|
+
*/
|
32
|
+
class HuggingFaceTextEmbeddingModel extends AbstractModel_js_1.AbstractModel {
|
33
|
+
constructor(settings) {
|
34
|
+
super({ settings });
|
35
|
+
Object.defineProperty(this, "provider", {
|
36
|
+
enumerable: true,
|
37
|
+
configurable: true,
|
38
|
+
writable: true,
|
39
|
+
value: "huggingface"
|
40
|
+
});
|
41
|
+
Object.defineProperty(this, "maxTextsPerCall", {
|
42
|
+
enumerable: true,
|
43
|
+
configurable: true,
|
44
|
+
writable: true,
|
45
|
+
value: void 0
|
46
|
+
});
|
47
|
+
Object.defineProperty(this, "contextWindowSize", {
|
48
|
+
enumerable: true,
|
49
|
+
configurable: true,
|
50
|
+
writable: true,
|
51
|
+
value: undefined
|
52
|
+
});
|
53
|
+
Object.defineProperty(this, "embeddingDimensions", {
|
54
|
+
enumerable: true,
|
55
|
+
configurable: true,
|
56
|
+
writable: true,
|
57
|
+
value: void 0
|
58
|
+
});
|
59
|
+
Object.defineProperty(this, "tokenizer", {
|
60
|
+
enumerable: true,
|
61
|
+
configurable: true,
|
62
|
+
writable: true,
|
63
|
+
value: undefined
|
64
|
+
});
|
65
|
+
Object.defineProperty(this, "countPromptTokens", {
|
66
|
+
enumerable: true,
|
67
|
+
configurable: true,
|
68
|
+
writable: true,
|
69
|
+
value: undefined
|
70
|
+
});
|
71
|
+
// There is no limit documented in the HuggingFace API. Use 1024 as a reasonable default.
|
72
|
+
this.maxTextsPerCall = settings.maxTextsPerCall ?? 1024;
|
73
|
+
this.embeddingDimensions = settings.embeddingDimensions;
|
74
|
+
}
|
75
|
+
get modelName() {
|
76
|
+
return this.settings.model;
|
77
|
+
}
|
78
|
+
get apiKey() {
|
79
|
+
const apiKey = this.settings.apiKey ?? process.env.HUGGINGFACE_API_KEY;
|
80
|
+
if (apiKey == null) {
|
81
|
+
throw new Error("No Hugging Face API key provided. Pass it in the constructor or set the HUGGINGFACE_API_KEY environment variable.");
|
82
|
+
}
|
83
|
+
return apiKey;
|
84
|
+
}
|
85
|
+
async callAPI(texts, options) {
|
86
|
+
if (texts.length > this.maxTextsPerCall) {
|
87
|
+
throw new Error(`The HuggingFace feature extraction API is configured to only support ${this.maxTextsPerCall} texts per API call.`);
|
88
|
+
}
|
89
|
+
const run = options?.run;
|
90
|
+
const settings = options?.settings;
|
91
|
+
const callSettings = Object.assign({
|
92
|
+
apiKey: this.apiKey,
|
93
|
+
options: {
|
94
|
+
useCache: true,
|
95
|
+
waitForModel: true,
|
96
|
+
},
|
97
|
+
}, this.settings, settings, {
|
98
|
+
abortSignal: run?.abortSignal,
|
99
|
+
inputs: texts,
|
100
|
+
});
|
101
|
+
return (0, callWithRetryAndThrottle_js_1.callWithRetryAndThrottle)({
|
102
|
+
retry: this.settings.retry,
|
103
|
+
throttle: this.settings.throttle,
|
104
|
+
call: async () => callHuggingFaceTextGenerationAPI(callSettings),
|
105
|
+
});
|
106
|
+
}
|
107
|
+
generateEmbeddingResponse(texts, options) {
|
108
|
+
return this.callAPI(texts, options);
|
109
|
+
}
|
110
|
+
extractEmbeddings(response) {
|
111
|
+
return response;
|
112
|
+
}
|
113
|
+
withSettings(additionalSettings) {
|
114
|
+
return new HuggingFaceTextEmbeddingModel(Object.assign({}, this.settings, additionalSettings));
|
115
|
+
}
|
116
|
+
}
|
117
|
+
exports.HuggingFaceTextEmbeddingModel = HuggingFaceTextEmbeddingModel;
|
118
|
+
const huggingFaceTextEmbeddingResponseSchema = zod_1.default.array(zod_1.default.array(zod_1.default.number()));
|
119
|
+
async function callHuggingFaceTextGenerationAPI({ baseUrl = "https://api-inference.huggingface.co/pipeline/feature-extraction", abortSignal, apiKey, model, inputs, options, }) {
|
120
|
+
return (0, postToApi_js_1.postJsonToApi)({
|
121
|
+
url: `${baseUrl}/${model}`,
|
122
|
+
headers: {
|
123
|
+
Authorization: `Bearer ${apiKey}`,
|
124
|
+
},
|
125
|
+
body: {
|
126
|
+
inputs,
|
127
|
+
options: options
|
128
|
+
? {
|
129
|
+
use_cache: options?.useCache,
|
130
|
+
wait_for_model: options?.waitForModel,
|
131
|
+
}
|
132
|
+
: undefined,
|
133
|
+
},
|
134
|
+
failedResponseHandler: HuggingFaceError_js_1.failedHuggingFaceCallResponseHandler,
|
135
|
+
successfulResponseHandler: (0, postToApi_js_1.createJsonResponseHandler)(huggingFaceTextEmbeddingResponseSchema),
|
136
|
+
abortSignal,
|
137
|
+
});
|
138
|
+
}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
import z from "zod";
|
2
|
+
import { AbstractModel } from "../../model-function/AbstractModel.js";
|
3
|
+
import { FunctionOptions } from "../../model-function/FunctionOptions.js";
|
4
|
+
import { TextEmbeddingModel, TextEmbeddingModelSettings } from "../../model-function/embed-text/TextEmbeddingModel.js";
|
5
|
+
import { RetryFunction } from "../../util/api/RetryFunction.js";
|
6
|
+
import { ThrottleFunction } from "../../util/api/ThrottleFunction.js";
|
7
|
+
export interface HuggingFaceTextEmbeddingModelSettings extends TextEmbeddingModelSettings {
|
8
|
+
model: string;
|
9
|
+
baseUrl?: string;
|
10
|
+
apiKey?: string;
|
11
|
+
maxTextsPerCall?: number;
|
12
|
+
embeddingDimensions?: number;
|
13
|
+
retry?: RetryFunction;
|
14
|
+
throttle?: ThrottleFunction;
|
15
|
+
options?: {
|
16
|
+
useCache?: boolean;
|
17
|
+
waitForModel?: boolean;
|
18
|
+
};
|
19
|
+
}
|
20
|
+
/**
|
21
|
+
* Create a text embeddinng model that calls a Hugging Face Inference API Feature Extraction Task.
|
22
|
+
*
|
23
|
+
* @see https://huggingface.co/docs/api-inference/detailed_parameters#feature-extraction-task
|
24
|
+
*
|
25
|
+
* @example
|
26
|
+
* const model = new HuggingFaceTextGenerationModel({
|
27
|
+
* model: "intfloat/e5-base-v2",
|
28
|
+
* maxTexstsPerCall: 5,
|
29
|
+
* retry: retryWithExponentialBackoff({ maxTries: 5 }),
|
30
|
+
* });
|
31
|
+
*
|
32
|
+
* const { embeddings } = await embedTexts(
|
33
|
+
* model,
|
34
|
+
* [
|
35
|
+
* "At first, Nox didn't know what to do with the pup.",
|
36
|
+
* "He keenly observed and absorbed everything around him, from the birds in the sky to the trees in the forest.",
|
37
|
+
* ]
|
38
|
+
* );
|
39
|
+
*/
|
40
|
+
export declare class HuggingFaceTextEmbeddingModel extends AbstractModel<HuggingFaceTextEmbeddingModelSettings> implements TextEmbeddingModel<HuggingFaceTextEmbeddingResponse, HuggingFaceTextEmbeddingModelSettings> {
|
41
|
+
constructor(settings: HuggingFaceTextEmbeddingModelSettings);
|
42
|
+
readonly provider = "huggingface";
|
43
|
+
get modelName(): string;
|
44
|
+
readonly maxTextsPerCall: number;
|
45
|
+
readonly contextWindowSize: undefined;
|
46
|
+
readonly embeddingDimensions: number | undefined;
|
47
|
+
readonly tokenizer: undefined;
|
48
|
+
private get apiKey();
|
49
|
+
callAPI(texts: Array<string>, options?: FunctionOptions<HuggingFaceTextEmbeddingModelSettings>): Promise<HuggingFaceTextEmbeddingResponse>;
|
50
|
+
readonly countPromptTokens: undefined;
|
51
|
+
generateEmbeddingResponse(texts: string[], options?: FunctionOptions<HuggingFaceTextEmbeddingModelSettings>): Promise<number[][]>;
|
52
|
+
extractEmbeddings(response: HuggingFaceTextEmbeddingResponse): number[][];
|
53
|
+
withSettings(additionalSettings: Partial<HuggingFaceTextEmbeddingModelSettings>): this;
|
54
|
+
}
|
55
|
+
declare const huggingFaceTextEmbeddingResponseSchema: z.ZodArray<z.ZodArray<z.ZodNumber, "many">, "many">;
|
56
|
+
export type HuggingFaceTextEmbeddingResponse = z.infer<typeof huggingFaceTextEmbeddingResponseSchema>;
|
57
|
+
export {};
|
@@ -0,0 +1,131 @@
|
|
1
|
+
import z from "zod";
|
2
|
+
import { AbstractModel } from "../../model-function/AbstractModel.js";
|
3
|
+
import { callWithRetryAndThrottle } from "../../util/api/callWithRetryAndThrottle.js";
|
4
|
+
import { createJsonResponseHandler, postJsonToApi, } from "../../util/api/postToApi.js";
|
5
|
+
import { failedHuggingFaceCallResponseHandler } from "./HuggingFaceError.js";
|
6
|
+
/**
|
7
|
+
* Create a text embeddinng model that calls a Hugging Face Inference API Feature Extraction Task.
|
8
|
+
*
|
9
|
+
* @see https://huggingface.co/docs/api-inference/detailed_parameters#feature-extraction-task
|
10
|
+
*
|
11
|
+
* @example
|
12
|
+
* const model = new HuggingFaceTextGenerationModel({
|
13
|
+
* model: "intfloat/e5-base-v2",
|
14
|
+
* maxTexstsPerCall: 5,
|
15
|
+
* retry: retryWithExponentialBackoff({ maxTries: 5 }),
|
16
|
+
* });
|
17
|
+
*
|
18
|
+
* const { embeddings } = await embedTexts(
|
19
|
+
* model,
|
20
|
+
* [
|
21
|
+
* "At first, Nox didn't know what to do with the pup.",
|
22
|
+
* "He keenly observed and absorbed everything around him, from the birds in the sky to the trees in the forest.",
|
23
|
+
* ]
|
24
|
+
* );
|
25
|
+
*/
|
26
|
+
export class HuggingFaceTextEmbeddingModel extends AbstractModel {
|
27
|
+
constructor(settings) {
|
28
|
+
super({ settings });
|
29
|
+
Object.defineProperty(this, "provider", {
|
30
|
+
enumerable: true,
|
31
|
+
configurable: true,
|
32
|
+
writable: true,
|
33
|
+
value: "huggingface"
|
34
|
+
});
|
35
|
+
Object.defineProperty(this, "maxTextsPerCall", {
|
36
|
+
enumerable: true,
|
37
|
+
configurable: true,
|
38
|
+
writable: true,
|
39
|
+
value: void 0
|
40
|
+
});
|
41
|
+
Object.defineProperty(this, "contextWindowSize", {
|
42
|
+
enumerable: true,
|
43
|
+
configurable: true,
|
44
|
+
writable: true,
|
45
|
+
value: undefined
|
46
|
+
});
|
47
|
+
Object.defineProperty(this, "embeddingDimensions", {
|
48
|
+
enumerable: true,
|
49
|
+
configurable: true,
|
50
|
+
writable: true,
|
51
|
+
value: void 0
|
52
|
+
});
|
53
|
+
Object.defineProperty(this, "tokenizer", {
|
54
|
+
enumerable: true,
|
55
|
+
configurable: true,
|
56
|
+
writable: true,
|
57
|
+
value: undefined
|
58
|
+
});
|
59
|
+
Object.defineProperty(this, "countPromptTokens", {
|
60
|
+
enumerable: true,
|
61
|
+
configurable: true,
|
62
|
+
writable: true,
|
63
|
+
value: undefined
|
64
|
+
});
|
65
|
+
// There is no limit documented in the HuggingFace API. Use 1024 as a reasonable default.
|
66
|
+
this.maxTextsPerCall = settings.maxTextsPerCall ?? 1024;
|
67
|
+
this.embeddingDimensions = settings.embeddingDimensions;
|
68
|
+
}
|
69
|
+
get modelName() {
|
70
|
+
return this.settings.model;
|
71
|
+
}
|
72
|
+
get apiKey() {
|
73
|
+
const apiKey = this.settings.apiKey ?? process.env.HUGGINGFACE_API_KEY;
|
74
|
+
if (apiKey == null) {
|
75
|
+
throw new Error("No Hugging Face API key provided. Pass it in the constructor or set the HUGGINGFACE_API_KEY environment variable.");
|
76
|
+
}
|
77
|
+
return apiKey;
|
78
|
+
}
|
79
|
+
async callAPI(texts, options) {
|
80
|
+
if (texts.length > this.maxTextsPerCall) {
|
81
|
+
throw new Error(`The HuggingFace feature extraction API is configured to only support ${this.maxTextsPerCall} texts per API call.`);
|
82
|
+
}
|
83
|
+
const run = options?.run;
|
84
|
+
const settings = options?.settings;
|
85
|
+
const callSettings = Object.assign({
|
86
|
+
apiKey: this.apiKey,
|
87
|
+
options: {
|
88
|
+
useCache: true,
|
89
|
+
waitForModel: true,
|
90
|
+
},
|
91
|
+
}, this.settings, settings, {
|
92
|
+
abortSignal: run?.abortSignal,
|
93
|
+
inputs: texts,
|
94
|
+
});
|
95
|
+
return callWithRetryAndThrottle({
|
96
|
+
retry: this.settings.retry,
|
97
|
+
throttle: this.settings.throttle,
|
98
|
+
call: async () => callHuggingFaceTextGenerationAPI(callSettings),
|
99
|
+
});
|
100
|
+
}
|
101
|
+
generateEmbeddingResponse(texts, options) {
|
102
|
+
return this.callAPI(texts, options);
|
103
|
+
}
|
104
|
+
extractEmbeddings(response) {
|
105
|
+
return response;
|
106
|
+
}
|
107
|
+
withSettings(additionalSettings) {
|
108
|
+
return new HuggingFaceTextEmbeddingModel(Object.assign({}, this.settings, additionalSettings));
|
109
|
+
}
|
110
|
+
}
|
111
|
+
const huggingFaceTextEmbeddingResponseSchema = z.array(z.array(z.number()));
|
112
|
+
async function callHuggingFaceTextGenerationAPI({ baseUrl = "https://api-inference.huggingface.co/pipeline/feature-extraction", abortSignal, apiKey, model, inputs, options, }) {
|
113
|
+
return postJsonToApi({
|
114
|
+
url: `${baseUrl}/${model}`,
|
115
|
+
headers: {
|
116
|
+
Authorization: `Bearer ${apiKey}`,
|
117
|
+
},
|
118
|
+
body: {
|
119
|
+
inputs,
|
120
|
+
options: options
|
121
|
+
? {
|
122
|
+
use_cache: options?.useCache,
|
123
|
+
wait_for_model: options?.waitForModel,
|
124
|
+
}
|
125
|
+
: undefined,
|
126
|
+
},
|
127
|
+
failedResponseHandler: failedHuggingFaceCallResponseHandler,
|
128
|
+
successfulResponseHandler: createJsonResponseHandler(huggingFaceTextEmbeddingResponseSchema),
|
129
|
+
abortSignal,
|
130
|
+
});
|
131
|
+
}
|
@@ -149,7 +149,9 @@ const huggingFaceTextGenerationResponseSchema = zod_1.default.array(zod_1.defaul
|
|
149
149
|
async function callHuggingFaceTextGenerationAPI({ baseUrl = "https://api-inference.huggingface.co/models", abortSignal, apiKey, model, inputs, topK, topP, temperature, repetitionPenalty, maxNewTokens, maxTime, numReturnSequences, doSample, options, }) {
|
150
150
|
return (0, postToApi_js_1.postJsonToApi)({
|
151
151
|
url: `${baseUrl}/${model}`,
|
152
|
-
|
152
|
+
headers: {
|
153
|
+
Authorization: `Bearer ${apiKey}`,
|
154
|
+
},
|
153
155
|
body: {
|
154
156
|
inputs,
|
155
157
|
top_k: topK,
|
@@ -142,7 +142,9 @@ const huggingFaceTextGenerationResponseSchema = z.array(z.object({
|
|
142
142
|
async function callHuggingFaceTextGenerationAPI({ baseUrl = "https://api-inference.huggingface.co/models", abortSignal, apiKey, model, inputs, topK, topP, temperature, repetitionPenalty, maxNewTokens, maxTime, numReturnSequences, doSample, options, }) {
|
143
143
|
return postJsonToApi({
|
144
144
|
url: `${baseUrl}/${model}`,
|
145
|
-
|
145
|
+
headers: {
|
146
|
+
Authorization: `Bearer ${apiKey}`,
|
147
|
+
},
|
146
148
|
body: {
|
147
149
|
inputs,
|
148
150
|
top_k: topK,
|
@@ -17,4 +17,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
exports.HuggingFaceError = void 0;
|
18
18
|
var HuggingFaceError_js_1 = require("./HuggingFaceError.cjs");
|
19
19
|
Object.defineProperty(exports, "HuggingFaceError", { enumerable: true, get: function () { return HuggingFaceError_js_1.HuggingFaceError; } });
|
20
|
+
__exportStar(require("./HuggingFaceTextEmbeddingModel.cjs"), exports);
|
20
21
|
__exportStar(require("./HuggingFaceTextGenerationModel.cjs"), exports);
|
@@ -35,7 +35,7 @@ class LlamaCppTextEmbeddingModel extends AbstractModel_js_1.AbstractModel {
|
|
35
35
|
enumerable: true,
|
36
36
|
configurable: true,
|
37
37
|
writable: true,
|
38
|
-
value:
|
38
|
+
value: void 0
|
39
39
|
});
|
40
40
|
Object.defineProperty(this, "tokenizer", {
|
41
41
|
enumerable: true,
|
@@ -48,6 +48,7 @@ class LlamaCppTextEmbeddingModel extends AbstractModel_js_1.AbstractModel {
|
|
48
48
|
retry: this.settings.tokenizerSettings?.retry,
|
49
49
|
throttle: this.settings.tokenizerSettings?.throttle,
|
50
50
|
});
|
51
|
+
this.embeddingDimensions = this.settings.embeddingDimensions;
|
51
52
|
}
|
52
53
|
get modelName() {
|
53
54
|
return null;
|
@@ -4,8 +4,9 @@ import { FunctionOptions } from "../../model-function/FunctionOptions.js";
|
|
4
4
|
import { TextEmbeddingModel, TextEmbeddingModelSettings } from "../../model-function/embed-text/TextEmbeddingModel.js";
|
5
5
|
import { RetryFunction } from "../../util/api/RetryFunction.js";
|
6
6
|
import { ThrottleFunction } from "../../util/api/ThrottleFunction.js";
|
7
|
-
export interface
|
7
|
+
export interface LlamaCppTextEmbeddingModelSettings extends TextEmbeddingModelSettings {
|
8
8
|
baseUrl?: string;
|
9
|
+
embeddingDimensions?: number;
|
9
10
|
retry?: RetryFunction;
|
10
11
|
throttle?: ThrottleFunction;
|
11
12
|
tokenizerSettings?: {
|
@@ -13,21 +14,21 @@ export interface LlamaCppEmbeddingModelSettings extends TextEmbeddingModelSettin
|
|
13
14
|
throttle?: ThrottleFunction;
|
14
15
|
};
|
15
16
|
}
|
16
|
-
export declare class LlamaCppTextEmbeddingModel extends AbstractModel<
|
17
|
-
constructor(settings?:
|
17
|
+
export declare class LlamaCppTextEmbeddingModel extends AbstractModel<LlamaCppTextEmbeddingModelSettings> implements TextEmbeddingModel<LlamaCppTextEmbeddingResponse, LlamaCppTextEmbeddingModelSettings> {
|
18
|
+
constructor(settings?: LlamaCppTextEmbeddingModelSettings);
|
18
19
|
readonly provider: "llamacpp";
|
19
20
|
get modelName(): null;
|
20
21
|
readonly maxTextsPerCall = 1;
|
21
22
|
readonly contextWindowSize: undefined;
|
22
|
-
readonly embeddingDimensions: undefined;
|
23
|
+
readonly embeddingDimensions: number | undefined;
|
23
24
|
private readonly tokenizer;
|
24
25
|
tokenize(text: string): Promise<number[]>;
|
25
|
-
callAPI(texts: Array<string>, options?: FunctionOptions<
|
26
|
-
generateEmbeddingResponse(texts: string[], options?: FunctionOptions<
|
26
|
+
callAPI(texts: Array<string>, options?: FunctionOptions<LlamaCppTextEmbeddingModelSettings>): Promise<LlamaCppTextEmbeddingResponse>;
|
27
|
+
generateEmbeddingResponse(texts: string[], options?: FunctionOptions<LlamaCppTextEmbeddingModelSettings>): Promise<{
|
27
28
|
embedding: number[];
|
28
29
|
}>;
|
29
30
|
extractEmbeddings(response: LlamaCppTextEmbeddingResponse): number[][];
|
30
|
-
withSettings(additionalSettings: Partial<
|
31
|
+
withSettings(additionalSettings: Partial<LlamaCppTextEmbeddingModelSettings>): this;
|
31
32
|
}
|
32
33
|
declare const llamaCppTextEmbeddingResponseSchema: z.ZodObject<{
|
33
34
|
embedding: z.ZodArray<z.ZodNumber, "many">;
|
@@ -29,7 +29,7 @@ export class LlamaCppTextEmbeddingModel extends AbstractModel {
|
|
29
29
|
enumerable: true,
|
30
30
|
configurable: true,
|
31
31
|
writable: true,
|
32
|
-
value:
|
32
|
+
value: void 0
|
33
33
|
});
|
34
34
|
Object.defineProperty(this, "tokenizer", {
|
35
35
|
enumerable: true,
|
@@ -42,6 +42,7 @@ export class LlamaCppTextEmbeddingModel extends AbstractModel {
|
|
42
42
|
retry: this.settings.tokenizerSettings?.retry,
|
43
43
|
throttle: this.settings.tokenizerSettings?.throttle,
|
44
44
|
});
|
45
|
+
this.embeddingDimensions = this.settings.embeddingDimensions;
|
45
46
|
}
|
46
47
|
get modelName() {
|
47
48
|
return null;
|
@@ -16,7 +16,7 @@ exports.openAIErrorDataSchema = zod_1.z.object({
|
|
16
16
|
}),
|
17
17
|
});
|
18
18
|
class OpenAIError extends ApiCallError_js_1.ApiCallError {
|
19
|
-
constructor({ data, statusCode, url, requestBodyValues, message
|
19
|
+
constructor({ data, statusCode, url, requestBodyValues, message, }) {
|
20
20
|
super({
|
21
21
|
message,
|
22
22
|
statusCode,
|
@@ -24,7 +24,7 @@ class OpenAIError extends ApiCallError_js_1.ApiCallError {
|
|
24
24
|
url,
|
25
25
|
isRetryable: (statusCode === 429 &&
|
26
26
|
// insufficient_quota is also reported as a 429, but it's not retryable:
|
27
|
-
data
|
27
|
+
data?.error.type !== "insufficient_quota") ||
|
28
28
|
statusCode >= 500,
|
29
29
|
});
|
30
30
|
Object.defineProperty(this, "data", {
|
@@ -39,12 +39,24 @@ class OpenAIError extends ApiCallError_js_1.ApiCallError {
|
|
39
39
|
exports.OpenAIError = OpenAIError;
|
40
40
|
const failedOpenAICallResponseHandler = async ({ response, url, requestBodyValues }) => {
|
41
41
|
const responseBody = await response.text();
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
42
|
+
// resilient parsing in case the response is not JSON or does not match the schema:
|
43
|
+
try {
|
44
|
+
const parsedError = exports.openAIErrorDataSchema.parse(secure_json_parse_1.default.parse(responseBody));
|
45
|
+
return new OpenAIError({
|
46
|
+
url,
|
47
|
+
requestBodyValues,
|
48
|
+
statusCode: response.status,
|
49
|
+
message: parsedError.error.message,
|
50
|
+
data: parsedError,
|
51
|
+
});
|
52
|
+
}
|
53
|
+
catch (parseError) {
|
54
|
+
return new OpenAIError({
|
55
|
+
url,
|
56
|
+
requestBodyValues,
|
57
|
+
statusCode: response.status,
|
58
|
+
message: responseBody.trim() !== "" ? responseBody : response.statusText,
|
59
|
+
});
|
60
|
+
}
|
49
61
|
};
|
50
62
|
exports.failedOpenAICallResponseHandler = failedOpenAICallResponseHandler;
|
@@ -35,13 +35,13 @@ export declare const openAIErrorDataSchema: z.ZodObject<{
|
|
35
35
|
}>;
|
36
36
|
export type OpenAIErrorData = z.infer<typeof openAIErrorDataSchema>;
|
37
37
|
export declare class OpenAIError extends ApiCallError {
|
38
|
-
readonly data
|
38
|
+
readonly data?: OpenAIErrorData;
|
39
39
|
constructor({ data, statusCode, url, requestBodyValues, message, }: {
|
40
|
-
message
|
40
|
+
message: string;
|
41
41
|
statusCode: number;
|
42
42
|
url: string;
|
43
43
|
requestBodyValues: unknown;
|
44
|
-
data
|
44
|
+
data?: OpenAIErrorData;
|
45
45
|
});
|
46
46
|
}
|
47
47
|
export declare const failedOpenAICallResponseHandler: ResponseHandler<ApiCallError>;
|
@@ -10,7 +10,7 @@ export const openAIErrorDataSchema = z.object({
|
|
10
10
|
}),
|
11
11
|
});
|
12
12
|
export class OpenAIError extends ApiCallError {
|
13
|
-
constructor({ data, statusCode, url, requestBodyValues, message
|
13
|
+
constructor({ data, statusCode, url, requestBodyValues, message, }) {
|
14
14
|
super({
|
15
15
|
message,
|
16
16
|
statusCode,
|
@@ -18,7 +18,7 @@ export class OpenAIError extends ApiCallError {
|
|
18
18
|
url,
|
19
19
|
isRetryable: (statusCode === 429 &&
|
20
20
|
// insufficient_quota is also reported as a 429, but it's not retryable:
|
21
|
-
data
|
21
|
+
data?.error.type !== "insufficient_quota") ||
|
22
22
|
statusCode >= 500,
|
23
23
|
});
|
24
24
|
Object.defineProperty(this, "data", {
|
@@ -32,11 +32,23 @@ export class OpenAIError extends ApiCallError {
|
|
32
32
|
}
|
33
33
|
export const failedOpenAICallResponseHandler = async ({ response, url, requestBodyValues }) => {
|
34
34
|
const responseBody = await response.text();
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
35
|
+
// resilient parsing in case the response is not JSON or does not match the schema:
|
36
|
+
try {
|
37
|
+
const parsedError = openAIErrorDataSchema.parse(SecureJSON.parse(responseBody));
|
38
|
+
return new OpenAIError({
|
39
|
+
url,
|
40
|
+
requestBodyValues,
|
41
|
+
statusCode: response.status,
|
42
|
+
message: parsedError.error.message,
|
43
|
+
data: parsedError,
|
44
|
+
});
|
45
|
+
}
|
46
|
+
catch (parseError) {
|
47
|
+
return new OpenAIError({
|
48
|
+
url,
|
49
|
+
requestBodyValues,
|
50
|
+
statusCode: response.status,
|
51
|
+
message: responseBody.trim() !== "" ? responseBody : response.statusText,
|
52
|
+
});
|
53
|
+
}
|
42
54
|
};
|
@@ -109,7 +109,9 @@ exports.OpenAIImageGenerationResponseFormat = {
|
|
109
109
|
async function callOpenAIImageGenerationAPI({ baseUrl = "https://api.openai.com/v1", abortSignal, apiKey, prompt, n, size, responseFormat, user, }) {
|
110
110
|
return (0, postToApi_js_1.postJsonToApi)({
|
111
111
|
url: `${baseUrl}/images/generations`,
|
112
|
-
|
112
|
+
headers: {
|
113
|
+
Authorization: `Bearer ${apiKey}`,
|
114
|
+
},
|
113
115
|
body: {
|
114
116
|
prompt,
|
115
117
|
n,
|
@@ -104,7 +104,9 @@ export const OpenAIImageGenerationResponseFormat = {
|
|
104
104
|
async function callOpenAIImageGenerationAPI({ baseUrl = "https://api.openai.com/v1", abortSignal, apiKey, prompt, n, size, responseFormat, user, }) {
|
105
105
|
return postJsonToApi({
|
106
106
|
url: `${baseUrl}/images/generations`,
|
107
|
-
|
107
|
+
headers: {
|
108
|
+
Authorization: `Bearer ${apiKey}`,
|
109
|
+
},
|
108
110
|
body: {
|
109
111
|
prompt,
|
110
112
|
n,
|
@@ -158,7 +158,9 @@ const openAITextEmbeddingResponseSchema = zod_1.default.object({
|
|
158
158
|
async function callOpenAITextEmbeddingAPI({ baseUrl = "https://api.openai.com/v1", abortSignal, apiKey, model, input, user, }) {
|
159
159
|
return (0, postToApi_js_1.postJsonToApi)({
|
160
160
|
url: `${baseUrl}/embeddings`,
|
161
|
-
|
161
|
+
headers: {
|
162
|
+
Authorization: `Bearer ${apiKey}`,
|
163
|
+
},
|
162
164
|
body: {
|
163
165
|
model,
|
164
166
|
input,
|
@@ -149,7 +149,9 @@ const openAITextEmbeddingResponseSchema = z.object({
|
|
149
149
|
async function callOpenAITextEmbeddingAPI({ baseUrl = "https://api.openai.com/v1", abortSignal, apiKey, model, input, user, }) {
|
150
150
|
return postJsonToApi({
|
151
151
|
url: `${baseUrl}/embeddings`,
|
152
|
-
|
152
|
+
headers: {
|
153
|
+
Authorization: `Bearer ${apiKey}`,
|
154
|
+
},
|
153
155
|
body: {
|
154
156
|
model,
|
155
157
|
input,
|
@@ -209,10 +209,13 @@ const openAITextGenerationResponseSchema = zod_1.default.object({
|
|
209
209
|
*
|
210
210
|
* console.log(response.choices[0].text);
|
211
211
|
*/
|
212
|
-
async function callOpenAITextGenerationAPI({ baseUrl = "https://api.openai.com/v1", abortSignal, responseFormat, apiKey, model, prompt, suffix, maxTokens, temperature, topP, n, logprobs, echo, stop, presencePenalty, frequencyPenalty, bestOf, user, }) {
|
212
|
+
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, }) {
|
213
213
|
return (0, postToApi_js_1.postJsonToApi)({
|
214
214
|
url: `${baseUrl}/completions`,
|
215
|
-
|
215
|
+
headers: {
|
216
|
+
...headers,
|
217
|
+
Authorization: `Bearer ${apiKey}`,
|
218
|
+
},
|
216
219
|
body: {
|
217
220
|
stream: responseFormat.stream,
|
218
221
|
model,
|
@@ -65,6 +65,7 @@ export declare const calculateOpenAITextGenerationCostInMillicents: ({ model, re
|
|
65
65
|
}) => number;
|
66
66
|
export interface OpenAITextGenerationModelSettings extends TextGenerationModelSettings {
|
67
67
|
model: OpenAITextGenerationModelType;
|
68
|
+
headers?: Record<string, string>;
|
68
69
|
baseUrl?: string;
|
69
70
|
apiKey?: string;
|
70
71
|
retry?: RetryFunction;
|
@@ -200,10 +200,13 @@ const openAITextGenerationResponseSchema = z.object({
|
|
200
200
|
*
|
201
201
|
* console.log(response.choices[0].text);
|
202
202
|
*/
|
203
|
-
async function callOpenAITextGenerationAPI({ baseUrl = "https://api.openai.com/v1", abortSignal, responseFormat, apiKey, model, prompt, suffix, maxTokens, temperature, topP, n, logprobs, echo, stop, presencePenalty, frequencyPenalty, bestOf, user, }) {
|
203
|
+
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, }) {
|
204
204
|
return postJsonToApi({
|
205
205
|
url: `${baseUrl}/completions`,
|
206
|
-
|
206
|
+
headers: {
|
207
|
+
...headers,
|
208
|
+
Authorization: `Bearer ${apiKey}`,
|
209
|
+
},
|
207
210
|
body: {
|
208
211
|
stream: responseFormat.stream,
|
209
212
|
model,
|
@@ -132,8 +132,9 @@ async function callOpenAITranscriptionAPI({ baseUrl = "https://api.openai.com/v1
|
|
132
132
|
}
|
133
133
|
return (0, postToApi_js_1.postToApi)({
|
134
134
|
url: `${baseUrl}/audio/transcriptions`,
|
135
|
-
|
136
|
-
|
135
|
+
headers: {
|
136
|
+
Authorization: `Bearer ${apiKey}`,
|
137
|
+
},
|
137
138
|
body: {
|
138
139
|
content: formData,
|
139
140
|
values: {
|
@@ -124,8 +124,9 @@ async function callOpenAITranscriptionAPI({ baseUrl = "https://api.openai.com/v1
|
|
124
124
|
}
|
125
125
|
return postToApi({
|
126
126
|
url: `${baseUrl}/audio/transcriptions`,
|
127
|
-
|
128
|
-
|
127
|
+
headers: {
|
128
|
+
Authorization: `Bearer ${apiKey}`,
|
129
|
+
},
|
129
130
|
body: {
|
130
131
|
content: formData,
|
131
132
|
values: {
|
@@ -246,10 +246,13 @@ const openAIChatResponseSchema = zod_1.default.object({
|
|
246
246
|
total_tokens: zod_1.default.number(),
|
247
247
|
}),
|
248
248
|
});
|
249
|
-
async function callOpenAIChatCompletionAPI({ baseUrl = "https://api.openai.com/v1", abortSignal, responseFormat, apiKey, model, messages, functions, functionCall, temperature, topP, n, stop, maxTokens, presencePenalty, frequencyPenalty, user, }) {
|
249
|
+
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, }) {
|
250
250
|
return (0, postToApi_js_1.postJsonToApi)({
|
251
251
|
url: `${baseUrl}/chat/completions`,
|
252
|
-
|
252
|
+
headers: {
|
253
|
+
...headers,
|
254
|
+
Authorization: `Bearer ${apiKey}`,
|
255
|
+
},
|
253
256
|
body: {
|
254
257
|
stream: responseFormat.stream,
|
255
258
|
model,
|
@@ -77,6 +77,7 @@ export declare const calculateOpenAIChatCostInMillicents: ({ model, response, }:
|
|
77
77
|
}) => number;
|
78
78
|
export interface OpenAIChatCallSettings {
|
79
79
|
model: OpenAIChatModelType;
|
80
|
+
headers?: Record<string, string>;
|
80
81
|
functions?: Array<{
|
81
82
|
name: string;
|
82
83
|
description?: string;
|
@@ -237,10 +237,13 @@ const openAIChatResponseSchema = z.object({
|
|
237
237
|
total_tokens: z.number(),
|
238
238
|
}),
|
239
239
|
});
|
240
|
-
async function callOpenAIChatCompletionAPI({ baseUrl = "https://api.openai.com/v1", abortSignal, responseFormat, apiKey, model, messages, functions, functionCall, temperature, topP, n, stop, maxTokens, presencePenalty, frequencyPenalty, user, }) {
|
240
|
+
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, }) {
|
241
241
|
return postJsonToApi({
|
242
242
|
url: `${baseUrl}/chat/completions`,
|
243
|
-
|
243
|
+
headers: {
|
244
|
+
...headers,
|
245
|
+
Authorization: `Bearer ${apiKey}`,
|
246
|
+
},
|
244
247
|
body: {
|
245
248
|
stream: responseFormat.stream,
|
246
249
|
model,
|
@@ -113,7 +113,9 @@ const stabilityImageGenerationResponseSchema = zod_1.z.object({
|
|
113
113
|
async function callStabilityImageGenerationAPI({ baseUrl = "https://api.stability.ai/v1", abortSignal, apiKey, engineId, height, width, textPrompts, cfgScale, clipGuidancePreset, sampler, samples, seed, steps, stylePreset, }) {
|
114
114
|
return (0, postToApi_js_1.postJsonToApi)({
|
115
115
|
url: `${baseUrl}/generation/${engineId}/text-to-image`,
|
116
|
-
|
116
|
+
headers: {
|
117
|
+
Authorization: `Bearer ${apiKey}`,
|
118
|
+
},
|
117
119
|
body: {
|
118
120
|
height,
|
119
121
|
width,
|
@@ -109,7 +109,9 @@ const stabilityImageGenerationResponseSchema = z.object({
|
|
109
109
|
async function callStabilityImageGenerationAPI({ baseUrl = "https://api.stability.ai/v1", abortSignal, apiKey, engineId, height, width, textPrompts, cfgScale, clipGuidancePreset, sampler, samples, seed, steps, stylePreset, }) {
|
110
110
|
return postJsonToApi({
|
111
111
|
url: `${baseUrl}/generation/${engineId}/text-to-image`,
|
112
|
-
|
112
|
+
headers: {
|
113
|
+
Authorization: `Bearer ${apiKey}`,
|
114
|
+
},
|
113
115
|
body: {
|
114
116
|
height,
|
115
117
|
width,
|
package/package.json
CHANGED
@@ -9,6 +9,8 @@ const validateChatPrompt_js_1 = require("./validateChatPrompt.cjs");
|
|
9
9
|
*
|
10
10
|
* When the minimal chat prompt (system message + last user message) is already too long, it will only
|
11
11
|
* return this minimal chat prompt.
|
12
|
+
*
|
13
|
+
* @see https://modelfusion.dev/guide/function/generate-text/prompt-mapping#limiting-the-chat-length
|
12
14
|
*/
|
13
15
|
async function trimChatPrompt({ prompt, model, tokenLimit = model.contextWindowSize - model.maxCompletionTokens, }) {
|
14
16
|
(0, validateChatPrompt_js_1.validateChatPrompt)(prompt);
|
@@ -7,6 +7,8 @@ import { ChatPrompt } from "./ChatPrompt.js";
|
|
7
7
|
*
|
8
8
|
* When the minimal chat prompt (system message + last user message) is already too long, it will only
|
9
9
|
* return this minimal chat prompt.
|
10
|
+
*
|
11
|
+
* @see https://modelfusion.dev/guide/function/generate-text/prompt-mapping#limiting-the-chat-length
|
10
12
|
*/
|
11
13
|
export declare function trimChatPrompt({ prompt, model, tokenLimit, }: {
|
12
14
|
prompt: ChatPrompt;
|
@@ -6,6 +6,8 @@ import { validateChatPrompt } from "./validateChatPrompt.js";
|
|
6
6
|
*
|
7
7
|
* When the minimal chat prompt (system message + last user message) is already too long, it will only
|
8
8
|
* return this minimal chat prompt.
|
9
|
+
*
|
10
|
+
* @see https://modelfusion.dev/guide/function/generate-text/prompt-mapping#limiting-the-chat-length
|
9
11
|
*/
|
10
12
|
export async function trimChatPrompt({ prompt, model, tokenLimit = model.contextWindowSize - model.maxCompletionTokens, }) {
|
11
13
|
validateChatPrompt(prompt);
|
package/util/api/postToApi.cjs
CHANGED
@@ -18,10 +18,12 @@ const createJsonResponseHandler = (responseSchema) => async ({ response, url, re
|
|
18
18
|
exports.createJsonResponseHandler = createJsonResponseHandler;
|
19
19
|
const createTextResponseHandler = () => async ({ response }) => response.text();
|
20
20
|
exports.createTextResponseHandler = createTextResponseHandler;
|
21
|
-
const postJsonToApi = async ({ url,
|
21
|
+
const postJsonToApi = async ({ url, headers, body, failedResponseHandler, successfulResponseHandler, abortSignal, }) => (0, exports.postToApi)({
|
22
22
|
url,
|
23
|
-
|
24
|
-
|
23
|
+
headers: {
|
24
|
+
...headers,
|
25
|
+
"Content-Type": "application/json",
|
26
|
+
},
|
25
27
|
body: {
|
26
28
|
content: JSON.stringify(body),
|
27
29
|
values: body,
|
@@ -31,15 +33,8 @@ const postJsonToApi = async ({ url, apiKey, body, failedResponseHandler, success
|
|
31
33
|
abortSignal,
|
32
34
|
});
|
33
35
|
exports.postJsonToApi = postJsonToApi;
|
34
|
-
const postToApi = async ({ url,
|
36
|
+
const postToApi = async ({ url, headers = {}, body, successfulResponseHandler, failedResponseHandler, abortSignal, }) => {
|
35
37
|
try {
|
36
|
-
const headers = {};
|
37
|
-
if (apiKey !== undefined) {
|
38
|
-
headers["Authorization"] = `Bearer ${apiKey}`;
|
39
|
-
}
|
40
|
-
if (contentType !== null) {
|
41
|
-
headers["Content-Type"] = contentType;
|
42
|
-
}
|
43
38
|
const response = await fetch(url, {
|
44
39
|
method: "POST",
|
45
40
|
headers,
|
package/util/api/postToApi.d.ts
CHANGED
@@ -7,18 +7,17 @@ export type ResponseHandler<T> = (options: {
|
|
7
7
|
}) => PromiseLike<T>;
|
8
8
|
export declare const createJsonResponseHandler: <T>(responseSchema: z.ZodType<T, z.ZodTypeDef, T>) => ResponseHandler<T>;
|
9
9
|
export declare const createTextResponseHandler: () => ResponseHandler<string>;
|
10
|
-
export declare const postJsonToApi: <T>({ url,
|
10
|
+
export declare const postJsonToApi: <T>({ url, headers, body, failedResponseHandler, successfulResponseHandler, abortSignal, }: {
|
11
11
|
url: string;
|
12
|
-
|
12
|
+
headers?: Record<string, string> | undefined;
|
13
13
|
body: unknown;
|
14
14
|
failedResponseHandler: ResponseHandler<ApiCallError>;
|
15
15
|
successfulResponseHandler: ResponseHandler<T>;
|
16
16
|
abortSignal?: AbortSignal | undefined;
|
17
17
|
}) => Promise<T>;
|
18
|
-
export declare const postToApi: <T>({ url,
|
18
|
+
export declare const postToApi: <T>({ url, headers, body, successfulResponseHandler, failedResponseHandler, abortSignal, }: {
|
19
19
|
url: string;
|
20
|
-
|
21
|
-
contentType: string | null;
|
20
|
+
headers?: Record<string, string> | undefined;
|
22
21
|
body: {
|
23
22
|
content: string | FormData;
|
24
23
|
values: unknown;
|
package/util/api/postToApi.js
CHANGED
@@ -13,10 +13,12 @@ export const createJsonResponseHandler = (responseSchema) => async ({ response,
|
|
13
13
|
return parsedResult.data;
|
14
14
|
};
|
15
15
|
export const createTextResponseHandler = () => async ({ response }) => response.text();
|
16
|
-
export const postJsonToApi = async ({ url,
|
16
|
+
export const postJsonToApi = async ({ url, headers, body, failedResponseHandler, successfulResponseHandler, abortSignal, }) => postToApi({
|
17
17
|
url,
|
18
|
-
|
19
|
-
|
18
|
+
headers: {
|
19
|
+
...headers,
|
20
|
+
"Content-Type": "application/json",
|
21
|
+
},
|
20
22
|
body: {
|
21
23
|
content: JSON.stringify(body),
|
22
24
|
values: body,
|
@@ -25,15 +27,8 @@ export const postJsonToApi = async ({ url, apiKey, body, failedResponseHandler,
|
|
25
27
|
successfulResponseHandler,
|
26
28
|
abortSignal,
|
27
29
|
});
|
28
|
-
export const postToApi = async ({ url,
|
30
|
+
export const postToApi = async ({ url, headers = {}, body, successfulResponseHandler, failedResponseHandler, abortSignal, }) => {
|
29
31
|
try {
|
30
|
-
const headers = {};
|
31
|
-
if (apiKey !== undefined) {
|
32
|
-
headers["Authorization"] = `Bearer ${apiKey}`;
|
33
|
-
}
|
34
|
-
if (contentType !== null) {
|
35
|
-
headers["Content-Type"] = contentType;
|
36
|
-
}
|
37
32
|
const response = await fetch(url, {
|
38
33
|
method: "POST",
|
39
34
|
headers,
|
@@ -20,7 +20,7 @@ async function _retryWithExponentialBackoff(f, { maxTries, delay, backoffFactor,
|
|
20
20
|
catch (error) {
|
21
21
|
const newErrors = [...errors, error];
|
22
22
|
const tryNumber = newErrors.length;
|
23
|
-
if (tryNumber
|
23
|
+
if (tryNumber >= maxTries) {
|
24
24
|
throw new RetryError_js_1.RetryError({
|
25
25
|
message: `Failed after ${tryNumber} tries.`,
|
26
26
|
reason: "maxTriesExceeded",
|
@@ -16,7 +16,7 @@ async function _retryWithExponentialBackoff(f, { maxTries, delay, backoffFactor,
|
|
16
16
|
catch (error) {
|
17
17
|
const newErrors = [...errors, error];
|
18
18
|
const tryNumber = newErrors.length;
|
19
|
-
if (tryNumber
|
19
|
+
if (tryNumber >= maxTries) {
|
20
20
|
throw new RetryError({
|
21
21
|
message: `Failed after ${tryNumber} tries.`,
|
22
22
|
reason: "maxTriesExceeded",
|