@retrivora-ai/rag-engine 1.0.5 → 1.0.7
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/{MongoDBProvider-BO2Y5DRR.mjs → MongoDBProvider-YNKC7EJ6.mjs} +1 -1
- package/dist/{RagConfig-BEmz4hVP.d.mts → RagConfig-BjC6zSTV.d.mts} +4 -0
- package/dist/{RagConfig-BEmz4hVP.d.ts → RagConfig-BjC6zSTV.d.ts} +4 -0
- package/dist/{chunk-MWL4AGQI.mjs → chunk-3GKA3PJF.mjs} +27 -7
- package/dist/{chunk-73I6VWU3.mjs → chunk-5AJ4XHLW.mjs} +22 -4
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +48 -10
- package/dist/handlers/index.mjs +1 -1
- package/dist/{index-CSfaCeux.d.ts → index-C3bLmWcR.d.ts} +1 -1
- package/dist/{index-DFSy0CG6.d.mts → index-CU_fQq__.d.mts} +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/server.d.mts +3 -3
- package/dist/server.d.ts +3 -3
- package/dist/server.js +48 -10
- package/dist/server.mjs +2 -2
- package/package.json +1 -1
- package/src/config/RagConfig.ts +4 -0
- package/src/core/Pipeline.ts +1 -1
- package/src/core/QueryProcessor.ts +31 -4
- package/src/providers/vectordb/MongoDBProvider.ts +32 -6
|
@@ -244,6 +244,10 @@ interface RAGConfig {
|
|
|
244
244
|
useGraphRetrieval?: boolean;
|
|
245
245
|
/** Whether to perform reranking on retrieved results */
|
|
246
246
|
useReranking?: boolean;
|
|
247
|
+
/** List of metadata fields that are valid for filtering.
|
|
248
|
+
* Used to dynamically extract hints from natural language queries.
|
|
249
|
+
*/
|
|
250
|
+
filterableFields?: string[];
|
|
247
251
|
}
|
|
248
252
|
interface RagConfig {
|
|
249
253
|
/**
|
|
@@ -244,6 +244,10 @@ interface RAGConfig {
|
|
|
244
244
|
useGraphRetrieval?: boolean;
|
|
245
245
|
/** Whether to perform reranking on retrieved results */
|
|
246
246
|
useReranking?: boolean;
|
|
247
|
+
/** List of metadata fields that are valid for filtering.
|
|
248
|
+
* Used to dynamically extract hints from natural language queries.
|
|
249
|
+
*/
|
|
250
|
+
filterableFields?: string[];
|
|
247
251
|
}
|
|
248
252
|
interface RagConfig {
|
|
249
253
|
/**
|
|
@@ -1098,7 +1098,7 @@ var ProviderRegistry = class {
|
|
|
1098
1098
|
return PostgreSQLProvider;
|
|
1099
1099
|
}
|
|
1100
1100
|
case "mongodb": {
|
|
1101
|
-
const { MongoDBProvider } = await import("./MongoDBProvider-
|
|
1101
|
+
const { MongoDBProvider } = await import("./MongoDBProvider-YNKC7EJ6.mjs");
|
|
1102
1102
|
return MongoDBProvider;
|
|
1103
1103
|
}
|
|
1104
1104
|
case "milvus": {
|
|
@@ -1904,12 +1904,14 @@ var QueryProcessor = class {
|
|
|
1904
1904
|
* Checks if a string is likely a question word or common prompt phrase.
|
|
1905
1905
|
*/
|
|
1906
1906
|
static isLikelyPromptPhrase(value) {
|
|
1907
|
-
return /^(what|which|who|where|when|why|how)\b/i.test(value.trim());
|
|
1907
|
+
return /^(what|which|who|where|when|why|how|the|is|are|was|were|in|on|at|by|for|with|about|a|an|to|of)\b/i.test(value.trim());
|
|
1908
1908
|
}
|
|
1909
1909
|
/**
|
|
1910
1910
|
* Scans a natural language question for potential metadata hints and keywords.
|
|
1911
|
+
* @param question The user's query
|
|
1912
|
+
* @param validFields Optional list of known filterable fields to look for
|
|
1911
1913
|
*/
|
|
1912
|
-
static extractQueryFieldHints(question) {
|
|
1914
|
+
static extractQueryFieldHints(question, validFields = []) {
|
|
1913
1915
|
var _a, _b, _c, _d;
|
|
1914
1916
|
if (!question.trim()) return [];
|
|
1915
1917
|
const hints = /* @__PURE__ */ new Map();
|
|
@@ -1943,11 +1945,29 @@ var QueryProcessor = class {
|
|
|
1943
1945
|
if (name) addHint(name, "name");
|
|
1944
1946
|
}
|
|
1945
1947
|
}
|
|
1948
|
+
const genericPattern = /\b([a-z][a-z0-9_]{1,30})\s*[:=]\s*["']?([^"'\n?.!,]{1,60})["']?/gi;
|
|
1949
|
+
for (const match of question.matchAll(genericPattern)) {
|
|
1950
|
+
const field = match[1];
|
|
1951
|
+
const value = match[2];
|
|
1952
|
+
if (field && !this.isLikelyPromptPhrase(field)) {
|
|
1953
|
+
addHint(value, field);
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
if (validFields.length > 0) {
|
|
1957
|
+
for (const field of validFields) {
|
|
1958
|
+
const pattern = new RegExp(`\\b${field}\\s*(?:is|are|:|of)?\\s+["']?([^"\\n?.!,]{1,60})["']?(?=[?.!,]|$)`, "gi");
|
|
1959
|
+
for (const match of question.matchAll(pattern)) {
|
|
1960
|
+
const value = match[1];
|
|
1961
|
+
if (value && !this.isLikelyPromptPhrase(value)) {
|
|
1962
|
+
addHint(value, field);
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1946
1967
|
const universalPatterns = [
|
|
1947
1968
|
{ regex: /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/gi, field: "email", group: 1 },
|
|
1948
1969
|
{ regex: /(\+?\d[\d\-\.\s\(\)]{6,}\d)/g, field: "phone", group: 1 },
|
|
1949
1970
|
{ regex: /(\b\d{4}-\d{2}-\d{2}\b|\b\d{1,2}\/\d{1,2}\/\d{2,4}\b)/g, field: "date", group: 1 },
|
|
1950
|
-
{ regex: /(\$\s?\d{1,3}(?:,\d{3})*(?:\.\d+)?)/g, field: "amount", group: 1 },
|
|
1951
1971
|
{ regex: /\b(ID|id|identifier)[: ]\s*([A-Za-z0-9\-]{3,})\b/gi, field: "id", group: 2 },
|
|
1952
1972
|
{ regex: /"([^"]{2,120})"/g, group: 1 },
|
|
1953
1973
|
{ regex: /'([^']{2,120})'/g, group: 1 }
|
|
@@ -2241,7 +2261,7 @@ var Pipeline = class {
|
|
|
2241
2261
|
*/
|
|
2242
2262
|
askStream(_0) {
|
|
2243
2263
|
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
2244
|
-
var _a, _b, _c, _d, _e, _f;
|
|
2264
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
2245
2265
|
yield new __await(this.initialize());
|
|
2246
2266
|
const ns = namespace != null ? namespace : this.config.projectId;
|
|
2247
2267
|
const topK = (_b = (_a = this.config.rag) == null ? void 0 : _a.topK) != null ? _b : 5;
|
|
@@ -2251,7 +2271,7 @@ var Pipeline = class {
|
|
|
2251
2271
|
if ((_e = this.config.rag) == null ? void 0 : _e.useQueryTransformation) {
|
|
2252
2272
|
searchQuery = yield new __await(this.rewriteQuery(question, history));
|
|
2253
2273
|
}
|
|
2254
|
-
const hints = QueryProcessor.extractQueryFieldHints(question);
|
|
2274
|
+
const hints = QueryProcessor.extractQueryFieldHints(question, (_f = this.config.rag) == null ? void 0 : _f.filterableFields);
|
|
2255
2275
|
const filter = QueryProcessor.buildQueryFilter(question, hints);
|
|
2256
2276
|
const { sources: rawSources, graphData } = yield new __await(this.retrieve(searchQuery, {
|
|
2257
2277
|
namespace: ns,
|
|
@@ -2259,7 +2279,7 @@ var Pipeline = class {
|
|
|
2259
2279
|
filter
|
|
2260
2280
|
}));
|
|
2261
2281
|
let sources = rawSources.filter((m) => m.score >= scoreThreshold);
|
|
2262
|
-
if ((
|
|
2282
|
+
if ((_g = this.config.rag) == null ? void 0 : _g.useReranking) {
|
|
2263
2283
|
sources = yield new __await(this.reranker.rerank(sources, question, topK));
|
|
2264
2284
|
} else {
|
|
2265
2285
|
sources = sources.slice(0, topK);
|
|
@@ -118,6 +118,18 @@ var MongoDBProvider = class extends BaseVectorProvider {
|
|
|
118
118
|
}
|
|
119
119
|
async query(vector, topK, namespace, filter) {
|
|
120
120
|
const publicFilter = this.sanitizeFilter(filter);
|
|
121
|
+
const vectorSearchFilter = {};
|
|
122
|
+
const matchFilter = {};
|
|
123
|
+
if (namespace) {
|
|
124
|
+
vectorSearchFilter.namespace = namespace;
|
|
125
|
+
}
|
|
126
|
+
for (const [key, value] of Object.entries(publicFilter)) {
|
|
127
|
+
if (key === "namespace") {
|
|
128
|
+
vectorSearchFilter.namespace = value;
|
|
129
|
+
} else {
|
|
130
|
+
matchFilter[key] = value;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
121
133
|
const pipeline = [
|
|
122
134
|
{
|
|
123
135
|
$vectorSearch: __spreadValues({
|
|
@@ -125,9 +137,15 @@ var MongoDBProvider = class extends BaseVectorProvider {
|
|
|
125
137
|
path: this.embeddingKey,
|
|
126
138
|
queryVector: vector,
|
|
127
139
|
numCandidates: this.config.options.numCandidates || Math.max(topK * 20, 200),
|
|
128
|
-
limit: topK
|
|
129
|
-
}, Object.keys(
|
|
130
|
-
}
|
|
140
|
+
limit: topK * 2
|
|
141
|
+
}, Object.keys(vectorSearchFilter).length > 0 ? { filter: vectorSearchFilter } : {})
|
|
142
|
+
}
|
|
143
|
+
];
|
|
144
|
+
if (Object.keys(matchFilter).length > 0) {
|
|
145
|
+
pipeline.push({ $match: matchFilter });
|
|
146
|
+
}
|
|
147
|
+
pipeline.push(
|
|
148
|
+
{ $limit: topK },
|
|
131
149
|
{
|
|
132
150
|
$project: {
|
|
133
151
|
_id: 1,
|
|
@@ -137,7 +155,7 @@ var MongoDBProvider = class extends BaseVectorProvider {
|
|
|
137
155
|
score: { $meta: "vectorSearchScore" }
|
|
138
156
|
}
|
|
139
157
|
}
|
|
140
|
-
|
|
158
|
+
);
|
|
141
159
|
const results = await this.collection.aggregate(pipeline).toArray();
|
|
142
160
|
return results.map((res) => ({
|
|
143
161
|
id: res._id,
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import '../RagConfig-
|
|
2
|
-
export { c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from '../index-
|
|
1
|
+
import '../RagConfig-BjC6zSTV.mjs';
|
|
2
|
+
export { c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from '../index-CU_fQq__.mjs';
|
|
3
3
|
import 'next/server';
|
package/dist/handlers/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import '../RagConfig-
|
|
2
|
-
export { c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from '../index-
|
|
1
|
+
import '../RagConfig-BjC6zSTV.js';
|
|
2
|
+
export { c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from '../index-C3bLmWcR.js';
|
|
3
3
|
import 'next/server';
|
package/dist/handlers/index.js
CHANGED
|
@@ -650,6 +650,18 @@ var init_MongoDBProvider = __esm({
|
|
|
650
650
|
}
|
|
651
651
|
async query(vector, topK, namespace, filter) {
|
|
652
652
|
const publicFilter = this.sanitizeFilter(filter);
|
|
653
|
+
const vectorSearchFilter = {};
|
|
654
|
+
const matchFilter = {};
|
|
655
|
+
if (namespace) {
|
|
656
|
+
vectorSearchFilter.namespace = namespace;
|
|
657
|
+
}
|
|
658
|
+
for (const [key, value] of Object.entries(publicFilter)) {
|
|
659
|
+
if (key === "namespace") {
|
|
660
|
+
vectorSearchFilter.namespace = value;
|
|
661
|
+
} else {
|
|
662
|
+
matchFilter[key] = value;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
653
665
|
const pipeline = [
|
|
654
666
|
{
|
|
655
667
|
$vectorSearch: __spreadValues({
|
|
@@ -657,9 +669,15 @@ var init_MongoDBProvider = __esm({
|
|
|
657
669
|
path: this.embeddingKey,
|
|
658
670
|
queryVector: vector,
|
|
659
671
|
numCandidates: this.config.options.numCandidates || Math.max(topK * 20, 200),
|
|
660
|
-
limit: topK
|
|
661
|
-
}, Object.keys(
|
|
662
|
-
}
|
|
672
|
+
limit: topK * 2
|
|
673
|
+
}, Object.keys(vectorSearchFilter).length > 0 ? { filter: vectorSearchFilter } : {})
|
|
674
|
+
}
|
|
675
|
+
];
|
|
676
|
+
if (Object.keys(matchFilter).length > 0) {
|
|
677
|
+
pipeline.push({ $match: matchFilter });
|
|
678
|
+
}
|
|
679
|
+
pipeline.push(
|
|
680
|
+
{ $limit: topK },
|
|
663
681
|
{
|
|
664
682
|
$project: {
|
|
665
683
|
_id: 1,
|
|
@@ -669,7 +687,7 @@ var init_MongoDBProvider = __esm({
|
|
|
669
687
|
score: { $meta: "vectorSearchScore" }
|
|
670
688
|
}
|
|
671
689
|
}
|
|
672
|
-
|
|
690
|
+
);
|
|
673
691
|
const results = await this.collection.aggregate(pipeline).toArray();
|
|
674
692
|
return results.map((res) => ({
|
|
675
693
|
id: res._id,
|
|
@@ -3362,12 +3380,14 @@ var QueryProcessor = class {
|
|
|
3362
3380
|
* Checks if a string is likely a question word or common prompt phrase.
|
|
3363
3381
|
*/
|
|
3364
3382
|
static isLikelyPromptPhrase(value) {
|
|
3365
|
-
return /^(what|which|who|where|when|why|how)\b/i.test(value.trim());
|
|
3383
|
+
return /^(what|which|who|where|when|why|how|the|is|are|was|were|in|on|at|by|for|with|about|a|an|to|of)\b/i.test(value.trim());
|
|
3366
3384
|
}
|
|
3367
3385
|
/**
|
|
3368
3386
|
* Scans a natural language question for potential metadata hints and keywords.
|
|
3387
|
+
* @param question The user's query
|
|
3388
|
+
* @param validFields Optional list of known filterable fields to look for
|
|
3369
3389
|
*/
|
|
3370
|
-
static extractQueryFieldHints(question) {
|
|
3390
|
+
static extractQueryFieldHints(question, validFields = []) {
|
|
3371
3391
|
var _a, _b, _c, _d;
|
|
3372
3392
|
if (!question.trim()) return [];
|
|
3373
3393
|
const hints = /* @__PURE__ */ new Map();
|
|
@@ -3401,11 +3421,29 @@ var QueryProcessor = class {
|
|
|
3401
3421
|
if (name) addHint(name, "name");
|
|
3402
3422
|
}
|
|
3403
3423
|
}
|
|
3424
|
+
const genericPattern = /\b([a-z][a-z0-9_]{1,30})\s*[:=]\s*["']?([^"'\n?.!,]{1,60})["']?/gi;
|
|
3425
|
+
for (const match of question.matchAll(genericPattern)) {
|
|
3426
|
+
const field = match[1];
|
|
3427
|
+
const value = match[2];
|
|
3428
|
+
if (field && !this.isLikelyPromptPhrase(field)) {
|
|
3429
|
+
addHint(value, field);
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
if (validFields.length > 0) {
|
|
3433
|
+
for (const field of validFields) {
|
|
3434
|
+
const pattern = new RegExp(`\\b${field}\\s*(?:is|are|:|of)?\\s+["']?([^"\\n?.!,]{1,60})["']?(?=[?.!,]|$)`, "gi");
|
|
3435
|
+
for (const match of question.matchAll(pattern)) {
|
|
3436
|
+
const value = match[1];
|
|
3437
|
+
if (value && !this.isLikelyPromptPhrase(value)) {
|
|
3438
|
+
addHint(value, field);
|
|
3439
|
+
}
|
|
3440
|
+
}
|
|
3441
|
+
}
|
|
3442
|
+
}
|
|
3404
3443
|
const universalPatterns = [
|
|
3405
3444
|
{ regex: /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/gi, field: "email", group: 1 },
|
|
3406
3445
|
{ regex: /(\+?\d[\d\-\.\s\(\)]{6,}\d)/g, field: "phone", group: 1 },
|
|
3407
3446
|
{ regex: /(\b\d{4}-\d{2}-\d{2}\b|\b\d{1,2}\/\d{1,2}\/\d{2,4}\b)/g, field: "date", group: 1 },
|
|
3408
|
-
{ regex: /(\$\s?\d{1,3}(?:,\d{3})*(?:\.\d+)?)/g, field: "amount", group: 1 },
|
|
3409
3447
|
{ regex: /\b(ID|id|identifier)[: ]\s*([A-Za-z0-9\-]{3,})\b/gi, field: "id", group: 2 },
|
|
3410
3448
|
{ regex: /"([^"]{2,120})"/g, group: 1 },
|
|
3411
3449
|
{ regex: /'([^']{2,120})'/g, group: 1 }
|
|
@@ -3699,7 +3737,7 @@ var Pipeline = class {
|
|
|
3699
3737
|
*/
|
|
3700
3738
|
askStream(_0) {
|
|
3701
3739
|
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
3702
|
-
var _a, _b, _c, _d, _e, _f;
|
|
3740
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
3703
3741
|
yield new __await(this.initialize());
|
|
3704
3742
|
const ns = namespace != null ? namespace : this.config.projectId;
|
|
3705
3743
|
const topK = (_b = (_a = this.config.rag) == null ? void 0 : _a.topK) != null ? _b : 5;
|
|
@@ -3709,7 +3747,7 @@ var Pipeline = class {
|
|
|
3709
3747
|
if ((_e = this.config.rag) == null ? void 0 : _e.useQueryTransformation) {
|
|
3710
3748
|
searchQuery = yield new __await(this.rewriteQuery(question, history));
|
|
3711
3749
|
}
|
|
3712
|
-
const hints = QueryProcessor.extractQueryFieldHints(question);
|
|
3750
|
+
const hints = QueryProcessor.extractQueryFieldHints(question, (_f = this.config.rag) == null ? void 0 : _f.filterableFields);
|
|
3713
3751
|
const filter = QueryProcessor.buildQueryFilter(question, hints);
|
|
3714
3752
|
const { sources: rawSources, graphData } = yield new __await(this.retrieve(searchQuery, {
|
|
3715
3753
|
namespace: ns,
|
|
@@ -3717,7 +3755,7 @@ var Pipeline = class {
|
|
|
3717
3755
|
filter
|
|
3718
3756
|
}));
|
|
3719
3757
|
let sources = rawSources.filter((m) => m.score >= scoreThreshold);
|
|
3720
|
-
if ((
|
|
3758
|
+
if ((_g = this.config.rag) == null ? void 0 : _g.useReranking) {
|
|
3721
3759
|
sources = yield new __await(this.reranker.rerank(sources, question, topK));
|
|
3722
3760
|
} else {
|
|
3723
3761
|
sources = sources.slice(0, topK);
|
package/dist/handlers/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { g as RagConfig, C as ChatMessage, b as ChatResponse, e as IngestDocument } from './RagConfig-
|
|
1
|
+
import { g as RagConfig, C as ChatMessage, b as ChatResponse, e as IngestDocument } from './RagConfig-BjC6zSTV.js';
|
|
2
2
|
import { NextRequest, NextResponse } from 'next/server';
|
|
3
3
|
|
|
4
4
|
interface ValidationError {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { g as RagConfig, C as ChatMessage, b as ChatResponse, e as IngestDocument } from './RagConfig-
|
|
1
|
+
import { g as RagConfig, C as ChatMessage, b as ChatResponse, e as IngestDocument } from './RagConfig-BjC6zSTV.mjs';
|
|
2
2
|
import { NextRequest, NextResponse } from 'next/server';
|
|
3
3
|
|
|
4
4
|
interface ValidationError {
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React$1, { ReactNode } from 'react';
|
|
2
|
-
import { C as ChatMessage, V as VectorMatch, U as UIConfig } from './RagConfig-
|
|
3
|
-
export { a as ChatOptions, b as ChatResponse, E as EmbedOptions, c as EmbeddingConfig, d as EmbeddingProvider, I as ILLMProvider, e as IngestDocument, L as LLMConfig, f as LLMProvider, R as RAGConfig, g as RagConfig, h as UpsertDocument, i as VectorDBConfig, j as VectorDBProvider } from './RagConfig-
|
|
2
|
+
import { C as ChatMessage, V as VectorMatch, U as UIConfig } from './RagConfig-BjC6zSTV.mjs';
|
|
3
|
+
export { a as ChatOptions, b as ChatResponse, E as EmbedOptions, c as EmbeddingConfig, d as EmbeddingProvider, I as ILLMProvider, e as IngestDocument, L as LLMConfig, f as LLMProvider, R as RAGConfig, g as RagConfig, h as UpsertDocument, i as VectorDBConfig, j as VectorDBProvider } from './RagConfig-BjC6zSTV.mjs';
|
|
4
4
|
export { C as Chunk, a as ChunkOptions } from './DocumentChunker-Dh9TvmGG.mjs';
|
|
5
5
|
|
|
6
6
|
interface ChatWidgetProps {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React$1, { ReactNode } from 'react';
|
|
2
|
-
import { C as ChatMessage, V as VectorMatch, U as UIConfig } from './RagConfig-
|
|
3
|
-
export { a as ChatOptions, b as ChatResponse, E as EmbedOptions, c as EmbeddingConfig, d as EmbeddingProvider, I as ILLMProvider, e as IngestDocument, L as LLMConfig, f as LLMProvider, R as RAGConfig, g as RagConfig, h as UpsertDocument, i as VectorDBConfig, j as VectorDBProvider } from './RagConfig-
|
|
2
|
+
import { C as ChatMessage, V as VectorMatch, U as UIConfig } from './RagConfig-BjC6zSTV.js';
|
|
3
|
+
export { a as ChatOptions, b as ChatResponse, E as EmbedOptions, c as EmbeddingConfig, d as EmbeddingProvider, I as ILLMProvider, e as IngestDocument, L as LLMConfig, f as LLMProvider, R as RAGConfig, g as RagConfig, h as UpsertDocument, i as VectorDBConfig, j as VectorDBProvider } from './RagConfig-BjC6zSTV.js';
|
|
4
4
|
export { C as Chunk, a as ChunkOptions } from './DocumentChunker-Dh9TvmGG.js';
|
|
5
5
|
|
|
6
6
|
interface ChatWidgetProps {
|
package/dist/server.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { i as VectorDBConfig, L as LLMConfig, c as EmbeddingConfig, g as RagConfig, e as IngestDocument, C as ChatMessage, b as ChatResponse, k as RetrievalResult, h as UpsertDocument, V as VectorMatch, G as GraphDBConfig, l as GraphNode, m as Edge, n as GraphSearchResult, I as ILLMProvider, j as VectorDBProvider, f as LLMProvider, d as EmbeddingProvider, R as RAGConfig, U as UIConfig, a as ChatOptions, E as EmbedOptions } from './RagConfig-
|
|
1
|
+
import { i as VectorDBConfig, L as LLMConfig, c as EmbeddingConfig, g as RagConfig, e as IngestDocument, C as ChatMessage, b as ChatResponse, k as RetrievalResult, h as UpsertDocument, V as VectorMatch, G as GraphDBConfig, l as GraphNode, m as Edge, n as GraphSearchResult, I as ILLMProvider, j as VectorDBProvider, f as LLMProvider, d as EmbeddingProvider, R as RAGConfig, U as UIConfig, a as ChatOptions, E as EmbedOptions } from './RagConfig-BjC6zSTV.mjs';
|
|
2
2
|
export { C as Chunk, a as ChunkOptions, D as DocumentChunker } from './DocumentChunker-Dh9TvmGG.mjs';
|
|
3
|
-
import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-
|
|
4
|
-
export { C as ConfigValidator, V as ValidationError, b as VectorPlugin, c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from './index-
|
|
3
|
+
import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-CU_fQq__.mjs';
|
|
4
|
+
export { C as ConfigValidator, V as ValidationError, b as VectorPlugin, c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from './index-CU_fQq__.mjs';
|
|
5
5
|
import 'next/server';
|
|
6
6
|
|
|
7
7
|
/**
|
package/dist/server.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { i as VectorDBConfig, L as LLMConfig, c as EmbeddingConfig, g as RagConfig, e as IngestDocument, C as ChatMessage, b as ChatResponse, k as RetrievalResult, h as UpsertDocument, V as VectorMatch, G as GraphDBConfig, l as GraphNode, m as Edge, n as GraphSearchResult, I as ILLMProvider, j as VectorDBProvider, f as LLMProvider, d as EmbeddingProvider, R as RAGConfig, U as UIConfig, a as ChatOptions, E as EmbedOptions } from './RagConfig-
|
|
1
|
+
import { i as VectorDBConfig, L as LLMConfig, c as EmbeddingConfig, g as RagConfig, e as IngestDocument, C as ChatMessage, b as ChatResponse, k as RetrievalResult, h as UpsertDocument, V as VectorMatch, G as GraphDBConfig, l as GraphNode, m as Edge, n as GraphSearchResult, I as ILLMProvider, j as VectorDBProvider, f as LLMProvider, d as EmbeddingProvider, R as RAGConfig, U as UIConfig, a as ChatOptions, E as EmbedOptions } from './RagConfig-BjC6zSTV.js';
|
|
2
2
|
export { C as Chunk, a as ChunkOptions, D as DocumentChunker } from './DocumentChunker-Dh9TvmGG.js';
|
|
3
|
-
import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-
|
|
4
|
-
export { C as ConfigValidator, V as ValidationError, b as VectorPlugin, c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from './index-
|
|
3
|
+
import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-C3bLmWcR.js';
|
|
4
|
+
export { C as ConfigValidator, V as ValidationError, b as VectorPlugin, c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from './index-C3bLmWcR.js';
|
|
5
5
|
import 'next/server';
|
|
6
6
|
|
|
7
7
|
/**
|
package/dist/server.js
CHANGED
|
@@ -662,6 +662,18 @@ var init_MongoDBProvider = __esm({
|
|
|
662
662
|
}
|
|
663
663
|
async query(vector, topK, namespace, filter) {
|
|
664
664
|
const publicFilter = this.sanitizeFilter(filter);
|
|
665
|
+
const vectorSearchFilter = {};
|
|
666
|
+
const matchFilter = {};
|
|
667
|
+
if (namespace) {
|
|
668
|
+
vectorSearchFilter.namespace = namespace;
|
|
669
|
+
}
|
|
670
|
+
for (const [key, value] of Object.entries(publicFilter)) {
|
|
671
|
+
if (key === "namespace") {
|
|
672
|
+
vectorSearchFilter.namespace = value;
|
|
673
|
+
} else {
|
|
674
|
+
matchFilter[key] = value;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
665
677
|
const pipeline = [
|
|
666
678
|
{
|
|
667
679
|
$vectorSearch: __spreadValues({
|
|
@@ -669,9 +681,15 @@ var init_MongoDBProvider = __esm({
|
|
|
669
681
|
path: this.embeddingKey,
|
|
670
682
|
queryVector: vector,
|
|
671
683
|
numCandidates: this.config.options.numCandidates || Math.max(topK * 20, 200),
|
|
672
|
-
limit: topK
|
|
673
|
-
}, Object.keys(
|
|
674
|
-
}
|
|
684
|
+
limit: topK * 2
|
|
685
|
+
}, Object.keys(vectorSearchFilter).length > 0 ? { filter: vectorSearchFilter } : {})
|
|
686
|
+
}
|
|
687
|
+
];
|
|
688
|
+
if (Object.keys(matchFilter).length > 0) {
|
|
689
|
+
pipeline.push({ $match: matchFilter });
|
|
690
|
+
}
|
|
691
|
+
pipeline.push(
|
|
692
|
+
{ $limit: topK },
|
|
675
693
|
{
|
|
676
694
|
$project: {
|
|
677
695
|
_id: 1,
|
|
@@ -681,7 +699,7 @@ var init_MongoDBProvider = __esm({
|
|
|
681
699
|
score: { $meta: "vectorSearchScore" }
|
|
682
700
|
}
|
|
683
701
|
}
|
|
684
|
-
|
|
702
|
+
);
|
|
685
703
|
const results = await this.collection.aggregate(pipeline).toArray();
|
|
686
704
|
return results.map((res) => ({
|
|
687
705
|
id: res._id,
|
|
@@ -3455,12 +3473,14 @@ var QueryProcessor = class {
|
|
|
3455
3473
|
* Checks if a string is likely a question word or common prompt phrase.
|
|
3456
3474
|
*/
|
|
3457
3475
|
static isLikelyPromptPhrase(value) {
|
|
3458
|
-
return /^(what|which|who|where|when|why|how)\b/i.test(value.trim());
|
|
3476
|
+
return /^(what|which|who|where|when|why|how|the|is|are|was|were|in|on|at|by|for|with|about|a|an|to|of)\b/i.test(value.trim());
|
|
3459
3477
|
}
|
|
3460
3478
|
/**
|
|
3461
3479
|
* Scans a natural language question for potential metadata hints and keywords.
|
|
3480
|
+
* @param question The user's query
|
|
3481
|
+
* @param validFields Optional list of known filterable fields to look for
|
|
3462
3482
|
*/
|
|
3463
|
-
static extractQueryFieldHints(question) {
|
|
3483
|
+
static extractQueryFieldHints(question, validFields = []) {
|
|
3464
3484
|
var _a, _b, _c, _d;
|
|
3465
3485
|
if (!question.trim()) return [];
|
|
3466
3486
|
const hints = /* @__PURE__ */ new Map();
|
|
@@ -3494,11 +3514,29 @@ var QueryProcessor = class {
|
|
|
3494
3514
|
if (name) addHint(name, "name");
|
|
3495
3515
|
}
|
|
3496
3516
|
}
|
|
3517
|
+
const genericPattern = /\b([a-z][a-z0-9_]{1,30})\s*[:=]\s*["']?([^"'\n?.!,]{1,60})["']?/gi;
|
|
3518
|
+
for (const match of question.matchAll(genericPattern)) {
|
|
3519
|
+
const field = match[1];
|
|
3520
|
+
const value = match[2];
|
|
3521
|
+
if (field && !this.isLikelyPromptPhrase(field)) {
|
|
3522
|
+
addHint(value, field);
|
|
3523
|
+
}
|
|
3524
|
+
}
|
|
3525
|
+
if (validFields.length > 0) {
|
|
3526
|
+
for (const field of validFields) {
|
|
3527
|
+
const pattern = new RegExp(`\\b${field}\\s*(?:is|are|:|of)?\\s+["']?([^"\\n?.!,]{1,60})["']?(?=[?.!,]|$)`, "gi");
|
|
3528
|
+
for (const match of question.matchAll(pattern)) {
|
|
3529
|
+
const value = match[1];
|
|
3530
|
+
if (value && !this.isLikelyPromptPhrase(value)) {
|
|
3531
|
+
addHint(value, field);
|
|
3532
|
+
}
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
}
|
|
3497
3536
|
const universalPatterns = [
|
|
3498
3537
|
{ regex: /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/gi, field: "email", group: 1 },
|
|
3499
3538
|
{ regex: /(\+?\d[\d\-\.\s\(\)]{6,}\d)/g, field: "phone", group: 1 },
|
|
3500
3539
|
{ regex: /(\b\d{4}-\d{2}-\d{2}\b|\b\d{1,2}\/\d{1,2}\/\d{2,4}\b)/g, field: "date", group: 1 },
|
|
3501
|
-
{ regex: /(\$\s?\d{1,3}(?:,\d{3})*(?:\.\d+)?)/g, field: "amount", group: 1 },
|
|
3502
3540
|
{ regex: /\b(ID|id|identifier)[: ]\s*([A-Za-z0-9\-]{3,})\b/gi, field: "id", group: 2 },
|
|
3503
3541
|
{ regex: /"([^"]{2,120})"/g, group: 1 },
|
|
3504
3542
|
{ regex: /'([^']{2,120})'/g, group: 1 }
|
|
@@ -3792,7 +3830,7 @@ var Pipeline = class {
|
|
|
3792
3830
|
*/
|
|
3793
3831
|
askStream(_0) {
|
|
3794
3832
|
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
3795
|
-
var _a, _b, _c, _d, _e, _f;
|
|
3833
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
3796
3834
|
yield new __await(this.initialize());
|
|
3797
3835
|
const ns = namespace != null ? namespace : this.config.projectId;
|
|
3798
3836
|
const topK = (_b = (_a = this.config.rag) == null ? void 0 : _a.topK) != null ? _b : 5;
|
|
@@ -3802,7 +3840,7 @@ var Pipeline = class {
|
|
|
3802
3840
|
if ((_e = this.config.rag) == null ? void 0 : _e.useQueryTransformation) {
|
|
3803
3841
|
searchQuery = yield new __await(this.rewriteQuery(question, history));
|
|
3804
3842
|
}
|
|
3805
|
-
const hints = QueryProcessor.extractQueryFieldHints(question);
|
|
3843
|
+
const hints = QueryProcessor.extractQueryFieldHints(question, (_f = this.config.rag) == null ? void 0 : _f.filterableFields);
|
|
3806
3844
|
const filter = QueryProcessor.buildQueryFilter(question, hints);
|
|
3807
3845
|
const { sources: rawSources, graphData } = yield new __await(this.retrieve(searchQuery, {
|
|
3808
3846
|
namespace: ns,
|
|
@@ -3810,7 +3848,7 @@ var Pipeline = class {
|
|
|
3810
3848
|
filter
|
|
3811
3849
|
}));
|
|
3812
3850
|
let sources = rawSources.filter((m) => m.score >= scoreThreshold);
|
|
3813
|
-
if ((
|
|
3851
|
+
if ((_g = this.config.rag) == null ? void 0 : _g.useReranking) {
|
|
3814
3852
|
sources = yield new __await(this.reranker.rerank(sources, question, topK));
|
|
3815
3853
|
} else {
|
|
3816
3854
|
sources = sources.slice(0, topK);
|
package/dist/server.mjs
CHANGED
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
sseFrame,
|
|
41
41
|
sseMetaFrame,
|
|
42
42
|
sseTextFrame
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-3GKA3PJF.mjs";
|
|
44
44
|
import "./chunk-YLTMFW4M.mjs";
|
|
45
45
|
import {
|
|
46
46
|
PineconeProvider
|
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
} from "./chunk-FLOSGE6A.mjs";
|
|
51
51
|
import {
|
|
52
52
|
MongoDBProvider
|
|
53
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-5AJ4XHLW.mjs";
|
|
54
54
|
import {
|
|
55
55
|
MilvusProvider
|
|
56
56
|
} from "./chunk-U55XRW3U.mjs";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retrivora-ai/rag-engine",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
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/config/RagConfig.ts
CHANGED
|
@@ -174,6 +174,10 @@ export interface RAGConfig {
|
|
|
174
174
|
useGraphRetrieval?: boolean;
|
|
175
175
|
/** Whether to perform reranking on retrieved results */
|
|
176
176
|
useReranking?: boolean;
|
|
177
|
+
/** List of metadata fields that are valid for filtering.
|
|
178
|
+
* Used to dynamically extract hints from natural language queries.
|
|
179
|
+
*/
|
|
180
|
+
filterableFields?: string[];
|
|
177
181
|
}
|
|
178
182
|
|
|
179
183
|
// ---------------------------------------------------------------------------
|
package/src/core/Pipeline.ts
CHANGED
|
@@ -315,7 +315,7 @@ export class Pipeline {
|
|
|
315
315
|
}
|
|
316
316
|
|
|
317
317
|
// 2. Parallel Retrieval
|
|
318
|
-
const hints = QueryProcessor.extractQueryFieldHints(question);
|
|
318
|
+
const hints = QueryProcessor.extractQueryFieldHints(question, this.config.rag?.filterableFields);
|
|
319
319
|
const filter = QueryProcessor.buildQueryFilter(question, hints);
|
|
320
320
|
|
|
321
321
|
const { sources: rawSources, graphData } = await this.retrieve(searchQuery, {
|
|
@@ -31,13 +31,16 @@ export class QueryProcessor {
|
|
|
31
31
|
* Checks if a string is likely a question word or common prompt phrase.
|
|
32
32
|
*/
|
|
33
33
|
static isLikelyPromptPhrase(value: string): boolean {
|
|
34
|
-
return /^(what|which|who|where|when|why|how)\b/i.test(value.trim());
|
|
34
|
+
return /^(what|which|who|where|when|why|how|the|is|are|was|were|in|on|at|by|for|with|about|a|an|to|of)\b/i.test(value.trim());
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
|
|
37
38
|
/**
|
|
38
39
|
* Scans a natural language question for potential metadata hints and keywords.
|
|
40
|
+
* @param question The user's query
|
|
41
|
+
* @param validFields Optional list of known filterable fields to look for
|
|
39
42
|
*/
|
|
40
|
-
static extractQueryFieldHints(question: string): QueryFieldHint[] {
|
|
43
|
+
static extractQueryFieldHints(question: string, validFields: string[] = []): QueryFieldHint[] {
|
|
41
44
|
if (!question.trim()) return [];
|
|
42
45
|
|
|
43
46
|
const hints = new Map<string, QueryFieldHint>();
|
|
@@ -88,12 +91,36 @@ export class QueryProcessor {
|
|
|
88
91
|
}
|
|
89
92
|
}
|
|
90
93
|
|
|
91
|
-
// 4.
|
|
94
|
+
// 4. Dynamic Schema-driven patterns
|
|
95
|
+
// We look for any word-like key followed by a colon or equals.
|
|
96
|
+
const genericPattern = /\b([a-z][a-z0-9_]{1,30})\s*[:=]\s*["']?([^"'\n?.!,]{1,60})["']?/gi;
|
|
97
|
+
for (const match of question.matchAll(genericPattern)) {
|
|
98
|
+
const field = match[1];
|
|
99
|
+
const value = match[2];
|
|
100
|
+
if (field && !this.isLikelyPromptPhrase(field)) {
|
|
101
|
+
addHint(value, field);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 5. Explicitly requested fields (if any)
|
|
106
|
+
if (validFields.length > 0) {
|
|
107
|
+
for (const field of validFields) {
|
|
108
|
+
// More aggressive pattern for explicitly allowed fields: "[field] [value]"
|
|
109
|
+
const pattern = new RegExp(`\\b${field}\\s*(?:is|are|:|of)?\\s+["']?([^"\\n?.!,]{1,60})["']?(?=[?.!,]|$)`, 'gi');
|
|
110
|
+
for (const match of question.matchAll(pattern)) {
|
|
111
|
+
const value = match[1];
|
|
112
|
+
if (value && !this.isLikelyPromptPhrase(value)) {
|
|
113
|
+
addHint(value, field);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// 5. Universal patterns (email, phone, etc.)
|
|
92
120
|
const universalPatterns: Array<{ regex: RegExp; field?: string; group?: number }> = [
|
|
93
121
|
{ regex: /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/gi, field: 'email', group: 1 },
|
|
94
122
|
{ regex: /(\+?\d[\d\-\.\s\(\)]{6,}\d)/g, field: 'phone', group: 1 },
|
|
95
123
|
{ regex: /(\b\d{4}-\d{2}-\d{2}\b|\b\d{1,2}\/\d{1,2}\/\d{2,4}\b)/g, field: 'date', group: 1 },
|
|
96
|
-
{ regex: /(\$\s?\d{1,3}(?:,\d{3})*(?:\.\d+)?)/g, field: 'amount', group: 1 },
|
|
97
124
|
{ regex: /\b(ID|id|identifier)[: ]\s*([A-Za-z0-9\-]{3,})\b/gi, field: 'id', group: 2 },
|
|
98
125
|
{ regex: /"([^"]{2,120})"/g, group: 1 },
|
|
99
126
|
{ regex: /'([^']{2,120})'/g, group: 1 },
|
|
@@ -139,6 +139,24 @@ export class MongoDBProvider extends BaseVectorProvider {
|
|
|
139
139
|
|
|
140
140
|
async query(vector: number[], topK: number, namespace?: string, filter?: Record<string, unknown>): Promise<VectorMatch[]> {
|
|
141
141
|
const publicFilter = this.sanitizeFilter(filter);
|
|
142
|
+
|
|
143
|
+
// Split filters: only 'namespace' is safe for the $vectorSearch 'filter' argument
|
|
144
|
+
// unless explicitly indexed. Moving others to a subsequent $match stage.
|
|
145
|
+
const vectorSearchFilter: Record<string, unknown> = {};
|
|
146
|
+
const matchFilter: Record<string, unknown> = {};
|
|
147
|
+
|
|
148
|
+
if (namespace) {
|
|
149
|
+
vectorSearchFilter.namespace = namespace;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
for (const [key, value] of Object.entries(publicFilter)) {
|
|
153
|
+
if (key === 'namespace') {
|
|
154
|
+
vectorSearchFilter.namespace = value;
|
|
155
|
+
} else {
|
|
156
|
+
matchFilter[key] = value;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
142
160
|
const pipeline: Record<string, unknown>[] = [
|
|
143
161
|
{
|
|
144
162
|
$vectorSearch: {
|
|
@@ -146,12 +164,20 @@ export class MongoDBProvider extends BaseVectorProvider {
|
|
|
146
164
|
path: this.embeddingKey,
|
|
147
165
|
queryVector: vector,
|
|
148
166
|
numCandidates: (this.config.options.numCandidates as number) || Math.max(topK * 20, 200),
|
|
149
|
-
limit: topK,
|
|
150
|
-
...(Object.keys(
|
|
151
|
-
? { filter: { ...publicFilter, ...(namespace ? { namespace } : {}) } }
|
|
152
|
-
: {}),
|
|
167
|
+
limit: topK * 2, // Increase limit slightly to account for post-filtering
|
|
168
|
+
...(Object.keys(vectorSearchFilter).length > 0 ? { filter: vectorSearchFilter } : {}),
|
|
153
169
|
},
|
|
154
170
|
},
|
|
171
|
+
];
|
|
172
|
+
|
|
173
|
+
// Add post-filtering stage if there are additional filters
|
|
174
|
+
if (Object.keys(matchFilter).length > 0) {
|
|
175
|
+
pipeline.push({ $match: matchFilter });
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Final limit and projection
|
|
179
|
+
pipeline.push(
|
|
180
|
+
{ $limit: topK },
|
|
155
181
|
{
|
|
156
182
|
$project: {
|
|
157
183
|
_id: 1,
|
|
@@ -160,8 +186,8 @@ export class MongoDBProvider extends BaseVectorProvider {
|
|
|
160
186
|
namespace: 1,
|
|
161
187
|
score: { $meta: 'vectorSearchScore' },
|
|
162
188
|
},
|
|
163
|
-
}
|
|
164
|
-
|
|
189
|
+
}
|
|
190
|
+
);
|
|
165
191
|
|
|
166
192
|
const results = await this.collection!.aggregate(pipeline).toArray();
|
|
167
193
|
|