@retrivora-ai/rag-engine 1.9.1 → 1.9.3
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/{ILLMProvider-BQyKZLnd.d.mts → ILLMProvider-Bw2A28nU.d.mts} +2 -0
- package/dist/{ILLMProvider-BQyKZLnd.d.ts → ILLMProvider-Bw2A28nU.d.ts} +2 -0
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +193 -109
- package/dist/handlers/index.mjs +193 -109
- package/dist/{index-CDftK3qs.d.mts → index-B70ZLkfG.d.mts} +1 -1
- package/dist/{index-A0GqPsaG.d.ts → index-DVu-mkAM.d.ts} +1 -1
- package/dist/index.css +57 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +90 -36
- package/dist/index.mjs +91 -37
- package/dist/server.d.mts +3 -3
- package/dist/server.d.ts +3 -3
- package/dist/server.js +193 -109
- package/dist/server.mjs +193 -109
- package/package.json +1 -1
- package/src/components/ChatWindow.tsx +24 -14
- package/src/components/MessageBubble.tsx +41 -6
- package/src/components/ProductCard.tsx +4 -4
- package/src/core/Pipeline.ts +53 -25
- package/src/core/QueryProcessor.ts +10 -9
- package/src/handlers/index.ts +31 -8
- package/src/hooks/useRagChat.ts +24 -0
- package/src/providers/vectordb/MongoDBProvider.ts +13 -6
- package/src/providers/vectordb/MultiTablePostgresProvider.ts +36 -4
- package/src/types/chat.ts +2 -0
- package/src/utils/SchemaMapper.ts +6 -4
- package/src/utils/UITransformer.ts +2 -1
- package/src/utils/synonyms.ts +5 -5
package/dist/server.js
CHANGED
|
@@ -540,6 +540,82 @@ var init_PostgreSQLProvider = __esm({
|
|
|
540
540
|
}
|
|
541
541
|
});
|
|
542
542
|
|
|
543
|
+
// src/utils/synonyms.ts
|
|
544
|
+
function resolveMetadataValue(meta, uiKey) {
|
|
545
|
+
var _a;
|
|
546
|
+
const synonyms = (_a = FIELD_SYNONYMS[uiKey]) != null ? _a : [];
|
|
547
|
+
const keys = Object.keys(meta);
|
|
548
|
+
const systemKeys = ["namespace", "filename", "filesize", "filetype", "docid", "uploadedat", "dimension", "chunkindex"];
|
|
549
|
+
let match = keys.find((k) => k.toLowerCase() === uiKey.toLowerCase());
|
|
550
|
+
if (match !== void 0) return meta[match];
|
|
551
|
+
match = keys.find((k) => synonyms.map((s) => s.toLowerCase()).includes(k.toLowerCase()));
|
|
552
|
+
if (match !== void 0) return meta[match];
|
|
553
|
+
const isBlacklisted = (kl) => {
|
|
554
|
+
return systemKeys.includes(kl) || kl.startsWith("option1") || kl.startsWith("option2") || kl.startsWith("option3");
|
|
555
|
+
};
|
|
556
|
+
match = keys.find((k) => {
|
|
557
|
+
const kl = k.toLowerCase();
|
|
558
|
+
if (isBlacklisted(kl)) return false;
|
|
559
|
+
return kl.includes(uiKey.toLowerCase());
|
|
560
|
+
});
|
|
561
|
+
if (match !== void 0) return meta[match];
|
|
562
|
+
match = keys.find((k) => {
|
|
563
|
+
const kl = k.toLowerCase();
|
|
564
|
+
if (isBlacklisted(kl)) return false;
|
|
565
|
+
return synonyms.some((sk) => kl.includes(sk.toLowerCase()) || sk.toLowerCase().includes(kl));
|
|
566
|
+
});
|
|
567
|
+
return match !== void 0 ? meta[match] : void 0;
|
|
568
|
+
}
|
|
569
|
+
var FIELD_SYNONYMS;
|
|
570
|
+
var init_synonyms = __esm({
|
|
571
|
+
"src/utils/synonyms.ts"() {
|
|
572
|
+
"use strict";
|
|
573
|
+
FIELD_SYNONYMS = {
|
|
574
|
+
name: ["product", "item", "title", "label", "heading", "subject", "product name", "item name"],
|
|
575
|
+
price: ["cost", "amount", "msrp", "price", "rate", "value", "price_usd", "variant price"],
|
|
576
|
+
brand: ["manufacturer", "vendor", "make", "company", "brand_name", "supplier"],
|
|
577
|
+
image: [
|
|
578
|
+
"imageUrl",
|
|
579
|
+
"thumbnail",
|
|
580
|
+
"img",
|
|
581
|
+
"url",
|
|
582
|
+
"photo",
|
|
583
|
+
"picture",
|
|
584
|
+
"media",
|
|
585
|
+
"image_url",
|
|
586
|
+
"main_image",
|
|
587
|
+
"product_image",
|
|
588
|
+
"thumb",
|
|
589
|
+
"image src",
|
|
590
|
+
"variant image"
|
|
591
|
+
],
|
|
592
|
+
stock: [
|
|
593
|
+
"inventory",
|
|
594
|
+
"quantity",
|
|
595
|
+
"count",
|
|
596
|
+
"availability",
|
|
597
|
+
"stock_level",
|
|
598
|
+
"inStock",
|
|
599
|
+
"is_available",
|
|
600
|
+
"in stock",
|
|
601
|
+
"status",
|
|
602
|
+
"variant inventory qty"
|
|
603
|
+
],
|
|
604
|
+
category: [
|
|
605
|
+
"product_category",
|
|
606
|
+
"product category",
|
|
607
|
+
"category_name",
|
|
608
|
+
"category name",
|
|
609
|
+
"department",
|
|
610
|
+
"collection",
|
|
611
|
+
"type"
|
|
612
|
+
],
|
|
613
|
+
description: ["summary", "content", "body", "text", "info", "details", "body (html)", "seo description"],
|
|
614
|
+
link: ["url", "href", "product_url", "page_url", "link"]
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
|
|
543
619
|
// src/providers/vectordb/MultiTablePostgresProvider.ts
|
|
544
620
|
var MultiTablePostgresProvider_exports = {};
|
|
545
621
|
__export(MultiTablePostgresProvider_exports, {
|
|
@@ -551,6 +627,7 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
551
627
|
"use strict";
|
|
552
628
|
import_pg2 = require("pg");
|
|
553
629
|
init_BaseVectorProvider();
|
|
630
|
+
init_synonyms();
|
|
554
631
|
MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
555
632
|
constructor(config) {
|
|
556
633
|
var _a, _b, _c;
|
|
@@ -631,8 +708,13 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
631
708
|
}
|
|
632
709
|
tableName = tableName.replace(/[^a-z0-9_]/gi, "_").toLowerCase() || this.uploadTable;
|
|
633
710
|
const firstMeta = fileDocs[0].metadata || {};
|
|
634
|
-
|
|
635
|
-
|
|
711
|
+
let csvHeaders = [];
|
|
712
|
+
if (Array.isArray(firstMeta.csvHeaders)) {
|
|
713
|
+
csvHeaders = firstMeta.csvHeaders;
|
|
714
|
+
} else {
|
|
715
|
+
const systemKeys = ["fileName", "fileSize", "fileType", "uploadedAt", "dimension", "chunkIndex", "id", "namespace", "content", "metadata", "embedding", "docId", "docid", "chunkId", "chunkid", "csvHeaders", "csvheaders"];
|
|
716
|
+
csvHeaders = Object.keys(firstMeta).filter((k) => !systemKeys.includes(k) && !systemKeys.includes(k.toLowerCase()));
|
|
717
|
+
}
|
|
636
718
|
const columnDefs = csvHeaders.map((h) => `"${h}" TEXT`).join(",\n ");
|
|
637
719
|
const createTableSql = `
|
|
638
720
|
CREATE TABLE IF NOT EXISTS "${tableName}" (
|
|
@@ -725,10 +807,26 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
725
807
|
};
|
|
726
808
|
const dynamicKeywordQuery = getDynamicKeywordQuery();
|
|
727
809
|
const tableLimit = Math.max(topK, 50);
|
|
810
|
+
const metadataFilters = _filter == null ? void 0 : _filter.metadata;
|
|
728
811
|
const queryPromises = this.tables.map(async (table) => {
|
|
729
812
|
try {
|
|
730
813
|
let sqlQuery = "";
|
|
731
814
|
let params = [];
|
|
815
|
+
let whereClause = "";
|
|
816
|
+
const filterParams = [];
|
|
817
|
+
if (metadataFilters && Object.keys(metadataFilters).length > 0) {
|
|
818
|
+
const conditions = Object.entries(metadataFilters).map(([key, val]) => {
|
|
819
|
+
var _a3;
|
|
820
|
+
filterParams.push(String(val));
|
|
821
|
+
const baseOffset = queryText && dynamicKeywordQuery ? 2 : 1;
|
|
822
|
+
const paramIdx = baseOffset + filterParams.length;
|
|
823
|
+
const synonyms = (_a3 = FIELD_SYNONYMS[key]) != null ? _a3 : [];
|
|
824
|
+
const keysToCheck = [key, ...synonyms];
|
|
825
|
+
const coalesceExprs = keysToCheck.map((k) => `LOWER(metadata->>'${k}')`);
|
|
826
|
+
return `COALESCE(${coalesceExprs.join(", ")}) = LOWER($${paramIdx})`;
|
|
827
|
+
});
|
|
828
|
+
whereClause = `WHERE ${conditions.join(" AND ")}`;
|
|
829
|
+
}
|
|
732
830
|
if (queryText && dynamicKeywordQuery) {
|
|
733
831
|
const hasEntityHints = entityHints.length > 0;
|
|
734
832
|
const exactNameScoreExpr = hasEntityHints ? `+ (
|
|
@@ -745,19 +843,21 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
745
843
|
COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) AS keyword_score,
|
|
746
844
|
((1 - (embedding <=> $1::vector)) + (COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) * 2.0) ${exactNameScoreExpr}) AS hybrid_score
|
|
747
845
|
FROM "${table}" t
|
|
846
|
+
${whereClause}
|
|
748
847
|
ORDER BY hybrid_score DESC
|
|
749
848
|
LIMIT ${tableLimit}
|
|
750
849
|
`;
|
|
751
|
-
params = [vectorLiteral, dynamicKeywordQuery];
|
|
850
|
+
params = [vectorLiteral, dynamicKeywordQuery, ...filterParams];
|
|
752
851
|
} else {
|
|
753
852
|
sqlQuery = `
|
|
754
853
|
SELECT *,
|
|
755
854
|
(1 - (embedding <=> $1::vector)) AS hybrid_score
|
|
756
855
|
FROM "${table}" t
|
|
856
|
+
${whereClause}
|
|
757
857
|
ORDER BY hybrid_score DESC
|
|
758
858
|
LIMIT ${tableLimit}
|
|
759
859
|
`;
|
|
760
|
-
params = [vectorLiteral];
|
|
860
|
+
params = [vectorLiteral, ...filterParams];
|
|
761
861
|
}
|
|
762
862
|
const result = await this.pool.query(sqlQuery, params);
|
|
763
863
|
if (result.rowCount && result.rowCount > 0) {
|
|
@@ -990,12 +1090,15 @@ var init_MongoDBProvider = __esm({
|
|
|
990
1090
|
}
|
|
991
1091
|
);
|
|
992
1092
|
const results = await this.collection.aggregate(pipeline).toArray();
|
|
993
|
-
return results.map((res) =>
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1093
|
+
return results.map((res) => {
|
|
1094
|
+
const normalizedScore = res.score * 2 - 1;
|
|
1095
|
+
return {
|
|
1096
|
+
id: res._id,
|
|
1097
|
+
content: res[this.contentKey],
|
|
1098
|
+
metadata: res[this.metadataKey] || {},
|
|
1099
|
+
score: normalizedScore
|
|
1100
|
+
};
|
|
1101
|
+
});
|
|
999
1102
|
}
|
|
1000
1103
|
async delete(id, namespace) {
|
|
1001
1104
|
await this.collection.deleteOne(__spreadValues({ _id: id }, namespace ? { namespace } : {}));
|
|
@@ -4430,7 +4533,8 @@ var QueryProcessor = class {
|
|
|
4430
4533
|
const fieldValuePatterns = [
|
|
4431
4534
|
new RegExp(`\\b${fieldPattern}\\s*(?:=|:)\\s*["']?${valuePattern}["']?(?=[?.!,]|$)`, "gi"),
|
|
4432
4535
|
new RegExp(`\\b${fieldPattern}\\s+(?:is|are|was|were|equals?|equal to|named|called)\\s+["']?${valuePattern}["']?(?=[?.!,]|$)`, "gi"),
|
|
4433
|
-
new RegExp(`\\bwith\\s+${fieldPattern}\\s+["']?${valuePattern}["']?(?=[?.!,]|$)`, "gi")
|
|
4536
|
+
new RegExp(`\\bwith\\s+${fieldPattern}\\s+["']?${valuePattern}["']?(?=[?.!,]|$)`, "gi"),
|
|
4537
|
+
new RegExp(`\\b(?:under|in|for|from|of)\\s+${fieldPattern}\\s+["']?${valuePattern}["']?(?=[?.!,]|$)`, "gi")
|
|
4434
4538
|
];
|
|
4435
4539
|
for (const pattern of fieldValuePatterns) {
|
|
4436
4540
|
for (const match of question.matchAll(pattern)) {
|
|
@@ -4664,73 +4768,8 @@ var LLMRouter = class {
|
|
|
4664
4768
|
}
|
|
4665
4769
|
};
|
|
4666
4770
|
|
|
4667
|
-
// src/utils/synonyms.ts
|
|
4668
|
-
var FIELD_SYNONYMS = {
|
|
4669
|
-
name: ["product", "item", "title", "label", "heading", "subject", "product name", "item name"],
|
|
4670
|
-
price: ["cost", "amount", "msrp", "price", "rate", "value", "price_usd"],
|
|
4671
|
-
brand: ["manufacturer", "vendor", "make", "company", "brand_name", "supplier"],
|
|
4672
|
-
image: [
|
|
4673
|
-
"imageUrl",
|
|
4674
|
-
"thumbnail",
|
|
4675
|
-
"img",
|
|
4676
|
-
"url",
|
|
4677
|
-
"photo",
|
|
4678
|
-
"picture",
|
|
4679
|
-
"media",
|
|
4680
|
-
"image_url",
|
|
4681
|
-
"main_image",
|
|
4682
|
-
"product_image",
|
|
4683
|
-
"thumb"
|
|
4684
|
-
],
|
|
4685
|
-
stock: [
|
|
4686
|
-
"inventory",
|
|
4687
|
-
"quantity",
|
|
4688
|
-
"count",
|
|
4689
|
-
"availability",
|
|
4690
|
-
"stock_level",
|
|
4691
|
-
"inStock",
|
|
4692
|
-
"is_available",
|
|
4693
|
-
"in stock",
|
|
4694
|
-
"status"
|
|
4695
|
-
],
|
|
4696
|
-
category: [
|
|
4697
|
-
"product_category",
|
|
4698
|
-
"product category",
|
|
4699
|
-
"category_name",
|
|
4700
|
-
"category name",
|
|
4701
|
-
"department",
|
|
4702
|
-
"collection"
|
|
4703
|
-
],
|
|
4704
|
-
description: ["summary", "content", "body", "text", "info", "details"],
|
|
4705
|
-
link: ["url", "href", "product_url", "page_url", "link"]
|
|
4706
|
-
};
|
|
4707
|
-
function resolveMetadataValue(meta, uiKey) {
|
|
4708
|
-
var _a;
|
|
4709
|
-
const synonyms = (_a = FIELD_SYNONYMS[uiKey]) != null ? _a : [];
|
|
4710
|
-
const keys = Object.keys(meta);
|
|
4711
|
-
const systemKeys = ["namespace", "filename", "filesize", "filetype", "docid", "uploadedat", "dimension", "chunkindex"];
|
|
4712
|
-
let match = keys.find((k) => k.toLowerCase() === uiKey.toLowerCase());
|
|
4713
|
-
if (match !== void 0) return meta[match];
|
|
4714
|
-
match = keys.find((k) => synonyms.map((s) => s.toLowerCase()).includes(k.toLowerCase()));
|
|
4715
|
-
if (match !== void 0) return meta[match];
|
|
4716
|
-
const isBlacklisted = (kl) => {
|
|
4717
|
-
return systemKeys.includes(kl) || kl.startsWith("option1") || kl.startsWith("option2") || kl.startsWith("option3");
|
|
4718
|
-
};
|
|
4719
|
-
match = keys.find((k) => {
|
|
4720
|
-
const kl = k.toLowerCase();
|
|
4721
|
-
if (isBlacklisted(kl)) return false;
|
|
4722
|
-
return kl.includes(uiKey.toLowerCase());
|
|
4723
|
-
});
|
|
4724
|
-
if (match !== void 0) return meta[match];
|
|
4725
|
-
match = keys.find((k) => {
|
|
4726
|
-
const kl = k.toLowerCase();
|
|
4727
|
-
if (isBlacklisted(kl)) return false;
|
|
4728
|
-
return synonyms.some((sk) => kl.includes(sk.toLowerCase()) || sk.toLowerCase().includes(kl));
|
|
4729
|
-
});
|
|
4730
|
-
return match !== void 0 ? meta[match] : void 0;
|
|
4731
|
-
}
|
|
4732
|
-
|
|
4733
4771
|
// src/utils/UITransformer.ts
|
|
4772
|
+
init_synonyms();
|
|
4734
4773
|
var UITransformer = class {
|
|
4735
4774
|
// ─── Public Entry Points ─────────────────────────────────────────────────
|
|
4736
4775
|
/**
|
|
@@ -5027,7 +5066,7 @@ RULES:
|
|
|
5027
5066
|
}
|
|
5028
5067
|
// ─── Transform Helpers ────────────────────────────────────────────────────
|
|
5029
5068
|
static transformToProductCarousel(data, config, trainedSchema) {
|
|
5030
|
-
const products = data.map((item) => this.extractProductInfo(item, config, trainedSchema)).filter((p) => p !== null);
|
|
5069
|
+
const products = data.map((item) => this.extractProductInfo(item, config, trainedSchema)).filter((p) => p !== null).slice(0, 15);
|
|
5031
5070
|
return {
|
|
5032
5071
|
type: "product_carousel",
|
|
5033
5072
|
title: "Recommended Products",
|
|
@@ -5986,14 +6025,16 @@ Given these metadata keys from a database: [${keys.join(", ")}]
|
|
|
5986
6025
|
Identify which keys best correspond to these standard UI properties:
|
|
5987
6026
|
${propertyList}
|
|
5988
6027
|
|
|
5989
|
-
Return ONLY a JSON object where the keys are the UI properties and the values are the matching database keys.
|
|
6028
|
+
Return ONLY a valid JSON object where the keys are the UI properties and the values are the EXACT matching database keys from the list above.
|
|
5990
6029
|
If no good match is found for a property, omit it.
|
|
5991
6030
|
|
|
5992
6031
|
Example:
|
|
5993
6032
|
{
|
|
5994
|
-
"name": "
|
|
5995
|
-
"price": "
|
|
5996
|
-
"brand": "
|
|
6033
|
+
"name": "Title",
|
|
6034
|
+
"price": "Variant Price",
|
|
6035
|
+
"brand": "Vendor",
|
|
6036
|
+
"image": "Image Src",
|
|
6037
|
+
"stock": "Variant Inventory Qty"
|
|
5997
6038
|
}
|
|
5998
6039
|
`;
|
|
5999
6040
|
try {
|
|
@@ -6284,7 +6325,10 @@ var Pipeline = class {
|
|
|
6284
6325
|
upsertBatchOptions
|
|
6285
6326
|
);
|
|
6286
6327
|
if (upsertResult.errors.length > 0) {
|
|
6287
|
-
console.warn(`[Pipeline] Ingestion: ${upsertResult.errors.length} batches failed
|
|
6328
|
+
console.warn(`[Pipeline] Ingestion: ${upsertResult.errors.length} batches failed. Error details:`);
|
|
6329
|
+
upsertResult.errors.forEach((err, idx) => {
|
|
6330
|
+
console.warn(` Batch ${idx + 1} Error: ${err.error.message || String(err.error)}`);
|
|
6331
|
+
});
|
|
6288
6332
|
}
|
|
6289
6333
|
return upsertResult.totalProcessed;
|
|
6290
6334
|
}
|
|
@@ -6399,8 +6443,9 @@ var Pipeline = class {
|
|
|
6399
6443
|
this.embeddingCache.set(cacheKey, queryVector);
|
|
6400
6444
|
}
|
|
6401
6445
|
const graphData = (strategyResult === "graph" || strategyResult === "both") && this.graphDB && ((_j = this.config.rag) == null ? void 0 : _j.useGraphRetrieval) ? yield new __await(this.graphDB.query(searchQuery)) : void 0;
|
|
6446
|
+
const hasMetadataFilter = filter.metadata && Object.keys(filter.metadata).length > 0;
|
|
6402
6447
|
const hasNumericPredicates = Array.isArray(filter.__numericPredicates) && filter.__numericPredicates.length > 0;
|
|
6403
|
-
const wantsExhaustiveList = hasNumericPredicates || /\b(list|all|show|provide|give|get)\b/i.test(question);
|
|
6448
|
+
const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
|
|
6404
6449
|
const retrievalLimit = wantsExhaustiveList ? Math.max(topK * 20, 100) : topK * 2;
|
|
6405
6450
|
const rawSources = (strategyResult === "vector" || strategyResult === "both") && queryVector && queryVector.length > 0 ? yield new __await(this.vectorDB.query(queryVector, retrievalLimit, ns, filter)) : [];
|
|
6406
6451
|
const retrieveEnd = performance.now();
|
|
@@ -6408,15 +6453,28 @@ var Pipeline = class {
|
|
|
6408
6453
|
const retrieveMs = retrieveEnd - embedStart;
|
|
6409
6454
|
const rerankStart = performance.now();
|
|
6410
6455
|
const structuredSources = this.applyStructuredFilters(rawSources, filter);
|
|
6411
|
-
let
|
|
6456
|
+
let fullSources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) => m.score >= scoreThreshold);
|
|
6457
|
+
const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
|
|
6412
6458
|
if (!hasNumericPredicates && ((_k = this.config.rag) == null ? void 0 : _k.useReranking)) {
|
|
6413
|
-
|
|
6459
|
+
fullSources = yield new __await(this.reranker.rerank(fullSources, question, rerankLimit));
|
|
6414
6460
|
} else if (!wantsExhaustiveList) {
|
|
6415
|
-
|
|
6461
|
+
fullSources = fullSources.slice(0, topK);
|
|
6416
6462
|
}
|
|
6417
6463
|
const rerankMs = performance.now() - rerankStart;
|
|
6418
|
-
let context =
|
|
6464
|
+
let context = fullSources.length ? fullSources.map((m, i) => `[Source ${i + 1}]
|
|
6419
6465
|
${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
|
|
6466
|
+
let displayCount = 15;
|
|
6467
|
+
if (hasMetadataFilter) {
|
|
6468
|
+
displayCount = fullSources.length;
|
|
6469
|
+
} else {
|
|
6470
|
+
const baseThreshold = Math.max(scoreThreshold, 0.4);
|
|
6471
|
+
const highlyRelevant = fullSources.filter((m) => m.score >= baseThreshold);
|
|
6472
|
+
displayCount = Math.max(highlyRelevant.length, topK);
|
|
6473
|
+
if (displayCount > 15) {
|
|
6474
|
+
displayCount = 15;
|
|
6475
|
+
}
|
|
6476
|
+
}
|
|
6477
|
+
const sources = [...fullSources].sort((a, b) => b.score - a.score).slice(0, displayCount);
|
|
6420
6478
|
if (graphData && graphData.nodes.length > 0) {
|
|
6421
6479
|
const graphContext = graphData.nodes.map(
|
|
6422
6480
|
(n) => `Entity: ${n.label} (${n.id})${n.properties ? " - " + JSON.stringify(n.properties) : ""}`
|
|
@@ -6429,7 +6487,18 @@ ${context}`;
|
|
|
6429
6487
|
}
|
|
6430
6488
|
const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
|
|
6431
6489
|
const trainedSchemaPromise = allMetadataKeys.length > 0 ? SchemaMapper.train(this.llmProvider, ns, allMetadataKeys).catch(() => void 0) : Promise.resolve(void 0);
|
|
6432
|
-
const
|
|
6490
|
+
const uiTransformationPromise = trainedSchemaPromise.then(
|
|
6491
|
+
(trainedSchema) => this.generateUiTransformation(
|
|
6492
|
+
question,
|
|
6493
|
+
sources,
|
|
6494
|
+
trainedSchema,
|
|
6495
|
+
hasNumericPredicates
|
|
6496
|
+
)
|
|
6497
|
+
).catch((uiError) => {
|
|
6498
|
+
console.warn("[Pipeline] UI transformation failed concurrently:", uiError);
|
|
6499
|
+
return UITransformer.transform(question, sources, this.config);
|
|
6500
|
+
});
|
|
6501
|
+
const restrictionSuffix = "\n\n(IMPORTANT: Format your response beautifully using rich Markdown! Use bolding for emphasis, headings (##) for structure, bullet points for lists, and proper line breaks between paragraphs to make it highly readable. However, NEVER generate Markdown tables, HTML figures, or text charts (the UI renders requested charts separately, so NEVER say you cannot create, display, draw, render, or provide a chart/visualization). If listing products, use simple markdown bullet points or comma-separated names. NEVER use plus signs (+) to separate product names, category names, or list items. For product description/detail questions, provide customer-facing prose only and do NOT list internal catalog fields such as Handle, Body (HTML), Vendor, Type, Tags, Published, Option, Variant, SKU, or raw metadata labels. You CAN use numbers for years/counts like 2006 or 5800, but NEVER put a dollar sign ($) before them.)";
|
|
6433
6502
|
const hardenedHistory = [...history];
|
|
6434
6503
|
const userQuestion = { role: "user", content: question + restrictionSuffix };
|
|
6435
6504
|
const messages = [...hardenedHistory, userQuestion];
|
|
@@ -6499,19 +6568,7 @@ ${context}`;
|
|
|
6499
6568
|
tokens,
|
|
6500
6569
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6501
6570
|
};
|
|
6502
|
-
|
|
6503
|
-
try {
|
|
6504
|
-
const trainedSchema = yield new __await(trainedSchemaPromise);
|
|
6505
|
-
uiTransformation = yield new __await(this.generateUiTransformation(
|
|
6506
|
-
question,
|
|
6507
|
-
sources,
|
|
6508
|
-
trainedSchema,
|
|
6509
|
-
hasNumericPredicates
|
|
6510
|
-
));
|
|
6511
|
-
} catch (uiError) {
|
|
6512
|
-
console.warn("[Pipeline] UI transformation failed before metadata yield:", uiError);
|
|
6513
|
-
uiTransformation = UITransformer.transform(question, sources, this.config);
|
|
6514
|
-
}
|
|
6571
|
+
const uiTransformation = yield new __await(uiTransformationPromise);
|
|
6515
6572
|
yield {
|
|
6516
6573
|
reply: "",
|
|
6517
6574
|
sources,
|
|
@@ -7245,15 +7302,24 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7245
7302
|
});
|
|
7246
7303
|
}
|
|
7247
7304
|
const encoder = new TextEncoder();
|
|
7305
|
+
let isActive = true;
|
|
7248
7306
|
const stream = new ReadableStream({
|
|
7249
7307
|
async start(controller) {
|
|
7250
7308
|
var _a;
|
|
7251
|
-
const enqueue = (text) =>
|
|
7309
|
+
const enqueue = (text) => {
|
|
7310
|
+
if (!isActive) return;
|
|
7311
|
+
try {
|
|
7312
|
+
controller.enqueue(encoder.encode(text));
|
|
7313
|
+
} catch (err) {
|
|
7314
|
+
console.warn("[createStreamHandler] Failed to enqueue (stream already closed):", err);
|
|
7315
|
+
}
|
|
7316
|
+
};
|
|
7252
7317
|
try {
|
|
7253
7318
|
const pipelineStream = plugin.chatStream(message, history, namespace);
|
|
7254
7319
|
try {
|
|
7255
7320
|
for (var iter = __forAwait(pipelineStream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
7256
7321
|
const chunk = temp.value;
|
|
7322
|
+
if (!isActive) break;
|
|
7257
7323
|
if (typeof chunk === "string") {
|
|
7258
7324
|
enqueue(sseTextFrame(chunk));
|
|
7259
7325
|
} else {
|
|
@@ -7291,12 +7357,27 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7291
7357
|
}
|
|
7292
7358
|
}
|
|
7293
7359
|
} catch (streamError) {
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
|
|
7360
|
+
if (isActive) {
|
|
7361
|
+
const errorMessage = streamError instanceof Error ? streamError.message : String(streamError);
|
|
7362
|
+
console.error("[createStreamHandler] Stream error:", streamError);
|
|
7363
|
+
try {
|
|
7364
|
+
enqueue(sseErrorFrame(errorMessage));
|
|
7365
|
+
} catch (e) {
|
|
7366
|
+
}
|
|
7367
|
+
}
|
|
7297
7368
|
} finally {
|
|
7298
|
-
|
|
7369
|
+
if (isActive) {
|
|
7370
|
+
isActive = false;
|
|
7371
|
+
try {
|
|
7372
|
+
controller.close();
|
|
7373
|
+
} catch (e) {
|
|
7374
|
+
}
|
|
7375
|
+
}
|
|
7299
7376
|
}
|
|
7377
|
+
},
|
|
7378
|
+
cancel(reason) {
|
|
7379
|
+
isActive = false;
|
|
7380
|
+
console.log("[createStreamHandler] Stream connection closed by client:", reason);
|
|
7300
7381
|
}
|
|
7301
7382
|
});
|
|
7302
7383
|
return new Response(stream, { headers: SSE_HEADERS });
|
|
@@ -7357,6 +7438,7 @@ function createUploadHandler(configOrPlugin) {
|
|
|
7357
7438
|
if (parsed.data && parsed.data.length > 0) {
|
|
7358
7439
|
let i = 0;
|
|
7359
7440
|
let lastRowData = null;
|
|
7441
|
+
const csvCols = Object.keys(parsed.data[0]);
|
|
7360
7442
|
for (const row of parsed.data) {
|
|
7361
7443
|
i++;
|
|
7362
7444
|
const rowData = row;
|
|
@@ -7378,12 +7460,14 @@ function createUploadHandler(configOrPlugin) {
|
|
|
7378
7460
|
documents.push({
|
|
7379
7461
|
docId: `${file.name}-row-${i}`,
|
|
7380
7462
|
content: contentParts.join(", "),
|
|
7381
|
-
metadata: __spreadValues(__spreadValues({
|
|
7463
|
+
metadata: __spreadValues(__spreadProps(__spreadValues({
|
|
7382
7464
|
fileName: file.name,
|
|
7383
7465
|
fileSize: file.size,
|
|
7384
7466
|
fileType: file.type,
|
|
7385
7467
|
uploadedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7386
|
-
}, dimension ? { dimension } : {}),
|
|
7468
|
+
}, dimension ? { dimension } : {}), {
|
|
7469
|
+
csvHeaders: csvCols
|
|
7470
|
+
}), rowData)
|
|
7387
7471
|
});
|
|
7388
7472
|
}
|
|
7389
7473
|
}
|