modelfusion 0.25.0 → 0.26.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 +48 -63
- package/model-provider/index.cjs +1 -0
- package/model-provider/index.d.ts +1 -0
- package/model-provider/index.js +1 -0
- package/model-provider/lmnt/LmntError.cjs +31 -0
- package/model-provider/lmnt/LmntError.d.ts +3 -0
- package/model-provider/lmnt/LmntError.js +27 -0
- package/model-provider/lmnt/LmntSpeechSynthesisModel.cjs +106 -0
- package/model-provider/lmnt/LmntSpeechSynthesisModel.d.ts +26 -0
- package/model-provider/lmnt/LmntSpeechSynthesisModel.js +102 -0
- package/model-provider/lmnt/index.cjs +17 -0
- package/model-provider/lmnt/index.d.ts +1 -0
- package/model-provider/lmnt/index.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
@@ -8,7 +8,7 @@
|
|
8
8
|
[](https://discord.gg/GqCwYZATem)
|
9
9
|
[](https://twitter.com/lgrammel)
|
10
10
|
|
11
|
-
[Introduction](#introduction) | [Quick Install](#quick-install) | [Usage](#usage-examples) | [
|
11
|
+
[Introduction](#introduction) | [Quick Install](#quick-install) | [Usage](#usage-examples) | [Documentation](#documentation) | [Examples](#more-examples) | [Contributing](#contributing) | [modelfusion.dev](https://modelfusion.dev)
|
12
12
|
|
13
13
|
> [!NOTE]
|
14
14
|
> ModelFusion is in its initial development phase. Until version 1.0 there may be breaking changes, because I am still exploring the API design. Feedback and suggestions are welcome.
|
@@ -19,7 +19,7 @@ ModelFusion is a library for building AI apps, chatbots, and agents. It provides
|
|
19
19
|
|
20
20
|
- **Type inference and validation**: ModelFusion uses TypeScript and [Zod](https://github.com/colinhacks/zod) to infer types wherever possible and to validate model responses.
|
21
21
|
- **Flexibility and control**: AI application development can be complex and unique to each project. With ModelFusion, you have complete control over the prompts and model settings, and you can access the raw responses from the models quickly to build what you need.
|
22
|
-
- **No chains and predefined prompts**: Use the concepts provided by JavaScript (variables, functions, etc.) and explicit prompts to build applications you can easily understand and control. Not
|
22
|
+
- **No chains and predefined prompts**: Use the concepts provided by JavaScript (variables, functions, etc.) and explicit prompts to build applications you can easily understand and control. Not hidden prompts and logic.
|
23
23
|
- **Multimodal Support**: Beyond just LLMs, ModelFusion encompasses a diverse array of models including text generation, text-to-speech, speech-to-text, and image generation, allowing you to build multifaceted AI applications with ease.
|
24
24
|
- **Integrated support features**: Essential features like logging, retries, throttling, tracing, and error handling are built-in, helping you focus more on building your application.
|
25
25
|
|
@@ -56,6 +56,8 @@ const text = await generateText(
|
|
56
56
|
);
|
57
57
|
```
|
58
58
|
|
59
|
+
Providers: [OpenAI](https://modelfusion.dev/integration/model-provider/openai), [Cohere](https://modelfusion.dev/integration/model-provider/cohere), [Llama.cpp](https://modelfusion.dev/integration/model-provider/llamacpp), [Hugging Face](https://modelfusion.dev/integration/model-provider/huggingface)
|
60
|
+
|
59
61
|
#### streamText
|
60
62
|
|
61
63
|
```ts
|
@@ -75,6 +77,8 @@ for await (const textFragment of textStream) {
|
|
75
77
|
}
|
76
78
|
```
|
77
79
|
|
80
|
+
Providers: [OpenAI](https://modelfusion.dev/integration/model-provider/openai), [Cohere](https://modelfusion.dev/integration/model-provider/cohere), [Llama.cpp](https://modelfusion.dev/integration/model-provider/llamacpp)
|
81
|
+
|
78
82
|
#### Prompt Format
|
79
83
|
|
80
84
|
[Prompt format](https://modelfusion.dev/guide/function/generate-text/prompt-format) lets you use higher level prompt structures (such as instruction or chat prompts) for different models.
|
@@ -106,6 +110,14 @@ const textStream = await streamText(
|
|
106
110
|
);
|
107
111
|
```
|
108
112
|
|
113
|
+
| Prompt Format | Instruction Prompt | Chat Prompt |
|
114
|
+
| ------------- | ------------------ | ----------- |
|
115
|
+
| OpenAI Chat | ✅ | ✅ |
|
116
|
+
| Llama 2 | ✅ | ✅ |
|
117
|
+
| Alpaca | ✅ | ❌ |
|
118
|
+
| Vicuna | ❌ | ✅ |
|
119
|
+
| Generic Text | ✅ | ✅ |
|
120
|
+
|
109
121
|
#### Metadata and original responses
|
110
122
|
|
111
123
|
ModelFusion model functions return rich results that include the original response and metadata when you call `.asFullResponse()` before resolving the promise.
|
@@ -162,6 +174,8 @@ const value = await generateJson(
|
|
162
174
|
);
|
163
175
|
```
|
164
176
|
|
177
|
+
Providers: [OpenAI](https://modelfusion.dev/integration/model-provider/openai)
|
178
|
+
|
165
179
|
### [Generate JSON or Text](https://modelfusion.dev/guide/function/generate-json-or-text)
|
166
180
|
|
167
181
|
Generate JSON (or text as a fallback) using a prompt and multiple schemas.
|
@@ -196,10 +210,14 @@ const { schema, value, text } = await generateJsonOrText(
|
|
196
210
|
);
|
197
211
|
```
|
198
212
|
|
213
|
+
Providers: [OpenAI](https://modelfusion.dev/integration/model-provider/openai)
|
214
|
+
|
199
215
|
### [Tools](https://modelfusion.dev/guide/tools)
|
200
216
|
|
201
217
|
Tools are functions that can be executed by an AI model. They are useful for building chatbots and agents.
|
202
218
|
|
219
|
+
Predefined tools: [SerpAPI](https://modelfusion.dev/integration/tool/serpapi), [Google Custom Search](https://modelfusion.dev/integration/tool/google-custom-search)
|
220
|
+
|
203
221
|
#### Create Tool
|
204
222
|
|
205
223
|
A tool is a function with a name, a description, and a schema for the input parameters.
|
@@ -275,6 +293,8 @@ const transcription = await transcribe(
|
|
275
293
|
);
|
276
294
|
```
|
277
295
|
|
296
|
+
Providers: [OpenAI (Whisper)](https://modelfusion.dev/integration/model-provider/openai)
|
297
|
+
|
278
298
|
### [Synthesize Speech](https://modelfusion.dev/guide/function/synthesize-speech)
|
279
299
|
|
280
300
|
Turn text into speech (audio).
|
@@ -282,13 +302,18 @@ Turn text into speech (audio).
|
|
282
302
|
```ts
|
283
303
|
// `speech` is a Buffer with MP3 audio data
|
284
304
|
const speech = await synthesizeSpeech(
|
285
|
-
new
|
286
|
-
voice: "
|
305
|
+
new LmntSpeechSynthesisModel({
|
306
|
+
voice: "034b632b-df71-46c8-b440-86a42ffc3cf3", // Henry
|
287
307
|
}),
|
288
|
-
"
|
308
|
+
"Good evening, ladies and gentlemen! Exciting news on the airwaves tonight " +
|
309
|
+
"as The Rolling Stones unveil 'Hackney Diamonds,' their first collection of " +
|
310
|
+
"fresh tunes in nearly twenty years, featuring the illustrious Lady Gaga, the " +
|
311
|
+
"magical Stevie Wonder, and the final beats from the late Charlie Watts."
|
289
312
|
);
|
290
313
|
```
|
291
314
|
|
315
|
+
Providers: [Eleven Labs](https://modelfusion.dev/integration/model-provider/elevenlabs), [LMNT](https://modelfusion.dev/integration/model-provider/lmnt)
|
316
|
+
|
292
317
|
### [Generate Image](https://modelfusion.dev/guide/function/generate-image)
|
293
318
|
|
294
319
|
Generate a base64-encoded image from a prompt.
|
@@ -300,6 +325,8 @@ const image = await generateImage(
|
|
300
325
|
);
|
301
326
|
```
|
302
327
|
|
328
|
+
Providers: [OpenAI (Dall·E)](https://modelfusion.dev/integration/model-provider/openai), [Stability AI](https://modelfusion.dev/integration/model-provider/stability), [Automatic1111](https://modelfusion.dev/integration/model-provider/automatic1111)
|
329
|
+
|
303
330
|
### [Embed Text](https://modelfusion.dev/guide/function/embed-text)
|
304
331
|
|
305
332
|
Create embeddings for text. Embeddings are vectors that represent the meaning of the text.
|
@@ -314,6 +341,8 @@ const embeddings = await embedTexts(
|
|
314
341
|
);
|
315
342
|
```
|
316
343
|
|
344
|
+
Providers: [OpenAI](https://modelfusion.dev/integration/model-provider/openai), [Cohere](https://modelfusion.dev/integration/model-provider/cohere), [Llama.cpp](https://modelfusion.dev/integration/model-provider/llamacpp), [Hugging Face](https://modelfusion.dev/integration/model-provider/huggingface)
|
345
|
+
|
317
346
|
### [Tokenize Text](https://modelfusion.dev/guide/function/tokenize-text)
|
318
347
|
|
319
348
|
Split text into tokens and reconstruct the text from tokens.
|
@@ -330,6 +359,8 @@ const tokensAndTokenTexts = await tokenizer.tokenizeWithTexts(text);
|
|
330
359
|
const reconstructedText = await tokenizer.detokenize(tokens);
|
331
360
|
```
|
332
361
|
|
362
|
+
Providers: [OpenAI](https://modelfusion.dev/integration/model-provider/openai), [Cohere](https://modelfusion.dev/integration/model-provider/cohere), [Llama.cpp](https://modelfusion.dev/integration/model-provider/llamacpp)
|
363
|
+
|
333
364
|
### [Upserting and Retrieving Text Chunks from Vector Indices](https://modelfusion.dev/guide/text-chunks)
|
334
365
|
|
335
366
|
```ts
|
@@ -363,7 +394,15 @@ const { chunks } = await retrieveTextChunks(
|
|
363
394
|
);
|
364
395
|
```
|
365
396
|
|
366
|
-
|
397
|
+
Available Vector Stores: [Memory](https://modelfusion.dev/integration/vector-index/memory), [Pinecone](https://modelfusion.dev/integration/vector-index/pinecone)
|
398
|
+
|
399
|
+
### Observability
|
400
|
+
|
401
|
+
Integrations: [Helicone](https://modelfusion.dev/integration/observability/helicone)
|
402
|
+
|
403
|
+
## Documentation
|
404
|
+
|
405
|
+
### [Guide](https://modelfusion.dev/guide)
|
367
406
|
|
368
407
|
- [Model Functions](https://modelfusion.dev/guide/function/)
|
369
408
|
- [Generate and stream text](https://modelfusion.dev/guide/function/generate-text)
|
@@ -386,69 +425,15 @@ const { chunks } = await retrieveTextChunks(
|
|
386
425
|
- [Abort signals](https://modelfusion.dev/guide/util/abort)
|
387
426
|
- [Cost calculation](https://modelfusion.dev/guide/util/cost-calculation)
|
388
427
|
|
389
|
-
|
390
|
-
|
391
|
-
### Model Providers
|
392
|
-
|
393
|
-
#### Text and JSON Generation
|
394
|
-
|
395
|
-
| | [OpenAI](https://modelfusion.dev/integration/model-provider/openai) | [Cohere](https://modelfusion.dev/integration/model-provider/cohere) | [Llama.cpp](https://modelfusion.dev/integration/model-provider/llamacpp) | [Hugging Face](https://modelfusion.dev/integration/model-provider/huggingface) |
|
396
|
-
| ------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------ |
|
397
|
-
| [Generate text](https://modelfusion.dev/guide/function/generate-text) | ✅ | ✅ | ✅ | ✅ |
|
398
|
-
| [Stream text](https://modelfusion.dev/guide/function/generate-text) | ✅ | ✅ | ✅ | |
|
399
|
-
| [Generate JSON](https://modelfusion.dev/guide/function/generate-json) | chat models | | | |
|
400
|
-
| [Generate JSON or Text](https://modelfusion.dev/guide/function/generate-json-or-text) | chat models | | | |
|
401
|
-
| [Embed text](https://modelfusion.dev/guide/function/embed-text) | ✅ | ✅ | ✅ | ✅ |
|
402
|
-
| [Tokenize text](https://modelfusion.dev/guide/function/tokenize-text) | full | full | basic | |
|
403
|
-
|
404
|
-
#### Image Generation
|
405
|
-
|
406
|
-
- [OpenAI (Dall·E)](https://modelfusion.dev/integration/model-provider/openai)
|
407
|
-
- [Stability AI](https://modelfusion.dev/integration/model-provider/stability)
|
408
|
-
- [Automatic1111](https://modelfusion.dev/integration/model-provider/automatic1111)
|
409
|
-
|
410
|
-
#### Speech Transcription
|
411
|
-
|
412
|
-
- [OpenAI (Whisper)](https://modelfusion.dev/integration/model-provider/openai)
|
413
|
-
|
414
|
-
#### Speech Synthesis
|
415
|
-
|
416
|
-
- [Eleven Labs](https://modelfusion.dev/integration/model-provider/elevenlabs)
|
417
|
-
|
418
|
-
### Vector Indices
|
419
|
-
|
420
|
-
- [Memory](https://modelfusion.dev/integration/vector-index/memory)
|
421
|
-
- [Pinecone](https://modelfusion.dev/integration/vector-index/pinecone)
|
422
|
-
|
423
|
-
### Observability
|
424
|
-
|
425
|
-
- [Helicone](https://modelfusion.dev/integration/observability/helicone)
|
426
|
-
|
427
|
-
### Prompt Formats
|
428
|
-
|
429
|
-
Use higher level prompts that are mapped into model specific prompt formats.
|
430
|
-
|
431
|
-
| Prompt Format | Instruction Prompt | Chat Prompt |
|
432
|
-
| ------------- | ------------------ | ----------- |
|
433
|
-
| OpenAI Chat | ✅ | ✅ |
|
434
|
-
| Llama 2 | ✅ | ✅ |
|
435
|
-
| Alpaca | ✅ | ❌ |
|
436
|
-
| Vicuna | ❌ | ✅ |
|
437
|
-
| Generic Text | ✅ | ✅ |
|
438
|
-
|
439
|
-
## Documentation
|
428
|
+
### [Integrations](https://modelfusion.dev/integration/model-provider)
|
440
429
|
|
441
|
-
|
442
|
-
- [Examples & Tutorials](https://modelfusion.dev/tutorial)
|
443
|
-
- [Integrations](https://modelfusion.dev/integration/model-provider)
|
444
|
-
- [API Reference](https://modelfusion.dev/api/modules)
|
445
|
-
- [Blog](https://modelfusion.dev/api/blog)
|
430
|
+
### [API Reference](https://modelfusion.dev/api/modules)
|
446
431
|
|
447
432
|
## More Examples
|
448
433
|
|
449
434
|
### [Basic Examples](https://github.com/lgrammel/modelfusion/tree/main/examples/basic)
|
450
435
|
|
451
|
-
Examples for the individual functions and objects.
|
436
|
+
Examples for almost all of the individual functions and objects. Highly recommended to get started.
|
452
437
|
|
453
438
|
### [Chatbot (Terminal)](https://github.com/lgrammel/modelfusion/tree/main/examples/chatbot-terminal)
|
454
439
|
|
package/model-provider/index.cjs
CHANGED
@@ -19,5 +19,6 @@ __exportStar(require("./cohere/index.cjs"), exports);
|
|
19
19
|
__exportStar(require("./elevenlabs/index.cjs"), exports);
|
20
20
|
__exportStar(require("./huggingface/index.cjs"), exports);
|
21
21
|
__exportStar(require("./llamacpp/index.cjs"), exports);
|
22
|
+
__exportStar(require("./lmnt/index.cjs"), exports);
|
22
23
|
__exportStar(require("./openai/index.cjs"), exports);
|
23
24
|
__exportStar(require("./stability/index.cjs"), exports);
|
package/model-provider/index.js
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.failedLmntCallResponseHandler = void 0;
|
4
|
+
const ApiCallError_js_1 = require("../../util/api/ApiCallError.cjs");
|
5
|
+
const failedLmntCallResponseHandler = async ({ response, url, requestBodyValues }) => {
|
6
|
+
const responseBody = await response.text();
|
7
|
+
try {
|
8
|
+
// TODO implement LmntError
|
9
|
+
return new ApiCallError_js_1.ApiCallError({
|
10
|
+
message: responseBody,
|
11
|
+
statusCode: response.status,
|
12
|
+
url,
|
13
|
+
requestBodyValues,
|
14
|
+
});
|
15
|
+
}
|
16
|
+
catch (error) {
|
17
|
+
if (error instanceof Error) {
|
18
|
+
if (error.name === "AbortError" || error instanceof ApiCallError_js_1.ApiCallError) {
|
19
|
+
throw error;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
throw new ApiCallError_js_1.ApiCallError({
|
23
|
+
message: responseBody,
|
24
|
+
cause: error,
|
25
|
+
statusCode: response.status,
|
26
|
+
url,
|
27
|
+
requestBodyValues,
|
28
|
+
});
|
29
|
+
}
|
30
|
+
};
|
31
|
+
exports.failedLmntCallResponseHandler = failedLmntCallResponseHandler;
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { ApiCallError } from "../../util/api/ApiCallError.js";
|
2
|
+
export const failedLmntCallResponseHandler = async ({ response, url, requestBodyValues }) => {
|
3
|
+
const responseBody = await response.text();
|
4
|
+
try {
|
5
|
+
// TODO implement LmntError
|
6
|
+
return new ApiCallError({
|
7
|
+
message: responseBody,
|
8
|
+
statusCode: response.status,
|
9
|
+
url,
|
10
|
+
requestBodyValues,
|
11
|
+
});
|
12
|
+
}
|
13
|
+
catch (error) {
|
14
|
+
if (error instanceof Error) {
|
15
|
+
if (error.name === "AbortError" || error instanceof ApiCallError) {
|
16
|
+
throw error;
|
17
|
+
}
|
18
|
+
}
|
19
|
+
throw new ApiCallError({
|
20
|
+
message: responseBody,
|
21
|
+
cause: error,
|
22
|
+
statusCode: response.status,
|
23
|
+
url,
|
24
|
+
requestBodyValues,
|
25
|
+
});
|
26
|
+
}
|
27
|
+
};
|
@@ -0,0 +1,106 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.LmntSpeechSynthesisModel = void 0;
|
4
|
+
const AbstractModel_js_1 = require("../../model-function/AbstractModel.cjs");
|
5
|
+
const callWithRetryAndThrottle_js_1 = require("../../util/api/callWithRetryAndThrottle.cjs");
|
6
|
+
const postToApi_js_1 = require("../../util/api/postToApi.cjs");
|
7
|
+
const LmntError_js_1 = require("./LmntError.cjs");
|
8
|
+
class LmntSpeechSynthesisModel extends AbstractModel_js_1.AbstractModel {
|
9
|
+
constructor(settings) {
|
10
|
+
super({ settings });
|
11
|
+
Object.defineProperty(this, "provider", {
|
12
|
+
enumerable: true,
|
13
|
+
configurable: true,
|
14
|
+
writable: true,
|
15
|
+
value: "lmnt"
|
16
|
+
});
|
17
|
+
Object.defineProperty(this, "modelName", {
|
18
|
+
enumerable: true,
|
19
|
+
configurable: true,
|
20
|
+
writable: true,
|
21
|
+
value: null
|
22
|
+
});
|
23
|
+
}
|
24
|
+
get apiKey() {
|
25
|
+
const apiKey = this.settings.apiKey ?? process.env.LMNT_API_KEY;
|
26
|
+
if (apiKey == null) {
|
27
|
+
throw new Error("No LMNT API key provided. Pass it in the constructor or set the LMNT_API_KEY environment variable.");
|
28
|
+
}
|
29
|
+
return apiKey;
|
30
|
+
}
|
31
|
+
async callAPI(text, options) {
|
32
|
+
const run = options?.run;
|
33
|
+
const settings = options?.settings;
|
34
|
+
const combinedSettings = {
|
35
|
+
...this.settings,
|
36
|
+
...settings,
|
37
|
+
};
|
38
|
+
return (0, callWithRetryAndThrottle_js_1.callWithRetryAndThrottle)({
|
39
|
+
retry: this.settings.retry,
|
40
|
+
throttle: this.settings.throttle,
|
41
|
+
call: async () => callLmntTextToSpeechAPI({
|
42
|
+
baseUrl: combinedSettings.baseUrl,
|
43
|
+
abortSignal: run?.abortSignal,
|
44
|
+
apiKey: this.apiKey,
|
45
|
+
text,
|
46
|
+
voice: combinedSettings.voice,
|
47
|
+
speed: combinedSettings.speed,
|
48
|
+
seed: combinedSettings.seed,
|
49
|
+
length: combinedSettings.length,
|
50
|
+
}),
|
51
|
+
});
|
52
|
+
}
|
53
|
+
get settingsForEvent() {
|
54
|
+
return {
|
55
|
+
baseUrl: this.settings.baseUrl,
|
56
|
+
voice: this.settings.voice,
|
57
|
+
speed: this.settings.speed,
|
58
|
+
seed: this.settings.seed,
|
59
|
+
length: this.settings.length,
|
60
|
+
};
|
61
|
+
}
|
62
|
+
generateSpeechResponse(text, options) {
|
63
|
+
return this.callAPI(text, options);
|
64
|
+
}
|
65
|
+
withSettings(additionalSettings) {
|
66
|
+
return new LmntSpeechSynthesisModel({
|
67
|
+
...this.settings,
|
68
|
+
...additionalSettings,
|
69
|
+
});
|
70
|
+
}
|
71
|
+
}
|
72
|
+
exports.LmntSpeechSynthesisModel = LmntSpeechSynthesisModel;
|
73
|
+
/**
|
74
|
+
* @see https://www.lmnt.com/docs/rest/#synthesize-speech
|
75
|
+
*/
|
76
|
+
async function callLmntTextToSpeechAPI({ baseUrl = "https://api.lmnt.com/speech/beta", abortSignal, apiKey, text, voice, speed, seed, length, }) {
|
77
|
+
const formData = new FormData();
|
78
|
+
formData.append("text", text);
|
79
|
+
formData.append("voice", voice);
|
80
|
+
formData.append("format", "mp3");
|
81
|
+
if (speed != null)
|
82
|
+
formData.append("speed", speed.toString());
|
83
|
+
if (seed != null)
|
84
|
+
formData.append("seed", seed.toString());
|
85
|
+
if (length != null)
|
86
|
+
formData.append("length", length.toString());
|
87
|
+
return (0, postToApi_js_1.postToApi)({
|
88
|
+
url: `${baseUrl}/synthesize`,
|
89
|
+
headers: {
|
90
|
+
"X-API-Key": apiKey,
|
91
|
+
},
|
92
|
+
body: {
|
93
|
+
content: formData,
|
94
|
+
values: {
|
95
|
+
text,
|
96
|
+
voice,
|
97
|
+
speed,
|
98
|
+
seed,
|
99
|
+
length,
|
100
|
+
},
|
101
|
+
},
|
102
|
+
failedResponseHandler: LmntError_js_1.failedLmntCallResponseHandler,
|
103
|
+
successfulResponseHandler: (0, postToApi_js_1.createAudioMpegResponseHandler)(),
|
104
|
+
abortSignal,
|
105
|
+
});
|
106
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
2
|
+
import { AbstractModel } from "../../model-function/AbstractModel.js";
|
3
|
+
import { ModelFunctionOptions } from "../../model-function/ModelFunctionOptions.js";
|
4
|
+
import { SpeechSynthesisModel, SpeechSynthesisModelSettings } from "../../model-function/synthesize-speech/SpeechSynthesisModel.js";
|
5
|
+
import { RetryFunction } from "../../util/api/RetryFunction.js";
|
6
|
+
import { ThrottleFunction } from "../../util/api/ThrottleFunction.js";
|
7
|
+
export interface LmntSpeechSynthesisModelSettings extends SpeechSynthesisModelSettings {
|
8
|
+
baseUrl?: string;
|
9
|
+
apiKey?: string;
|
10
|
+
voice: string;
|
11
|
+
speed?: number;
|
12
|
+
seed?: number;
|
13
|
+
length?: number;
|
14
|
+
retry?: RetryFunction;
|
15
|
+
throttle?: ThrottleFunction;
|
16
|
+
}
|
17
|
+
export declare class LmntSpeechSynthesisModel extends AbstractModel<LmntSpeechSynthesisModelSettings> implements SpeechSynthesisModel<LmntSpeechSynthesisModelSettings> {
|
18
|
+
constructor(settings: LmntSpeechSynthesisModelSettings);
|
19
|
+
readonly provider = "lmnt";
|
20
|
+
readonly modelName: null;
|
21
|
+
private get apiKey();
|
22
|
+
private callAPI;
|
23
|
+
get settingsForEvent(): Partial<LmntSpeechSynthesisModelSettings>;
|
24
|
+
generateSpeechResponse(text: string, options?: ModelFunctionOptions<LmntSpeechSynthesisModelSettings> | undefined): Promise<Buffer>;
|
25
|
+
withSettings(additionalSettings: Partial<LmntSpeechSynthesisModelSettings>): this;
|
26
|
+
}
|
@@ -0,0 +1,102 @@
|
|
1
|
+
import { AbstractModel } from "../../model-function/AbstractModel.js";
|
2
|
+
import { callWithRetryAndThrottle } from "../../util/api/callWithRetryAndThrottle.js";
|
3
|
+
import { createAudioMpegResponseHandler, postToApi, } from "../../util/api/postToApi.js";
|
4
|
+
import { failedLmntCallResponseHandler } from "./LmntError.js";
|
5
|
+
export class LmntSpeechSynthesisModel extends AbstractModel {
|
6
|
+
constructor(settings) {
|
7
|
+
super({ settings });
|
8
|
+
Object.defineProperty(this, "provider", {
|
9
|
+
enumerable: true,
|
10
|
+
configurable: true,
|
11
|
+
writable: true,
|
12
|
+
value: "lmnt"
|
13
|
+
});
|
14
|
+
Object.defineProperty(this, "modelName", {
|
15
|
+
enumerable: true,
|
16
|
+
configurable: true,
|
17
|
+
writable: true,
|
18
|
+
value: null
|
19
|
+
});
|
20
|
+
}
|
21
|
+
get apiKey() {
|
22
|
+
const apiKey = this.settings.apiKey ?? process.env.LMNT_API_KEY;
|
23
|
+
if (apiKey == null) {
|
24
|
+
throw new Error("No LMNT API key provided. Pass it in the constructor or set the LMNT_API_KEY environment variable.");
|
25
|
+
}
|
26
|
+
return apiKey;
|
27
|
+
}
|
28
|
+
async callAPI(text, options) {
|
29
|
+
const run = options?.run;
|
30
|
+
const settings = options?.settings;
|
31
|
+
const combinedSettings = {
|
32
|
+
...this.settings,
|
33
|
+
...settings,
|
34
|
+
};
|
35
|
+
return callWithRetryAndThrottle({
|
36
|
+
retry: this.settings.retry,
|
37
|
+
throttle: this.settings.throttle,
|
38
|
+
call: async () => callLmntTextToSpeechAPI({
|
39
|
+
baseUrl: combinedSettings.baseUrl,
|
40
|
+
abortSignal: run?.abortSignal,
|
41
|
+
apiKey: this.apiKey,
|
42
|
+
text,
|
43
|
+
voice: combinedSettings.voice,
|
44
|
+
speed: combinedSettings.speed,
|
45
|
+
seed: combinedSettings.seed,
|
46
|
+
length: combinedSettings.length,
|
47
|
+
}),
|
48
|
+
});
|
49
|
+
}
|
50
|
+
get settingsForEvent() {
|
51
|
+
return {
|
52
|
+
baseUrl: this.settings.baseUrl,
|
53
|
+
voice: this.settings.voice,
|
54
|
+
speed: this.settings.speed,
|
55
|
+
seed: this.settings.seed,
|
56
|
+
length: this.settings.length,
|
57
|
+
};
|
58
|
+
}
|
59
|
+
generateSpeechResponse(text, options) {
|
60
|
+
return this.callAPI(text, options);
|
61
|
+
}
|
62
|
+
withSettings(additionalSettings) {
|
63
|
+
return new LmntSpeechSynthesisModel({
|
64
|
+
...this.settings,
|
65
|
+
...additionalSettings,
|
66
|
+
});
|
67
|
+
}
|
68
|
+
}
|
69
|
+
/**
|
70
|
+
* @see https://www.lmnt.com/docs/rest/#synthesize-speech
|
71
|
+
*/
|
72
|
+
async function callLmntTextToSpeechAPI({ baseUrl = "https://api.lmnt.com/speech/beta", abortSignal, apiKey, text, voice, speed, seed, length, }) {
|
73
|
+
const formData = new FormData();
|
74
|
+
formData.append("text", text);
|
75
|
+
formData.append("voice", voice);
|
76
|
+
formData.append("format", "mp3");
|
77
|
+
if (speed != null)
|
78
|
+
formData.append("speed", speed.toString());
|
79
|
+
if (seed != null)
|
80
|
+
formData.append("seed", seed.toString());
|
81
|
+
if (length != null)
|
82
|
+
formData.append("length", length.toString());
|
83
|
+
return postToApi({
|
84
|
+
url: `${baseUrl}/synthesize`,
|
85
|
+
headers: {
|
86
|
+
"X-API-Key": apiKey,
|
87
|
+
},
|
88
|
+
body: {
|
89
|
+
content: formData,
|
90
|
+
values: {
|
91
|
+
text,
|
92
|
+
voice,
|
93
|
+
speed,
|
94
|
+
seed,
|
95
|
+
length,
|
96
|
+
},
|
97
|
+
},
|
98
|
+
failedResponseHandler: failedLmntCallResponseHandler,
|
99
|
+
successfulResponseHandler: createAudioMpegResponseHandler(),
|
100
|
+
abortSignal,
|
101
|
+
});
|
102
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
15
|
+
};
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
17
|
+
__exportStar(require("./LmntSpeechSynthesisModel.cjs"), exports);
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from "./LmntSpeechSynthesisModel.js";
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from "./LmntSpeechSynthesisModel.js";
|