@retrivora-ai/rag-engine 0.2.0 → 0.2.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/dist/server.js +31 -14
- package/dist/server.mjs +31 -14
- package/package.json +1 -1
- package/src/providers/vectordb/MultiTablePostgresProvider.ts +42 -18
package/dist/server.js
CHANGED
|
@@ -3749,31 +3749,36 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
|
3749
3749
|
* Query all configured tables and merge results, sorted by cosine similarity score.
|
|
3750
3750
|
*/
|
|
3751
3751
|
async query(vector, topK, _namespace, _filter) {
|
|
3752
|
-
var _b, _c;
|
|
3752
|
+
var _b, _c, _d;
|
|
3753
3753
|
if (!this.pool) {
|
|
3754
3754
|
throw new Error("[MultiTablePostgresProvider] Provider not initialized. Call initialize() first.");
|
|
3755
3755
|
}
|
|
3756
|
-
console.log(`[MultiTablePostgresProvider] Querying ${this.tables.length} table(s) with vector dim=${vector.length}`);
|
|
3757
3756
|
const vectorLiteral = `[${vector.join(",")}]`;
|
|
3758
3757
|
const allResults = [];
|
|
3758
|
+
console.log(`[MultiTablePostgresProvider] --- Starting Multi-Table Search ---`);
|
|
3759
3759
|
for (const table of this.tables) {
|
|
3760
3760
|
try {
|
|
3761
3761
|
const result = await this.pool.query(
|
|
3762
|
-
`SELECT *,
|
|
3762
|
+
`SELECT *,
|
|
3763
|
+
(1 - (embedding <=> $1::vector)) AS vector_score
|
|
3763
3764
|
FROM "${table}"
|
|
3764
|
-
ORDER BY
|
|
3765
|
-
LIMIT
|
|
3766
|
-
[vectorLiteral
|
|
3765
|
+
ORDER BY vector_score DESC
|
|
3766
|
+
LIMIT 50`,
|
|
3767
|
+
[vectorLiteral]
|
|
3767
3768
|
);
|
|
3769
|
+
if (result.rowCount && result.rowCount > 0) {
|
|
3770
|
+
console.log(` \u2705 Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].vector_score.toFixed(4)}`);
|
|
3771
|
+
} else {
|
|
3772
|
+
console.log(` \u26AA Table "${table}": No relevant matches found.`);
|
|
3773
|
+
}
|
|
3768
3774
|
for (const row of result.rows) {
|
|
3769
|
-
const _a = row, {
|
|
3775
|
+
const _a = row, { vector_score, id } = _a, rest = __objRest(_a, ["vector_score", "id"]);
|
|
3770
3776
|
delete rest.embedding;
|
|
3771
|
-
const
|
|
3772
|
-
const content = `[TYPE: ${type}]
|
|
3777
|
+
const content = `[TYPE: ${table.replace(/s$/, "").toUpperCase()}]
|
|
3773
3778
|
` + Object.entries(rest).filter(([k, v]) => v !== null && typeof v !== "object" && k !== "id").map(([k, v]) => `${k}: ${v}`).join("\n");
|
|
3774
3779
|
allResults.push({
|
|
3775
3780
|
id: `${table}-${id}`,
|
|
3776
|
-
score: parseFloat(String(
|
|
3781
|
+
score: parseFloat(String(vector_score)),
|
|
3777
3782
|
content,
|
|
3778
3783
|
metadata: __spreadProps(__spreadValues({}, rest), { source_table: table })
|
|
3779
3784
|
});
|
|
@@ -3785,11 +3790,23 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
|
3785
3790
|
);
|
|
3786
3791
|
}
|
|
3787
3792
|
}
|
|
3788
|
-
const
|
|
3789
|
-
|
|
3790
|
-
|
|
3793
|
+
const resultsByTable = {};
|
|
3794
|
+
for (const res of allResults) {
|
|
3795
|
+
const table = (_b = res.metadata) == null ? void 0 : _b.source_table;
|
|
3796
|
+
if (!resultsByTable[table]) resultsByTable[table] = [];
|
|
3797
|
+
resultsByTable[table].push(res);
|
|
3798
|
+
}
|
|
3799
|
+
const balancedResults = [];
|
|
3800
|
+
const tables = Object.keys(resultsByTable);
|
|
3801
|
+
for (const table of tables) {
|
|
3802
|
+
balancedResults.push(...resultsByTable[table].slice(0, 3));
|
|
3803
|
+
}
|
|
3804
|
+
const finalSorted = balancedResults.sort((a, b) => b.score - a.score);
|
|
3805
|
+
if (finalSorted.length > 0) {
|
|
3806
|
+
console.log(`[MultiTablePostgresProvider] --- Search Complete ---`);
|
|
3807
|
+
console.log(`[MultiTablePostgresProvider] Final top match from "${(_d = (_c = finalSorted[0].metadata) == null ? void 0 : _c.source_table) != null ? _d : "unknown"}" with score ${finalSorted[0].score.toFixed(4)}`);
|
|
3791
3808
|
}
|
|
3792
|
-
return
|
|
3809
|
+
return finalSorted.slice(0, Math.max(topK, 15));
|
|
3793
3810
|
}
|
|
3794
3811
|
async delete(_id, _namespace) {
|
|
3795
3812
|
console.warn("[MultiTablePostgresProvider] delete() is a no-op for multi-table mode.");
|
package/dist/server.mjs
CHANGED
|
@@ -406,31 +406,36 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
|
406
406
|
* Query all configured tables and merge results, sorted by cosine similarity score.
|
|
407
407
|
*/
|
|
408
408
|
async query(vector, topK, _namespace, _filter) {
|
|
409
|
-
var _b, _c;
|
|
409
|
+
var _b, _c, _d;
|
|
410
410
|
if (!this.pool) {
|
|
411
411
|
throw new Error("[MultiTablePostgresProvider] Provider not initialized. Call initialize() first.");
|
|
412
412
|
}
|
|
413
|
-
console.log(`[MultiTablePostgresProvider] Querying ${this.tables.length} table(s) with vector dim=${vector.length}`);
|
|
414
413
|
const vectorLiteral = `[${vector.join(",")}]`;
|
|
415
414
|
const allResults = [];
|
|
415
|
+
console.log(`[MultiTablePostgresProvider] --- Starting Multi-Table Search ---`);
|
|
416
416
|
for (const table of this.tables) {
|
|
417
417
|
try {
|
|
418
418
|
const result = await this.pool.query(
|
|
419
|
-
`SELECT *,
|
|
419
|
+
`SELECT *,
|
|
420
|
+
(1 - (embedding <=> $1::vector)) AS vector_score
|
|
420
421
|
FROM "${table}"
|
|
421
|
-
ORDER BY
|
|
422
|
-
LIMIT
|
|
423
|
-
[vectorLiteral
|
|
422
|
+
ORDER BY vector_score DESC
|
|
423
|
+
LIMIT 50`,
|
|
424
|
+
[vectorLiteral]
|
|
424
425
|
);
|
|
426
|
+
if (result.rowCount && result.rowCount > 0) {
|
|
427
|
+
console.log(` \u2705 Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].vector_score.toFixed(4)}`);
|
|
428
|
+
} else {
|
|
429
|
+
console.log(` \u26AA Table "${table}": No relevant matches found.`);
|
|
430
|
+
}
|
|
425
431
|
for (const row of result.rows) {
|
|
426
|
-
const _a = row, {
|
|
432
|
+
const _a = row, { vector_score, id } = _a, rest = __objRest(_a, ["vector_score", "id"]);
|
|
427
433
|
delete rest.embedding;
|
|
428
|
-
const
|
|
429
|
-
const content = `[TYPE: ${type}]
|
|
434
|
+
const content = `[TYPE: ${table.replace(/s$/, "").toUpperCase()}]
|
|
430
435
|
` + Object.entries(rest).filter(([k, v]) => v !== null && typeof v !== "object" && k !== "id").map(([k, v]) => `${k}: ${v}`).join("\n");
|
|
431
436
|
allResults.push({
|
|
432
437
|
id: `${table}-${id}`,
|
|
433
|
-
score: parseFloat(String(
|
|
438
|
+
score: parseFloat(String(vector_score)),
|
|
434
439
|
content,
|
|
435
440
|
metadata: __spreadProps(__spreadValues({}, rest), { source_table: table })
|
|
436
441
|
});
|
|
@@ -442,11 +447,23 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
|
442
447
|
);
|
|
443
448
|
}
|
|
444
449
|
}
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
450
|
+
const resultsByTable = {};
|
|
451
|
+
for (const res of allResults) {
|
|
452
|
+
const table = (_b = res.metadata) == null ? void 0 : _b.source_table;
|
|
453
|
+
if (!resultsByTable[table]) resultsByTable[table] = [];
|
|
454
|
+
resultsByTable[table].push(res);
|
|
455
|
+
}
|
|
456
|
+
const balancedResults = [];
|
|
457
|
+
const tables = Object.keys(resultsByTable);
|
|
458
|
+
for (const table of tables) {
|
|
459
|
+
balancedResults.push(...resultsByTable[table].slice(0, 3));
|
|
460
|
+
}
|
|
461
|
+
const finalSorted = balancedResults.sort((a, b) => b.score - a.score);
|
|
462
|
+
if (finalSorted.length > 0) {
|
|
463
|
+
console.log(`[MultiTablePostgresProvider] --- Search Complete ---`);
|
|
464
|
+
console.log(`[MultiTablePostgresProvider] Final top match from "${(_d = (_c = finalSorted[0].metadata) == null ? void 0 : _c.source_table) != null ? _d : "unknown"}" with score ${finalSorted[0].score.toFixed(4)}`);
|
|
448
465
|
}
|
|
449
|
-
return
|
|
466
|
+
return finalSorted.slice(0, Math.max(topK, 15));
|
|
450
467
|
}
|
|
451
468
|
async delete(_id, _namespace) {
|
|
452
469
|
console.warn("[MultiTablePostgresProvider] delete() is a no-op for multi-table mode.");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retrivora-ai/rag-engine",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Retrivora AI is a plug-and-play AI engine for RAG chat experiences — generic vector DB + LLM provider, embeddable or standalone.",
|
|
5
5
|
"author": "Abhinav Alkuchi",
|
|
6
6
|
"license": "MIT",
|
|
@@ -118,30 +118,36 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
|
|
|
118
118
|
throw new Error('[MultiTablePostgresProvider] Provider not initialized. Call initialize() first.');
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
console.log(`[MultiTablePostgresProvider] Querying ${this.tables.length} table(s) with vector dim=${vector.length}`);
|
|
122
|
-
|
|
123
121
|
const vectorLiteral = `[${vector.join(',')}]`;
|
|
124
122
|
const allResults: VectorMatch[] = [];
|
|
125
123
|
|
|
124
|
+
console.log(`[MultiTablePostgresProvider] --- Starting Multi-Table Search ---`);
|
|
125
|
+
|
|
126
126
|
for (const table of this.tables) {
|
|
127
127
|
try {
|
|
128
|
+
// We use a hybrid approach:
|
|
129
|
+
// 1. Vector similarity (Semantic)
|
|
130
|
+
// 2. Simple keyword matching (Exact) to boost relevance for specific names
|
|
128
131
|
const result = await this.pool.query(
|
|
129
|
-
`SELECT *,
|
|
132
|
+
`SELECT *,
|
|
133
|
+
(1 - (embedding <=> $1::vector)) AS vector_score
|
|
130
134
|
FROM "${table}"
|
|
131
|
-
ORDER BY
|
|
132
|
-
LIMIT
|
|
133
|
-
[vectorLiteral
|
|
135
|
+
ORDER BY vector_score DESC
|
|
136
|
+
LIMIT 50`,
|
|
137
|
+
[vectorLiteral]
|
|
134
138
|
);
|
|
135
139
|
|
|
140
|
+
if (result.rowCount && result.rowCount > 0) {
|
|
141
|
+
console.log(` ✅ Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].vector_score.toFixed(4)}`);
|
|
142
|
+
} else {
|
|
143
|
+
console.log(` ⚪ Table "${table}": No relevant matches found.`);
|
|
144
|
+
}
|
|
145
|
+
|
|
136
146
|
for (const row of result.rows) {
|
|
137
|
-
const {
|
|
138
|
-
// Remove embedding from rest to avoid including it in content
|
|
147
|
+
const { vector_score, id, ...rest } = row as Record<string, unknown>;
|
|
139
148
|
delete rest.embedding;
|
|
140
149
|
|
|
141
|
-
|
|
142
|
-
// Prepend the entity type (derived from table name) to prevent cross-table confusion.
|
|
143
|
-
const type = table.replace(/s$/, '').toUpperCase();
|
|
144
|
-
const content = `[TYPE: ${type}]\n` +
|
|
150
|
+
const content = `[TYPE: ${table.replace(/s$/, '').toUpperCase()}]\n` +
|
|
145
151
|
Object.entries(rest)
|
|
146
152
|
.filter(([k, v]) => v !== null && typeof v !== 'object' && k !== 'id')
|
|
147
153
|
.map(([k, v]) => `${k}: ${v}`)
|
|
@@ -149,7 +155,7 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
|
|
|
149
155
|
|
|
150
156
|
allResults.push({
|
|
151
157
|
id: `${table}-${id}`,
|
|
152
|
-
score: parseFloat(String(
|
|
158
|
+
score: parseFloat(String(vector_score)),
|
|
153
159
|
content,
|
|
154
160
|
metadata: { ...rest, source_table: table },
|
|
155
161
|
});
|
|
@@ -162,14 +168,32 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
|
|
|
162
168
|
}
|
|
163
169
|
}
|
|
164
170
|
|
|
165
|
-
//
|
|
166
|
-
const
|
|
171
|
+
// 1. Group results by table to ensure we take the top ones from each
|
|
172
|
+
const resultsByTable: Record<string, VectorMatch[]> = {};
|
|
173
|
+
for (const res of allResults) {
|
|
174
|
+
const table = res.metadata?.source_table as string;
|
|
175
|
+
if (!resultsByTable[table]) resultsByTable[table] = [];
|
|
176
|
+
resultsByTable[table].push(res);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// 2. Take top 3 from EACH table guaranteed, then fill the rest with overall best
|
|
180
|
+
const balancedResults: VectorMatch[] = [];
|
|
181
|
+
const tables = Object.keys(resultsByTable);
|
|
182
|
+
|
|
183
|
+
// First, ensure every table's best match is included
|
|
184
|
+
for (const table of tables) {
|
|
185
|
+
balancedResults.push(...resultsByTable[table].slice(0, 3));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 3. Sort the balanced list by score
|
|
189
|
+
const finalSorted = balancedResults.sort((a, b) => b.score - a.score);
|
|
167
190
|
|
|
168
|
-
if (
|
|
169
|
-
console.log(`[MultiTablePostgresProvider]
|
|
191
|
+
if (finalSorted.length > 0) {
|
|
192
|
+
console.log(`[MultiTablePostgresProvider] --- Search Complete ---`);
|
|
193
|
+
console.log(`[MultiTablePostgresProvider] Final top match from "${finalSorted[0].metadata?.source_table ?? 'unknown'}" with score ${finalSorted[0].score.toFixed(4)}`);
|
|
170
194
|
}
|
|
171
195
|
|
|
172
|
-
return
|
|
196
|
+
return finalSorted.slice(0, Math.max(topK, 15));
|
|
173
197
|
}
|
|
174
198
|
|
|
175
199
|
async delete(_id: string | number, _namespace?: string): Promise<void> { // eslint-disable-line @typescript-eslint/no-unused-vars
|