ruvector 0.1.59 → 0.1.60
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.
|
@@ -11,12 +11,19 @@
|
|
|
11
11
|
* - Real semantic understanding (not hash-based)
|
|
12
12
|
* - Cached model loading (downloads from HuggingFace on first use)
|
|
13
13
|
* - Batch embedding support
|
|
14
|
+
* - Optional parallel workers for 3.8x batch speedup
|
|
14
15
|
*/
|
|
15
16
|
export interface OnnxEmbedderConfig {
|
|
16
17
|
modelId?: string;
|
|
17
18
|
maxLength?: number;
|
|
18
19
|
normalize?: boolean;
|
|
19
20
|
cacheDir?: string;
|
|
21
|
+
/** Enable parallel workers for batch operations (default: auto-detect) */
|
|
22
|
+
enableParallel?: boolean | 'auto';
|
|
23
|
+
/** Number of worker threads (default: CPU cores - 1) */
|
|
24
|
+
numWorkers?: number;
|
|
25
|
+
/** Minimum batch size to use parallel processing (default: 4) */
|
|
26
|
+
parallelThreshold?: number;
|
|
20
27
|
}
|
|
21
28
|
export interface EmbeddingResult {
|
|
22
29
|
embedding: number[];
|
|
@@ -41,6 +48,7 @@ export declare function initOnnxEmbedder(config?: OnnxEmbedderConfig): Promise<b
|
|
|
41
48
|
export declare function embed(text: string): Promise<EmbeddingResult>;
|
|
42
49
|
/**
|
|
43
50
|
* Generate embeddings for multiple texts
|
|
51
|
+
* Uses parallel workers automatically for batches >= parallelThreshold
|
|
44
52
|
*/
|
|
45
53
|
export declare function embedBatch(texts: string[]): Promise<EmbeddingResult[]>;
|
|
46
54
|
/**
|
|
@@ -60,13 +68,21 @@ export declare function getDimension(): number;
|
|
|
60
68
|
*/
|
|
61
69
|
export declare function isReady(): boolean;
|
|
62
70
|
/**
|
|
63
|
-
* Get embedder stats
|
|
71
|
+
* Get embedder stats including SIMD and parallel capabilities
|
|
64
72
|
*/
|
|
65
73
|
export declare function getStats(): {
|
|
66
74
|
ready: boolean;
|
|
67
75
|
dimension: number;
|
|
68
76
|
model: string;
|
|
77
|
+
simd: boolean;
|
|
78
|
+
parallel: boolean;
|
|
79
|
+
parallelWorkers: number;
|
|
80
|
+
parallelThreshold: number;
|
|
69
81
|
};
|
|
82
|
+
/**
|
|
83
|
+
* Shutdown parallel workers (call on exit)
|
|
84
|
+
*/
|
|
85
|
+
export declare function shutdown(): Promise<void>;
|
|
70
86
|
export declare class OnnxEmbedder {
|
|
71
87
|
private config;
|
|
72
88
|
constructor(config?: OnnxEmbedderConfig);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"onnx-embedder.d.ts","sourceRoot":"","sources":["../../src/core/onnx-embedder.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"onnx-embedder.d.ts","sourceRoot":"","sources":["../../src/core/onnx-embedder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAWH,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAClC,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAMD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAeD;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAOzC;AA6DD;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,GAAE,kBAAuB,GAAG,OAAO,CAAC,OAAO,CAAC,CA2ExF;AAED;;GAEG;AACH,wBAAsB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAiBlE;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAwC5E;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAaxF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAiBjE;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;GAEG;AACH,wBAAgB,OAAO,IAAI,OAAO,CAEjC;AAED;;GAEG;AACH,wBAAgB,QAAQ,IAAI;IAC1B,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAUA;AAED;;GAEG;AACH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAM9C;AAGD,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAqB;gBAEvB,MAAM,GAAE,kBAAuB;IAIrC,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;IAIxB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAKtC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;IAKhD,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK/D,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,KAAK,IAAI,OAAO,CAEnB;CACF;AAED,eAAe,YAAY,CAAC"}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* - Real semantic understanding (not hash-based)
|
|
13
13
|
* - Cached model loading (downloads from HuggingFace on first use)
|
|
14
14
|
* - Batch embedding support
|
|
15
|
+
* - Optional parallel workers for 3.8x batch speedup
|
|
15
16
|
*/
|
|
16
17
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
17
18
|
if (k2 === undefined) k2 = k;
|
|
@@ -57,18 +58,25 @@ exports.cosineSimilarity = cosineSimilarity;
|
|
|
57
58
|
exports.getDimension = getDimension;
|
|
58
59
|
exports.isReady = isReady;
|
|
59
60
|
exports.getStats = getStats;
|
|
61
|
+
exports.shutdown = shutdown;
|
|
60
62
|
const path = __importStar(require("path"));
|
|
61
63
|
const fs = __importStar(require("fs"));
|
|
62
64
|
const url_1 = require("url");
|
|
63
65
|
// Force native dynamic import (avoids TypeScript transpiling to require)
|
|
64
66
|
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
65
67
|
const dynamicImport = new Function('specifier', 'return import(specifier)');
|
|
68
|
+
// Capability detection
|
|
69
|
+
let simdAvailable = false;
|
|
70
|
+
let parallelAvailable = false;
|
|
66
71
|
// Lazy-loaded module state
|
|
67
72
|
let wasmModule = null;
|
|
68
73
|
let embedder = null;
|
|
74
|
+
let parallelEmbedder = null;
|
|
69
75
|
let loadError = null;
|
|
70
76
|
let loadPromise = null;
|
|
71
77
|
let isInitialized = false;
|
|
78
|
+
let parallelEnabled = false;
|
|
79
|
+
let parallelThreshold = 4;
|
|
72
80
|
// Default model
|
|
73
81
|
const DEFAULT_MODEL = 'all-MiniLM-L6-v2';
|
|
74
82
|
/**
|
|
@@ -83,6 +91,63 @@ function isOnnxAvailable() {
|
|
|
83
91
|
return false;
|
|
84
92
|
}
|
|
85
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Check if parallel workers are available (npm package installed)
|
|
96
|
+
*/
|
|
97
|
+
async function detectParallelAvailable() {
|
|
98
|
+
try {
|
|
99
|
+
await dynamicImport('ruvector-onnx-embeddings-wasm/parallel');
|
|
100
|
+
parallelAvailable = true;
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
parallelAvailable = false;
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Check if SIMD is available (from WASM module)
|
|
110
|
+
*/
|
|
111
|
+
function detectSimd() {
|
|
112
|
+
try {
|
|
113
|
+
if (wasmModule && typeof wasmModule.simd_available === 'function') {
|
|
114
|
+
simdAvailable = wasmModule.simd_available();
|
|
115
|
+
return simdAvailable;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch { }
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Try to load ParallelEmbedder from npm package (optional)
|
|
123
|
+
*/
|
|
124
|
+
async function tryInitParallel(config) {
|
|
125
|
+
// Skip if explicitly disabled
|
|
126
|
+
if (config.enableParallel === false)
|
|
127
|
+
return false;
|
|
128
|
+
// For 'auto' or true, try to initialize
|
|
129
|
+
try {
|
|
130
|
+
const parallelModule = await dynamicImport('ruvector-onnx-embeddings-wasm/parallel');
|
|
131
|
+
const { ParallelEmbedder } = parallelModule;
|
|
132
|
+
parallelEmbedder = new ParallelEmbedder({
|
|
133
|
+
numWorkers: config.numWorkers,
|
|
134
|
+
});
|
|
135
|
+
await parallelEmbedder.init(config.modelId || DEFAULT_MODEL);
|
|
136
|
+
parallelThreshold = config.parallelThreshold || 4;
|
|
137
|
+
parallelEnabled = true;
|
|
138
|
+
parallelAvailable = true;
|
|
139
|
+
console.error(`Parallel embedder ready: ${parallelEmbedder.numWorkers} workers, SIMD: ${simdAvailable}`);
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
catch (e) {
|
|
143
|
+
parallelAvailable = false;
|
|
144
|
+
if (config.enableParallel === true) {
|
|
145
|
+
// Only warn if explicitly requested
|
|
146
|
+
console.error(`Parallel embedder not available: ${e.message}`);
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
86
151
|
/**
|
|
87
152
|
* Initialize the ONNX embedder (downloads model if needed)
|
|
88
153
|
*/
|
|
@@ -132,8 +197,15 @@ async function initOnnxEmbedder(config = {}) {
|
|
|
132
197
|
.setNormalize(config.normalize !== false)
|
|
133
198
|
.setPooling(0); // Mean pooling
|
|
134
199
|
embedder = wasmModule.WasmEmbedder.withConfig(modelBytes, tokenizerJson, embedderConfig);
|
|
135
|
-
|
|
200
|
+
// Detect SIMD capability
|
|
201
|
+
detectSimd();
|
|
202
|
+
console.error(`ONNX embedder ready: ${embedder.dimension()}d, SIMD: ${simdAvailable}`);
|
|
136
203
|
isInitialized = true;
|
|
204
|
+
// Try parallel by default ('auto') or if explicitly enabled
|
|
205
|
+
const shouldTryParallel = config.enableParallel !== false;
|
|
206
|
+
if (shouldTryParallel) {
|
|
207
|
+
await tryInitParallel(config);
|
|
208
|
+
}
|
|
137
209
|
}
|
|
138
210
|
catch (e) {
|
|
139
211
|
loadError = new Error(`Failed to initialize ONNX embedder: ${e.message}`);
|
|
@@ -164,6 +236,7 @@ async function embed(text) {
|
|
|
164
236
|
}
|
|
165
237
|
/**
|
|
166
238
|
* Generate embeddings for multiple texts
|
|
239
|
+
* Uses parallel workers automatically for batches >= parallelThreshold
|
|
167
240
|
*/
|
|
168
241
|
async function embedBatch(texts) {
|
|
169
242
|
if (!isInitialized) {
|
|
@@ -173,6 +246,18 @@ async function embedBatch(texts) {
|
|
|
173
246
|
throw new Error('ONNX embedder not initialized');
|
|
174
247
|
}
|
|
175
248
|
const start = performance.now();
|
|
249
|
+
// Use parallel workers for large batches
|
|
250
|
+
if (parallelEnabled && parallelEmbedder && texts.length >= parallelThreshold) {
|
|
251
|
+
const batchResults = await parallelEmbedder.embedBatch(texts);
|
|
252
|
+
const totalTime = performance.now() - start;
|
|
253
|
+
const dimension = parallelEmbedder.dimension || 384;
|
|
254
|
+
return batchResults.map((emb) => ({
|
|
255
|
+
embedding: Array.from(emb),
|
|
256
|
+
dimension,
|
|
257
|
+
timeMs: totalTime / texts.length,
|
|
258
|
+
}));
|
|
259
|
+
}
|
|
260
|
+
// Sequential fallback
|
|
176
261
|
const batchEmbeddings = embedder.embedBatch(texts);
|
|
177
262
|
const totalTime = performance.now() - start;
|
|
178
263
|
const dimension = embedder.dimension();
|
|
@@ -233,15 +318,29 @@ function isReady() {
|
|
|
233
318
|
return isInitialized;
|
|
234
319
|
}
|
|
235
320
|
/**
|
|
236
|
-
* Get embedder stats
|
|
321
|
+
* Get embedder stats including SIMD and parallel capabilities
|
|
237
322
|
*/
|
|
238
323
|
function getStats() {
|
|
239
324
|
return {
|
|
240
325
|
ready: isInitialized,
|
|
241
326
|
dimension: embedder ? embedder.dimension() : 384,
|
|
242
327
|
model: DEFAULT_MODEL,
|
|
328
|
+
simd: simdAvailable,
|
|
329
|
+
parallel: parallelEnabled,
|
|
330
|
+
parallelWorkers: parallelEmbedder?.numWorkers || 0,
|
|
331
|
+
parallelThreshold,
|
|
243
332
|
};
|
|
244
333
|
}
|
|
334
|
+
/**
|
|
335
|
+
* Shutdown parallel workers (call on exit)
|
|
336
|
+
*/
|
|
337
|
+
async function shutdown() {
|
|
338
|
+
if (parallelEmbedder) {
|
|
339
|
+
await parallelEmbedder.shutdown();
|
|
340
|
+
parallelEmbedder = null;
|
|
341
|
+
parallelEnabled = false;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
245
344
|
// Export class wrapper for compatibility
|
|
246
345
|
class OnnxEmbedder {
|
|
247
346
|
constructor(config = {}) {
|
package/package.json
CHANGED
package/ruvector.db
CHANGED
|
Binary file
|