modelmix 2.6.0 → 2.6.2
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 +37 -4
- package/demo/demo.mjs +1 -1
- package/demo/lmstudio.mjs +1 -1
- package/demo/parallel.mjs +22 -21
- package/index.js +31 -7
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# 🧬 ModelMix: Unified API for Diverse AI LLM
|
|
2
2
|
|
|
3
|
-
**ModelMix** is a versatile module that enables seamless integration of various language models from different providers through a unified interface. With ModelMix, you can effortlessly manage and utilize multiple AI models while controlling
|
|
3
|
+
**ModelMix** is a versatile module that enables seamless integration of various language models from different providers through a unified interface. With ModelMix, you can effortlessly manage and utilize multiple AI models while controlling request rates to avoid provider restrictions.
|
|
4
4
|
|
|
5
5
|
## ✨ Features
|
|
6
6
|
|
|
7
7
|
- **Unified Interface**: Interact with multiple AI models through a single, coherent API.
|
|
8
|
-
- **Request Control**: Manage the
|
|
8
|
+
- **Request Rate Control**: Manage the rate of requests to adhere to provider limitations using Bottleneck.
|
|
9
9
|
- **Flexible Integration**: Easily integrate popular models like OpenAI, Anthropic, Perplexity, Groq, Ollama, LM Studio or custom models.
|
|
10
10
|
- **History Tracking**: Automatically logs the conversation history with model responses, allowing you to limit the number of historical messages with `max_history`.
|
|
11
11
|
|
|
@@ -50,7 +50,7 @@ Here's a quick example to get you started:
|
|
|
50
50
|
config: {
|
|
51
51
|
system: "You are {name} from Melmac.",
|
|
52
52
|
max_history: 2,
|
|
53
|
-
|
|
53
|
+
bottleneck: { maxConcurrent: 2 },
|
|
54
54
|
debug: true
|
|
55
55
|
}
|
|
56
56
|
});
|
|
@@ -198,6 +198,34 @@ When you run your script this way, you'll see detailed information about the req
|
|
|
198
198
|
|
|
199
199
|
This information is valuable for debugging and understanding how ModelMix is processing your requests.
|
|
200
200
|
|
|
201
|
+
## 🚦 Bottleneck Integration
|
|
202
|
+
|
|
203
|
+
ModelMix now uses Bottleneck for efficient rate limiting of API requests. This integration helps prevent exceeding API rate limits and ensures smooth operation when working with multiple models or high request volumes.
|
|
204
|
+
|
|
205
|
+
### How it works:
|
|
206
|
+
|
|
207
|
+
1. **Configuration**: Bottleneck is configured in the ModelMix constructor. You can customize the settings or use the default configuration:
|
|
208
|
+
|
|
209
|
+
```javascript
|
|
210
|
+
const mmix = new ModelMix({
|
|
211
|
+
config: {
|
|
212
|
+
bottleneck: {
|
|
213
|
+
maxConcurrent: 5, // Maximum number of concurrent requests
|
|
214
|
+
minTime: 200, // Minimum time between requests (in ms)
|
|
215
|
+
reservoir: 60, // Number of requests allowed in the reservoir period
|
|
216
|
+
reservoirRefreshAmount: 60, // How many requests are added when the reservoir refreshes
|
|
217
|
+
reservoirRefreshInterval: 60 * 1000 // Reservoir refresh interval (60 seconds)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
2. **Rate Limiting**: When you make a request using any of the attached models, Bottleneck automatically manages the request flow based on the configured settings.
|
|
224
|
+
|
|
225
|
+
3. **Automatic Queueing**: If the rate limit is reached, Bottleneck will automatically queue subsequent requests and process them as capacity becomes available.
|
|
226
|
+
|
|
227
|
+
This integration ensures that your application respects API rate limits while maximizing throughput, providing a robust solution for managing multiple AI model interactions.
|
|
228
|
+
|
|
201
229
|
## 📚 ModelMix Class Overview
|
|
202
230
|
|
|
203
231
|
```javascript
|
|
@@ -213,7 +241,12 @@ new ModelMix(args = { options: {}, config: {} })
|
|
|
213
241
|
- **config**: This object contains configuration settings that control the behavior of the `ModelMix` instance. These settings can also be overridden for specific model instances. Examples of configuration settings include:
|
|
214
242
|
- `system`: Sets the default system message for the model, e.g., "You are an assistant."
|
|
215
243
|
- `max_history`: Limits the number of historical messages to retain, e.g., 5.
|
|
216
|
-
- `
|
|
244
|
+
- `bottleneck`: Configures the rate limiting behavior using Bottleneck. For example:
|
|
245
|
+
- `maxConcurrent`: 5 Maximum number of concurrent requests
|
|
246
|
+
- `minTime`: 200 Minimum time between requests (in ms)
|
|
247
|
+
- `reservoir`: 60 Number of requests allowed in the reservoir period
|
|
248
|
+
- `reservoirRefreshAmount`: 60 How many requests are added when the reservoir refreshes
|
|
249
|
+
- `reservoirRefreshInterval`: 60 * 1000 // Reservoir refresh interval (60 seconds)
|
|
217
250
|
- ...(Additional configuration parameters can be added as needed)
|
|
218
251
|
|
|
219
252
|
**Methods**
|
package/demo/demo.mjs
CHANGED
package/demo/lmstudio.mjs
CHANGED
package/demo/parallel.mjs
CHANGED
|
@@ -1,50 +1,51 @@
|
|
|
1
1
|
import 'dotenv/config';
|
|
2
|
-
import { ModelMix, MixOpenAI
|
|
2
|
+
import { ModelMix, MixOpenAI } from '../index.js';
|
|
3
3
|
|
|
4
4
|
const mix = new ModelMix({
|
|
5
5
|
options: {
|
|
6
6
|
max_tokens: 200,
|
|
7
7
|
},
|
|
8
8
|
config: {
|
|
9
|
-
system: 'You are {name} from Melmac.',
|
|
10
9
|
max_history: 2,
|
|
11
|
-
|
|
10
|
+
bottleneck: {
|
|
11
|
+
maxConcurrent: 1, // Maximum number of concurrent requests
|
|
12
|
+
},
|
|
12
13
|
debug: true,
|
|
13
14
|
}
|
|
14
15
|
});
|
|
15
16
|
|
|
16
17
|
mix.attach(new MixOpenAI());
|
|
17
18
|
|
|
18
|
-
//
|
|
19
|
+
// Function to create a promise that resolves after a random time
|
|
19
20
|
const randomDelay = () => new Promise(resolve => setTimeout(resolve, Math.random() * 2000 + 1000));
|
|
20
21
|
|
|
21
|
-
//
|
|
22
|
+
// Function to make a request to the model
|
|
22
23
|
async function makeRequest(id) {
|
|
23
24
|
const start = Date.now();
|
|
24
|
-
console.log(`
|
|
25
|
-
|
|
25
|
+
console.log(`Starting request ${id}`);
|
|
26
|
+
|
|
26
27
|
const message = await mix.create('gpt-4o-mini')
|
|
27
|
-
.addText(`
|
|
28
|
+
.addText(`Generate an interesting fact about the number ${id}.`)
|
|
28
29
|
.message();
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
|
|
31
|
+
await randomDelay(); // Simulates some additional processing
|
|
32
|
+
|
|
32
33
|
const duration = Date.now() - start;
|
|
33
|
-
console.log(`
|
|
34
|
+
console.log(`Request ${id} finished in ${duration}ms: ${message}`);
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
//
|
|
37
|
+
// Main function to run the example
|
|
37
38
|
async function runExample() {
|
|
38
|
-
console.log("
|
|
39
|
-
|
|
40
|
-
//
|
|
39
|
+
console.log("Starting concurrency example...");
|
|
40
|
+
|
|
41
|
+
// Create a promise array for 5 requests
|
|
41
42
|
const requests = Array.from({ length: 5 }, (_, i) => makeRequest(i + 1));
|
|
42
|
-
|
|
43
|
-
//
|
|
43
|
+
|
|
44
|
+
// Execute all requests and wait for them to complete
|
|
44
45
|
await Promise.all(requests);
|
|
45
|
-
|
|
46
|
-
console.log("
|
|
46
|
+
|
|
47
|
+
console.log("Completed concurrency example.");
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
//
|
|
50
|
+
// Run the example
|
|
50
51
|
runExample().catch(console.error);
|
package/index.js
CHANGED
|
@@ -2,7 +2,7 @@ const axios = require('axios');
|
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const mime = require('mime-types');
|
|
4
4
|
const log = require('lemonlog')('ModelMix');
|
|
5
|
-
const
|
|
5
|
+
const Bottleneck = require('bottleneck');
|
|
6
6
|
|
|
7
7
|
class ModelMix {
|
|
8
8
|
constructor(args = { options: {}, config: {} }) {
|
|
@@ -14,15 +14,24 @@ class ModelMix {
|
|
|
14
14
|
...args.options
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
+
// Standard Bottleneck configuration
|
|
18
|
+
const defaultBottleneckConfig = {
|
|
19
|
+
maxConcurrent: 5, // Maximum number of concurrent requests
|
|
20
|
+
minTime: 200, // Minimum time between requests (in ms)
|
|
21
|
+
reservoir: 60, // Number of requests allowed in the reservoir period
|
|
22
|
+
reservoirRefreshAmount: 60, // How many requests are added when the reservoir refreshes
|
|
23
|
+
reservoirRefreshInterval: 60 * 1000 // Reservoir refresh interval (60 seconds)
|
|
24
|
+
};
|
|
25
|
+
|
|
17
26
|
this.config = {
|
|
18
27
|
system: 'You are an assistant.',
|
|
19
|
-
max_request: 1,
|
|
20
28
|
max_history: 5, // Default max history
|
|
21
29
|
debug: false,
|
|
30
|
+
bottleneck: defaultBottleneckConfig,
|
|
22
31
|
...args.config
|
|
23
32
|
}
|
|
24
33
|
|
|
25
|
-
this.
|
|
34
|
+
this.limiter = new Bottleneck(this.config.bottleneck);
|
|
26
35
|
}
|
|
27
36
|
|
|
28
37
|
replace(keyValues) {
|
|
@@ -60,6 +69,21 @@ class ModelMix {
|
|
|
60
69
|
|
|
61
70
|
return new MessageHandler(this, modelEntry, options, config);
|
|
62
71
|
}
|
|
72
|
+
|
|
73
|
+
setSystem(text) {
|
|
74
|
+
this.config.system = text;
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
setSystemFromFile(filePath) {
|
|
79
|
+
try {
|
|
80
|
+
const content = fs.readFileSync(filePath, { encoding: 'utf8' });
|
|
81
|
+
this.setSystem(content);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error(`Error reading system message file ${filePath}:`, error);
|
|
84
|
+
}
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
63
87
|
}
|
|
64
88
|
|
|
65
89
|
class MessageHandler {
|
|
@@ -255,7 +279,7 @@ class MessageHandler {
|
|
|
255
279
|
}
|
|
256
280
|
|
|
257
281
|
async execute() {
|
|
258
|
-
return this.mix.
|
|
282
|
+
return this.mix.limiter.schedule(async () => {
|
|
259
283
|
await this.processImageUrls();
|
|
260
284
|
|
|
261
285
|
this.applyTemplate();
|
|
@@ -271,11 +295,11 @@ class MessageHandler {
|
|
|
271
295
|
try {
|
|
272
296
|
const result = await this.modelEntry.create({ options: this.options, config: this.config });
|
|
273
297
|
this.messages.push({ role: "assistant", content: result.message });
|
|
274
|
-
|
|
298
|
+
return result;
|
|
275
299
|
} catch (error) {
|
|
276
|
-
|
|
300
|
+
throw error;
|
|
277
301
|
}
|
|
278
|
-
})
|
|
302
|
+
});
|
|
279
303
|
}
|
|
280
304
|
}
|
|
281
305
|
class MixCustom {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "modelmix",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.2",
|
|
4
4
|
"description": "🧬 ModelMix - Unified API for Diverse AI LLM.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
"gpt-4o-mini",
|
|
28
28
|
"4o",
|
|
29
29
|
"ollama",
|
|
30
|
-
"lmstudio"
|
|
30
|
+
"lmstudio",
|
|
31
|
+
"bottleneck"
|
|
31
32
|
],
|
|
32
33
|
"author": "Martin Clasen",
|
|
33
34
|
"license": "MIT",
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
"homepage": "https://github.com/clasen/ModelMix#readme",
|
|
38
39
|
"dependencies": {
|
|
39
40
|
"axios": "^1.7.4",
|
|
40
|
-
"
|
|
41
|
-
"
|
|
41
|
+
"bottleneck": "^2.19.5",
|
|
42
|
+
"lemonlog": "^1.1.2"
|
|
42
43
|
}
|
|
43
44
|
}
|