rag-lite-ts 2.0.5 → 2.1.1
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 +815 -808
- package/dist/cli/indexer.js +3 -39
- package/dist/cli/search.d.ts +1 -1
- package/dist/cli/search.js +123 -19
- package/dist/cli.js +77 -94
- package/dist/core/binary-index-format.d.ts +28 -2
- package/dist/core/binary-index-format.js +196 -27
- package/dist/core/db.js +173 -173
- package/dist/core/ingestion.d.ts +5 -1
- package/dist/core/ingestion.js +123 -18
- package/dist/core/lazy-dependency-loader.d.ts +3 -8
- package/dist/core/lazy-dependency-loader.js +11 -29
- package/dist/core/mode-detection-service.js +1 -1
- package/dist/core/reranking-config.d.ts +1 -1
- package/dist/core/reranking-config.js +7 -16
- package/dist/core/reranking-factory.js +3 -184
- package/dist/core/search.d.ts +10 -0
- package/dist/core/search.js +35 -11
- package/dist/core/types.d.ts +1 -1
- package/dist/core/vector-index.d.ts +4 -0
- package/dist/core/vector-index.js +6 -0
- package/dist/factories/ingestion-factory.js +3 -1
- package/dist/file-processor.d.ts +2 -0
- package/dist/file-processor.js +20 -0
- package/dist/index-manager.d.ts +17 -1
- package/dist/index-manager.js +148 -7
- package/dist/mcp-server.js +127 -105
- package/dist/multimodal/clip-embedder.js +6 -2
- package/package.json +1 -1
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import { readFileSync, writeFileSync } from 'fs';
|
|
18
18
|
export class BinaryIndexFormat {
|
|
19
19
|
/**
|
|
20
|
-
* Save index data to binary format
|
|
20
|
+
* Save index data to binary format (original format for backward compatibility)
|
|
21
21
|
*
|
|
22
22
|
* File structure:
|
|
23
23
|
* - Header (24 bytes): dimensions, maxElements, M, efConstruction, seed, currentSize
|
|
@@ -66,7 +66,115 @@ export class BinaryIndexFormat {
|
|
|
66
66
|
writeFileSync(indexPath, Buffer.from(buffer));
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
|
-
*
|
|
69
|
+
* Save index data to grouped binary format
|
|
70
|
+
*
|
|
71
|
+
* File structure:
|
|
72
|
+
* - Extended Header (40 bytes):
|
|
73
|
+
* - Original 6 fields (24 bytes)
|
|
74
|
+
* - hasGroups flag (4 bytes)
|
|
75
|
+
* - textOffset (4 bytes)
|
|
76
|
+
* - textCount (4 bytes)
|
|
77
|
+
* - imageOffset (4 bytes)
|
|
78
|
+
* - imageCount (4 bytes)
|
|
79
|
+
* - Data section: [text vectors...][image vectors...]
|
|
80
|
+
*
|
|
81
|
+
* @param indexPath Path to save the binary index file
|
|
82
|
+
* @param data Index data to serialize
|
|
83
|
+
*/
|
|
84
|
+
static async saveGrouped(indexPath, data) {
|
|
85
|
+
if (!data.hasContentTypeGroups || !data.textVectors || !data.imageVectors) {
|
|
86
|
+
// Fallback to original format
|
|
87
|
+
return this.save(indexPath, data);
|
|
88
|
+
}
|
|
89
|
+
const headerSize = 44; // Extended header: 24 + 20 bytes (hasGroups + textOffset + textCount + imageOffset + imageCount)
|
|
90
|
+
const vectorSize = 4 + (data.dimensions * 4); // id + vector
|
|
91
|
+
// Calculate offsets and total size
|
|
92
|
+
const textOffset = headerSize;
|
|
93
|
+
const imageOffset = textOffset + (data.textVectors.length * vectorSize);
|
|
94
|
+
const totalSize = imageOffset + (data.imageVectors.length * vectorSize);
|
|
95
|
+
const buffer = new ArrayBuffer(totalSize);
|
|
96
|
+
const view = new DataView(buffer);
|
|
97
|
+
let offset = 0;
|
|
98
|
+
// Write extended header (40 bytes, all little-endian)
|
|
99
|
+
if (offset + 40 > buffer.byteLength) {
|
|
100
|
+
throw new Error(`Header write would exceed buffer bounds: offset=${offset}, headerSize=40, bufferSize=${buffer.byteLength}`);
|
|
101
|
+
}
|
|
102
|
+
view.setUint32(offset, data.dimensions, true);
|
|
103
|
+
offset += 4;
|
|
104
|
+
view.setUint32(offset, data.maxElements, true);
|
|
105
|
+
offset += 4;
|
|
106
|
+
view.setUint32(offset, data.M, true);
|
|
107
|
+
offset += 4;
|
|
108
|
+
view.setUint32(offset, data.efConstruction, true);
|
|
109
|
+
offset += 4;
|
|
110
|
+
view.setUint32(offset, data.seed, true);
|
|
111
|
+
offset += 4;
|
|
112
|
+
view.setUint32(offset, data.currentSize, true);
|
|
113
|
+
offset += 4;
|
|
114
|
+
// Extended fields
|
|
115
|
+
view.setUint32(offset, 1, true);
|
|
116
|
+
offset += 4; // hasGroups = 1
|
|
117
|
+
view.setUint32(offset, textOffset, true);
|
|
118
|
+
offset += 4;
|
|
119
|
+
view.setUint32(offset, data.textVectors.length, true);
|
|
120
|
+
offset += 4;
|
|
121
|
+
view.setUint32(offset, imageOffset, true);
|
|
122
|
+
offset += 4;
|
|
123
|
+
view.setUint32(offset, data.imageVectors.length, true);
|
|
124
|
+
offset += 4;
|
|
125
|
+
// Write text vectors
|
|
126
|
+
for (const item of data.textVectors) {
|
|
127
|
+
// Ensure 4-byte alignment
|
|
128
|
+
if (offset % 4 !== 0) {
|
|
129
|
+
throw new Error(`Offset ${offset} is not 4-byte aligned`);
|
|
130
|
+
}
|
|
131
|
+
// Check bounds before writing
|
|
132
|
+
if (offset + 4 > buffer.byteLength) {
|
|
133
|
+
throw new Error(`ID write would exceed buffer bounds: offset=${offset}, bufferSize=${buffer.byteLength}`);
|
|
134
|
+
}
|
|
135
|
+
// Write vector ID
|
|
136
|
+
view.setUint32(offset, item.id, true);
|
|
137
|
+
offset += 4;
|
|
138
|
+
// Check bounds for vector data
|
|
139
|
+
const vectorDataSize = item.vector.length * 4;
|
|
140
|
+
if (offset + vectorDataSize > buffer.byteLength) {
|
|
141
|
+
throw new Error(`Vector data write would exceed buffer bounds: offset=${offset}, dataSize=${vectorDataSize}, bufferSize=${buffer.byteLength}`);
|
|
142
|
+
}
|
|
143
|
+
// Write vector data
|
|
144
|
+
for (let i = 0; i < item.vector.length; i++) {
|
|
145
|
+
view.setFloat32(offset, item.vector[i], true);
|
|
146
|
+
offset += 4;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Write image vectors
|
|
150
|
+
for (const item of data.imageVectors) {
|
|
151
|
+
// Ensure 4-byte alignment
|
|
152
|
+
if (offset % 4 !== 0) {
|
|
153
|
+
throw new Error(`Offset ${offset} is not 4-byte aligned`);
|
|
154
|
+
}
|
|
155
|
+
// Check bounds before writing
|
|
156
|
+
if (offset + 4 > buffer.byteLength) {
|
|
157
|
+
throw new Error(`ID write would exceed buffer bounds: offset=${offset}, bufferSize=${buffer.byteLength}`);
|
|
158
|
+
}
|
|
159
|
+
// Write vector ID
|
|
160
|
+
view.setUint32(offset, item.id, true);
|
|
161
|
+
offset += 4;
|
|
162
|
+
// Check bounds for vector data
|
|
163
|
+
const vectorDataSize = item.vector.length * 4;
|
|
164
|
+
if (offset + vectorDataSize > buffer.byteLength) {
|
|
165
|
+
throw new Error(`Vector data write would exceed buffer bounds: offset=${offset}, dataSize=${vectorDataSize}, bufferSize=${buffer.byteLength}`);
|
|
166
|
+
}
|
|
167
|
+
// Write vector data
|
|
168
|
+
for (let i = 0; i < item.vector.length; i++) {
|
|
169
|
+
view.setFloat32(offset, item.vector[i], true);
|
|
170
|
+
offset += 4;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// Write to file
|
|
174
|
+
writeFileSync(indexPath, Buffer.from(buffer));
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Load index data from binary format (supports both original and grouped formats)
|
|
70
178
|
*
|
|
71
179
|
* Uses zero-copy Float32Array views for efficient loading.
|
|
72
180
|
* Copies the views to ensure data persistence after buffer lifecycle.
|
|
@@ -78,7 +186,7 @@ export class BinaryIndexFormat {
|
|
|
78
186
|
const buffer = readFileSync(indexPath);
|
|
79
187
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
80
188
|
let offset = 0;
|
|
81
|
-
// Read header (24 bytes, all little-endian)
|
|
189
|
+
// Read basic header (24 bytes, all little-endian)
|
|
82
190
|
const dimensions = view.getUint32(offset, true);
|
|
83
191
|
offset += 4;
|
|
84
192
|
const maxElements = view.getUint32(offset, true);
|
|
@@ -91,32 +199,93 @@ export class BinaryIndexFormat {
|
|
|
91
199
|
offset += 4;
|
|
92
200
|
const currentSize = view.getUint32(offset, true);
|
|
93
201
|
offset += 4;
|
|
94
|
-
//
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
|
|
202
|
+
// Check if this is the extended grouped format (40+ bytes header)
|
|
203
|
+
const hasGroups = buffer.byteLength >= 40 ? view.getUint32(offset, true) : 0;
|
|
204
|
+
if (hasGroups === 1 && buffer.byteLength >= 40) {
|
|
205
|
+
// Load grouped format
|
|
206
|
+
const textOffset = view.getUint32(offset + 4, true);
|
|
207
|
+
const textCount = view.getUint32(offset + 8, true);
|
|
208
|
+
const imageOffset = view.getUint32(offset + 12, true);
|
|
209
|
+
const imageCount = view.getUint32(offset + 16, true);
|
|
210
|
+
// Load text vectors
|
|
211
|
+
const textVectors = [];
|
|
212
|
+
offset = textOffset;
|
|
213
|
+
for (let i = 0; i < textCount; i++) {
|
|
214
|
+
// Ensure 4-byte alignment
|
|
215
|
+
if (offset % 4 !== 0) {
|
|
216
|
+
throw new Error(`Offset ${offset} is not 4-byte aligned`);
|
|
217
|
+
}
|
|
218
|
+
// Read vector ID
|
|
219
|
+
const id = view.getUint32(offset, true);
|
|
220
|
+
offset += 4;
|
|
221
|
+
// Zero-copy Float32Array view
|
|
222
|
+
const vectorView = new Float32Array(buffer.buffer, buffer.byteOffset + offset, dimensions);
|
|
223
|
+
// Copy to avoid buffer lifecycle issues
|
|
224
|
+
const vector = new Float32Array(vectorView);
|
|
225
|
+
offset += dimensions * 4;
|
|
226
|
+
textVectors.push({ id, vector });
|
|
100
227
|
}
|
|
101
|
-
//
|
|
102
|
-
const
|
|
103
|
-
offset
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
228
|
+
// Load image vectors
|
|
229
|
+
const imageVectors = [];
|
|
230
|
+
offset = imageOffset;
|
|
231
|
+
for (let i = 0; i < imageCount; i++) {
|
|
232
|
+
// Ensure 4-byte alignment
|
|
233
|
+
if (offset % 4 !== 0) {
|
|
234
|
+
throw new Error(`Offset ${offset} is not 4-byte aligned`);
|
|
235
|
+
}
|
|
236
|
+
// Read vector ID
|
|
237
|
+
const id = view.getUint32(offset, true);
|
|
238
|
+
offset += 4;
|
|
239
|
+
// Zero-copy Float32Array view
|
|
240
|
+
const vectorView = new Float32Array(buffer.buffer, buffer.byteOffset + offset, dimensions);
|
|
241
|
+
// Copy to avoid buffer lifecycle issues
|
|
242
|
+
const vector = new Float32Array(vectorView);
|
|
243
|
+
offset += dimensions * 4;
|
|
244
|
+
imageVectors.push({ id, vector });
|
|
245
|
+
}
|
|
246
|
+
// Combine all vectors for backward compatibility
|
|
247
|
+
const allVectors = [...textVectors, ...imageVectors];
|
|
248
|
+
return {
|
|
249
|
+
dimensions,
|
|
250
|
+
maxElements,
|
|
251
|
+
M,
|
|
252
|
+
efConstruction,
|
|
253
|
+
seed,
|
|
254
|
+
currentSize,
|
|
255
|
+
vectors: allVectors,
|
|
256
|
+
hasContentTypeGroups: true,
|
|
257
|
+
textVectors,
|
|
258
|
+
imageVectors
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
// Load original format
|
|
263
|
+
const vectors = [];
|
|
264
|
+
for (let i = 0; i < currentSize; i++) {
|
|
265
|
+
// Ensure 4-byte alignment (should always be true with our format)
|
|
266
|
+
if (offset % 4 !== 0) {
|
|
267
|
+
throw new Error(`Offset ${offset} is not 4-byte aligned`);
|
|
268
|
+
}
|
|
269
|
+
// Read vector ID
|
|
270
|
+
const id = view.getUint32(offset, true);
|
|
271
|
+
offset += 4;
|
|
272
|
+
// Zero-copy Float32Array view (fast!)
|
|
273
|
+
const vectorView = new Float32Array(buffer.buffer, buffer.byteOffset + offset, dimensions);
|
|
274
|
+
// Copy to avoid buffer lifecycle issues
|
|
275
|
+
const vector = new Float32Array(vectorView);
|
|
276
|
+
offset += dimensions * 4;
|
|
277
|
+
vectors.push({ id, vector });
|
|
278
|
+
}
|
|
279
|
+
return {
|
|
280
|
+
dimensions,
|
|
281
|
+
maxElements,
|
|
282
|
+
M,
|
|
283
|
+
efConstruction,
|
|
284
|
+
seed,
|
|
285
|
+
currentSize,
|
|
286
|
+
vectors
|
|
287
|
+
};
|
|
110
288
|
}
|
|
111
|
-
return {
|
|
112
|
-
dimensions,
|
|
113
|
-
maxElements,
|
|
114
|
-
M,
|
|
115
|
-
efConstruction,
|
|
116
|
-
seed,
|
|
117
|
-
currentSize,
|
|
118
|
-
vectors
|
|
119
|
-
};
|
|
120
289
|
}
|
|
121
290
|
}
|
|
122
291
|
//# sourceMappingURL=binary-index-format.js.map
|