@retrivora-ai/rag-engine 0.2.3 → 0.2.4
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/{chunk-K53N7SEE.mjs → chunk-7K4KXB6G.mjs} +1 -1
- package/dist/handlers/index.js +1 -1
- package/dist/handlers/index.mjs +1 -1
- package/dist/server.js +29 -12
- package/dist/server.mjs +29 -12
- package/package.json +1 -1
- package/src/core/Pipeline.ts +2 -1
- package/src/providers/vectordb/MultiTablePostgresProvider.ts +39 -20
|
@@ -1640,7 +1640,7 @@ var Pipeline = class {
|
|
|
1640
1640
|
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0;
|
|
1641
1641
|
try {
|
|
1642
1642
|
const queryVector = await this.embeddingProvider.embed(question, { taskType: "query" });
|
|
1643
|
-
const rawMatches = await this.vectorDB.query(queryVector, topK, ns);
|
|
1643
|
+
const rawMatches = await this.vectorDB.query(queryVector, topK, ns, { __queryText: question });
|
|
1644
1644
|
const sources = rawMatches.filter((m) => m.score >= scoreThreshold);
|
|
1645
1645
|
const context = sources.length ? sources.map((m, i) => `[Source ${i + 1}]
|
|
1646
1646
|
${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
|
package/dist/handlers/index.js
CHANGED
|
@@ -2750,7 +2750,7 @@ var Pipeline = class {
|
|
|
2750
2750
|
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0;
|
|
2751
2751
|
try {
|
|
2752
2752
|
const queryVector = await this.embeddingProvider.embed(question, { taskType: "query" });
|
|
2753
|
-
const rawMatches = await this.vectorDB.query(queryVector, topK, ns);
|
|
2753
|
+
const rawMatches = await this.vectorDB.query(queryVector, topK, ns, { __queryText: question });
|
|
2754
2754
|
const sources = rawMatches.filter((m) => m.score >= scoreThreshold);
|
|
2755
2755
|
const context = sources.length ? sources.map((m, i) => `[Source ${i + 1}]
|
|
2756
2756
|
${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
|
package/dist/handlers/index.mjs
CHANGED
package/dist/server.js
CHANGED
|
@@ -2839,7 +2839,7 @@ var Pipeline = class {
|
|
|
2839
2839
|
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0;
|
|
2840
2840
|
try {
|
|
2841
2841
|
const queryVector = await this.embeddingProvider.embed(question, { taskType: "query" });
|
|
2842
|
-
const rawMatches = await this.vectorDB.query(queryVector, topK, ns);
|
|
2842
|
+
const rawMatches = await this.vectorDB.query(queryVector, topK, ns, { __queryText: question });
|
|
2843
2843
|
const sources = rawMatches.filter((m) => m.score >= scoreThreshold);
|
|
2844
2844
|
const context = sources.length ? sources.map((m, i) => `[Source ${i + 1}]
|
|
2845
2845
|
${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
|
|
@@ -3770,29 +3770,46 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
|
3770
3770
|
const vectorLiteral = `[${vector.join(",")}]`;
|
|
3771
3771
|
const allResults = [];
|
|
3772
3772
|
console.log(`[MultiTablePostgresProvider] --- Starting Multi-Table Search ---`);
|
|
3773
|
+
const queryText = _filter == null ? void 0 : _filter.__queryText;
|
|
3773
3774
|
for (const table of this.tables) {
|
|
3774
3775
|
try {
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3776
|
+
let sqlQuery = "";
|
|
3777
|
+
let params = [];
|
|
3778
|
+
if (queryText) {
|
|
3779
|
+
sqlQuery = `
|
|
3780
|
+
SELECT *,
|
|
3781
|
+
(1 - (embedding <=> $1::vector)) AS vector_score,
|
|
3782
|
+
ts_rank(to_tsvector('english', t.*::text), plainto_tsquery('english', $2)) AS keyword_score,
|
|
3783
|
+
((1 - (embedding <=> $1::vector)) + (ts_rank(to_tsvector('english', t.*::text), plainto_tsquery('english', $2)) * 2.0)) AS hybrid_score
|
|
3784
|
+
FROM "${table}" t
|
|
3785
|
+
ORDER BY hybrid_score DESC
|
|
3786
|
+
LIMIT 50
|
|
3787
|
+
`;
|
|
3788
|
+
params = [vectorLiteral, queryText];
|
|
3789
|
+
} else {
|
|
3790
|
+
sqlQuery = `
|
|
3791
|
+
SELECT *,
|
|
3792
|
+
(1 - (embedding <=> $1::vector)) AS hybrid_score
|
|
3793
|
+
FROM "${table}" t
|
|
3794
|
+
ORDER BY hybrid_score DESC
|
|
3795
|
+
LIMIT 50
|
|
3796
|
+
`;
|
|
3797
|
+
params = [vectorLiteral];
|
|
3798
|
+
}
|
|
3799
|
+
const result = await this.pool.query(sqlQuery, params);
|
|
3783
3800
|
if (result.rowCount && result.rowCount > 0) {
|
|
3784
|
-
console.log(` \u2705 Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].
|
|
3801
|
+
console.log(` \u2705 Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].hybrid_score.toFixed(4)}`);
|
|
3785
3802
|
} else {
|
|
3786
3803
|
console.log(` \u26AA Table "${table}": No relevant matches found.`);
|
|
3787
3804
|
}
|
|
3788
3805
|
for (const row of result.rows) {
|
|
3789
|
-
const _a = row, { vector_score, id } = _a, rest = __objRest(_a, ["vector_score", "id"]);
|
|
3806
|
+
const _a = row, { hybrid_score, vector_score, keyword_score, id } = _a, rest = __objRest(_a, ["hybrid_score", "vector_score", "keyword_score", "id"]);
|
|
3790
3807
|
delete rest.embedding;
|
|
3791
3808
|
const content = `[TYPE: ${table.replace(/s$/, "").toUpperCase()}]
|
|
3792
3809
|
` + Object.entries(rest).filter(([k, v]) => v !== null && typeof v !== "object" && k !== "id").map(([k, v]) => `${k}: ${v}`).join("\n");
|
|
3793
3810
|
allResults.push({
|
|
3794
3811
|
id: `${table}-${id}`,
|
|
3795
|
-
score: parseFloat(String(
|
|
3812
|
+
score: parseFloat(String(hybrid_score)),
|
|
3796
3813
|
content,
|
|
3797
3814
|
metadata: __spreadProps(__spreadValues({}, rest), { source_table: table })
|
|
3798
3815
|
});
|
package/dist/server.mjs
CHANGED
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
createIngestHandler,
|
|
35
35
|
createUploadHandler,
|
|
36
36
|
getRagConfig
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-7K4KXB6G.mjs";
|
|
38
38
|
import "./chunk-EDLTMSNY.mjs";
|
|
39
39
|
import {
|
|
40
40
|
PineconeProvider
|
|
@@ -413,29 +413,46 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
|
413
413
|
const vectorLiteral = `[${vector.join(",")}]`;
|
|
414
414
|
const allResults = [];
|
|
415
415
|
console.log(`[MultiTablePostgresProvider] --- Starting Multi-Table Search ---`);
|
|
416
|
+
const queryText = _filter == null ? void 0 : _filter.__queryText;
|
|
416
417
|
for (const table of this.tables) {
|
|
417
418
|
try {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
419
|
+
let sqlQuery = "";
|
|
420
|
+
let params = [];
|
|
421
|
+
if (queryText) {
|
|
422
|
+
sqlQuery = `
|
|
423
|
+
SELECT *,
|
|
424
|
+
(1 - (embedding <=> $1::vector)) AS vector_score,
|
|
425
|
+
ts_rank(to_tsvector('english', t.*::text), plainto_tsquery('english', $2)) AS keyword_score,
|
|
426
|
+
((1 - (embedding <=> $1::vector)) + (ts_rank(to_tsvector('english', t.*::text), plainto_tsquery('english', $2)) * 2.0)) AS hybrid_score
|
|
427
|
+
FROM "${table}" t
|
|
428
|
+
ORDER BY hybrid_score DESC
|
|
429
|
+
LIMIT 50
|
|
430
|
+
`;
|
|
431
|
+
params = [vectorLiteral, queryText];
|
|
432
|
+
} else {
|
|
433
|
+
sqlQuery = `
|
|
434
|
+
SELECT *,
|
|
435
|
+
(1 - (embedding <=> $1::vector)) AS hybrid_score
|
|
436
|
+
FROM "${table}" t
|
|
437
|
+
ORDER BY hybrid_score DESC
|
|
438
|
+
LIMIT 50
|
|
439
|
+
`;
|
|
440
|
+
params = [vectorLiteral];
|
|
441
|
+
}
|
|
442
|
+
const result = await this.pool.query(sqlQuery, params);
|
|
426
443
|
if (result.rowCount && result.rowCount > 0) {
|
|
427
|
-
console.log(` \u2705 Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].
|
|
444
|
+
console.log(` \u2705 Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].hybrid_score.toFixed(4)}`);
|
|
428
445
|
} else {
|
|
429
446
|
console.log(` \u26AA Table "${table}": No relevant matches found.`);
|
|
430
447
|
}
|
|
431
448
|
for (const row of result.rows) {
|
|
432
|
-
const _a = row, { vector_score, id } = _a, rest = __objRest(_a, ["vector_score", "id"]);
|
|
449
|
+
const _a = row, { hybrid_score, vector_score, keyword_score, id } = _a, rest = __objRest(_a, ["hybrid_score", "vector_score", "keyword_score", "id"]);
|
|
433
450
|
delete rest.embedding;
|
|
434
451
|
const content = `[TYPE: ${table.replace(/s$/, "").toUpperCase()}]
|
|
435
452
|
` + Object.entries(rest).filter(([k, v]) => v !== null && typeof v !== "object" && k !== "id").map(([k, v]) => `${k}: ${v}`).join("\n");
|
|
436
453
|
allResults.push({
|
|
437
454
|
id: `${table}-${id}`,
|
|
438
|
-
score: parseFloat(String(
|
|
455
|
+
score: parseFloat(String(hybrid_score)),
|
|
439
456
|
content,
|
|
440
457
|
metadata: __spreadProps(__spreadValues({}, rest), { source_table: table })
|
|
441
458
|
});
|
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.4",
|
|
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",
|
package/src/core/Pipeline.ts
CHANGED
|
@@ -135,7 +135,8 @@ export class Pipeline {
|
|
|
135
135
|
|
|
136
136
|
try {
|
|
137
137
|
const queryVector = await this.embeddingProvider.embed(question, { taskType: 'query' });
|
|
138
|
-
|
|
138
|
+
// Pass the original text to the vector DB so it can perform hybrid (keyword) search if supported
|
|
139
|
+
const rawMatches = await this.vectorDB.query(queryVector, topK, ns, { __queryText: question });
|
|
139
140
|
|
|
140
141
|
const sources = rawMatches.filter((m) => m.score >= scoreThreshold);
|
|
141
142
|
const context = sources.length
|
|
@@ -46,7 +46,7 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
|
|
|
46
46
|
|
|
47
47
|
async initialize(): Promise<void> {
|
|
48
48
|
this.pool = new Pool({ connectionString: this.connectionString });
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
// Dynamically discover all tables that have an 'embedding' column
|
|
51
51
|
const client: PoolClient = await this.pool.connect();
|
|
52
52
|
try {
|
|
@@ -56,9 +56,9 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
|
|
|
56
56
|
WHERE column_name = 'embedding'
|
|
57
57
|
AND table_schema = 'public'
|
|
58
58
|
`);
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
const discoveredTables = res.rows.map(r => r.table_name);
|
|
61
|
-
|
|
61
|
+
|
|
62
62
|
if (this.tables.length === 0) {
|
|
63
63
|
// No static tables configured, use everything discovered
|
|
64
64
|
this.tables = discoveredTables;
|
|
@@ -66,7 +66,7 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
|
|
|
66
66
|
// Filter configured tables to ensure they actually exist with embeddings
|
|
67
67
|
const staticTables = [...this.tables];
|
|
68
68
|
this.tables = staticTables.filter(t => discoveredTables.includes(t));
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
if (this.tables.length < staticTables.length) {
|
|
71
71
|
const missing = staticTables.filter(t => !discoveredTables.includes(t));
|
|
72
72
|
console.warn(`[MultiTablePostgresProvider] Some configured tables were skipped (missing 'embedding' column): ${missing.join(', ')}`);
|
|
@@ -123,31 +123,50 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
|
|
|
123
123
|
|
|
124
124
|
console.log(`[MultiTablePostgresProvider] --- Starting Multi-Table Search ---`);
|
|
125
125
|
|
|
126
|
+
const queryText = _filter?.__queryText as string | undefined;
|
|
127
|
+
|
|
126
128
|
for (const table of this.tables) {
|
|
127
129
|
try {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
130
|
+
let sqlQuery = '';
|
|
131
|
+
let params: any[] = [];
|
|
132
|
+
|
|
133
|
+
if (queryText) {
|
|
134
|
+
// Actual Hybrid Search: Semantic Vector Score + Full-Text Keyword Rank
|
|
135
|
+
sqlQuery = `
|
|
136
|
+
SELECT *,
|
|
137
|
+
(1 - (embedding <=> $1::vector)) AS vector_score,
|
|
138
|
+
ts_rank(to_tsvector('english', t.*::text), plainto_tsquery('english', $2)) AS keyword_score,
|
|
139
|
+
((1 - (embedding <=> $1::vector)) + (ts_rank(to_tsvector('english', t.*::text), plainto_tsquery('english', $2)) * 2.0)) AS hybrid_score
|
|
140
|
+
FROM "${table}" t
|
|
141
|
+
ORDER BY hybrid_score DESC
|
|
142
|
+
LIMIT 50
|
|
143
|
+
`;
|
|
144
|
+
params = [vectorLiteral, queryText];
|
|
145
|
+
} else {
|
|
146
|
+
// Fallback to Vector-only Search
|
|
147
|
+
sqlQuery = `
|
|
148
|
+
SELECT *,
|
|
149
|
+
(1 - (embedding <=> $1::vector)) AS hybrid_score
|
|
150
|
+
FROM "${table}" t
|
|
151
|
+
ORDER BY hybrid_score DESC
|
|
152
|
+
LIMIT 50
|
|
153
|
+
`;
|
|
154
|
+
params = [vectorLiteral];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const result = await this.pool.query(sqlQuery, params);
|
|
139
158
|
|
|
140
159
|
if (result.rowCount && result.rowCount > 0) {
|
|
141
|
-
console.log(` ✅ Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].
|
|
160
|
+
console.log(` ✅ Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].hybrid_score.toFixed(4)}`);
|
|
142
161
|
} else {
|
|
143
162
|
console.log(` ⚪ Table "${table}": No relevant matches found.`);
|
|
144
163
|
}
|
|
145
164
|
|
|
146
165
|
for (const row of result.rows) {
|
|
147
|
-
const { vector_score, id, ...rest } = row as Record<string, unknown>;
|
|
166
|
+
const { hybrid_score, vector_score, keyword_score, id, ...rest } = row as Record<string, unknown>;
|
|
148
167
|
delete rest.embedding;
|
|
149
168
|
|
|
150
|
-
const content = `[TYPE: ${table.replace(/s$/, '').toUpperCase()}]\n` +
|
|
169
|
+
const content = `[TYPE: ${table.replace(/s$/, '').toUpperCase()}]\n` +
|
|
151
170
|
Object.entries(rest)
|
|
152
171
|
.filter(([k, v]) => v !== null && typeof v !== 'object' && k !== 'id')
|
|
153
172
|
.map(([k, v]) => `${k}: ${v}`)
|
|
@@ -155,7 +174,7 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
|
|
|
155
174
|
|
|
156
175
|
allResults.push({
|
|
157
176
|
id: `${table}-${id}`,
|
|
158
|
-
score: parseFloat(String(
|
|
177
|
+
score: parseFloat(String(hybrid_score)),
|
|
159
178
|
content,
|
|
160
179
|
metadata: { ...rest, source_table: table },
|
|
161
180
|
});
|
|
@@ -179,7 +198,7 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
|
|
|
179
198
|
// 2. Take top 3 from EACH table guaranteed, then fill the rest with overall best
|
|
180
199
|
const balancedResults: VectorMatch[] = [];
|
|
181
200
|
const tables = Object.keys(resultsByTable);
|
|
182
|
-
|
|
201
|
+
|
|
183
202
|
// First, ensure every table's best match is included
|
|
184
203
|
for (const table of tables) {
|
|
185
204
|
balancedResults.push(...resultsByTable[table].slice(0, 3));
|