modelmix 2.6.2 → 2.6.6
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 +7 -10
- package/index.js +47 -54
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -210,11 +210,8 @@ ModelMix now uses Bottleneck for efficient rate limiting of API requests. This i
|
|
|
210
210
|
const mmix = new ModelMix({
|
|
211
211
|
config: {
|
|
212
212
|
bottleneck: {
|
|
213
|
-
maxConcurrent:
|
|
214
|
-
minTime:
|
|
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)
|
|
213
|
+
maxConcurrent: 8, // Maximum number of concurrent requests
|
|
214
|
+
minTime: 500 // Minimum time between requests (in ms)
|
|
218
215
|
}
|
|
219
216
|
}
|
|
220
217
|
});
|
|
@@ -242,11 +239,11 @@ new ModelMix(args = { options: {}, config: {} })
|
|
|
242
239
|
- `system`: Sets the default system message for the model, e.g., "You are an assistant."
|
|
243
240
|
- `max_history`: Limits the number of historical messages to retain, e.g., 5.
|
|
244
241
|
- `bottleneck`: Configures the rate limiting behavior using Bottleneck. For example:
|
|
245
|
-
- `maxConcurrent`:
|
|
246
|
-
- `minTime`:
|
|
247
|
-
- `reservoir`:
|
|
248
|
-
- `reservoirRefreshAmount`:
|
|
249
|
-
- `reservoirRefreshInterval`:
|
|
242
|
+
- `maxConcurrent`: Maximum number of concurrent requests
|
|
243
|
+
- `minTime`: Minimum time between requests (in ms)
|
|
244
|
+
- `reservoir`: Number of requests allowed in the reservoir period
|
|
245
|
+
- `reservoirRefreshAmount`: How many requests are added when the reservoir refreshes
|
|
246
|
+
- `reservoirRefreshInterval`: Reservoir refresh interval
|
|
250
247
|
- ...(Additional configuration parameters can be added as needed)
|
|
251
248
|
|
|
252
249
|
**Methods**
|
package/index.js
CHANGED
|
@@ -3,6 +3,7 @@ const fs = require('fs');
|
|
|
3
3
|
const mime = require('mime-types');
|
|
4
4
|
const log = require('lemonlog')('ModelMix');
|
|
5
5
|
const Bottleneck = require('bottleneck');
|
|
6
|
+
const path = require('path');
|
|
6
7
|
|
|
7
8
|
class ModelMix {
|
|
8
9
|
constructor(args = { options: {}, config: {} }) {
|
|
@@ -16,12 +17,9 @@ class ModelMix {
|
|
|
16
17
|
|
|
17
18
|
// Standard Bottleneck configuration
|
|
18
19
|
const defaultBottleneckConfig = {
|
|
19
|
-
maxConcurrent:
|
|
20
|
-
minTime:
|
|
21
|
-
|
|
22
|
-
reservoirRefreshAmount: 60, // How many requests are added when the reservoir refreshes
|
|
23
|
-
reservoirRefreshInterval: 60 * 1000 // Reservoir refresh interval (60 seconds)
|
|
24
|
-
};
|
|
20
|
+
maxConcurrent: 8, // Maximum number of concurrent requests
|
|
21
|
+
minTime: 500, // Minimum time between requests (in ms)
|
|
22
|
+
};
|
|
25
23
|
|
|
26
24
|
this.config = {
|
|
27
25
|
system: 'You are an assistant.',
|
|
@@ -76,14 +74,25 @@ class ModelMix {
|
|
|
76
74
|
}
|
|
77
75
|
|
|
78
76
|
setSystemFromFile(filePath) {
|
|
77
|
+
const content = this.readFile(filePath);
|
|
78
|
+
this.setSystem(content);
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
readFile(filePath, options = { encoding: 'utf8' }) {
|
|
79
83
|
try {
|
|
80
|
-
const
|
|
81
|
-
|
|
84
|
+
const absolutePath = path.resolve(process.cwd(), filePath);
|
|
85
|
+
return fs.readFileSync(absolutePath, options);
|
|
82
86
|
} catch (error) {
|
|
83
|
-
|
|
87
|
+
if (error.code === 'ENOENT') {
|
|
88
|
+
throw new Error(`File not found: ${filePath}`);
|
|
89
|
+
} else if (error.code === 'EACCES') {
|
|
90
|
+
throw new Error(`Permission denied: ${filePath}`);
|
|
91
|
+
} else {
|
|
92
|
+
throw new Error(`Error reading file ${filePath}: ${error.message}`);
|
|
93
|
+
}
|
|
84
94
|
}
|
|
85
|
-
|
|
86
|
-
}
|
|
95
|
+
}
|
|
87
96
|
}
|
|
88
97
|
|
|
89
98
|
class MessageHandler {
|
|
@@ -113,12 +122,8 @@ class MessageHandler {
|
|
|
113
122
|
}
|
|
114
123
|
|
|
115
124
|
addTextFromFile(filePath, config = { role: "user" }) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
this.addText(content, config);
|
|
119
|
-
} catch (error) {
|
|
120
|
-
console.error(`Error reading file ${filePath}:`, error);
|
|
121
|
-
}
|
|
125
|
+
const content = this.mix.readFile(filePath);
|
|
126
|
+
this.addText(content, config);
|
|
122
127
|
return this;
|
|
123
128
|
}
|
|
124
129
|
|
|
@@ -128,44 +133,36 @@ class MessageHandler {
|
|
|
128
133
|
}
|
|
129
134
|
|
|
130
135
|
setSystemFromFile(filePath) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
this.setSystem(content);
|
|
134
|
-
} catch (error) {
|
|
135
|
-
console.error(`Error reading system message file ${filePath}:`, error);
|
|
136
|
-
}
|
|
136
|
+
const content = this.mix.readFile(filePath);
|
|
137
|
+
this.setSystem(content);
|
|
137
138
|
return this;
|
|
138
139
|
}
|
|
139
140
|
|
|
140
141
|
addImage(filePath, config = { role: "user" }) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const mimeType = mime.lookup(filePath);
|
|
142
|
+
const imageBuffer = this.mix.readFile(filePath, { encoding: null });
|
|
143
|
+
const mimeType = mime.lookup(filePath);
|
|
144
144
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
145
|
+
if (!mimeType || !mimeType.startsWith('image/')) {
|
|
146
|
+
throw new Error('Invalid image file type');
|
|
147
|
+
}
|
|
148
148
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
149
|
+
const data = imageBuffer.toString('base64');
|
|
150
|
+
|
|
151
|
+
const imageMessage = {
|
|
152
|
+
...config,
|
|
153
|
+
content: [
|
|
154
|
+
{
|
|
155
|
+
type: "image",
|
|
156
|
+
"source": {
|
|
157
|
+
type: "base64",
|
|
158
|
+
media_type: mimeType,
|
|
159
|
+
data
|
|
161
160
|
}
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
}
|
|
162
|
+
]
|
|
163
|
+
};
|
|
164
164
|
|
|
165
|
-
|
|
166
|
-
} catch (error) {
|
|
167
|
-
console.error('Error reading the image file:', error);
|
|
168
|
-
}
|
|
165
|
+
this.messages.push(imageMessage);
|
|
169
166
|
|
|
170
167
|
return this;
|
|
171
168
|
}
|
|
@@ -233,17 +230,13 @@ class MessageHandler {
|
|
|
233
230
|
}
|
|
234
231
|
|
|
235
232
|
replaceKeyFromFile(key, filePath) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
this.replace({ [key]: this.template(content, this.config.replace) });
|
|
239
|
-
} catch (error) {
|
|
240
|
-
console.error(`Error reading file ${filePath}:`, error);
|
|
241
|
-
}
|
|
233
|
+
const content = this.mix.readFile(filePath);
|
|
234
|
+
this.replace({ [key]: this.template(content, this.config.replace) });
|
|
242
235
|
return this;
|
|
243
236
|
}
|
|
244
237
|
|
|
245
238
|
template(input, replace) {
|
|
246
|
-
return input.split(/([¿?¡!,"'
|
|
239
|
+
return input.split(/([¿?¡!,"';:\(\)\.\s])/).map(x => x in replace ? replace[x] : x).join("");
|
|
247
240
|
}
|
|
248
241
|
|
|
249
242
|
groupByRoles(messages) {
|