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 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 parallel requests to avoid provider restrictions.
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 number of parallel requests to adhere to provider limitations with `max_request`.
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
- max_request: 1,
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
- - `max_request`: Limits the number of parallel requests, e.g., 1.
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
@@ -8,7 +8,7 @@ const mmix = new ModelMix({
8
8
  config: {
9
9
  system: 'You are {name} from Melmac.',
10
10
  max_history: 2,
11
- max_request: 1,
11
+ bottleneck: { maxConcurrent: 1 },
12
12
  debug: true,
13
13
  }
14
14
  });
package/demo/lmstudio.mjs CHANGED
@@ -6,7 +6,7 @@ const mmix = new ModelMix({
6
6
  },
7
7
  config: {
8
8
  max_history: 2,
9
- max_request: 1,
9
+ bottleneck: { maxConcurrent: 1 },
10
10
  }
11
11
  });
12
12
 
package/demo/parallel.mjs CHANGED
@@ -1,50 +1,51 @@
1
1
  import 'dotenv/config';
2
- import { ModelMix, MixOpenAI, MixAnthropic, MixPerplexity, MixOllama } from '../index.js';
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
- max_request: 3,
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
- // Función para crear una promesa que se resuelve después de un tiempo aleatorio
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
- // Función para realizar una solicitud al modelo
22
+ // Function to make a request to the model
22
23
  async function makeRequest(id) {
23
24
  const start = Date.now();
24
- console.log(`Iniciando solicitud ${id}`);
25
-
25
+ console.log(`Starting request ${id}`);
26
+
26
27
  const message = await mix.create('gpt-4o-mini')
27
- .addText(`Genera un hecho interesante sobre el número ${id}.`)
28
+ .addText(`Generate an interesting fact about the number ${id}.`)
28
29
  .message();
29
-
30
- // await randomDelay(); // Simula algún procesamiento adicional
31
-
30
+
31
+ await randomDelay(); // Simulates some additional processing
32
+
32
33
  const duration = Date.now() - start;
33
- console.log(`Solicitud ${id} completada en ${duration}ms: ${message}`);
34
+ console.log(`Request ${id} finished in ${duration}ms: ${message}`);
34
35
  }
35
36
 
36
- // Función principal para ejecutar el ejemplo
37
+ // Main function to run the example
37
38
  async function runExample() {
38
- console.log("Iniciando ejemplo de concurrencia...");
39
-
40
- // Crear un array de promesas para 5 solicitudes
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
- // Ejecutar todas las solicitudes y esperar a que se completen
43
+
44
+ // Execute all requests and wait for them to complete
44
45
  await Promise.all(requests);
45
-
46
- console.log("Ejemplo de concurrencia completado.");
46
+
47
+ console.log("Completed concurrency example.");
47
48
  }
48
49
 
49
- // Ejecutar el ejemplo
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 pLimit = require('p-limit');
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.limit = pLimit(this.config.max_request);
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.limit(() => new Promise(async (resolve, reject) => {
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
- resolve(result);
298
+ return result;
275
299
  } catch (error) {
276
- reject(error);
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.0",
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
- "lemonlog": "^1.1.2",
41
- "p-limit": "^3.1.0"
41
+ "bottleneck": "^2.19.5",
42
+ "lemonlog": "^1.1.2"
42
43
  }
43
44
  }