@retrivora-ai/rag-engine 1.8.3 → 1.8.5
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/LICENSE.txt +21 -0
- package/dist/{ILLMProvider-BOJFz3Na.d.mts → ILLMProvider-CbUtvWAW.d.mts} +2 -0
- package/dist/{ILLMProvider-BOJFz3Na.d.ts → ILLMProvider-CbUtvWAW.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 +100 -52
- package/dist/handlers/index.mjs +100 -52
- package/dist/{index-BwpcaziY.d.ts → index-DgzcnqZs.d.ts} +1 -1
- package/dist/{index-D3V9Et2M.d.mts → index-c_y_5qdw.d.mts} +1 -1
- package/dist/index.css +3189 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +18 -4
- package/dist/index.mjs +18 -4
- package/dist/server.d.mts +3 -3
- package/dist/server.d.ts +3 -3
- package/dist/server.js +108 -55
- package/dist/server.mjs +108 -55
- package/package.json +4 -2
- package/src/app/globals.css +97 -0
- package/src/components/ChatWidget.tsx +23 -10
- package/src/config/RagConfig.ts +2 -0
- package/src/providers/vectordb/ChromaDBProvider.ts +4 -0
- package/src/providers/vectordb/MultiTablePostgresProvider.ts +18 -5
- package/src/providers/vectordb/PostgreSQLProvider.ts +14 -3
- package/src/providers/vectordb/QdrantProvider.ts +4 -1
- package/src/tailwind.css +2 -0
- package/src/utils/UITransformer.ts +99 -51
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { CSSProperties, MouseEvent, ReactNode } from 'react';
|
|
3
|
-
import { P as Product, U as UIConfig, R as RagMessage, V as VectorMatch, O as ObservabilityTrace, a as UseRagChatOptions, b as UseRagChatReturn } from './ILLMProvider-
|
|
4
|
-
export { C as ChatMessage, c as ChatOptions, d as ChatResponse, E as EmbedOptions, e as EmbeddingConfig, f as EmbeddingProvider, I as ILLMProvider, g as IngestDocument, L as LLMConfig, h as LLMProvider, i as LatencyBreakdown, j as RAGConfig, k as RagConfig, l as RetrievedChunk, T as TokenUsage, m as UpsertDocument, n as VectorDBConfig, o as VectorDBProvider } from './ILLMProvider-
|
|
3
|
+
import { P as Product, U as UIConfig, R as RagMessage, V as VectorMatch, O as ObservabilityTrace, a as UseRagChatOptions, b as UseRagChatReturn } from './ILLMProvider-CbUtvWAW.mjs';
|
|
4
|
+
export { C as ChatMessage, c as ChatOptions, d as ChatResponse, E as EmbedOptions, e as EmbeddingConfig, f as EmbeddingProvider, I as ILLMProvider, g as IngestDocument, L as LLMConfig, h as LLMProvider, i as LatencyBreakdown, j as RAGConfig, k as RagConfig, l as RetrievedChunk, T as TokenUsage, m as UpsertDocument, n as VectorDBConfig, o as VectorDBProvider } from './ILLMProvider-CbUtvWAW.mjs';
|
|
5
5
|
export { C as Chunk, a as ChunkOptions } from './DocumentChunker-Dh9TvmGG.mjs';
|
|
6
6
|
|
|
7
7
|
type ChatViewportSize = 'compact' | 'medium' | 'large';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { CSSProperties, MouseEvent, ReactNode } from 'react';
|
|
3
|
-
import { P as Product, U as UIConfig, R as RagMessage, V as VectorMatch, O as ObservabilityTrace, a as UseRagChatOptions, b as UseRagChatReturn } from './ILLMProvider-
|
|
4
|
-
export { C as ChatMessage, c as ChatOptions, d as ChatResponse, E as EmbedOptions, e as EmbeddingConfig, f as EmbeddingProvider, I as ILLMProvider, g as IngestDocument, L as LLMConfig, h as LLMProvider, i as LatencyBreakdown, j as RAGConfig, k as RagConfig, l as RetrievedChunk, T as TokenUsage, m as UpsertDocument, n as VectorDBConfig, o as VectorDBProvider } from './ILLMProvider-
|
|
3
|
+
import { P as Product, U as UIConfig, R as RagMessage, V as VectorMatch, O as ObservabilityTrace, a as UseRagChatOptions, b as UseRagChatReturn } from './ILLMProvider-CbUtvWAW.js';
|
|
4
|
+
export { C as ChatMessage, c as ChatOptions, d as ChatResponse, E as EmbedOptions, e as EmbeddingConfig, f as EmbeddingProvider, I as ILLMProvider, g as IngestDocument, L as LLMConfig, h as LLMProvider, i as LatencyBreakdown, j as RAGConfig, k as RagConfig, l as RetrievedChunk, T as TokenUsage, m as UpsertDocument, n as VectorDBConfig, o as VectorDBProvider } from './ILLMProvider-CbUtvWAW.js';
|
|
5
5
|
export { C as Chunk, a as ChunkOptions } from './DocumentChunker-Dh9TvmGG.js';
|
|
6
6
|
|
|
7
7
|
type ChatViewportSize = 'compact' | 'medium' | 'large';
|
package/dist/index.js
CHANGED
|
@@ -2975,21 +2975,35 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
|
|
|
2975
2975
|
"button",
|
|
2976
2976
|
{
|
|
2977
2977
|
onClick: isOpen ? () => setIsOpen(false) : handleOpen,
|
|
2978
|
-
className: `fixed z-[9999] w-14 h-14 shadow-2xl flex items-center justify-center transition-all duration-300 cursor-pointer hover:scale-110 active:scale-95 ${
|
|
2979
|
-
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` },
|
|
2978
|
+
className: `group fixed z-[9999] w-14 h-14 drop-shadow-2xl flex items-center justify-center transition-all duration-300 cursor-pointer hover:scale-110 active:scale-95 ${positionClass}`,
|
|
2980
2979
|
"aria-label": "Open chat",
|
|
2981
2980
|
children: [
|
|
2981
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2982
|
+
"div",
|
|
2983
|
+
{
|
|
2984
|
+
className: `absolute inset-0 transition-all duration-300 overflow-hidden ${ui.borderRadius === "full" ? "rounded-full" : "rounded-2xl"} group-hover:rounded-none group-hover:animate-shapeshift`,
|
|
2985
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2986
|
+
"div",
|
|
2987
|
+
{
|
|
2988
|
+
className: "absolute top-0 left-0 w-[400%] h-[400%] transition-transform duration-300 group-hover:animate-gradientMove",
|
|
2989
|
+
style: {
|
|
2990
|
+
background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor}, ${ui.primaryColor}, ${ui.accentColor})`
|
|
2991
|
+
}
|
|
2992
|
+
}
|
|
2993
|
+
)
|
|
2994
|
+
}
|
|
2995
|
+
),
|
|
2982
2996
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2983
2997
|
"span",
|
|
2984
2998
|
{
|
|
2985
|
-
className: "absolute inset-0 rounded-full animate-ping opacity-20",
|
|
2999
|
+
className: "absolute inset-0 rounded-full animate-ping opacity-20 pointer-events-none",
|
|
2986
3000
|
style: { background: ui.primaryColor }
|
|
2987
3001
|
}
|
|
2988
3002
|
),
|
|
2989
3003
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2990
3004
|
"span",
|
|
2991
3005
|
{
|
|
2992
|
-
className: `transition-transform duration-300 ${isOpen ? "rotate-90 scale-90" : "rotate-0 scale-100"}`,
|
|
3006
|
+
className: `relative z-10 transition-transform duration-300 ${isOpen ? "rotate-90 scale-90" : "rotate-0 scale-100"}`,
|
|
2993
3007
|
children: isOpen ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react8.X, { className: "w-6 h-6 text-white" }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react8.MessageSquare, { className: "w-6 h-6 text-white" })
|
|
2994
3008
|
}
|
|
2995
3009
|
),
|
package/dist/index.mjs
CHANGED
|
@@ -2990,21 +2990,35 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
|
|
|
2990
2990
|
"button",
|
|
2991
2991
|
{
|
|
2992
2992
|
onClick: isOpen ? () => setIsOpen(false) : handleOpen,
|
|
2993
|
-
className: `fixed z-[9999] w-14 h-14 shadow-2xl flex items-center justify-center transition-all duration-300 cursor-pointer hover:scale-110 active:scale-95 ${
|
|
2994
|
-
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` },
|
|
2993
|
+
className: `group fixed z-[9999] w-14 h-14 drop-shadow-2xl flex items-center justify-center transition-all duration-300 cursor-pointer hover:scale-110 active:scale-95 ${positionClass}`,
|
|
2995
2994
|
"aria-label": "Open chat",
|
|
2996
2995
|
children: [
|
|
2996
|
+
/* @__PURE__ */ jsx14(
|
|
2997
|
+
"div",
|
|
2998
|
+
{
|
|
2999
|
+
className: `absolute inset-0 transition-all duration-300 overflow-hidden ${ui.borderRadius === "full" ? "rounded-full" : "rounded-2xl"} group-hover:rounded-none group-hover:animate-shapeshift`,
|
|
3000
|
+
children: /* @__PURE__ */ jsx14(
|
|
3001
|
+
"div",
|
|
3002
|
+
{
|
|
3003
|
+
className: "absolute top-0 left-0 w-[400%] h-[400%] transition-transform duration-300 group-hover:animate-gradientMove",
|
|
3004
|
+
style: {
|
|
3005
|
+
background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor}, ${ui.primaryColor}, ${ui.accentColor})`
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
)
|
|
3009
|
+
}
|
|
3010
|
+
),
|
|
2997
3011
|
/* @__PURE__ */ jsx14(
|
|
2998
3012
|
"span",
|
|
2999
3013
|
{
|
|
3000
|
-
className: "absolute inset-0 rounded-full animate-ping opacity-20",
|
|
3014
|
+
className: "absolute inset-0 rounded-full animate-ping opacity-20 pointer-events-none",
|
|
3001
3015
|
style: { background: ui.primaryColor }
|
|
3002
3016
|
}
|
|
3003
3017
|
),
|
|
3004
3018
|
/* @__PURE__ */ jsx14(
|
|
3005
3019
|
"span",
|
|
3006
3020
|
{
|
|
3007
|
-
className: `transition-transform duration-300 ${isOpen ? "rotate-90 scale-90" : "rotate-0 scale-100"}`,
|
|
3021
|
+
className: `relative z-10 transition-transform duration-300 ${isOpen ? "rotate-90 scale-90" : "rotate-0 scale-100"}`,
|
|
3008
3022
|
children: isOpen ? /* @__PURE__ */ jsx14(X3, { className: "w-6 h-6 text-white" }) : /* @__PURE__ */ jsx14(MessageSquare, { className: "w-6 h-6 text-white" })
|
|
3009
3023
|
}
|
|
3010
3024
|
),
|
package/dist/server.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { n as VectorDBConfig, L as LLMConfig, e as EmbeddingConfig, k as RagConfig, I as ILLMProvider, g as IngestDocument, C as ChatMessage, d as ChatResponse, p as RetrievalResult, m as UpsertDocument, V as VectorMatch, G as GraphDBConfig, q as GraphNode, r as Edge, s as GraphSearchResult, o as VectorDBProvider, h as LLMProvider, f as EmbeddingProvider, j as RAGConfig, U as UIConfig, c as ChatOptions, E as EmbedOptions } from './ILLMProvider-
|
|
1
|
+
import { n as VectorDBConfig, L as LLMConfig, e as EmbeddingConfig, k as RagConfig, I as ILLMProvider, g as IngestDocument, C as ChatMessage, d as ChatResponse, p as RetrievalResult, m as UpsertDocument, V as VectorMatch, G as GraphDBConfig, q as GraphNode, r as Edge, s as GraphSearchResult, o as VectorDBProvider, h as LLMProvider, f as EmbeddingProvider, j as RAGConfig, U as UIConfig, c as ChatOptions, E as EmbedOptions } from './ILLMProvider-CbUtvWAW.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-c_y_5qdw.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-c_y_5qdw.mjs';
|
|
5
5
|
import 'next/server';
|
|
6
6
|
|
|
7
7
|
/**
|
package/dist/server.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { n as VectorDBConfig, L as LLMConfig, e as EmbeddingConfig, k as RagConfig, I as ILLMProvider, g as IngestDocument, C as ChatMessage, d as ChatResponse, p as RetrievalResult, m as UpsertDocument, V as VectorMatch, G as GraphDBConfig, q as GraphNode, r as Edge, s as GraphSearchResult, o as VectorDBProvider, h as LLMProvider, f as EmbeddingProvider, j as RAGConfig, U as UIConfig, c as ChatOptions, E as EmbedOptions } from './ILLMProvider-
|
|
1
|
+
import { n as VectorDBConfig, L as LLMConfig, e as EmbeddingConfig, k as RagConfig, I as ILLMProvider, g as IngestDocument, C as ChatMessage, d as ChatResponse, p as RetrievalResult, m as UpsertDocument, V as VectorMatch, G as GraphDBConfig, q as GraphNode, r as Edge, s as GraphSearchResult, o as VectorDBProvider, h as LLMProvider, f as EmbeddingProvider, j as RAGConfig, U as UIConfig, c as ChatOptions, E as EmbedOptions } from './ILLMProvider-CbUtvWAW.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-DgzcnqZs.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-DgzcnqZs.js';
|
|
5
5
|
import 'next/server';
|
|
6
6
|
|
|
7
7
|
/**
|
package/dist/server.js
CHANGED
|
@@ -374,10 +374,12 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
374
374
|
embedding VECTOR(${this.dimensions})
|
|
375
375
|
)
|
|
376
376
|
`);
|
|
377
|
+
const metric = this.config.distanceMetric || "cosine";
|
|
378
|
+
const indexOps = metric === "euclidean" ? "vector_l2_ops" : metric === "dotproduct" ? "vector_ip_ops" : "vector_cosine_ops";
|
|
377
379
|
await client.query(`
|
|
378
380
|
CREATE INDEX IF NOT EXISTS ${this.uploadTable}_embedding_idx
|
|
379
381
|
ON ${this.uploadTable}
|
|
380
|
-
USING hnsw (embedding
|
|
382
|
+
USING hnsw (embedding ${indexOps})
|
|
381
383
|
`);
|
|
382
384
|
const res = await client.query(`
|
|
383
385
|
SELECT table_name
|
|
@@ -439,10 +441,12 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
439
441
|
)
|
|
440
442
|
`;
|
|
441
443
|
await client.query(createTableSql);
|
|
444
|
+
const metric = this.config.distanceMetric || "cosine";
|
|
445
|
+
const indexOps = metric === "euclidean" ? "vector_l2_ops" : metric === "dotproduct" ? "vector_ip_ops" : "vector_cosine_ops";
|
|
442
446
|
await client.query(`
|
|
443
447
|
CREATE INDEX IF NOT EXISTS "${tableName}_embedding_idx"
|
|
444
448
|
ON "${tableName}"
|
|
445
|
-
USING hnsw (embedding
|
|
449
|
+
USING hnsw (embedding ${indexOps})
|
|
446
450
|
`);
|
|
447
451
|
if (!this.tables.includes(tableName)) {
|
|
448
452
|
this.tables.push(tableName);
|
|
@@ -524,6 +528,8 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
524
528
|
try {
|
|
525
529
|
let sqlQuery = "";
|
|
526
530
|
let params = [];
|
|
531
|
+
const metric = this.config.distanceMetric || "cosine";
|
|
532
|
+
const scoreExpr = metric === "euclidean" ? `1 / (1 + (embedding <-> $1::vector))` : metric === "dotproduct" ? `(embedding <#> $1::vector) * -1` : `1 - (embedding <=> $1::vector)`;
|
|
527
533
|
if (queryText) {
|
|
528
534
|
const hasEntityHints = entityHints.length > 0;
|
|
529
535
|
const exactNameScoreExpr = hasEntityHints ? `+ (
|
|
@@ -536,9 +542,9 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
536
542
|
) * 3.0` : "";
|
|
537
543
|
sqlQuery = `
|
|
538
544
|
SELECT *,
|
|
539
|
-
(
|
|
545
|
+
(${scoreExpr}) AS vector_score,
|
|
540
546
|
COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) AS keyword_score,
|
|
541
|
-
((
|
|
547
|
+
((${scoreExpr}) + (COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) * 2.0) ${exactNameScoreExpr}) AS hybrid_score
|
|
542
548
|
FROM "${table}" t
|
|
543
549
|
ORDER BY hybrid_score DESC
|
|
544
550
|
LIMIT 50
|
|
@@ -547,7 +553,7 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
547
553
|
} else {
|
|
548
554
|
sqlQuery = `
|
|
549
555
|
SELECT *,
|
|
550
|
-
(
|
|
556
|
+
(${scoreExpr}) AS hybrid_score
|
|
551
557
|
FROM "${table}" t
|
|
552
558
|
ORDER BY hybrid_score DESC
|
|
553
559
|
LIMIT 50
|
|
@@ -1021,11 +1027,13 @@ var init_QdrantProvider = __esm({
|
|
|
1021
1027
|
if (import_axios4.default.isAxiosError(err) && ((_a = err.response) == null ? void 0 : _a.status) === 404) {
|
|
1022
1028
|
const opts = this.config.options;
|
|
1023
1029
|
const dimensionsForCreate = opts.dimensions || 1536;
|
|
1030
|
+
const metric = this.config.distanceMetric || "cosine";
|
|
1031
|
+
const distance = metric === "euclidean" ? "Euclid" : metric === "dotproduct" ? "Dot" : "Cosine";
|
|
1024
1032
|
console.log(`[QdrantProvider] \u23F3 Creating collection "${this.indexName}" (dimensions: ${dimensionsForCreate})...`);
|
|
1025
1033
|
await this.http.put(`/collections/${this.indexName}`, {
|
|
1026
1034
|
vectors: {
|
|
1027
1035
|
size: dimensionsForCreate,
|
|
1028
|
-
distance
|
|
1036
|
+
distance
|
|
1029
1037
|
}
|
|
1030
1038
|
});
|
|
1031
1039
|
console.log(`[QdrantProvider] \u2705 Created collection "${this.indexName}"`);
|
|
@@ -1203,9 +1211,12 @@ var init_ChromaDBProvider = __esm({
|
|
|
1203
1211
|
console.log(`[ChromaDBProvider] \u2705 Collection "${this.indexName}" found (id: ${this.collectionId})`);
|
|
1204
1212
|
} catch (err) {
|
|
1205
1213
|
if (import_axios5.default.isAxiosError(err) && ((_a = err.response) == null ? void 0 : _a.status) === 404) {
|
|
1214
|
+
const metric = this.config.distanceMetric || "cosine";
|
|
1215
|
+
const space = metric === "euclidean" ? "l2" : metric === "dotproduct" ? "ip" : "cosine";
|
|
1206
1216
|
console.log(`[ChromaDBProvider] \u23F3 Collection "${this.indexName}" not found. Creating...`);
|
|
1207
1217
|
const { data } = await this.http.post("/api/v1/collections", {
|
|
1208
|
-
name: this.indexName
|
|
1218
|
+
name: this.indexName,
|
|
1219
|
+
metadata: { "hnsw:space": space }
|
|
1209
1220
|
});
|
|
1210
1221
|
this.collectionId = data.id;
|
|
1211
1222
|
console.log(`[ChromaDBProvider] \u2705 Created collection "${this.indexName}" (id: ${this.collectionId})`);
|
|
@@ -4242,18 +4253,20 @@ var UITransformer = class {
|
|
|
4242
4253
|
}
|
|
4243
4254
|
const isStockRequest = this.isStockQuery(userQuery);
|
|
4244
4255
|
const filteredData = isStockRequest ? retrievedData.filter((item) => this.determineStockStatus(item)) : retrievedData;
|
|
4245
|
-
const
|
|
4256
|
+
const groupByField = this.determineGroupByField(userQuery, filteredData);
|
|
4257
|
+
const categories = this.detectCategories(filteredData, groupByField);
|
|
4246
4258
|
const hasProducts = filteredData.some((item) => this.isProductData(item));
|
|
4247
4259
|
const isTimeSeries = filteredData.some((item) => this.isTimeSeriesData(item));
|
|
4248
4260
|
const isTrendQuery = this.isTrendQuery(userQuery);
|
|
4249
4261
|
if (isTrendQuery && isTimeSeries) {
|
|
4250
4262
|
return this.transformToLineChart(filteredData);
|
|
4251
4263
|
}
|
|
4252
|
-
|
|
4264
|
+
const explicitChartRequest = this.isExplicitChartQuery(userQuery);
|
|
4265
|
+
if (hasProducts && !explicitChartRequest && !this.shouldShowCategoryChart(userQuery)) {
|
|
4253
4266
|
return this.transformToProductCarousel(filteredData, config, trainedSchema);
|
|
4254
4267
|
}
|
|
4255
|
-
if (categories.length > 1 && this.shouldShowCategoryChart(userQuery
|
|
4256
|
-
return this.transformToPieChart(filteredData);
|
|
4268
|
+
if (explicitChartRequest || categories.length > 1 && this.shouldShowCategoryChart(userQuery)) {
|
|
4269
|
+
return this.transformToPieChart(filteredData, groupByField);
|
|
4257
4270
|
}
|
|
4258
4271
|
if (hasProducts) {
|
|
4259
4272
|
return this.transformToProductCarousel(filteredData, config, trainedSchema);
|
|
@@ -4278,11 +4291,12 @@ var UITransformer = class {
|
|
|
4278
4291
|
/**
|
|
4279
4292
|
* Transform data to pie chart format
|
|
4280
4293
|
*/
|
|
4281
|
-
static transformToPieChart(data) {
|
|
4282
|
-
|
|
4283
|
-
|
|
4294
|
+
static transformToPieChart(data, groupByField) {
|
|
4295
|
+
let categories = this.detectCategories(data, groupByField);
|
|
4296
|
+
if (categories.length === 0) categories = ["All Data"];
|
|
4297
|
+
const categoryData = this.aggregateByCategory(data, categories, groupByField);
|
|
4284
4298
|
const pieData = Object.entries(categoryData).map(([label, count]) => {
|
|
4285
|
-
const { inStockCount, outOfStockCount } = this.calculateStockCounts(label, data);
|
|
4299
|
+
const { inStockCount, outOfStockCount } = this.calculateStockCounts(label, data, groupByField);
|
|
4286
4300
|
return {
|
|
4287
4301
|
label,
|
|
4288
4302
|
value: count,
|
|
@@ -4292,7 +4306,7 @@ var UITransformer = class {
|
|
|
4292
4306
|
});
|
|
4293
4307
|
return {
|
|
4294
4308
|
type: "pie_chart",
|
|
4295
|
-
title:
|
|
4309
|
+
title: `Distribution by ${groupByField.charAt(0).toUpperCase() + groupByField.slice(1)}`,
|
|
4296
4310
|
description: `Showing breakdown across ${categories.length} categories`,
|
|
4297
4311
|
data: pieData
|
|
4298
4312
|
};
|
|
@@ -4515,10 +4529,11 @@ var UITransformer = class {
|
|
|
4515
4529
|
});
|
|
4516
4530
|
return hasTimeKeyword || hasValidDateValue;
|
|
4517
4531
|
}
|
|
4518
|
-
static
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4532
|
+
static isExplicitChartQuery(query) {
|
|
4533
|
+
const normalized = query.toLowerCase();
|
|
4534
|
+
return normalized.includes("pie chart") || normalized.includes("piechart") || normalized.includes("bar chart") || normalized.includes("barchart") || normalized.includes("radar chart");
|
|
4535
|
+
}
|
|
4536
|
+
static shouldShowCategoryChart(query) {
|
|
4522
4537
|
const normalized = query.toLowerCase();
|
|
4523
4538
|
const chartKeywords = [
|
|
4524
4539
|
"distribution",
|
|
@@ -4531,7 +4546,11 @@ var UITransformer = class {
|
|
|
4531
4546
|
"segmentation",
|
|
4532
4547
|
"split",
|
|
4533
4548
|
"category breakdown",
|
|
4534
|
-
"category distribution"
|
|
4549
|
+
"category distribution",
|
|
4550
|
+
"pie chart",
|
|
4551
|
+
"piechart",
|
|
4552
|
+
"bar chart",
|
|
4553
|
+
"barchart"
|
|
4535
4554
|
];
|
|
4536
4555
|
return chartKeywords.some((keyword) => normalized.includes(keyword));
|
|
4537
4556
|
}
|
|
@@ -4607,44 +4626,67 @@ var UITransformer = class {
|
|
|
4607
4626
|
return null;
|
|
4608
4627
|
}
|
|
4609
4628
|
/**
|
|
4610
|
-
* Helper:
|
|
4629
|
+
* Helper: Dynamically determine what field to group by based on user query
|
|
4630
|
+
*/
|
|
4631
|
+
static determineGroupByField(query, data) {
|
|
4632
|
+
const normalized = query.toLowerCase();
|
|
4633
|
+
const match = normalized.match(/(?:by|across|per|based on)\s+([a-zA-Z]+)/i);
|
|
4634
|
+
let targetField = "category";
|
|
4635
|
+
if (match && match[1]) {
|
|
4636
|
+
let field = match[1].toLowerCase();
|
|
4637
|
+
if (field.endsWith("ies")) field = field.replace(/ies$/, "y");
|
|
4638
|
+
else if (field.endsWith("s") && field !== "status") field = field.slice(0, -1);
|
|
4639
|
+
const stopWords = ["the", "all", "different", "various", "some", "these", "those"];
|
|
4640
|
+
if (!stopWords.includes(field)) {
|
|
4641
|
+
targetField = field;
|
|
4642
|
+
}
|
|
4643
|
+
}
|
|
4644
|
+
const hasTargetField = data.some((d) => d.metadata && d.metadata[targetField] !== void 0);
|
|
4645
|
+
if (!hasTargetField && targetField === "category") {
|
|
4646
|
+
if (data.some((d) => d.metadata && d.metadata["type"] !== void 0)) return "type";
|
|
4647
|
+
if (data.some((d) => d.metadata && d.metadata["brand"] !== void 0)) return "brand";
|
|
4648
|
+
}
|
|
4649
|
+
return targetField;
|
|
4650
|
+
}
|
|
4651
|
+
/**
|
|
4652
|
+
* Helper: Detect grouping values dynamically
|
|
4611
4653
|
*/
|
|
4612
|
-
static detectCategories(data) {
|
|
4654
|
+
static detectCategories(data, groupByField) {
|
|
4613
4655
|
const categories = /* @__PURE__ */ new Set();
|
|
4614
4656
|
data.forEach((item) => {
|
|
4615
4657
|
const meta = item.metadata || {};
|
|
4616
|
-
if (meta
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
));
|
|
4629
|
-
contentCategories.forEach((category) => categories.add(category));
|
|
4630
|
-
const categoryMatch = item.content.match(/(?:Category|Type|Class):\s*([^\n]+)/i);
|
|
4631
|
-
if (categoryMatch) {
|
|
4632
|
-
categories.add(categoryMatch[1].trim());
|
|
4658
|
+
if (meta[groupByField] !== void 0) {
|
|
4659
|
+
const val = meta[groupByField];
|
|
4660
|
+
if (Array.isArray(val)) val.forEach((v) => categories.add(String(v)));
|
|
4661
|
+
else categories.add(String(val));
|
|
4662
|
+
} else if (groupByField === "category") {
|
|
4663
|
+
if (meta.type) categories.add(String(meta.type));
|
|
4664
|
+
if (meta.tag) {
|
|
4665
|
+
const tags = Array.isArray(meta.tag) ? meta.tag : [meta.tag];
|
|
4666
|
+
tags.forEach((t) => categories.add(String(t)));
|
|
4667
|
+
}
|
|
4668
|
+
const categoryMatch = item.content.match(/(?:Category|Type|Class):\s*([^\n]+)/i);
|
|
4669
|
+
if (categoryMatch) categories.add(categoryMatch[1].trim());
|
|
4633
4670
|
}
|
|
4634
4671
|
});
|
|
4635
4672
|
return Array.from(categories);
|
|
4636
4673
|
}
|
|
4637
4674
|
/**
|
|
4638
|
-
* Helper: Aggregate data
|
|
4675
|
+
* Helper: Aggregate data dynamically
|
|
4639
4676
|
*/
|
|
4640
|
-
static aggregateByCategory(data, categories) {
|
|
4677
|
+
static aggregateByCategory(data, categories, groupByField) {
|
|
4641
4678
|
const result = {};
|
|
4642
4679
|
categories.forEach((cat) => {
|
|
4643
4680
|
result[cat] = 0;
|
|
4644
4681
|
});
|
|
4645
4682
|
data.forEach((item) => {
|
|
4646
4683
|
const meta = item.metadata || {};
|
|
4647
|
-
|
|
4684
|
+
let itemCategory = "Other";
|
|
4685
|
+
if (meta[groupByField] !== void 0) {
|
|
4686
|
+
itemCategory = String(meta[groupByField]);
|
|
4687
|
+
} else if (groupByField === "category" && meta.type) {
|
|
4688
|
+
itemCategory = String(meta.type);
|
|
4689
|
+
}
|
|
4648
4690
|
if (Object.prototype.hasOwnProperty.call(result, itemCategory)) {
|
|
4649
4691
|
result[itemCategory]++;
|
|
4650
4692
|
} else {
|
|
@@ -4694,14 +4736,19 @@ var UITransformer = class {
|
|
|
4694
4736
|
});
|
|
4695
4737
|
}
|
|
4696
4738
|
/**
|
|
4697
|
-
* Helper: Calculate stock counts
|
|
4739
|
+
* Helper: Calculate stock counts dynamically
|
|
4698
4740
|
*/
|
|
4699
|
-
static calculateStockCounts(category, data) {
|
|
4741
|
+
static calculateStockCounts(category, data, groupByField) {
|
|
4700
4742
|
let inStock = 0;
|
|
4701
4743
|
let outOfStock = 0;
|
|
4702
4744
|
data.forEach((d) => {
|
|
4703
4745
|
const meta = d.metadata || {};
|
|
4704
|
-
|
|
4746
|
+
let itemCategory = "Other";
|
|
4747
|
+
if (meta[groupByField] !== void 0) {
|
|
4748
|
+
itemCategory = String(meta[groupByField]);
|
|
4749
|
+
} else if (groupByField === "category" && meta.type) {
|
|
4750
|
+
itemCategory = String(meta.type);
|
|
4751
|
+
}
|
|
4705
4752
|
if (itemCategory === category) {
|
|
4706
4753
|
if (this.determineStockStatus(d)) {
|
|
4707
4754
|
inStock++;
|
|
@@ -4826,12 +4873,13 @@ DATA SHAPE per type:
|
|
|
4826
4873
|
- text: { "content": "<prose answer>" }
|
|
4827
4874
|
|
|
4828
4875
|
DECISION RULES (follow strictly):
|
|
4829
|
-
1.
|
|
4830
|
-
2.
|
|
4831
|
-
3.
|
|
4832
|
-
4.
|
|
4833
|
-
5.
|
|
4834
|
-
6.
|
|
4876
|
+
1. IF the user explicitly asks for a "pie chart", "bar chart", or "table", you MUST output that exact type. Do not deviate from their request.
|
|
4877
|
+
2. bar_chart \u2192 comparing quantities across categories (e.g. sales by region, price by product). Use this when there is only ONE value per category.
|
|
4878
|
+
3. line_chart \u2192 trends or changes over time (dates, months, years, sequential events)
|
|
4879
|
+
4. pie_chart \u2192 proportional breakdown or percentage distribution
|
|
4880
|
+
5. radar_chart \u2192 comparing 2 or more products across MULTIPLE attributes.
|
|
4881
|
+
6. table \u2192 multi-field structured records where each item has \u2265 3 attributes
|
|
4882
|
+
7. text \u2192 conversational or free-form answers where no chart adds value
|
|
4835
4883
|
|
|
4836
4884
|
IMPORTANT:
|
|
4837
4885
|
- Aggregate numeric values from the raw data \u2014 do not pass raw object arrays as data.
|
|
@@ -5989,10 +6037,12 @@ var PostgreSQLProvider = class extends BaseVectorProvider {
|
|
|
5989
6037
|
embedding VECTOR(${this.dimensions})
|
|
5990
6038
|
)
|
|
5991
6039
|
`);
|
|
6040
|
+
const metric = this.config.distanceMetric || "cosine";
|
|
6041
|
+
const indexOps = metric === "euclidean" ? "vector_l2_ops" : metric === "dotproduct" ? "vector_ip_ops" : "vector_cosine_ops";
|
|
5992
6042
|
await client.query(`
|
|
5993
6043
|
CREATE INDEX IF NOT EXISTS ${this.tableName}_embedding_idx
|
|
5994
6044
|
ON ${this.tableName}
|
|
5995
|
-
USING hnsw (embedding
|
|
6045
|
+
USING hnsw (embedding ${indexOps})
|
|
5996
6046
|
`);
|
|
5997
6047
|
} finally {
|
|
5998
6048
|
client.release();
|
|
@@ -6064,11 +6114,14 @@ var PostgreSQLProvider = class extends BaseVectorProvider {
|
|
|
6064
6114
|
try {
|
|
6065
6115
|
const efSearch = this.config.options.efSearch || Math.max(topK * 10, 40);
|
|
6066
6116
|
await client.query(`SET LOCAL hnsw.ef_search = ${efSearch}`);
|
|
6117
|
+
const metric = this.config.distanceMetric || "cosine";
|
|
6118
|
+
const queryOp = metric === "euclidean" ? "<->" : metric === "dotproduct" ? "<#>" : "<=>";
|
|
6119
|
+
const scoreExpr = metric === "euclidean" ? `1 / (1 + (embedding <-> $1::vector))` : metric === "dotproduct" ? `(embedding <#> $1::vector) * -1` : `1 - (embedding <=> $1::vector)`;
|
|
6067
6120
|
const result = await client.query(
|
|
6068
|
-
`SELECT id, content, metadata,
|
|
6121
|
+
`SELECT id, content, metadata, ${scoreExpr} AS score
|
|
6069
6122
|
FROM ${this.tableName}
|
|
6070
6123
|
${whereClause}
|
|
6071
|
-
ORDER BY embedding
|
|
6124
|
+
ORDER BY embedding ${queryOp} $1::vector
|
|
6072
6125
|
LIMIT $2`,
|
|
6073
6126
|
params
|
|
6074
6127
|
);
|