doc2vec 2.0.0 → 2.3.0
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 +64 -5
- package/dist/code-chunker.js +179 -0
- package/dist/content-processor.js +469 -83
- package/dist/database.js +197 -7
- package/dist/doc2vec.js +474 -4
- package/dist/vitest.config.js +16 -0
- package/package.json +10 -2
package/dist/database.js
CHANGED
|
@@ -59,6 +59,8 @@ class DatabaseManager {
|
|
|
59
59
|
embedding FLOAT[3072],
|
|
60
60
|
product_name TEXT,
|
|
61
61
|
version TEXT,
|
|
62
|
+
branch TEXT,
|
|
63
|
+
repo TEXT,
|
|
62
64
|
heading_hierarchy TEXT,
|
|
63
65
|
section TEXT,
|
|
64
66
|
chunk_id TEXT UNIQUE,
|
|
@@ -141,6 +143,82 @@ class DatabaseManager {
|
|
|
141
143
|
// Nothing special to initialize as we'll use the same collection
|
|
142
144
|
}
|
|
143
145
|
}
|
|
146
|
+
static async getMetadataValue(dbConnection, key, defaultValue, logger) {
|
|
147
|
+
try {
|
|
148
|
+
if (dbConnection.type === 'sqlite') {
|
|
149
|
+
const stmt = dbConnection.db.prepare('SELECT value FROM vec_metadata WHERE key = ?');
|
|
150
|
+
const result = stmt.get(key);
|
|
151
|
+
if (result) {
|
|
152
|
+
logger.debug(`Retrieved metadata value for ${key}: ${result.value}`);
|
|
153
|
+
return result.value;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else if (dbConnection.type === 'qdrant') {
|
|
157
|
+
const metadataUUID = utils_1.Utils.generateMetadataUUID(key);
|
|
158
|
+
logger.debug(`Looking up metadata with UUID: ${metadataUUID}`);
|
|
159
|
+
try {
|
|
160
|
+
const response = await dbConnection.client.retrieve(dbConnection.collectionName, {
|
|
161
|
+
ids: [metadataUUID],
|
|
162
|
+
with_payload: true,
|
|
163
|
+
with_vector: false
|
|
164
|
+
});
|
|
165
|
+
if (response.length > 0 && response[0].payload?.metadata_value) {
|
|
166
|
+
const value = response[0].payload.metadata_value;
|
|
167
|
+
logger.debug(`Retrieved metadata value for ${key}: ${value}`);
|
|
168
|
+
return value;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
logger.warn(`Failed to retrieve metadata for ${key}:`, error);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
logger.warn(`Error retrieving metadata value for ${key}:`, error);
|
|
178
|
+
}
|
|
179
|
+
if (defaultValue !== undefined) {
|
|
180
|
+
logger.debug(`No metadata value found for ${key}, using default: ${defaultValue}`);
|
|
181
|
+
}
|
|
182
|
+
return defaultValue;
|
|
183
|
+
}
|
|
184
|
+
static async setMetadataValue(dbConnection, key, value, logger) {
|
|
185
|
+
try {
|
|
186
|
+
if (dbConnection.type === 'sqlite') {
|
|
187
|
+
const stmt = dbConnection.db.prepare(`
|
|
188
|
+
INSERT INTO vec_metadata (key, value) VALUES (?, ?)
|
|
189
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value
|
|
190
|
+
`);
|
|
191
|
+
stmt.run(key, value);
|
|
192
|
+
logger.debug(`Updated metadata value for ${key}`);
|
|
193
|
+
}
|
|
194
|
+
else if (dbConnection.type === 'qdrant') {
|
|
195
|
+
const metadataUUID = utils_1.Utils.generateMetadataUUID(key);
|
|
196
|
+
const dummyEmbeddingSize = 3072;
|
|
197
|
+
const dummyEmbedding = new Array(dummyEmbeddingSize).fill(0);
|
|
198
|
+
const metadataPoint = {
|
|
199
|
+
id: metadataUUID,
|
|
200
|
+
vector: dummyEmbedding,
|
|
201
|
+
payload: {
|
|
202
|
+
metadata_key: key,
|
|
203
|
+
metadata_value: value,
|
|
204
|
+
is_metadata: true,
|
|
205
|
+
content: `Metadata: ${key}`,
|
|
206
|
+
product_name: 'system',
|
|
207
|
+
version: 'metadata',
|
|
208
|
+
url: 'metadata://' + key
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
await dbConnection.client.upsert(dbConnection.collectionName, {
|
|
212
|
+
wait: true,
|
|
213
|
+
points: [metadataPoint]
|
|
214
|
+
});
|
|
215
|
+
logger.debug(`Updated metadata value for ${key}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
logger.error(`Failed to update metadata value for ${key}:`, error);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
144
222
|
static async getLastRunDate(dbConnection, repo, defaultDate, logger) {
|
|
145
223
|
const metadataKey = `last_run_${repo.replace('/', '_')}`;
|
|
146
224
|
try {
|
|
@@ -226,32 +304,98 @@ class DatabaseManager {
|
|
|
226
304
|
}
|
|
227
305
|
}
|
|
228
306
|
static prepareSQLiteStatements(db) {
|
|
307
|
+
let cached = this.columnCache.get(db);
|
|
308
|
+
if (!cached) {
|
|
309
|
+
cached = {
|
|
310
|
+
hasBranch: this.hasColumn(db, 'branch'),
|
|
311
|
+
hasRepo: this.hasColumn(db, 'repo')
|
|
312
|
+
};
|
|
313
|
+
this.columnCache.set(db, cached);
|
|
314
|
+
}
|
|
315
|
+
const hasBranchColumn = cached.hasBranch;
|
|
316
|
+
const hasRepoColumn = cached.hasRepo;
|
|
317
|
+
const insertColumns = [
|
|
318
|
+
'embedding',
|
|
319
|
+
'product_name',
|
|
320
|
+
'version',
|
|
321
|
+
...(hasBranchColumn ? ['branch'] : []),
|
|
322
|
+
...(hasRepoColumn ? ['repo'] : []),
|
|
323
|
+
'heading_hierarchy',
|
|
324
|
+
'section',
|
|
325
|
+
'chunk_id',
|
|
326
|
+
'content',
|
|
327
|
+
'url',
|
|
328
|
+
'hash',
|
|
329
|
+
'chunk_index',
|
|
330
|
+
'total_chunks'
|
|
331
|
+
];
|
|
332
|
+
const insertPlaceholders = insertColumns.map(() => '?').join(', ');
|
|
333
|
+
const updateSet = [
|
|
334
|
+
'embedding = ?',
|
|
335
|
+
'product_name = ?',
|
|
336
|
+
'version = ?',
|
|
337
|
+
...(hasBranchColumn ? ['branch = ?'] : []),
|
|
338
|
+
...(hasRepoColumn ? ['repo = ?'] : []),
|
|
339
|
+
'heading_hierarchy = ?',
|
|
340
|
+
'section = ?',
|
|
341
|
+
'content = ?',
|
|
342
|
+
'url = ?',
|
|
343
|
+
'hash = ?',
|
|
344
|
+
'chunk_index = ?',
|
|
345
|
+
'total_chunks = ?'
|
|
346
|
+
].join(', ');
|
|
229
347
|
return {
|
|
230
348
|
insertStmt: db.prepare(`
|
|
231
|
-
INSERT INTO vec_items (
|
|
232
|
-
VALUES (
|
|
349
|
+
INSERT INTO vec_items (${insertColumns})
|
|
350
|
+
VALUES (${insertPlaceholders})
|
|
233
351
|
`),
|
|
234
352
|
checkHashStmt: db.prepare(`SELECT hash FROM vec_items WHERE chunk_id = ?`),
|
|
235
353
|
updateStmt: db.prepare(`
|
|
236
|
-
UPDATE vec_items SET
|
|
354
|
+
UPDATE vec_items SET ${updateSet}
|
|
237
355
|
WHERE chunk_id = ?
|
|
238
356
|
`),
|
|
239
357
|
getAllChunkIdsStmt: db.prepare(`SELECT chunk_id FROM vec_items`),
|
|
240
|
-
deleteChunkStmt: db.prepare(`DELETE FROM vec_items WHERE chunk_id = ?`)
|
|
358
|
+
deleteChunkStmt: db.prepare(`DELETE FROM vec_items WHERE chunk_id = ?`),
|
|
359
|
+
hasBranchColumn,
|
|
360
|
+
hasRepoColumn
|
|
241
361
|
};
|
|
242
362
|
}
|
|
243
363
|
static insertVectorsSQLite(db, chunk, embedding, logger, chunkHash) {
|
|
244
|
-
const { insertStmt, updateStmt } = this.prepareSQLiteStatements(db);
|
|
364
|
+
const { insertStmt, updateStmt, hasBranchColumn, hasRepoColumn } = this.prepareSQLiteStatements(db);
|
|
245
365
|
const hash = chunkHash || utils_1.Utils.generateHash(chunk.content);
|
|
246
366
|
const transaction = db.transaction(() => {
|
|
247
367
|
// Use BigInt for true integer representation in SQLite vec0
|
|
248
368
|
const chunkIndex = BigInt(chunk.metadata.chunk_index | 0);
|
|
249
369
|
const totalChunks = BigInt(chunk.metadata.total_chunks | 0);
|
|
250
370
|
try {
|
|
251
|
-
|
|
371
|
+
const insertValues = [
|
|
372
|
+
new Float32Array(embedding),
|
|
373
|
+
chunk.metadata.product_name,
|
|
374
|
+
chunk.metadata.version
|
|
375
|
+
];
|
|
376
|
+
if (hasBranchColumn) {
|
|
377
|
+
insertValues.push(chunk.metadata.branch ?? '');
|
|
378
|
+
}
|
|
379
|
+
if (hasRepoColumn) {
|
|
380
|
+
insertValues.push(chunk.metadata.repo ?? '');
|
|
381
|
+
}
|
|
382
|
+
insertValues.push(JSON.stringify(chunk.metadata.heading_hierarchy), chunk.metadata.section, chunk.metadata.chunk_id, chunk.content, chunk.metadata.url, hash, chunkIndex, totalChunks);
|
|
383
|
+
insertStmt.run(...insertValues);
|
|
252
384
|
}
|
|
253
385
|
catch (error) {
|
|
254
|
-
|
|
386
|
+
const updateValues = [
|
|
387
|
+
new Float32Array(embedding),
|
|
388
|
+
chunk.metadata.product_name,
|
|
389
|
+
chunk.metadata.version
|
|
390
|
+
];
|
|
391
|
+
if (hasBranchColumn) {
|
|
392
|
+
updateValues.push(chunk.metadata.branch ?? '');
|
|
393
|
+
}
|
|
394
|
+
if (hasRepoColumn) {
|
|
395
|
+
updateValues.push(chunk.metadata.repo ?? '');
|
|
396
|
+
}
|
|
397
|
+
updateValues.push(JSON.stringify(chunk.metadata.heading_hierarchy), chunk.metadata.section, chunk.content, chunk.metadata.url, hash, chunkIndex, totalChunks, chunk.metadata.chunk_id);
|
|
398
|
+
updateStmt.run(...updateValues);
|
|
255
399
|
}
|
|
256
400
|
});
|
|
257
401
|
transaction();
|
|
@@ -277,6 +421,8 @@ class DatabaseManager {
|
|
|
277
421
|
content: chunk.content,
|
|
278
422
|
product_name: chunk.metadata.product_name,
|
|
279
423
|
version: chunk.metadata.version,
|
|
424
|
+
branch: chunk.metadata.branch,
|
|
425
|
+
repo: chunk.metadata.repo,
|
|
280
426
|
heading_hierarchy: chunk.metadata.heading_hierarchy,
|
|
281
427
|
section: chunk.metadata.section,
|
|
282
428
|
url: chunk.metadata.url,
|
|
@@ -366,6 +512,49 @@ class DatabaseManager {
|
|
|
366
512
|
logger.error(`Error removing obsolete chunks from Qdrant:`, error);
|
|
367
513
|
}
|
|
368
514
|
}
|
|
515
|
+
static hasColumn(db, columnName) {
|
|
516
|
+
try {
|
|
517
|
+
const columns = db.prepare('PRAGMA table_info(vec_items)').all();
|
|
518
|
+
return columns.some((column) => column.name === columnName);
|
|
519
|
+
}
|
|
520
|
+
catch (error) {
|
|
521
|
+
return false;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
static removeChunksByUrlSQLite(db, url, logger) {
|
|
525
|
+
const deleteStmt = db.prepare(`DELETE FROM vec_items WHERE url = ?`);
|
|
526
|
+
const result = deleteStmt.run(url);
|
|
527
|
+
logger.info(`Deleted ${result.changes} chunks from SQLite for URL ${url}`);
|
|
528
|
+
}
|
|
529
|
+
static async removeChunksByUrlQdrant(db, url, logger) {
|
|
530
|
+
const { client, collectionName } = db;
|
|
531
|
+
try {
|
|
532
|
+
await client.delete(collectionName, {
|
|
533
|
+
filter: {
|
|
534
|
+
must: [
|
|
535
|
+
{
|
|
536
|
+
key: 'url',
|
|
537
|
+
match: {
|
|
538
|
+
text: url
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
],
|
|
542
|
+
must_not: [
|
|
543
|
+
{
|
|
544
|
+
key: 'is_metadata',
|
|
545
|
+
match: {
|
|
546
|
+
value: true
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
]
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
logger.info(`Deleted chunks from Qdrant for URL ${url}`);
|
|
553
|
+
}
|
|
554
|
+
catch (error) {
|
|
555
|
+
logger.error(`Error deleting chunks from Qdrant for URL ${url}:`, error);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
369
558
|
static removeObsoleteFilesSQLite(db, processedFiles, pathConfig, logger) {
|
|
370
559
|
const getChunksForPathStmt = db.prepare(`
|
|
371
560
|
SELECT chunk_id, url FROM vec_items
|
|
@@ -501,3 +690,4 @@ class DatabaseManager {
|
|
|
501
690
|
}
|
|
502
691
|
}
|
|
503
692
|
exports.DatabaseManager = DatabaseManager;
|
|
693
|
+
DatabaseManager.columnCache = new WeakMap();
|