@retrivora-ai/rag-engine 2.0.1 → 2.0.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/FREE_TIER_ARCHITECTURE.md +232 -0
- package/README.md +9 -0
- package/dist/{ILLMProvider-DMxLyTdq.d.mts → ILLMProvider-0rRBYbVW.d.mts} +133 -1
- package/dist/{ILLMProvider-DMxLyTdq.d.ts → ILLMProvider-0rRBYbVW.d.ts} +133 -1
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +679 -15
- package/dist/handlers/index.mjs +679 -15
- package/dist/index-B1wGUlSL.d.mts +532 -0
- package/dist/{index-tzwc7UhY.d.ts → index-BIHHp_f6.d.ts} +1 -1
- package/dist/{index-DHsFLJXQ.d.mts → index-BvODr57d.d.mts} +1 -1
- package/dist/index-DcklhThn.d.ts +532 -0
- package/dist/index.css +51 -3
- package/dist/index.d.mts +6 -105
- package/dist/index.d.ts +6 -105
- package/dist/index.js +1918 -8
- package/dist/index.mjs +1913 -8
- package/dist/server.d.mts +51 -7
- package/dist/server.d.ts +51 -7
- package/dist/server.js +721 -15
- package/dist/server.mjs +704 -15
- package/package.json +9 -7
- package/src/app/page.tsx +54 -18
- package/src/components/ChatWindow.tsx +2 -2
- package/src/components/DocumentUpload.tsx +5 -4
- package/src/components/MessageBubble.tsx +2 -4
- package/src/core/Pipeline.ts +23 -5
- package/src/handlers/index.ts +48 -1
- package/src/index.ts +22 -4
- package/src/rendering/IntentClassifier.ts +167 -0
- package/src/rendering/RendererRegistry.ts +164 -0
- package/src/rendering/RuleEngine.ts +67 -0
- package/src/rendering/VisualizationDecisionEngine.ts +164 -0
- package/src/rendering/__tests__/VisualizationDecisionEngine.test.ts +237 -0
- package/src/rendering/index.ts +12 -0
- package/src/rendering/rules/Rule1SpecificInfoRule.ts +28 -0
- package/src/rendering/rules/Rule2ComparisonRule.ts +24 -0
- package/src/rendering/rules/Rule3ProductDiscoveryRule.ts +28 -0
- package/src/rendering/rules/Rule4AnalyticalRule.ts +38 -0
- package/src/rendering/rules/Rule5MixedResponseRule.ts +29 -0
- package/src/rendering/rules/Rule6SmallResultSetRule.ts +24 -0
- package/src/rendering/rules/Rule7LargeTableRule.ts +35 -0
- package/src/rendering/types.ts +96 -0
- package/src/server.ts +3 -2
- package/src/types/index.ts +48 -0
- package/src/utils/DocumentParser.ts +64 -28
- package/src/utils/UITransformer.ts +15 -4
- package/dist/index-CfkqZd2Y.d.ts +0 -197
- package/dist/index-xygonxpW.d.mts +0 -197
package/dist/server.js
CHANGED
|
@@ -2074,6 +2074,8 @@ __export(server_exports, {
|
|
|
2074
2074
|
AuthenticationException: () => AuthenticationException,
|
|
2075
2075
|
BaseVectorProvider: () => BaseVectorProvider,
|
|
2076
2076
|
BatchProcessor: () => BatchProcessor,
|
|
2077
|
+
CarouselRendererStrategy: () => CarouselRendererStrategy,
|
|
2078
|
+
ChartRendererStrategy: () => ChartRendererStrategy,
|
|
2077
2079
|
ChromaDBProvider: () => ChromaDBProvider,
|
|
2078
2080
|
ConfigBuilder: () => ConfigBuilder,
|
|
2079
2081
|
ConfigResolver: () => ConfigResolver,
|
|
@@ -2085,10 +2087,12 @@ __export(server_exports, {
|
|
|
2085
2087
|
EmbeddingStrategy: () => EmbeddingStrategy,
|
|
2086
2088
|
EmbeddingStrategyResolver: () => EmbeddingStrategyResolver,
|
|
2087
2089
|
GroqProvider: () => GroqProvider,
|
|
2090
|
+
IntentClassifier: () => IntentClassifier,
|
|
2088
2091
|
LLMFactory: () => LLMFactory,
|
|
2089
2092
|
LLM_PROFILES: () => LLM_PROFILES,
|
|
2090
2093
|
LicenseVerifier: () => LicenseVerifier,
|
|
2091
2094
|
MilvusProvider: () => MilvusProvider,
|
|
2095
|
+
MixedRendererStrategy: () => MixedRendererStrategy,
|
|
2092
2096
|
MongoDBProvider: () => MongoDBProvider,
|
|
2093
2097
|
MultiTablePostgresProvider: () => MultiTablePostgresProvider,
|
|
2094
2098
|
OllamaProvider: () => OllamaProvider,
|
|
@@ -2104,13 +2108,25 @@ __export(server_exports, {
|
|
|
2104
2108
|
QwenProvider: () => QwenProvider,
|
|
2105
2109
|
RateLimitException: () => RateLimitException,
|
|
2106
2110
|
RedisProvider: () => RedisProvider,
|
|
2111
|
+
RendererRegistry: () => RendererRegistry,
|
|
2107
2112
|
RetrievalException: () => RetrievalException,
|
|
2108
2113
|
Retrivora: () => Retrivora,
|
|
2109
2114
|
RetrivoraError: () => RetrivoraError,
|
|
2115
|
+
Rule1SpecificInfoRule: () => Rule1SpecificInfoRule,
|
|
2116
|
+
Rule2ComparisonRule: () => Rule2ComparisonRule,
|
|
2117
|
+
Rule3ProductDiscoveryRule: () => Rule3ProductDiscoveryRule,
|
|
2118
|
+
Rule4AnalyticalRule: () => Rule4AnalyticalRule,
|
|
2119
|
+
Rule5MixedResponseRule: () => Rule5MixedResponseRule,
|
|
2120
|
+
Rule6SmallResultSetRule: () => Rule6SmallResultSetRule,
|
|
2121
|
+
Rule7LargeTableRule: () => Rule7LargeTableRule,
|
|
2122
|
+
RuleEngine: () => RuleEngine,
|
|
2123
|
+
TableRendererStrategy: () => TableRendererStrategy,
|
|
2124
|
+
TextRendererStrategy: () => TextRendererStrategy,
|
|
2110
2125
|
UniversalLLMAdapter: () => UniversalLLMAdapter,
|
|
2111
2126
|
UniversalVectorProvider: () => UniversalVectorProvider,
|
|
2112
2127
|
VECTOR_PROFILES: () => VECTOR_PROFILES,
|
|
2113
2128
|
VectorPlugin: () => VectorPlugin,
|
|
2129
|
+
VisualizationDecisionEngine: () => VisualizationDecisionEngine,
|
|
2114
2130
|
WeaviateProvider: () => WeaviateProvider,
|
|
2115
2131
|
createChatHandler: () => createChatHandler,
|
|
2116
2132
|
createFeedbackHandler: () => createFeedbackHandler,
|
|
@@ -2122,6 +2138,7 @@ __export(server_exports, {
|
|
|
2122
2138
|
createSessionsHandler: () => createSessionsHandler,
|
|
2123
2139
|
createStreamHandler: () => createStreamHandler,
|
|
2124
2140
|
createUploadHandler: () => createUploadHandler,
|
|
2141
|
+
decideVisualization: () => decideVisualization,
|
|
2125
2142
|
getRagConfig: () => getRagConfig,
|
|
2126
2143
|
sseErrorFrame: () => sseErrorFrame,
|
|
2127
2144
|
sseFrame: () => sseFrame,
|
|
@@ -5983,6 +6000,606 @@ var LLMRouter = class {
|
|
|
5983
6000
|
|
|
5984
6001
|
// src/utils/UITransformer.ts
|
|
5985
6002
|
init_synonyms();
|
|
6003
|
+
|
|
6004
|
+
// src/rendering/IntentClassifier.ts
|
|
6005
|
+
var IntentClassifier = class {
|
|
6006
|
+
/**
|
|
6007
|
+
* Fast, zero-latency classifier that maps a user query and optional data context
|
|
6008
|
+
* into a high-level IntentCategory.
|
|
6009
|
+
*/
|
|
6010
|
+
static classify(context) {
|
|
6011
|
+
const q = (context.userQuery || "").toLowerCase().trim();
|
|
6012
|
+
const signals = this.extractDataSignals(context);
|
|
6013
|
+
if (this.isInformationLookup(q)) {
|
|
6014
|
+
return { intent: "information_lookup", signals };
|
|
6015
|
+
}
|
|
6016
|
+
if (this.isComparisonQuery(q)) {
|
|
6017
|
+
return { intent: "comparison", signals };
|
|
6018
|
+
}
|
|
6019
|
+
if (this.isProductQuery(q) || signals.isProductLike && this.isRecommendationQuery(q)) {
|
|
6020
|
+
return { intent: "product_search", signals };
|
|
6021
|
+
}
|
|
6022
|
+
if (this.isTrendQuery(q) || signals.hasDateFields && signals.hasNumericFields && /\b(growth|trend|over time|monthly|yearly|weekly)\b/.test(q)) {
|
|
6023
|
+
return { intent: "trend_analysis", signals };
|
|
6024
|
+
}
|
|
6025
|
+
if (this.isRankingQuery(q)) {
|
|
6026
|
+
return { intent: "ranking", signals };
|
|
6027
|
+
}
|
|
6028
|
+
if (this.isAnalyticsQuery(q) || signals.hasNumericFields && signals.hasCategoricalFields && /\b(sales|revenue|performance|count|total|average|breakdown|share|percentage|correlation)\b/.test(q)) {
|
|
6029
|
+
return { intent: "analytics", signals };
|
|
6030
|
+
}
|
|
6031
|
+
if (this.isRecommendationQuery(q)) {
|
|
6032
|
+
return { intent: "recommendation", signals };
|
|
6033
|
+
}
|
|
6034
|
+
return { intent: "information_lookup", signals };
|
|
6035
|
+
}
|
|
6036
|
+
/**
|
|
6037
|
+
* Extract key data structure signals from retrieved documents.
|
|
6038
|
+
*/
|
|
6039
|
+
static extractDataSignals(context) {
|
|
6040
|
+
const docs = context.retrievedDocuments || [];
|
|
6041
|
+
const rowCount = docs.length;
|
|
6042
|
+
let hasNumericFields = false;
|
|
6043
|
+
let hasDateFields = false;
|
|
6044
|
+
let hasCategoricalFields = false;
|
|
6045
|
+
let isProductLike = false;
|
|
6046
|
+
let numericFieldCount = 0;
|
|
6047
|
+
let categoricalFieldCount = 0;
|
|
6048
|
+
if (docs.length > 0) {
|
|
6049
|
+
const keys = /* @__PURE__ */ new Set();
|
|
6050
|
+
let numericKeys = /* @__PURE__ */ new Set();
|
|
6051
|
+
let dateKeys = /* @__PURE__ */ new Set();
|
|
6052
|
+
let catKeys = /* @__PURE__ */ new Set();
|
|
6053
|
+
let productKeyMatches = 0;
|
|
6054
|
+
docs.forEach((doc) => {
|
|
6055
|
+
const meta = doc.metadata || {};
|
|
6056
|
+
Object.entries(meta).forEach(([key, val]) => {
|
|
6057
|
+
keys.add(key);
|
|
6058
|
+
const kLower = key.toLowerCase();
|
|
6059
|
+
if (["price", "image", "brand", "in_stock", "rating", "sku", "product"].some((p) => kLower.includes(p))) {
|
|
6060
|
+
productKeyMatches++;
|
|
6061
|
+
}
|
|
6062
|
+
if (typeof val === "number") {
|
|
6063
|
+
numericKeys.add(key);
|
|
6064
|
+
} else if (typeof val === "string") {
|
|
6065
|
+
if (/^\d{4}-\d{2}-\d{2}/.test(val) || !isNaN(Date.parse(val)) && val.length > 5) {
|
|
6066
|
+
dateKeys.add(key);
|
|
6067
|
+
} else if (val.length < 50 && !val.includes("\n")) {
|
|
6068
|
+
catKeys.add(key);
|
|
6069
|
+
}
|
|
6070
|
+
}
|
|
6071
|
+
});
|
|
6072
|
+
});
|
|
6073
|
+
hasNumericFields = numericKeys.size > 0;
|
|
6074
|
+
hasDateFields = dateKeys.size > 0;
|
|
6075
|
+
hasCategoricalFields = catKeys.size > 0;
|
|
6076
|
+
numericFieldCount = numericKeys.size;
|
|
6077
|
+
categoricalFieldCount = catKeys.size;
|
|
6078
|
+
if (productKeyMatches >= 2 || docs.some((d) => d.content.toLowerCase().includes("price") || d.content.toLowerCase().includes("brand"))) {
|
|
6079
|
+
isProductLike = true;
|
|
6080
|
+
}
|
|
6081
|
+
}
|
|
6082
|
+
return {
|
|
6083
|
+
rowCount,
|
|
6084
|
+
hasNumericFields,
|
|
6085
|
+
hasDateFields,
|
|
6086
|
+
hasCategoricalFields,
|
|
6087
|
+
isProductLike,
|
|
6088
|
+
numericFieldCount,
|
|
6089
|
+
categoricalFieldCount
|
|
6090
|
+
};
|
|
6091
|
+
}
|
|
6092
|
+
// ─── Intent Heuristic Checkers ─────────────────────────────────────────────
|
|
6093
|
+
static isInformationLookup(query) {
|
|
6094
|
+
if (/^(what|who|explain|define|where|when|why|how|how does|can|could|does|do|is|are|has|have|will|should|would|meaning of)\s+/i.test(query)) {
|
|
6095
|
+
if (!/\b(compare|versus|vs\.?|trend|monthly|revenue|top selling|best)\b/i.test(query)) {
|
|
6096
|
+
return true;
|
|
6097
|
+
}
|
|
6098
|
+
}
|
|
6099
|
+
if (/^(what is the )?(price|cost|fee|rate) of\b/i.test(query)) {
|
|
6100
|
+
return true;
|
|
6101
|
+
}
|
|
6102
|
+
return false;
|
|
6103
|
+
}
|
|
6104
|
+
static isComparisonQuery(query) {
|
|
6105
|
+
return /\b(compare|comparison|vs\.?|versus|difference between|differ|contrast|against)\b/i.test(query);
|
|
6106
|
+
}
|
|
6107
|
+
static isProductQuery(query) {
|
|
6108
|
+
return /\b(best|recommend|top|buy|shopping|under \$|cheap|shoes|laptops|chairs|headphones|phone|sneakers|apparel|products)\b/i.test(query) && !/\b(compare|chart|sales|revenue|trend)\b/i.test(query);
|
|
6109
|
+
}
|
|
6110
|
+
static isRecommendationQuery(query) {
|
|
6111
|
+
return /\b(recommend|suggest|what should i (buy|get|choose)|best options|top picks)\b/i.test(query);
|
|
6112
|
+
}
|
|
6113
|
+
static isTrendQuery(query) {
|
|
6114
|
+
return /\b(trend|trends|growth|over time|historical|timeline|monthly|yearly|weekly|daily|revenue growth|sales growth)\b/i.test(query);
|
|
6115
|
+
}
|
|
6116
|
+
static isRankingQuery(query) {
|
|
6117
|
+
return /\b(highest|lowest|top\s*\d+|bottom\s*\d+|rank|ranking|top performing|best performing)\b/i.test(query);
|
|
6118
|
+
}
|
|
6119
|
+
static isAnalyticsQuery(query) {
|
|
6120
|
+
return /\b(sales|revenue|analytics|insights|distribution|percentage|share|breakdown|breakup|scatter|correlation|metrics|performance|by region|by category)\b/i.test(query);
|
|
6121
|
+
}
|
|
6122
|
+
};
|
|
6123
|
+
|
|
6124
|
+
// src/rendering/rules/Rule1SpecificInfoRule.ts
|
|
6125
|
+
var Rule1SpecificInfoRule = class {
|
|
6126
|
+
constructor() {
|
|
6127
|
+
this.name = "Rule1SpecificInfo";
|
|
6128
|
+
this.priority = 100;
|
|
6129
|
+
}
|
|
6130
|
+
evaluate(context, intent) {
|
|
6131
|
+
const q = (context.userQuery || "").toLowerCase().trim();
|
|
6132
|
+
const isFactQuery = intent === "information_lookup" || /^(what|who|explain|define|where|when|why|meaning of)\s+/i.test(q) || /^(what is the price of|price of|cost of)\b/i.test(q);
|
|
6133
|
+
const isNonVisual = !/\b(compare|versus|vs\.?|trend|monthly|revenue|best|top 10|chart|table|list|grid)\b/i.test(q);
|
|
6134
|
+
if (isFactQuery && isNonVisual) {
|
|
6135
|
+
return {
|
|
6136
|
+
renderType: "text",
|
|
6137
|
+
confidence: 0.95,
|
|
6138
|
+
reason: "Rule 1: Specific information request (fact, explanation, or definition) requires plain text rendering."
|
|
6139
|
+
};
|
|
6140
|
+
}
|
|
6141
|
+
return null;
|
|
6142
|
+
}
|
|
6143
|
+
};
|
|
6144
|
+
|
|
6145
|
+
// src/rendering/rules/Rule2ComparisonRule.ts
|
|
6146
|
+
var Rule2ComparisonRule = class {
|
|
6147
|
+
constructor() {
|
|
6148
|
+
this.name = "Rule2Comparison";
|
|
6149
|
+
this.priority = 90;
|
|
6150
|
+
}
|
|
6151
|
+
evaluate(context, intent) {
|
|
6152
|
+
const q = (context.userQuery || "").toLowerCase().trim();
|
|
6153
|
+
const isComparison = intent === "comparison" || /\b(compare|comparison|vs\.?|versus|difference between|differ|contrast|against)\b/i.test(q);
|
|
6154
|
+
if (isComparison) {
|
|
6155
|
+
return {
|
|
6156
|
+
renderType: "table",
|
|
6157
|
+
confidence: 0.9,
|
|
6158
|
+
reason: "Rule 2: Comparison query contrasting multiple entities requires structured table rendering."
|
|
6159
|
+
};
|
|
6160
|
+
}
|
|
6161
|
+
return null;
|
|
6162
|
+
}
|
|
6163
|
+
};
|
|
6164
|
+
|
|
6165
|
+
// src/rendering/rules/Rule3ProductDiscoveryRule.ts
|
|
6166
|
+
var Rule3ProductDiscoveryRule = class {
|
|
6167
|
+
constructor() {
|
|
6168
|
+
this.name = "Rule3ProductDiscovery";
|
|
6169
|
+
this.priority = 85;
|
|
6170
|
+
}
|
|
6171
|
+
evaluate(context, intent) {
|
|
6172
|
+
const q = (context.userQuery || "").toLowerCase().trim();
|
|
6173
|
+
const isDiscovery = intent === "product_search" || intent === "recommendation" || /\b(best|recommend|top|buy|shopping|under \$|cheap|shoes|laptops|chairs|headphones|sneakers|apparel|products|show available)\b/i.test(q);
|
|
6174
|
+
const isNotChart = !/\b(chart|sales|revenue|monthly|growth|trend|over time)\b/i.test(q);
|
|
6175
|
+
const isAnalyticalRanking = /\b(top performing|top selling|best performing|performing|sales|revenue|ranking)\b/i.test(q);
|
|
6176
|
+
if (isDiscovery && isNotChart && !isAnalyticalRanking) {
|
|
6177
|
+
return {
|
|
6178
|
+
renderType: "carousel",
|
|
6179
|
+
confidence: 0.9,
|
|
6180
|
+
reason: "Rule 3: Product discovery/recommendation query requires product carousel rendering."
|
|
6181
|
+
};
|
|
6182
|
+
}
|
|
6183
|
+
return null;
|
|
6184
|
+
}
|
|
6185
|
+
};
|
|
6186
|
+
|
|
6187
|
+
// src/rendering/rules/Rule4AnalyticalRule.ts
|
|
6188
|
+
var Rule4AnalyticalRule = class {
|
|
6189
|
+
constructor() {
|
|
6190
|
+
this.name = "Rule4Analytical";
|
|
6191
|
+
this.priority = 80;
|
|
6192
|
+
}
|
|
6193
|
+
evaluate(context, intent) {
|
|
6194
|
+
const q = (context.userQuery || "").toLowerCase().trim();
|
|
6195
|
+
const isAnalytical = intent === "analytics" || intent === "trend_analysis" || intent === "ranking" || /\b(monthly sales|revenue growth|top performing|population trends|sales by|growth|distribution|share|percentage|breakdown|correlation|scatter|trend)\b/i.test(q);
|
|
6196
|
+
if (!isAnalytical) return null;
|
|
6197
|
+
let chartType = "bar";
|
|
6198
|
+
if (intent === "trend_analysis" || /\b(monthly|yearly|weekly|growth|over time|trend|timeline|historical)\b/i.test(q)) {
|
|
6199
|
+
chartType = "line";
|
|
6200
|
+
} else if (/\b(share|percentage|percent|breakup|breakdown|composition|pie|donut|proportion)\b/i.test(q)) {
|
|
6201
|
+
chartType = "pie";
|
|
6202
|
+
} else if (/\b(correlation|scatter|relationship|relation|impact of|depends on)\b/i.test(q)) {
|
|
6203
|
+
chartType = "scatter";
|
|
6204
|
+
} else {
|
|
6205
|
+
chartType = "bar";
|
|
6206
|
+
}
|
|
6207
|
+
return {
|
|
6208
|
+
renderType: "chart",
|
|
6209
|
+
chartType,
|
|
6210
|
+
confidence: 0.85,
|
|
6211
|
+
reason: `Rule 4: Analytical query with numerical insights selects ${chartType} chart.`
|
|
6212
|
+
};
|
|
6213
|
+
}
|
|
6214
|
+
};
|
|
6215
|
+
|
|
6216
|
+
// src/rendering/rules/Rule5MixedResponseRule.ts
|
|
6217
|
+
var Rule5MixedResponseRule = class {
|
|
6218
|
+
constructor() {
|
|
6219
|
+
this.name = "Rule5MixedResponse";
|
|
6220
|
+
this.priority = 95;
|
|
6221
|
+
}
|
|
6222
|
+
evaluate(context, _intent) {
|
|
6223
|
+
const q = (context.userQuery || "").toLowerCase().trim();
|
|
6224
|
+
const isTopSellingThisMonth = /\btop\s*(selling|performing)?\s*products?\s*(this|last)?\s*(month|year|week)\b/i.test(q);
|
|
6225
|
+
const hasMultipleSectionsRequest = /\b(summary|overview)\b/i.test(q) && /\b(carousel|products?|items?)\b/i.test(q) && /\b(chart|sales|trend|revenue)\b/i.test(q);
|
|
6226
|
+
if (isTopSellingThisMonth || hasMultipleSectionsRequest) {
|
|
6227
|
+
return {
|
|
6228
|
+
renderType: "mixed",
|
|
6229
|
+
confidence: 0.95,
|
|
6230
|
+
reason: "Rule 5: Mixed response query requires multi-section composition (text, carousel, chart).",
|
|
6231
|
+
sections: [
|
|
6232
|
+
{ type: "text", title: "Summary" },
|
|
6233
|
+
{ type: "carousel", title: "Top Products" },
|
|
6234
|
+
{ type: "chart", chartType: "bar", title: "Sales Performance" }
|
|
6235
|
+
]
|
|
6236
|
+
};
|
|
6237
|
+
}
|
|
6238
|
+
return null;
|
|
6239
|
+
}
|
|
6240
|
+
};
|
|
6241
|
+
|
|
6242
|
+
// src/rendering/rules/Rule6SmallResultSetRule.ts
|
|
6243
|
+
var Rule6SmallResultSetRule = class {
|
|
6244
|
+
constructor() {
|
|
6245
|
+
this.name = "Rule6SmallResultSet";
|
|
6246
|
+
this.priority = 110;
|
|
6247
|
+
}
|
|
6248
|
+
evaluate(context, _intent) {
|
|
6249
|
+
const docs = context.retrievedDocuments || [];
|
|
6250
|
+
if (docs.length > 0 && docs.length < 3) {
|
|
6251
|
+
const q = (context.userQuery || "").toLowerCase().trim();
|
|
6252
|
+
const isExplicitComparison = /\b(compare|versus|vs\.?)\b/i.test(q);
|
|
6253
|
+
return {
|
|
6254
|
+
renderType: isExplicitComparison ? "table" : "text",
|
|
6255
|
+
confidence: 0.98,
|
|
6256
|
+
reason: `Rule 6: Small result set (${docs.length} rows < 3). Charts avoided to prevent sparse or uninformative visualizations.`
|
|
6257
|
+
};
|
|
6258
|
+
}
|
|
6259
|
+
return null;
|
|
6260
|
+
}
|
|
6261
|
+
};
|
|
6262
|
+
|
|
6263
|
+
// src/rendering/rules/Rule7LargeTableRule.ts
|
|
6264
|
+
var Rule7LargeTableRule = class {
|
|
6265
|
+
constructor() {
|
|
6266
|
+
this.name = "Rule7LargeTable";
|
|
6267
|
+
this.priority = 75;
|
|
6268
|
+
}
|
|
6269
|
+
evaluate(context, intent) {
|
|
6270
|
+
const docs = context.retrievedDocuments || [];
|
|
6271
|
+
if (docs.length > 5) {
|
|
6272
|
+
const q = (context.userQuery || "").toLowerCase().trim();
|
|
6273
|
+
const hasNumericAgg = intent === "analytics" || intent === "ranking" || /\b(sales|revenue|growth|count|total|average)\b/i.test(q);
|
|
6274
|
+
if (hasNumericAgg) {
|
|
6275
|
+
return {
|
|
6276
|
+
renderType: "mixed",
|
|
6277
|
+
confidence: 0.88,
|
|
6278
|
+
reason: `Rule 7: Large result set (${docs.length} rows > 5) with numeric aggregation rendered as Table + Chart.`,
|
|
6279
|
+
sections: [
|
|
6280
|
+
{ type: "table", title: "Detailed Data Table" },
|
|
6281
|
+
{ type: "chart", chartType: "bar", title: "Numerical Breakdown" }
|
|
6282
|
+
]
|
|
6283
|
+
};
|
|
6284
|
+
}
|
|
6285
|
+
return {
|
|
6286
|
+
renderType: "table",
|
|
6287
|
+
confidence: 0.85,
|
|
6288
|
+
reason: `Rule 7: Large result set (${docs.length} rows > 5) rendered as structured table for readability.`
|
|
6289
|
+
};
|
|
6290
|
+
}
|
|
6291
|
+
return null;
|
|
6292
|
+
}
|
|
6293
|
+
};
|
|
6294
|
+
|
|
6295
|
+
// src/rendering/RuleEngine.ts
|
|
6296
|
+
var RuleEngine = class {
|
|
6297
|
+
constructor() {
|
|
6298
|
+
this.rules = [];
|
|
6299
|
+
this.registerDefaultRules();
|
|
6300
|
+
}
|
|
6301
|
+
/**
|
|
6302
|
+
* Register standard rules in priority order.
|
|
6303
|
+
*/
|
|
6304
|
+
registerDefaultRules() {
|
|
6305
|
+
this.registerRule(new Rule6SmallResultSetRule());
|
|
6306
|
+
this.registerRule(new Rule1SpecificInfoRule());
|
|
6307
|
+
this.registerRule(new Rule5MixedResponseRule());
|
|
6308
|
+
this.registerRule(new Rule2ComparisonRule());
|
|
6309
|
+
this.registerRule(new Rule3ProductDiscoveryRule());
|
|
6310
|
+
this.registerRule(new Rule4AnalyticalRule());
|
|
6311
|
+
this.registerRule(new Rule7LargeTableRule());
|
|
6312
|
+
}
|
|
6313
|
+
/**
|
|
6314
|
+
* Add or replace a rule in the engine.
|
|
6315
|
+
* Automatically keeps rules sorted by descending priority.
|
|
6316
|
+
*/
|
|
6317
|
+
registerRule(rule) {
|
|
6318
|
+
this.rules = this.rules.filter((r) => r.name !== rule.name);
|
|
6319
|
+
this.rules.push(rule);
|
|
6320
|
+
this.rules.sort((a, b) => b.priority - a.priority);
|
|
6321
|
+
}
|
|
6322
|
+
/**
|
|
6323
|
+
* Evaluate context against rules in descending priority order.
|
|
6324
|
+
* Returns the first non-null RenderDecision.
|
|
6325
|
+
*/
|
|
6326
|
+
evaluate(context, intent) {
|
|
6327
|
+
for (const rule of this.rules) {
|
|
6328
|
+
const decision = rule.evaluate(context, intent);
|
|
6329
|
+
if (decision) {
|
|
6330
|
+
return decision;
|
|
6331
|
+
}
|
|
6332
|
+
}
|
|
6333
|
+
return {
|
|
6334
|
+
renderType: "text",
|
|
6335
|
+
confidence: 0.7,
|
|
6336
|
+
reason: "Default fallback: No specific visualization rule matched context."
|
|
6337
|
+
};
|
|
6338
|
+
}
|
|
6339
|
+
/**
|
|
6340
|
+
* List all registered rules.
|
|
6341
|
+
*/
|
|
6342
|
+
getRegisteredRules() {
|
|
6343
|
+
return this.rules.map((r) => ({ name: r.name, priority: r.priority }));
|
|
6344
|
+
}
|
|
6345
|
+
};
|
|
6346
|
+
|
|
6347
|
+
// src/rendering/RendererRegistry.ts
|
|
6348
|
+
var TextRendererStrategy = class {
|
|
6349
|
+
constructor() {
|
|
6350
|
+
this.type = "text";
|
|
6351
|
+
}
|
|
6352
|
+
render(data, options) {
|
|
6353
|
+
const title = (options == null ? void 0 : options.title) || "Information";
|
|
6354
|
+
if (typeof data === "string") {
|
|
6355
|
+
return { type: "text", title, data: { content: data } };
|
|
6356
|
+
}
|
|
6357
|
+
const docs = Array.isArray(data) ? data : [];
|
|
6358
|
+
const text = docs.map((d) => d.content).join("\n\n");
|
|
6359
|
+
return { type: "text", title, data: { content: text || "No detailed content available." } };
|
|
6360
|
+
}
|
|
6361
|
+
};
|
|
6362
|
+
var TableRendererStrategy = class {
|
|
6363
|
+
constructor() {
|
|
6364
|
+
this.type = "table";
|
|
6365
|
+
}
|
|
6366
|
+
render(data, options) {
|
|
6367
|
+
const docs = Array.isArray(data) ? data : [];
|
|
6368
|
+
const query = (options == null ? void 0 : options.query) || "";
|
|
6369
|
+
return UITransformer.transform(query, docs, void 0, void 0, {
|
|
6370
|
+
visualizationHint: "table",
|
|
6371
|
+
recommendedChart: "table",
|
|
6372
|
+
filterInStockOnly: false,
|
|
6373
|
+
wantsExplicitTable: true,
|
|
6374
|
+
isTemporal: false,
|
|
6375
|
+
isComparison: true,
|
|
6376
|
+
language: "en"
|
|
6377
|
+
});
|
|
6378
|
+
}
|
|
6379
|
+
};
|
|
6380
|
+
var CarouselRendererStrategy = class {
|
|
6381
|
+
constructor() {
|
|
6382
|
+
this.type = "carousel";
|
|
6383
|
+
}
|
|
6384
|
+
render(data, options) {
|
|
6385
|
+
const docs = Array.isArray(data) ? data : [];
|
|
6386
|
+
const query = (options == null ? void 0 : options.query) || "";
|
|
6387
|
+
return UITransformer.transform(query, docs, void 0, void 0, {
|
|
6388
|
+
visualizationHint: "product_browse",
|
|
6389
|
+
recommendedChart: "text",
|
|
6390
|
+
filterInStockOnly: false,
|
|
6391
|
+
wantsExplicitTable: false,
|
|
6392
|
+
isTemporal: false,
|
|
6393
|
+
isComparison: false,
|
|
6394
|
+
language: "en"
|
|
6395
|
+
});
|
|
6396
|
+
}
|
|
6397
|
+
};
|
|
6398
|
+
var ChartRendererStrategy = class {
|
|
6399
|
+
constructor() {
|
|
6400
|
+
this.type = "chart";
|
|
6401
|
+
}
|
|
6402
|
+
render(data, options) {
|
|
6403
|
+
const docs = Array.isArray(data) ? data : [];
|
|
6404
|
+
const query = (options == null ? void 0 : options.query) || "";
|
|
6405
|
+
const chartType = (options == null ? void 0 : options.chartType) || "bar";
|
|
6406
|
+
let hint = "comparison";
|
|
6407
|
+
let rec = "bar_chart";
|
|
6408
|
+
if (chartType === "line") {
|
|
6409
|
+
hint = "trend";
|
|
6410
|
+
rec = "line_chart";
|
|
6411
|
+
} else if (chartType === "pie") {
|
|
6412
|
+
hint = "composition";
|
|
6413
|
+
rec = "pie_chart";
|
|
6414
|
+
} else if (chartType === "scatter") {
|
|
6415
|
+
hint = "correlation";
|
|
6416
|
+
rec = "scatter_plot";
|
|
6417
|
+
}
|
|
6418
|
+
return UITransformer.transform(query, docs, void 0, void 0, {
|
|
6419
|
+
visualizationHint: hint,
|
|
6420
|
+
recommendedChart: rec,
|
|
6421
|
+
filterInStockOnly: false,
|
|
6422
|
+
wantsExplicitTable: false,
|
|
6423
|
+
isTemporal: chartType === "line",
|
|
6424
|
+
isComparison: chartType === "bar",
|
|
6425
|
+
language: "en"
|
|
6426
|
+
});
|
|
6427
|
+
}
|
|
6428
|
+
};
|
|
6429
|
+
var MixedRendererStrategy = class {
|
|
6430
|
+
constructor() {
|
|
6431
|
+
this.type = "mixed";
|
|
6432
|
+
}
|
|
6433
|
+
render(data, options) {
|
|
6434
|
+
const docs = Array.isArray(data) ? data : [];
|
|
6435
|
+
const sections = (options == null ? void 0 : options.sections) || [];
|
|
6436
|
+
const sectionPayloads = sections.map((s) => {
|
|
6437
|
+
const strategy = RendererRegistry.getStrategy(s.type);
|
|
6438
|
+
return {
|
|
6439
|
+
type: s.type,
|
|
6440
|
+
title: s.title,
|
|
6441
|
+
payload: strategy.render(data, __spreadProps(__spreadValues({}, options), { chartType: s.chartType, title: s.title }))
|
|
6442
|
+
};
|
|
6443
|
+
});
|
|
6444
|
+
return {
|
|
6445
|
+
type: "table",
|
|
6446
|
+
// Fallback container type for compatibility
|
|
6447
|
+
title: (options == null ? void 0 : options.title) || "Composite Response",
|
|
6448
|
+
description: `Mixed payload containing ${sectionPayloads.length} visual sections`,
|
|
6449
|
+
data: { sections: sectionPayloads }
|
|
6450
|
+
};
|
|
6451
|
+
}
|
|
6452
|
+
};
|
|
6453
|
+
var _RendererRegistry = class _RendererRegistry {
|
|
6454
|
+
/**
|
|
6455
|
+
* Register a new renderer strategy.
|
|
6456
|
+
* Enables seamless addition of custom visualizers (Timeline, Maps, Flow Diagrams, etc.).
|
|
6457
|
+
*/
|
|
6458
|
+
static registerStrategy(strategy) {
|
|
6459
|
+
this.strategies.set(String(strategy.type).toLowerCase(), strategy);
|
|
6460
|
+
}
|
|
6461
|
+
/**
|
|
6462
|
+
* Retrieve a registered renderer strategy by type string.
|
|
6463
|
+
*/
|
|
6464
|
+
static getStrategy(type) {
|
|
6465
|
+
const key = type.toLowerCase();
|
|
6466
|
+
const strategy = this.strategies.get(key);
|
|
6467
|
+
if (!strategy) {
|
|
6468
|
+
return this.strategies.get("text");
|
|
6469
|
+
}
|
|
6470
|
+
return strategy;
|
|
6471
|
+
}
|
|
6472
|
+
/**
|
|
6473
|
+
* Check if a renderer strategy is registered.
|
|
6474
|
+
*/
|
|
6475
|
+
static hasStrategy(type) {
|
|
6476
|
+
return this.strategies.has(type.toLowerCase());
|
|
6477
|
+
}
|
|
6478
|
+
/**
|
|
6479
|
+
* List all registered strategy types.
|
|
6480
|
+
*/
|
|
6481
|
+
static getRegisteredTypes() {
|
|
6482
|
+
return Array.from(this.strategies.keys());
|
|
6483
|
+
}
|
|
6484
|
+
};
|
|
6485
|
+
_RendererRegistry.strategies = /* @__PURE__ */ new Map();
|
|
6486
|
+
_RendererRegistry.registerStrategy(new TextRendererStrategy());
|
|
6487
|
+
_RendererRegistry.registerStrategy(new TableRendererStrategy());
|
|
6488
|
+
_RendererRegistry.registerStrategy(new CarouselRendererStrategy());
|
|
6489
|
+
_RendererRegistry.registerStrategy(new ChartRendererStrategy());
|
|
6490
|
+
_RendererRegistry.registerStrategy(new MixedRendererStrategy());
|
|
6491
|
+
var RendererRegistry = _RendererRegistry;
|
|
6492
|
+
|
|
6493
|
+
// src/rendering/VisualizationDecisionEngine.ts
|
|
6494
|
+
var LRUDecisionCache = class {
|
|
6495
|
+
constructor(maxSize = 200) {
|
|
6496
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
6497
|
+
this.maxSize = maxSize;
|
|
6498
|
+
}
|
|
6499
|
+
generateKey(context) {
|
|
6500
|
+
var _a2, _b;
|
|
6501
|
+
const q = (context.userQuery || "").toLowerCase().trim();
|
|
6502
|
+
const docCount = (_b = (_a2 = context.retrievedDocuments) == null ? void 0 : _a2.length) != null ? _b : 0;
|
|
6503
|
+
return `${q}::docs:${docCount}`;
|
|
6504
|
+
}
|
|
6505
|
+
get(context) {
|
|
6506
|
+
const key = this.generateKey(context);
|
|
6507
|
+
const item = this.cache.get(key);
|
|
6508
|
+
if (item) {
|
|
6509
|
+
this.cache.delete(key);
|
|
6510
|
+
this.cache.set(key, item);
|
|
6511
|
+
return item.decision;
|
|
6512
|
+
}
|
|
6513
|
+
return void 0;
|
|
6514
|
+
}
|
|
6515
|
+
set(context, decision) {
|
|
6516
|
+
const key = this.generateKey(context);
|
|
6517
|
+
if (this.cache.has(key)) {
|
|
6518
|
+
this.cache.delete(key);
|
|
6519
|
+
} else if (this.cache.size >= this.maxSize) {
|
|
6520
|
+
const oldest = this.cache.keys().next().value;
|
|
6521
|
+
if (oldest !== void 0) this.cache.delete(oldest);
|
|
6522
|
+
}
|
|
6523
|
+
this.cache.set(key, { decision, timestamp: Date.now() });
|
|
6524
|
+
}
|
|
6525
|
+
clear() {
|
|
6526
|
+
this.cache.clear();
|
|
6527
|
+
}
|
|
6528
|
+
get size() {
|
|
6529
|
+
return this.cache.size;
|
|
6530
|
+
}
|
|
6531
|
+
};
|
|
6532
|
+
var VisualizationDecisionEngine = class {
|
|
6533
|
+
/**
|
|
6534
|
+
* Evaluate user query, documents, and context to produce a RenderDecision.
|
|
6535
|
+
* Execution time is < 1ms for cached or rule-matched queries.
|
|
6536
|
+
*/
|
|
6537
|
+
static decideVisualization(userQuery, retrievedDocuments, llmResponse, metadata) {
|
|
6538
|
+
const context = {
|
|
6539
|
+
userQuery,
|
|
6540
|
+
retrievedDocuments,
|
|
6541
|
+
llmResponse,
|
|
6542
|
+
metadata
|
|
6543
|
+
};
|
|
6544
|
+
const cached = this.cache.get(context);
|
|
6545
|
+
if (cached) {
|
|
6546
|
+
return cached;
|
|
6547
|
+
}
|
|
6548
|
+
const { intent } = IntentClassifier.classify(context);
|
|
6549
|
+
const decision = this.ruleEngine.evaluate(context, intent);
|
|
6550
|
+
this.cache.set(context, decision);
|
|
6551
|
+
return decision;
|
|
6552
|
+
}
|
|
6553
|
+
/**
|
|
6554
|
+
* Convenience helper to decide AND render the data into a UITransformationResponse.
|
|
6555
|
+
*/
|
|
6556
|
+
static render(userQuery, retrievedDocuments, llmResponse, metadata) {
|
|
6557
|
+
const decision = this.decideVisualization(userQuery, retrievedDocuments, llmResponse, metadata);
|
|
6558
|
+
const strategy = RendererRegistry.getStrategy(decision.renderType);
|
|
6559
|
+
return strategy.render(retrievedDocuments || [], __spreadValues({
|
|
6560
|
+
query: userQuery,
|
|
6561
|
+
chartType: decision.chartType,
|
|
6562
|
+
sections: decision.sections
|
|
6563
|
+
}, metadata));
|
|
6564
|
+
}
|
|
6565
|
+
/**
|
|
6566
|
+
* Register a custom rule in the rule engine.
|
|
6567
|
+
*/
|
|
6568
|
+
static registerRule(rule) {
|
|
6569
|
+
this.ruleEngine.registerRule(rule);
|
|
6570
|
+
this.cache.clear();
|
|
6571
|
+
}
|
|
6572
|
+
/**
|
|
6573
|
+
* Register a custom renderer strategy.
|
|
6574
|
+
*/
|
|
6575
|
+
static registerRendererStrategy(strategy) {
|
|
6576
|
+
RendererRegistry.registerStrategy(strategy);
|
|
6577
|
+
}
|
|
6578
|
+
/**
|
|
6579
|
+
* Clear the decision cache.
|
|
6580
|
+
*/
|
|
6581
|
+
static clearCache() {
|
|
6582
|
+
this.cache.clear();
|
|
6583
|
+
}
|
|
6584
|
+
/**
|
|
6585
|
+
* Get size of current decision cache.
|
|
6586
|
+
*/
|
|
6587
|
+
static getCacheSize() {
|
|
6588
|
+
return this.cache.size;
|
|
6589
|
+
}
|
|
6590
|
+
};
|
|
6591
|
+
VisualizationDecisionEngine.ruleEngine = new RuleEngine();
|
|
6592
|
+
VisualizationDecisionEngine.cache = new LRUDecisionCache(200);
|
|
6593
|
+
function decideVisualization(userQuery, retrievedDocuments, llmResponse, metadata) {
|
|
6594
|
+
return VisualizationDecisionEngine.decideVisualization(
|
|
6595
|
+
userQuery,
|
|
6596
|
+
retrievedDocuments,
|
|
6597
|
+
llmResponse,
|
|
6598
|
+
metadata
|
|
6599
|
+
);
|
|
6600
|
+
}
|
|
6601
|
+
|
|
6602
|
+
// src/utils/UITransformer.ts
|
|
5986
6603
|
var UITransformer = class _UITransformer {
|
|
5987
6604
|
// ─── Public Entry Points ─────────────────────────────────────────────────
|
|
5988
6605
|
/**
|
|
@@ -6029,6 +6646,9 @@ var UITransformer = class _UITransformer {
|
|
|
6029
6646
|
return this.hasMultipleFields(filteredData) ? this.transformToTable(filteredData, userQuery) : this.transformToText(filteredData);
|
|
6030
6647
|
}
|
|
6031
6648
|
if ((hasProducts || this.isProductQuery(userQuery)) && resolvedIntent.visualizationHint === "product_browse") {
|
|
6649
|
+
if (!this.isProductQuery(userQuery)) {
|
|
6650
|
+
return this.transformToText(filteredData);
|
|
6651
|
+
}
|
|
6032
6652
|
return this.transformToProductCarousel(filteredData, config, trainedSchema);
|
|
6033
6653
|
}
|
|
6034
6654
|
const automatic = this.chooseAutomaticVisualization(filteredData, profile, userQuery);
|
|
@@ -6043,6 +6663,11 @@ var UITransformer = class _UITransformer {
|
|
|
6043
6663
|
* Step 3 — Fall back to the heuristic `transform()` if either LLM call fails.
|
|
6044
6664
|
*/
|
|
6045
6665
|
static async analyzeAndDecide(query, sources, llm) {
|
|
6666
|
+
const decision = VisualizationDecisionEngine.decideVisualization(query, sources);
|
|
6667
|
+
if (decision.renderType === "text") {
|
|
6668
|
+
console.debug("[UITransformer] Decision Engine selected plain text rendering \u2014 skipping visual LLM calls.");
|
|
6669
|
+
return this.transformToText(sources);
|
|
6670
|
+
}
|
|
6046
6671
|
let intent;
|
|
6047
6672
|
try {
|
|
6048
6673
|
intent = await this.detectIntent(query, llm, sources);
|
|
@@ -6492,7 +7117,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
6492
7117
|
}
|
|
6493
7118
|
static transformToText(data) {
|
|
6494
7119
|
return this.createTextResponse(
|
|
6495
|
-
"
|
|
7120
|
+
"Retrieved Context",
|
|
6496
7121
|
data.map((item) => item.content).join("\n\n"),
|
|
6497
7122
|
`Found ${data.length} relevant results`
|
|
6498
7123
|
);
|
|
@@ -6659,16 +7284,13 @@ ${schemaProfileText}` : ""}`;
|
|
|
6659
7284
|
"product",
|
|
6660
7285
|
"price",
|
|
6661
7286
|
"stock",
|
|
6662
|
-
"item",
|
|
6663
7287
|
"sku",
|
|
6664
7288
|
"brand",
|
|
6665
|
-
"model",
|
|
6666
7289
|
"msrp",
|
|
6667
7290
|
"inventory",
|
|
6668
7291
|
"buy",
|
|
6669
7292
|
"shop",
|
|
6670
7293
|
"beauty",
|
|
6671
|
-
"care",
|
|
6672
7294
|
"cosmetic",
|
|
6673
7295
|
"facial",
|
|
6674
7296
|
"cream",
|
|
@@ -6681,7 +7303,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
6681
7303
|
const metadata = item.metadata || {};
|
|
6682
7304
|
const hasMetadataKey = Object.keys(metadata).some((k) => {
|
|
6683
7305
|
const val = metadata[k];
|
|
6684
|
-
return ["price", "product", "sku", "brand", "
|
|
7306
|
+
return ["price", "product", "sku", "brand", "cost"].includes(k.toLowerCase()) && val !== null && val !== void 0 && val !== "";
|
|
6685
7307
|
});
|
|
6686
7308
|
const hasPricePattern = /\$\s*\d+\.\d{2}/.test(content);
|
|
6687
7309
|
return hasKeywords || hasMetadataKey || hasPricePattern;
|
|
@@ -7370,6 +7992,13 @@ SchemaMapper.TARGET_PROPERTIES = {
|
|
|
7370
7992
|
};
|
|
7371
7993
|
|
|
7372
7994
|
// src/core/Pipeline.ts
|
|
7995
|
+
function formatNamespace(raw) {
|
|
7996
|
+
if (!raw || !raw.trim()) return "retrivora-default";
|
|
7997
|
+
const trimmed = raw.trim();
|
|
7998
|
+
if (trimmed.startsWith("retrivora-")) return trimmed;
|
|
7999
|
+
const sanitized = trimmed.toLowerCase().replace(/[^a-z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
|
|
8000
|
+
return `retrivora-${sanitized}`;
|
|
8001
|
+
}
|
|
7373
8002
|
var LRUEmbeddingCache = class {
|
|
7374
8003
|
constructor(maxSize = 500) {
|
|
7375
8004
|
this.cache = /* @__PURE__ */ new Map();
|
|
@@ -7561,7 +8190,7 @@ ${m.content}`).join("\n\n---\n\n");
|
|
|
7561
8190
|
*/
|
|
7562
8191
|
async ingest(documents, namespace) {
|
|
7563
8192
|
await this.initialize();
|
|
7564
|
-
const ns = namespace != null ? namespace : this.config.projectId;
|
|
8193
|
+
const ns = formatNamespace(namespace != null ? namespace : this.config.projectId);
|
|
7565
8194
|
const results = [];
|
|
7566
8195
|
for (const doc of documents) {
|
|
7567
8196
|
try {
|
|
@@ -7780,7 +8409,7 @@ ${m.content}`).join("\n\n---\n\n");
|
|
|
7780
8409
|
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
7781
8410
|
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C;
|
|
7782
8411
|
yield new __await(this.initialize());
|
|
7783
|
-
const ns = namespace != null ? namespace : this.config.projectId;
|
|
8412
|
+
const ns = formatNamespace(namespace != null ? namespace : this.config.projectId);
|
|
7784
8413
|
const topK = (_b = (_a2 = this.config.rag) == null ? void 0 : _a2.topK) != null ? _b : 5;
|
|
7785
8414
|
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0.3;
|
|
7786
8415
|
const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -7918,7 +8547,7 @@ ${context}`;
|
|
|
7918
8547
|
const isNativeThinking = isClaude37 && (((_p = this.config.llm.options) == null ? void 0 : _p.thinking) === true || ((_q = this.config.llm.options) == null ? void 0 : _q.thinking) === "enabled" || ((_r = this.config.llm.options) == null ? void 0 : _r.thinking) !== false);
|
|
7919
8548
|
const modelNameLower = this.config.llm.model.toLowerCase();
|
|
7920
8549
|
const isReasoningModel = modelNameLower.includes("-r1") || modelNameLower.includes("deepseek-r1") || modelNameLower.includes("reasoning") || modelNameLower.includes("thinking");
|
|
7921
|
-
const isSimulatedThinking = !isNativeThinking && (((_s = this.config.llm.options) == null ? void 0 : _s.thinking) === true || ((_t = this.config.llm.options) == null ? void 0 : _t.thinking) === "enabled" ||
|
|
8550
|
+
const isSimulatedThinking = !isNativeThinking && (((_s = this.config.llm.options) == null ? void 0 : _s.thinking) === true || ((_t = this.config.llm.options) == null ? void 0 : _t.thinking) === "enabled" || ((_u = this.config.llm.options) == null ? void 0 : _u.thinking) !== false);
|
|
7922
8551
|
let finalRestrictionSuffix = restrictionSuffix;
|
|
7923
8552
|
if (isSimulatedThinking) {
|
|
7924
8553
|
finalRestrictionSuffix += "\n\n(IMPORTANT: You must think step-by-step before answering. Write your thinking process inside a `<think>...</think>` block. Write the `<think>` block first, then follow it with your final response. Keep the thinking process thorough and detailed. Example: `<think>Thinking details here...</think>Final answer text here.`)";
|
|
@@ -8244,7 +8873,7 @@ ${context}`;
|
|
|
8244
8873
|
}
|
|
8245
8874
|
async retrieve(query, options) {
|
|
8246
8875
|
var _a2, _b, _c, _d, _e, _f, _g2;
|
|
8247
|
-
const ns = (_a2 = options.namespace) != null ? _a2 : this.config.projectId;
|
|
8876
|
+
const ns = formatNamespace((_a2 = options.namespace) != null ? _a2 : this.config.projectId);
|
|
8248
8877
|
const topK = (_b = options.topK) != null ? _b : 5;
|
|
8249
8878
|
const cacheKey = `${ns}::${query}`;
|
|
8250
8879
|
let queryVector = this.embeddingCache.get(cacheKey);
|
|
@@ -8313,7 +8942,7 @@ Optimized Search Query:`;
|
|
|
8313
8942
|
async getSuggestions(query, namespace) {
|
|
8314
8943
|
if (!query || query.trim().length < 3) return [];
|
|
8315
8944
|
await this.initialize();
|
|
8316
|
-
const ns = namespace != null ? namespace : this.config.projectId;
|
|
8945
|
+
const ns = formatNamespace(namespace != null ? namespace : this.config.projectId);
|
|
8317
8946
|
try {
|
|
8318
8947
|
const { sources } = await this.retrieve(query, { namespace: ns, topK: 5 });
|
|
8319
8948
|
if (sources.length === 0) return [];
|
|
@@ -8883,7 +9512,7 @@ var DocumentParser = class {
|
|
|
8883
9512
|
*/
|
|
8884
9513
|
static async parse(file, fileName, mimeType) {
|
|
8885
9514
|
var _a2;
|
|
8886
|
-
const extension = (_a2 = fileName.split(".").pop()) == null ? void 0 : _a2.toLowerCase();
|
|
9515
|
+
const extension = ((_a2 = fileName.split(".").pop()) == null ? void 0 : _a2.toLowerCase()) || "";
|
|
8887
9516
|
if (extension === "txt" || extension === "md" || mimeType === "text/plain" || mimeType === "text/markdown") {
|
|
8888
9517
|
return this.readAsText(file);
|
|
8889
9518
|
}
|
|
@@ -8899,6 +9528,29 @@ var DocumentParser = class {
|
|
|
8899
9528
|
if (extension === "csv" || mimeType === "text/csv") {
|
|
8900
9529
|
return this.readAsText(file);
|
|
8901
9530
|
}
|
|
9531
|
+
if (extension === "xlsx" || extension === "xls" || mimeType.includes("spreadsheet") || mimeType.includes("excel")) {
|
|
9532
|
+
try {
|
|
9533
|
+
const xlsx = await import("xlsx");
|
|
9534
|
+
const buffer = Buffer.isBuffer(file) ? file : Buffer.from(await file.arrayBuffer());
|
|
9535
|
+
const workbook = xlsx.read(buffer, { type: "buffer" });
|
|
9536
|
+
const sheetsText = [];
|
|
9537
|
+
for (const sheetName of workbook.SheetNames) {
|
|
9538
|
+
const sheet = workbook.Sheets[sheetName];
|
|
9539
|
+
const csv = xlsx.utils.sheet_to_csv(sheet);
|
|
9540
|
+
if (csv && csv.trim()) {
|
|
9541
|
+
sheetsText.push(`--- Sheet: ${sheetName} ---
|
|
9542
|
+
${csv.trim()}`);
|
|
9543
|
+
}
|
|
9544
|
+
}
|
|
9545
|
+
return sheetsText.join("\n\n") || `[Empty Excel Workbook: ${fileName}]`;
|
|
9546
|
+
} catch (e) {
|
|
9547
|
+
try {
|
|
9548
|
+
return await this.readAsText(file);
|
|
9549
|
+
} catch (e2) {
|
|
9550
|
+
return `[Excel File Content: ${fileName}]`;
|
|
9551
|
+
}
|
|
9552
|
+
}
|
|
9553
|
+
}
|
|
8902
9554
|
if (extension === "pdf" || mimeType === "application/pdf") {
|
|
8903
9555
|
try {
|
|
8904
9556
|
const pdf = await import("pdf-parse");
|
|
@@ -8910,15 +9562,15 @@ var DocumentParser = class {
|
|
|
8910
9562
|
return `[PDF Parsing Error for ${fileName}]`;
|
|
8911
9563
|
}
|
|
8912
9564
|
}
|
|
8913
|
-
if (extension === "docx" || mimeType === "application/vnd.openxmlformats-officedocument.wordprocessingml.document") {
|
|
9565
|
+
if (extension === "docx" || extension === "doc" || mimeType === "application/vnd.openxmlformats-officedocument.wordprocessingml.document" || mimeType === "application/msword") {
|
|
8914
9566
|
try {
|
|
8915
9567
|
const mammoth = await import("mammoth");
|
|
8916
9568
|
const buffer = Buffer.isBuffer(file) ? file : Buffer.from(await file.arrayBuffer());
|
|
8917
9569
|
const result = await mammoth.extractRawText({ buffer });
|
|
8918
9570
|
return result.value;
|
|
8919
9571
|
} catch (err) {
|
|
8920
|
-
console.warn('[DocumentParser]
|
|
8921
|
-
return `[
|
|
9572
|
+
console.warn('[DocumentParser] Word parsing failed. Make sure "mammoth" is installed.', err);
|
|
9573
|
+
return `[Word Parsing Error for ${fileName}]`;
|
|
8922
9574
|
}
|
|
8923
9575
|
}
|
|
8924
9576
|
try {
|
|
@@ -9758,6 +10410,7 @@ function createUploadHandler(configOrPlugin, options) {
|
|
|
9758
10410
|
}
|
|
9759
10411
|
const documents = [];
|
|
9760
10412
|
for (const file of files) {
|
|
10413
|
+
const isExcel = file.name.toLowerCase().endsWith(".xlsx") || file.name.toLowerCase().endsWith(".xls") || file.type.includes("spreadsheet") || file.type.includes("excel");
|
|
9761
10414
|
if (file.name.toLowerCase().endsWith(".csv") || file.type === "text/csv") {
|
|
9762
10415
|
const text = await file.text();
|
|
9763
10416
|
const Papa = await import("papaparse");
|
|
@@ -9790,7 +10443,7 @@ function createUploadHandler(configOrPlugin, options) {
|
|
|
9790
10443
|
metadata: __spreadValues(__spreadProps(__spreadValues({
|
|
9791
10444
|
fileName: file.name,
|
|
9792
10445
|
fileSize: file.size,
|
|
9793
|
-
fileType: file.type,
|
|
10446
|
+
fileType: file.type || "text/csv",
|
|
9794
10447
|
uploadedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9795
10448
|
}, dimension ? { dimension } : {}), {
|
|
9796
10449
|
csvHeaders: csvCols
|
|
@@ -9798,6 +10451,42 @@ function createUploadHandler(configOrPlugin, options) {
|
|
|
9798
10451
|
});
|
|
9799
10452
|
}
|
|
9800
10453
|
}
|
|
10454
|
+
} else if (isExcel) {
|
|
10455
|
+
const xlsx = await import("xlsx");
|
|
10456
|
+
const buffer = Buffer.isBuffer(file) ? file : Buffer.from(await file.arrayBuffer());
|
|
10457
|
+
const workbook = xlsx.read(buffer, { type: "buffer" });
|
|
10458
|
+
for (const sheetName of workbook.SheetNames) {
|
|
10459
|
+
const sheet = workbook.Sheets[sheetName];
|
|
10460
|
+
const jsonRows = xlsx.utils.sheet_to_json(sheet, { defval: "" });
|
|
10461
|
+
if (jsonRows && jsonRows.length > 0) {
|
|
10462
|
+
let i = 0;
|
|
10463
|
+
const headers = Object.keys(jsonRows[0] || {});
|
|
10464
|
+
for (const rowData of jsonRows) {
|
|
10465
|
+
i++;
|
|
10466
|
+
const contentParts = [];
|
|
10467
|
+
for (const [key, val] of Object.entries(rowData)) {
|
|
10468
|
+
if (key && val !== void 0 && val !== null && String(val).trim()) {
|
|
10469
|
+
contentParts.push(`${key}: ${val}`);
|
|
10470
|
+
}
|
|
10471
|
+
}
|
|
10472
|
+
if (contentParts.length > 0) {
|
|
10473
|
+
documents.push({
|
|
10474
|
+
docId: `${file.name}-${sheetName}-row-${i}`,
|
|
10475
|
+
content: contentParts.join(", "),
|
|
10476
|
+
metadata: __spreadValues(__spreadProps(__spreadValues({
|
|
10477
|
+
fileName: file.name,
|
|
10478
|
+
sheetName,
|
|
10479
|
+
fileSize: file.size,
|
|
10480
|
+
fileType: file.type || "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
10481
|
+
uploadedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10482
|
+
}, dimension ? { dimension } : {}), {
|
|
10483
|
+
headers
|
|
10484
|
+
}), rowData)
|
|
10485
|
+
});
|
|
10486
|
+
}
|
|
10487
|
+
}
|
|
10488
|
+
}
|
|
10489
|
+
}
|
|
9801
10490
|
} else {
|
|
9802
10491
|
const content = await DocumentParser.parse(file, file.name, file.type);
|
|
9803
10492
|
documents.push({
|
|
@@ -10025,6 +10714,8 @@ function createRagHandler(configOrPlugin, options) {
|
|
|
10025
10714
|
AuthenticationException,
|
|
10026
10715
|
BaseVectorProvider,
|
|
10027
10716
|
BatchProcessor,
|
|
10717
|
+
CarouselRendererStrategy,
|
|
10718
|
+
ChartRendererStrategy,
|
|
10028
10719
|
ChromaDBProvider,
|
|
10029
10720
|
ConfigBuilder,
|
|
10030
10721
|
ConfigResolver,
|
|
@@ -10036,10 +10727,12 @@ function createRagHandler(configOrPlugin, options) {
|
|
|
10036
10727
|
EmbeddingStrategy,
|
|
10037
10728
|
EmbeddingStrategyResolver,
|
|
10038
10729
|
GroqProvider,
|
|
10730
|
+
IntentClassifier,
|
|
10039
10731
|
LLMFactory,
|
|
10040
10732
|
LLM_PROFILES,
|
|
10041
10733
|
LicenseVerifier,
|
|
10042
10734
|
MilvusProvider,
|
|
10735
|
+
MixedRendererStrategy,
|
|
10043
10736
|
MongoDBProvider,
|
|
10044
10737
|
MultiTablePostgresProvider,
|
|
10045
10738
|
OllamaProvider,
|
|
@@ -10055,13 +10748,25 @@ function createRagHandler(configOrPlugin, options) {
|
|
|
10055
10748
|
QwenProvider,
|
|
10056
10749
|
RateLimitException,
|
|
10057
10750
|
RedisProvider,
|
|
10751
|
+
RendererRegistry,
|
|
10058
10752
|
RetrievalException,
|
|
10059
10753
|
Retrivora,
|
|
10060
10754
|
RetrivoraError,
|
|
10755
|
+
Rule1SpecificInfoRule,
|
|
10756
|
+
Rule2ComparisonRule,
|
|
10757
|
+
Rule3ProductDiscoveryRule,
|
|
10758
|
+
Rule4AnalyticalRule,
|
|
10759
|
+
Rule5MixedResponseRule,
|
|
10760
|
+
Rule6SmallResultSetRule,
|
|
10761
|
+
Rule7LargeTableRule,
|
|
10762
|
+
RuleEngine,
|
|
10763
|
+
TableRendererStrategy,
|
|
10764
|
+
TextRendererStrategy,
|
|
10061
10765
|
UniversalLLMAdapter,
|
|
10062
10766
|
UniversalVectorProvider,
|
|
10063
10767
|
VECTOR_PROFILES,
|
|
10064
10768
|
VectorPlugin,
|
|
10769
|
+
VisualizationDecisionEngine,
|
|
10065
10770
|
WeaviateProvider,
|
|
10066
10771
|
createChatHandler,
|
|
10067
10772
|
createFeedbackHandler,
|
|
@@ -10073,6 +10778,7 @@ function createRagHandler(configOrPlugin, options) {
|
|
|
10073
10778
|
createSessionsHandler,
|
|
10074
10779
|
createStreamHandler,
|
|
10075
10780
|
createUploadHandler,
|
|
10781
|
+
decideVisualization,
|
|
10076
10782
|
getRagConfig,
|
|
10077
10783
|
sseErrorFrame,
|
|
10078
10784
|
sseFrame,
|