@retrivora-ai/rag-engine 1.9.0 → 1.9.2
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-BOJFz3Na.d.mts → ILLMProvider-Bw2A28nU.d.mts} +12 -0
- package/dist/{ILLMProvider-BOJFz3Na.d.ts → ILLMProvider-Bw2A28nU.d.ts} +12 -0
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +1874 -542
- package/dist/handlers/index.mjs +1873 -541
- package/dist/{index-D3V9Et2M.d.mts → index-B70ZLkfG.d.mts} +1 -1
- package/dist/{index-BwpcaziY.d.ts → index-DVu-mkAM.d.ts} +1 -1
- package/dist/index.css +83 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +330 -106
- package/dist/index.mjs +333 -107
- package/dist/server.d.mts +32 -5
- package/dist/server.d.ts +32 -5
- package/dist/server.js +1871 -736
- package/dist/server.mjs +1870 -735
- package/package.json +1 -1
- package/src/components/ChatWindow.tsx +24 -14
- package/src/components/MarkdownComponents.tsx +3 -3
- package/src/components/MessageBubble.tsx +89 -7
- package/src/components/ProductCard.tsx +29 -2
- package/src/components/UIDispatcher.tsx +1 -0
- package/src/components/VisualizationRenderer.tsx +143 -11
- package/src/config/EmbeddingStrategy.ts +5 -4
- package/src/config/RagConfig.ts +10 -0
- package/src/config/serverConfig.ts +16 -1
- package/src/core/LLMRouter.ts +79 -0
- package/src/core/Pipeline.ts +295 -51
- package/src/core/ProviderRegistry.ts +6 -0
- package/src/core/QueryProcessor.ts +108 -9
- package/src/handlers/index.ts +37 -11
- package/src/hooks/useRagChat.ts +77 -17
- package/src/llm/providers/UniversalLLMAdapter.ts +110 -13
- package/src/providers/vectordb/ChromaDBProvider.ts +13 -2
- package/src/providers/vectordb/MilvusProvider.ts +18 -2
- package/src/providers/vectordb/MultiTablePostgresProvider.ts +48 -16
- package/src/providers/vectordb/PostgreSQLProvider.ts +1 -1
- package/src/providers/vectordb/QdrantProvider.ts +1 -1
- package/src/providers/vectordb/RedisProvider.ts +3 -4
- package/src/providers/vectordb/WeaviateProvider.ts +41 -3
- package/src/types/chat.ts +2 -0
- package/src/types/index.ts +26 -0
- package/src/utils/ProductExtractor.ts +5 -3
- package/src/utils/SchemaMapper.ts +6 -4
- package/src/utils/UITransformer.ts +1350 -490
- package/src/utils/synonyms.ts +6 -4
package/dist/index.js
CHANGED
|
@@ -395,7 +395,20 @@ var import_lucide_react4 = require("lucide-react");
|
|
|
395
395
|
var import_image = __toESM(require("next/image"));
|
|
396
396
|
var import_lucide_react3 = require("lucide-react");
|
|
397
397
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
398
|
+
function cleanProductDescription(raw) {
|
|
399
|
+
var _a;
|
|
400
|
+
if (raw === null || raw === void 0) return "";
|
|
401
|
+
const source = String(raw);
|
|
402
|
+
const bodyMatch = source.match(
|
|
403
|
+
/\bBody\s*\(HTML\)\s*:\s*([\s\S]*?)(?=\s*[,.]?\s+\b(?:Handle|Title|Vendor|Type|Tags|Published|Option\d*\s+Name|Option\d*\s+Value|Option|Variant|Image|SKU|Price|Status|Category)\b\s*:|$)/i
|
|
404
|
+
);
|
|
405
|
+
const descriptionMatch = bodyMatch != null ? bodyMatch : source.match(
|
|
406
|
+
/\b(?:Description|Summary|Details|Body)\s*:\s*([\s\S]*?)(?=\s*[,.]?\s+\b(?:Handle|Title|Vendor|Type|Tags|Published|Option\d*\s+Name|Option\d*\s+Value|Option|Variant|Image|SKU|Price|Status|Category)\b\s*:|$)/i
|
|
407
|
+
);
|
|
408
|
+
return ((_a = descriptionMatch == null ? void 0 : descriptionMatch[1]) != null ? _a : source).replace(/<[^>]*>/g, " ").replace(/ /gi, " ").replace(/&/gi, "&").replace(/"/gi, '"').replace(/'/gi, "'").replace(/\[[^\]]*TYPE[^\]]*\]/gi, " ").replace(/\b(?:Handle|Title|Vendor|Type|Tags|Published|Option\d*\s+Name|Option\d*\s+Value|Option|Variant|Image|SKU|Price|Status|Category)\s*:\s*[^,.\n:]+[,.]?/gi, " ").replace(/\bBody\s*\(HTML\)\s*:\s*/gi, " ").replace(/\b(?:Description|Summary|Details|Body|Content)\s*:\s*/gi, " ").replace(/\s+/g, " ").trim();
|
|
409
|
+
}
|
|
398
410
|
function ProductCard({ product, primaryColor = "#6366f1", onAddToCart }) {
|
|
411
|
+
const description = cleanProductDescription(product.description);
|
|
399
412
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex-shrink-0 w-full bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 rounded-xl overflow-hidden shadow-sm hover:shadow-md transition-all duration-300 group", children: [
|
|
400
413
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "relative h-40 w-full bg-slate-100 dark:bg-white/5 flex items-center justify-center overflow-hidden", children: [
|
|
401
414
|
product.image ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -415,7 +428,7 @@ function ProductCard({ product, primaryColor = "#6366f1", onAddToCart }) {
|
|
|
415
428
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { className: "text-sm font-semibold text-slate-800 dark:text-white/90 line-clamp-1", children: product.name }),
|
|
416
429
|
product.price && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-sm font-bold", style: { color: primaryColor }, children: typeof product.price === "number" ? `$${product.price}` : String(product.price).match(/^[\d.]/) ? `$${product.price}` : product.price })
|
|
417
430
|
] }),
|
|
418
|
-
|
|
431
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "text-[11px] text-slate-500 dark:text-white/50 line-clamp-2 leading-relaxed", children: description }),
|
|
419
432
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mt-2 flex gap-2", children: [
|
|
420
433
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
421
434
|
"button",
|
|
@@ -720,6 +733,9 @@ var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
|
720
733
|
function getColor(index) {
|
|
721
734
|
return CHART_COLORS[index % CHART_COLORS.length];
|
|
722
735
|
}
|
|
736
|
+
function stripLeakedAnswerWrappers(raw) {
|
|
737
|
+
return raw.replace(/<prose\s+answer(?:\s+in\s+[^>]*)?>\s*([\s\S]*?)\s*<\/prose>/gi, "$1").replace(/<\/?prose(?:\s+answer)?[^>]*>/gi, "").trim();
|
|
738
|
+
}
|
|
723
739
|
function CustomTooltip({
|
|
724
740
|
active,
|
|
725
741
|
payload,
|
|
@@ -769,10 +785,20 @@ function renderVisualization(type, data, onAddToCart, primaryColor, isStreaming)
|
|
|
769
785
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PieChartView, { data, isStreaming });
|
|
770
786
|
case "bar_chart":
|
|
771
787
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(BarChartView, { data, primaryColor, isStreaming });
|
|
788
|
+
case "histogram":
|
|
789
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(BarChartView, { data, primaryColor, isStreaming });
|
|
790
|
+
case "horizontal_bar":
|
|
791
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(BarChartView, { data, primaryColor, isStreaming, layout: "vertical" });
|
|
772
792
|
case "line_chart":
|
|
773
793
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(LineChartView, { data, primaryColor, isStreaming });
|
|
794
|
+
case "scatter_plot":
|
|
795
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ScatterPlotView, { data, primaryColor, isStreaming });
|
|
774
796
|
case "radar_chart":
|
|
775
797
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RadarChartView, { data, isStreaming });
|
|
798
|
+
case "metric_card":
|
|
799
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MetricCardView, { data, isStreaming });
|
|
800
|
+
case "geo_map":
|
|
801
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(BarChartView, { data, primaryColor, isStreaming });
|
|
776
802
|
case "table":
|
|
777
803
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TableView, { data, isStreaming });
|
|
778
804
|
case "product_carousel":
|
|
@@ -807,28 +833,74 @@ function PieChartView({ data, isStreaming }) {
|
|
|
807
833
|
}
|
|
808
834
|
const chartData = data.map((item) => ({
|
|
809
835
|
name: item.label,
|
|
810
|
-
value: item.value
|
|
836
|
+
value: item.value,
|
|
837
|
+
inStockCount: item.inStockCount,
|
|
838
|
+
outOfStockCount: item.outOfStockCount
|
|
811
839
|
}));
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
840
|
+
const hasStockBreakdown = chartData.some(
|
|
841
|
+
(item) => item.inStockCount !== void 0 || item.outOfStockCount !== void 0
|
|
842
|
+
);
|
|
843
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm", children: [
|
|
844
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.ResponsiveContainer, { width: "100%", height: 280, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_recharts2.PieChart, { children: [
|
|
845
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
846
|
+
import_recharts2.Pie,
|
|
847
|
+
{
|
|
848
|
+
data: chartData,
|
|
849
|
+
dataKey: "value",
|
|
850
|
+
nameKey: "name",
|
|
851
|
+
cx: "50%",
|
|
852
|
+
cy: "50%",
|
|
853
|
+
outerRadius: "68%",
|
|
854
|
+
label: false,
|
|
855
|
+
labelLine: false,
|
|
856
|
+
children: chartData.map((_entry, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Cell, { fill: getColor(index) }, `cell-${index}`))
|
|
857
|
+
}
|
|
858
|
+
),
|
|
859
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Tooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CustomTooltip, {}) }),
|
|
860
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Legend, { wrapperStyle: { fontSize: 12 }, verticalAlign: "bottom" })
|
|
861
|
+
] }) }),
|
|
862
|
+
hasStockBreakdown && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mt-3 grid gap-2 sm:grid-cols-2", children: chartData.map((item, index) => {
|
|
863
|
+
var _a, _b;
|
|
864
|
+
const inStock = Number((_a = item.inStockCount) != null ? _a : 0);
|
|
865
|
+
const outOfStock = Number((_b = item.outOfStockCount) != null ? _b : 0);
|
|
866
|
+
const status = inStock > 0 ? `${inStock} in stock` : "Out of stock";
|
|
867
|
+
const mutedStatus = outOfStock > 0 ? `${outOfStock} out` : null;
|
|
868
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
869
|
+
"div",
|
|
870
|
+
{
|
|
871
|
+
className: "flex min-w-0 items-center justify-between gap-3 rounded-md border border-slate-100 px-2.5 py-2 text-xs dark:border-white/10",
|
|
872
|
+
children: [
|
|
873
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "flex min-w-0 items-center gap-2 text-slate-700 dark:text-white/75", children: [
|
|
874
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
875
|
+
"span",
|
|
876
|
+
{
|
|
877
|
+
className: "h-2.5 w-2.5 flex-shrink-0 rounded-full",
|
|
878
|
+
style: { background: getColor(index) }
|
|
879
|
+
}
|
|
880
|
+
),
|
|
881
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "truncate", children: item.name })
|
|
882
|
+
] }),
|
|
883
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: inStock > 0 ? "whitespace-nowrap font-medium text-emerald-600" : "whitespace-nowrap font-medium text-rose-600", children: [
|
|
884
|
+
status,
|
|
885
|
+
mutedStatus && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "ml-1 text-slate-400", children: [
|
|
886
|
+
"(",
|
|
887
|
+
mutedStatus,
|
|
888
|
+
")"
|
|
889
|
+
] })
|
|
890
|
+
] })
|
|
891
|
+
]
|
|
892
|
+
},
|
|
893
|
+
item.name
|
|
894
|
+
);
|
|
895
|
+
}) })
|
|
896
|
+
] });
|
|
830
897
|
}
|
|
831
|
-
function BarChartView({
|
|
898
|
+
function BarChartView({
|
|
899
|
+
data,
|
|
900
|
+
primaryColor,
|
|
901
|
+
isStreaming,
|
|
902
|
+
layout = "horizontal"
|
|
903
|
+
}) {
|
|
832
904
|
if (isStreaming) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChartSkeleton, { type: "bar" });
|
|
833
905
|
if (!Array.isArray(data) || data.length === 0) {
|
|
834
906
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs text-red-500", children: "Invalid bar chart data" });
|
|
@@ -839,26 +911,66 @@ function BarChartView({ data, primaryColor, isStreaming }) {
|
|
|
839
911
|
}, item.inStockCount !== void 0 && { inStockCount: item.inStockCount }), item.outOfStockCount !== void 0 && { outOfStockCount: item.outOfStockCount }));
|
|
840
912
|
const barColor = primaryColor != null ? primaryColor : getColor(0);
|
|
841
913
|
const hasStock = chartData.some((d) => "inStockCount" in d);
|
|
842
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.ResponsiveContainer, { width: "100%", height: 260, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
914
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.ResponsiveContainer, { width: "100%", height: 260, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
915
|
+
import_recharts2.BarChart,
|
|
916
|
+
{
|
|
917
|
+
data: chartData,
|
|
918
|
+
layout,
|
|
919
|
+
margin: { top: 10, right: 10, left: layout === "vertical" ? 20 : -20, bottom: 0 },
|
|
920
|
+
children: [
|
|
921
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }),
|
|
922
|
+
layout === "vertical" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
923
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.XAxis, { type: "number", tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: { stroke: "#cbd5e1" } }),
|
|
924
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.YAxis, { type: "category", dataKey: "category", width: 110, tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: false })
|
|
925
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
926
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
927
|
+
import_recharts2.XAxis,
|
|
928
|
+
{
|
|
929
|
+
dataKey: "category",
|
|
930
|
+
tick: { fontSize: 11, fill: "#64748b" },
|
|
931
|
+
tickLine: false,
|
|
932
|
+
axisLine: { stroke: "#cbd5e1" }
|
|
933
|
+
}
|
|
934
|
+
),
|
|
935
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.YAxis, { tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: false })
|
|
936
|
+
] }),
|
|
937
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Tooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CustomTooltip, {}), cursor: { fill: "#f1f5f9" } }),
|
|
938
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Legend, { wrapperStyle: { fontSize: 12 } }),
|
|
939
|
+
hasStock ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
940
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Bar, { dataKey: "inStockCount", name: "In Stock", fill: getColor(1), radius: [4, 4, 0, 0] }),
|
|
941
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Bar, { dataKey: "outOfStockCount", name: "Out of Stock", fill: getColor(3), radius: [4, 4, 0, 0] })
|
|
942
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Bar, { dataKey: "value", name: "Value", fill: barColor, radius: [4, 4, 0, 0] })
|
|
943
|
+
]
|
|
944
|
+
}
|
|
945
|
+
) }) });
|
|
946
|
+
}
|
|
947
|
+
function ScatterPlotView({ data, primaryColor, isStreaming }) {
|
|
948
|
+
if (isStreaming) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChartSkeleton, { type: "bar" });
|
|
949
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
950
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs text-red-500", children: "Invalid scatter plot data" });
|
|
951
|
+
}
|
|
952
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.ResponsiveContainer, { width: "100%", height: 260, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_recharts2.ScatterChart, { margin: { top: 10, right: 10, left: -20, bottom: 0 }, children: [
|
|
953
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.CartesianGrid, { strokeDasharray: "3 3", stroke: "#e2e8f0" }),
|
|
954
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.XAxis, { type: "number", dataKey: "x", tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: { stroke: "#cbd5e1" } }),
|
|
955
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.YAxis, { type: "number", dataKey: "y", tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: false }),
|
|
956
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Tooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CustomTooltip, {}), cursor: { strokeDasharray: "3 3" } }),
|
|
957
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Scatter, { name: "Value", data, fill: primaryColor != null ? primaryColor : getColor(0) })
|
|
860
958
|
] }) }) });
|
|
861
959
|
}
|
|
960
|
+
function MetricCardView({ data, isStreaming }) {
|
|
961
|
+
if (isStreaming) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChartSkeleton, { type: "bar" });
|
|
962
|
+
if (!data || typeof data.value !== "number") {
|
|
963
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs text-red-500", children: "Invalid metric data" });
|
|
964
|
+
}
|
|
965
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rounded-xl border border-slate-200 bg-white p-4 shadow-sm dark:border-white/10 dark:bg-slate-900", children: [
|
|
966
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs font-medium uppercase text-slate-500 dark:text-slate-400", children: data.label }),
|
|
967
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "mt-2 text-3xl font-semibold text-slate-900 dark:text-white", children: [
|
|
968
|
+
data.value.toLocaleString(),
|
|
969
|
+
data.unit && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ml-1 text-base text-slate-500", children: data.unit })
|
|
970
|
+
] }),
|
|
971
|
+
data.operation && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: data.operation })
|
|
972
|
+
] });
|
|
973
|
+
}
|
|
862
974
|
function LineChartView({ data, primaryColor, isStreaming }) {
|
|
863
975
|
if (isStreaming) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChartSkeleton, { type: "bar" });
|
|
864
976
|
if (!Array.isArray(data) || data.length === 0) {
|
|
@@ -992,7 +1104,7 @@ function CarouselView({
|
|
|
992
1104
|
) });
|
|
993
1105
|
}
|
|
994
1106
|
function TextView({ data }) {
|
|
995
|
-
const content = (data == null ? void 0 : data.content) || String(data != null ? data : "");
|
|
1107
|
+
const content = stripLeakedAnswerWrappers((data == null ? void 0 : data.content) || String(data != null ? data : ""));
|
|
996
1108
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-sm text-slate-700 dark:text-slate-300 whitespace-pre-wrap leading-relaxed", children: content }) });
|
|
997
1109
|
}
|
|
998
1110
|
|
|
@@ -1404,7 +1516,7 @@ var HourglassLoader_default = HourglassLoader;
|
|
|
1404
1516
|
// src/utils/synonyms.ts
|
|
1405
1517
|
var FIELD_SYNONYMS = {
|
|
1406
1518
|
name: ["product", "item", "title", "label", "heading", "subject", "product name", "item name"],
|
|
1407
|
-
price: ["cost", "amount", "msrp", "price", "rate", "value", "price_usd"],
|
|
1519
|
+
price: ["cost", "amount", "msrp", "price", "rate", "value", "price_usd", "variant price"],
|
|
1408
1520
|
brand: ["manufacturer", "vendor", "make", "company", "brand_name", "supplier"],
|
|
1409
1521
|
image: [
|
|
1410
1522
|
"imageUrl",
|
|
@@ -1417,7 +1529,9 @@ var FIELD_SYNONYMS = {
|
|
|
1417
1529
|
"image_url",
|
|
1418
1530
|
"main_image",
|
|
1419
1531
|
"product_image",
|
|
1420
|
-
"thumb"
|
|
1532
|
+
"thumb",
|
|
1533
|
+
"image src",
|
|
1534
|
+
"variant image"
|
|
1421
1535
|
],
|
|
1422
1536
|
stock: [
|
|
1423
1537
|
"inventory",
|
|
@@ -1428,9 +1542,19 @@ var FIELD_SYNONYMS = {
|
|
|
1428
1542
|
"inStock",
|
|
1429
1543
|
"is_available",
|
|
1430
1544
|
"in stock",
|
|
1431
|
-
"status"
|
|
1545
|
+
"status",
|
|
1546
|
+
"variant inventory qty"
|
|
1432
1547
|
],
|
|
1433
|
-
|
|
1548
|
+
category: [
|
|
1549
|
+
"product_category",
|
|
1550
|
+
"product category",
|
|
1551
|
+
"category_name",
|
|
1552
|
+
"category name",
|
|
1553
|
+
"department",
|
|
1554
|
+
"collection",
|
|
1555
|
+
"type"
|
|
1556
|
+
],
|
|
1557
|
+
description: ["summary", "content", "body", "text", "info", "details", "body (html)", "seo description"],
|
|
1434
1558
|
link: ["url", "href", "product_url", "page_url", "link"]
|
|
1435
1559
|
};
|
|
1436
1560
|
function addSynonyms(customSynonyms) {
|
|
@@ -1637,11 +1761,12 @@ function extractProductsFromSources(sources, isUser) {
|
|
|
1637
1761
|
var _a;
|
|
1638
1762
|
const m = (_a = s.metadata) != null ? _a : {};
|
|
1639
1763
|
const keys = Object.keys(m).map((k) => k.toLowerCase());
|
|
1640
|
-
const
|
|
1641
|
-
(k) => ["price", "image", "img", "thumbnail", "images", "
|
|
1764
|
+
const hasStrongProductKey = keys.some(
|
|
1765
|
+
(k) => ["price", "image", "img", "thumbnail", "images", "product", "sku", "cost"].includes(k)
|
|
1642
1766
|
);
|
|
1767
|
+
const hasProductIdentity = keys.some((k) => ["brand", "model"].includes(k)) && keys.some((k) => ["name", "title", "product_name", "product"].includes(k));
|
|
1643
1768
|
const hasPricePattern = /\$\s*\d+/.test(s.content);
|
|
1644
|
-
return
|
|
1769
|
+
return hasStrongProductKey || hasProductIdentity || hasPricePattern || m.type === "product";
|
|
1645
1770
|
}).map((s) => {
|
|
1646
1771
|
var _a, _b;
|
|
1647
1772
|
const m = (_a = s.metadata) != null ? _a : {};
|
|
@@ -1828,6 +1953,7 @@ function resolveStructuredRows(config) {
|
|
|
1828
1953
|
}
|
|
1829
1954
|
function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAddToCart, viewportSize = "large" }) {
|
|
1830
1955
|
var _a;
|
|
1956
|
+
console.log("rawContent", rawContent);
|
|
1831
1957
|
const result = import_react7.default.useMemo(() => {
|
|
1832
1958
|
try {
|
|
1833
1959
|
const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
|
|
@@ -1962,12 +2088,11 @@ function createMarkdownComponents({
|
|
|
1962
2088
|
viewportSize
|
|
1963
2089
|
}) {
|
|
1964
2090
|
return {
|
|
1965
|
-
p: (
|
|
2091
|
+
// p: ({ ...props }: React.HTMLAttributes<HTMLParagraphElement>) => (
|
|
2092
|
+
// <p className="whitespace-pre-line" {...props} />
|
|
2093
|
+
// ),
|
|
2094
|
+
table: (_a) => {
|
|
1966
2095
|
var props = __objRest(_a, []);
|
|
1967
|
-
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", __spreadValues({ className: "whitespace-pre-line" }, props));
|
|
1968
|
-
},
|
|
1969
|
-
table: (_b) => {
|
|
1970
|
-
var props = __objRest(_b, []);
|
|
1971
2096
|
if (isStreaming) {
|
|
1972
2097
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "my-5 p-6 bg-slate-50 dark:bg-white/5 rounded-xl border border-dashed border-slate-300 dark:border-white/10 flex items-center justify-center gap-3 select-none", children: [
|
|
1973
2098
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "w-4 h-4 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }),
|
|
@@ -1981,8 +2106,8 @@ function createMarkdownComponents({
|
|
|
1981
2106
|
}, props)
|
|
1982
2107
|
) }) });
|
|
1983
2108
|
},
|
|
1984
|
-
thead: (
|
|
1985
|
-
var props = __objRest(
|
|
2109
|
+
thead: (_b) => {
|
|
2110
|
+
var props = __objRest(_b, []);
|
|
1986
2111
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1987
2112
|
"thead",
|
|
1988
2113
|
__spreadValues({
|
|
@@ -1990,12 +2115,12 @@ function createMarkdownComponents({
|
|
|
1990
2115
|
}, props)
|
|
1991
2116
|
);
|
|
1992
2117
|
},
|
|
1993
|
-
tbody: (
|
|
1994
|
-
var props = __objRest(
|
|
2118
|
+
tbody: (_c) => {
|
|
2119
|
+
var props = __objRest(_c, []);
|
|
1995
2120
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tbody", __spreadValues({ className: "!table-row-group divide-y divide-slate-100 dark:divide-white/5" }, props));
|
|
1996
2121
|
},
|
|
1997
|
-
tr: (
|
|
1998
|
-
var props = __objRest(
|
|
2122
|
+
tr: (_d) => {
|
|
2123
|
+
var props = __objRest(_d, []);
|
|
1999
2124
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2000
2125
|
"tr",
|
|
2001
2126
|
__spreadValues({
|
|
@@ -2003,8 +2128,8 @@ function createMarkdownComponents({
|
|
|
2003
2128
|
}, props)
|
|
2004
2129
|
);
|
|
2005
2130
|
},
|
|
2006
|
-
th: (
|
|
2007
|
-
var
|
|
2131
|
+
th: (_e) => {
|
|
2132
|
+
var _f = _e, { children } = _f, props = __objRest(_f, ["children"]);
|
|
2008
2133
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2009
2134
|
"th",
|
|
2010
2135
|
__spreadProps(__spreadValues({
|
|
@@ -2014,8 +2139,8 @@ function createMarkdownComponents({
|
|
|
2014
2139
|
})
|
|
2015
2140
|
);
|
|
2016
2141
|
},
|
|
2017
|
-
td: (
|
|
2018
|
-
var
|
|
2142
|
+
td: (_g) => {
|
|
2143
|
+
var _h = _g, { children } = _h, props = __objRest(_h, ["children"]);
|
|
2019
2144
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2020
2145
|
"td",
|
|
2021
2146
|
__spreadProps(__spreadValues({
|
|
@@ -2025,12 +2150,12 @@ function createMarkdownComponents({
|
|
|
2025
2150
|
})
|
|
2026
2151
|
);
|
|
2027
2152
|
},
|
|
2028
|
-
code(
|
|
2029
|
-
var
|
|
2153
|
+
code(_i) {
|
|
2154
|
+
var _j = _i, {
|
|
2030
2155
|
inline,
|
|
2031
2156
|
className,
|
|
2032
2157
|
children
|
|
2033
|
-
} =
|
|
2158
|
+
} = _j, props = __objRest(_j, [
|
|
2034
2159
|
"inline",
|
|
2035
2160
|
"className",
|
|
2036
2161
|
"children"
|
|
@@ -2080,6 +2205,16 @@ function normaliseChild(children) {
|
|
|
2080
2205
|
|
|
2081
2206
|
// src/components/MessageBubble.tsx
|
|
2082
2207
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
2208
|
+
function normalizePlusSeparatedLists(raw) {
|
|
2209
|
+
return raw.split("\n").map((line) => {
|
|
2210
|
+
const productListLine = /[—:]\s*\d+\s+\+\s+[A-Za-z]/.test(line) || /\b(products?|categories?|in stock|out of stock)\b/i.test(line);
|
|
2211
|
+
if (!productListLine) return line;
|
|
2212
|
+
return line.replace(/\s+\+\s+(?=[A-Za-z0-9])/g, ", ");
|
|
2213
|
+
}).join("\n");
|
|
2214
|
+
}
|
|
2215
|
+
function stripLeakedAnswerWrappers2(raw) {
|
|
2216
|
+
return raw.replace(/<prose\s+answer(?:\s+in\s+[^>]*)?>\s*([\s\S]*?)\s*<\/prose>/gi, "$1").replace(/<\/?prose(?:\s+answer)?[^>]*>/gi, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
2217
|
+
}
|
|
2083
2218
|
function MessageBubble({
|
|
2084
2219
|
message,
|
|
2085
2220
|
sources,
|
|
@@ -2089,11 +2224,22 @@ function MessageBubble({
|
|
|
2089
2224
|
onAddToCart,
|
|
2090
2225
|
viewportSize = "large"
|
|
2091
2226
|
}) {
|
|
2227
|
+
var _a;
|
|
2092
2228
|
const isUser = message.role === "user";
|
|
2093
2229
|
const isCompact = viewportSize === "compact";
|
|
2094
2230
|
const isMedium = viewportSize === "medium";
|
|
2095
2231
|
const [showSources, setShowSources] = import_react9.default.useState(false);
|
|
2096
2232
|
const [showTrace, setShowTrace] = import_react9.default.useState(false);
|
|
2233
|
+
const [copied, setCopied] = import_react9.default.useState(false);
|
|
2234
|
+
const handleCopy = import_react9.default.useCallback(async () => {
|
|
2235
|
+
try {
|
|
2236
|
+
await navigator.clipboard.writeText(message.content);
|
|
2237
|
+
setCopied(true);
|
|
2238
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
2239
|
+
} catch (err) {
|
|
2240
|
+
console.error("Failed to copy text:", err);
|
|
2241
|
+
}
|
|
2242
|
+
}, [message.content]);
|
|
2097
2243
|
const structuredContent = import_react9.default.useMemo(
|
|
2098
2244
|
() => isUser ? { payload: null, text: message.content } : extractStructuredPayload(message.content),
|
|
2099
2245
|
[isUser, message.content]
|
|
@@ -2108,6 +2254,10 @@ function MessageBubble({
|
|
|
2108
2254
|
}
|
|
2109
2255
|
return false;
|
|
2110
2256
|
}, [message.uiTransformation, structuredContent.payload]);
|
|
2257
|
+
const uiTransformationType = (_a = message.uiTransformation) == null ? void 0 : _a.type;
|
|
2258
|
+
const shouldSuppressProductCarousel = Boolean(
|
|
2259
|
+
uiTransformationType && !["text", "product_carousel", "carousel"].includes(uiTransformationType)
|
|
2260
|
+
);
|
|
2111
2261
|
const shouldRenderStructuredOnly = !isUser && hasRichUI && isLikelyUiOnlyMessage(structuredContent.text);
|
|
2112
2262
|
const productsFromSources = import_react9.default.useMemo(() => {
|
|
2113
2263
|
return extractProductsFromSources(sources, isUser);
|
|
@@ -2133,6 +2283,14 @@ function MessageBubble({
|
|
|
2133
2283
|
}, [productsFromSources, productsFromContent, message.content]);
|
|
2134
2284
|
const processedMarkdown = import_react9.default.useMemo(() => {
|
|
2135
2285
|
let raw = structuredContent.payload ? structuredContent.text : cleanContent || message.content;
|
|
2286
|
+
raw = raw.replace(/\$\s*(\d+)(?!\.\d)/g, "$1");
|
|
2287
|
+
raw = normalizePlusSeparatedLists(raw);
|
|
2288
|
+
raw = stripLeakedAnswerWrappers2(raw);
|
|
2289
|
+
raw = raw.replace(/\*\*([^*\n]+)\*\*(\s*[—\-–:]\s*)/g, "$1$2");
|
|
2290
|
+
raw = raw.split("\n").filter((line, idx, arr) => {
|
|
2291
|
+
const trimmed = line.trim();
|
|
2292
|
+
return !trimmed || arr.findIndex((l) => l.trim() === trimmed) === idx;
|
|
2293
|
+
}).join("\n");
|
|
2136
2294
|
const hasStructuredUiBlock = Boolean(structuredContent.payload) || /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|chartType|type|data|items|rows|products|results)"\s*:/i.test(raw);
|
|
2137
2295
|
raw = raw.replace(/([^\n])\n\|/g, "$1\n\n|").replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, "$1\n");
|
|
2138
2296
|
if (!isStreaming) {
|
|
@@ -2168,49 +2326,61 @@ ${match.trim()}
|
|
|
2168
2326
|
}
|
|
2169
2327
|
),
|
|
2170
2328
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `flex flex-col gap-1 min-w-0 ${isCompact ? "max-w-[94%]" : isMedium ? "max-w-[92%]" : "max-w-[90%]"} ${isUser ? "items-end" : "items-start"}`, children: [
|
|
2171
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.
|
|
2329
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
2172
2330
|
"div",
|
|
2173
2331
|
{
|
|
2174
|
-
className: `relative ${isCompact ? "px-3 py-2.5 text-[13px]" : "px-4 py-3 text-sm"} rounded-2xl leading-relaxed shadow-sm dark:shadow-lg ${isUser ? "text-white rounded-tr-sm" : "bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 text-slate-800 dark:text-white/90 rounded-tl-sm"}`,
|
|
2332
|
+
className: `relative group ${isCompact ? "px-3 py-2.5 text-[13px]" : "px-4 py-3 text-sm"} rounded-2xl leading-relaxed shadow-sm dark:shadow-lg ${isUser ? "text-white rounded-tr-sm" : "bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 text-slate-800 dark:text-white/90 rounded-tl-sm"}`,
|
|
2175
2333
|
style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {},
|
|
2176
|
-
children:
|
|
2177
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2178
|
-
|
|
2179
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })
|
|
2180
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `prose ${isCompact ? "prose-xs" : "prose-sm"} max-w-none break-words ${isUser ? "prose-invert" : "dark:prose-invert"}`, children: [
|
|
2181
|
-
!isUser && structuredContent.payload && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2182
|
-
UIDispatcher,
|
|
2334
|
+
children: [
|
|
2335
|
+
!isUser && !isStreaming && message.content && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2336
|
+
"button",
|
|
2183
2337
|
{
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
onAddToCart,
|
|
2189
|
-
viewportSize
|
|
2338
|
+
onClick: handleCopy,
|
|
2339
|
+
className: `absolute top-2 right-2 p-1.5 rounded-lg border transition-all duration-200 cursor-pointer ${copied ? "bg-emerald-500/10 border-emerald-500/20 text-emerald-500 dark:text-emerald-400" : "bg-slate-500/5 hover:bg-slate-500/10 border-slate-200 dark:border-white/10 text-slate-400 dark:text-white/30 hover:text-slate-600 dark:hover:text-white/60"} opacity-0 group-hover:opacity-100 backdrop-blur-sm shadow-sm scale-95 group-hover:scale-100`,
|
|
2340
|
+
title: copied ? "Copied!" : "Copy response",
|
|
2341
|
+
children: copied ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react6.Check, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react6.Copy, { className: "w-3.5 h-3.5" })
|
|
2190
2342
|
}
|
|
2191
2343
|
),
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2195
|
-
|
|
2344
|
+
isStreaming && !message.content ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "flex items-center gap-1 py-1", children: [
|
|
2345
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }),
|
|
2346
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }),
|
|
2347
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })
|
|
2348
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `prose ${isCompact ? "prose-xs" : "prose-sm"} max-w-none break-words ${isUser ? "prose-invert" : "dark:prose-invert"}`, children: [
|
|
2349
|
+
!isUser && structuredContent.payload && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2350
|
+
UIDispatcher,
|
|
2196
2351
|
{
|
|
2197
|
-
|
|
2352
|
+
rawContent: structuredContent.payload,
|
|
2198
2353
|
primaryColor,
|
|
2199
2354
|
accentColor,
|
|
2200
|
-
|
|
2355
|
+
isStreaming,
|
|
2356
|
+
onAddToCart,
|
|
2357
|
+
viewportSize
|
|
2201
2358
|
}
|
|
2202
2359
|
),
|
|
2203
|
-
|
|
2360
|
+
!shouldRenderStructuredOnly && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_markdown.default, { components: markdownComponents, children: processedMarkdown }),
|
|
2361
|
+
isStreaming && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "inline-flex items-center gap-1.5 ml-2 text-emerald-500 animate-pulse align-middle text-xs font-medium", children: [
|
|
2362
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2363
|
+
HourglassLoader_default,
|
|
2364
|
+
{
|
|
2365
|
+
size: 18,
|
|
2366
|
+
primaryColor,
|
|
2367
|
+
accentColor,
|
|
2368
|
+
glow: false
|
|
2369
|
+
}
|
|
2370
|
+
),
|
|
2371
|
+
"Thinking..."
|
|
2372
|
+
] })
|
|
2204
2373
|
] })
|
|
2205
|
-
]
|
|
2374
|
+
]
|
|
2206
2375
|
}
|
|
2207
2376
|
),
|
|
2208
2377
|
(() => {
|
|
2209
|
-
var
|
|
2378
|
+
var _a2, _b;
|
|
2210
2379
|
if (isUser || structuredContent.payload || !message.uiTransformation) return null;
|
|
2211
2380
|
const ui = message.uiTransformation;
|
|
2212
|
-
const textContent = (_b = (
|
|
2213
|
-
const
|
|
2381
|
+
const textContent = (_b = (_a2 = ui.data) == null ? void 0 : _a2.content) != null ? _b : "";
|
|
2382
|
+
const isNegativeOrFallbackText = textContent.toLowerCase().includes("cannot answer") || textContent.toLowerCase().includes("no relevant data") || textContent.toLowerCase().includes("no data available") || typeof ui.title === "string" && ui.title.toLowerCase().includes("no data") || typeof ui.description === "string" && ui.description.toLowerCase().includes("no relevant data");
|
|
2383
|
+
const shouldShow = !isNegativeOrFallbackText && (ui.type === "table" || !["text", "table"].includes(ui.type) || ui.type === "text" && !hasRichUI && allProducts.length === 0 && textContent && !processedMarkdown.toLowerCase().includes(textContent.trim().toLowerCase()));
|
|
2214
2384
|
if (!shouldShow) return null;
|
|
2215
2385
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "w-full mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2216
2386
|
VisualizationRenderer,
|
|
@@ -2223,7 +2393,7 @@ ${match.trim()}
|
|
|
2223
2393
|
}
|
|
2224
2394
|
) });
|
|
2225
2395
|
})(),
|
|
2226
|
-
!isUser && !hasRichUI && allProducts.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "w-full mt-1", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2396
|
+
!isUser && !hasRichUI && !shouldSuppressProductCarousel && allProducts.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "w-full mt-1", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2227
2397
|
ProductCarousel,
|
|
2228
2398
|
{
|
|
2229
2399
|
products: allProducts,
|
|
@@ -2332,6 +2502,7 @@ function useRagChat(projectId, options = {}) {
|
|
|
2332
2502
|
const [error, setError] = (0, import_react10.useState)(null);
|
|
2333
2503
|
const lastInputRef = (0, import_react10.useRef)("");
|
|
2334
2504
|
const messagesRef = (0, import_react10.useRef)(messages);
|
|
2505
|
+
const abortControllerRef = (0, import_react10.useRef)(null);
|
|
2335
2506
|
(0, import_react10.useEffect)(() => {
|
|
2336
2507
|
messagesRef.current = messages;
|
|
2337
2508
|
}, [messages]);
|
|
@@ -2352,11 +2523,17 @@ function useRagChat(projectId, options = {}) {
|
|
|
2352
2523
|
}
|
|
2353
2524
|
setError(null);
|
|
2354
2525
|
setIsLoading(true);
|
|
2526
|
+
if (abortControllerRef.current) {
|
|
2527
|
+
abortControllerRef.current.abort();
|
|
2528
|
+
}
|
|
2529
|
+
const controller = new AbortController();
|
|
2530
|
+
abortControllerRef.current = controller;
|
|
2355
2531
|
try {
|
|
2356
2532
|
const history = messagesRef.current.map(({ role, content }) => ({ role, content }));
|
|
2357
2533
|
const response = await fetch(apiUrl, {
|
|
2358
2534
|
method: "POST",
|
|
2359
2535
|
headers: { "Content-Type": "application/json" },
|
|
2536
|
+
signal: controller.signal,
|
|
2360
2537
|
body: JSON.stringify({
|
|
2361
2538
|
message: trimmed,
|
|
2362
2539
|
history,
|
|
@@ -2377,6 +2554,23 @@ function useRagChat(projectId, options = {}) {
|
|
|
2377
2554
|
let uiTransformation = null;
|
|
2378
2555
|
let trace;
|
|
2379
2556
|
let buffer = "";
|
|
2557
|
+
let pendingFlush = false;
|
|
2558
|
+
const pendingContentRef = { current: "" };
|
|
2559
|
+
const flushTextUpdate = (msgId) => {
|
|
2560
|
+
pendingFlush = false;
|
|
2561
|
+
const snapshot = pendingContentRef.current;
|
|
2562
|
+
setMessages(
|
|
2563
|
+
(prev) => prev.map(
|
|
2564
|
+
(msg) => msg.id === msgId ? __spreadProps(__spreadValues({}, msg), { content: snapshot }) : msg
|
|
2565
|
+
)
|
|
2566
|
+
);
|
|
2567
|
+
};
|
|
2568
|
+
const scheduleFlush = (msgId) => {
|
|
2569
|
+
if (!pendingFlush) {
|
|
2570
|
+
pendingFlush = true;
|
|
2571
|
+
requestAnimationFrame(() => flushTextUpdate(msgId));
|
|
2572
|
+
}
|
|
2573
|
+
};
|
|
2380
2574
|
const assistantMessageId = `assistant_${Date.now()}`;
|
|
2381
2575
|
setMessages((prev) => [
|
|
2382
2576
|
...prev,
|
|
@@ -2395,28 +2589,37 @@ function useRagChat(projectId, options = {}) {
|
|
|
2395
2589
|
if (lastBoundary === -1) continue;
|
|
2396
2590
|
const complete = buffer.slice(0, lastBoundary + 2);
|
|
2397
2591
|
buffer = buffer.slice(lastBoundary + 2);
|
|
2592
|
+
let hasNonTextFrame = false;
|
|
2398
2593
|
for (const frame of parseSseChunk(complete)) {
|
|
2399
2594
|
if (frame.type === "text" && frame.text) {
|
|
2400
2595
|
assistantContent += frame.text;
|
|
2596
|
+
pendingContentRef.current = assistantContent;
|
|
2597
|
+
scheduleFlush(assistantMessageId);
|
|
2401
2598
|
} else if (frame.type === "metadata") {
|
|
2402
2599
|
sources = (_a = frame.sources) != null ? _a : [];
|
|
2600
|
+
hasNonTextFrame = true;
|
|
2403
2601
|
} else if (frame.type === "ui_transformation") {
|
|
2404
2602
|
uiTransformation = frame.data;
|
|
2603
|
+
hasNonTextFrame = true;
|
|
2405
2604
|
} else if (frame.type === "observability") {
|
|
2406
2605
|
trace = frame.data;
|
|
2606
|
+
hasNonTextFrame = true;
|
|
2407
2607
|
} else if (frame.type === "error") {
|
|
2408
2608
|
setError(frame.error || "Stream error");
|
|
2409
2609
|
}
|
|
2410
2610
|
}
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2611
|
+
if (hasNonTextFrame) {
|
|
2612
|
+
pendingFlush = false;
|
|
2613
|
+
setMessages(
|
|
2614
|
+
(prev) => prev.map(
|
|
2615
|
+
(msg) => msg.id === assistantMessageId ? __spreadProps(__spreadValues({}, msg), {
|
|
2616
|
+
content: assistantContent,
|
|
2617
|
+
sources: sources.length > 0 ? sources : msg.sources,
|
|
2618
|
+
uiTransformation: uiTransformation || msg.uiTransformation
|
|
2619
|
+
}) : msg
|
|
2620
|
+
)
|
|
2621
|
+
);
|
|
2622
|
+
}
|
|
2420
2623
|
}
|
|
2421
2624
|
if (buffer.trim()) {
|
|
2422
2625
|
for (const frame of parseSseChunk(buffer)) {
|
|
@@ -2439,11 +2642,16 @@ function useRagChat(projectId, options = {}) {
|
|
|
2439
2642
|
);
|
|
2440
2643
|
onReply == null ? void 0 : onReply(finalMsg);
|
|
2441
2644
|
} catch (err) {
|
|
2645
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
2646
|
+
console.log("[useRagChat] Streaming stopped by user.");
|
|
2647
|
+
return;
|
|
2648
|
+
}
|
|
2442
2649
|
const msg = err instanceof Error ? err.message : "Something went wrong. Please try again.";
|
|
2443
2650
|
setError(msg);
|
|
2444
2651
|
onError == null ? void 0 : onError(msg);
|
|
2445
2652
|
} finally {
|
|
2446
2653
|
setIsLoading(false);
|
|
2654
|
+
abortControllerRef.current = null;
|
|
2447
2655
|
}
|
|
2448
2656
|
},
|
|
2449
2657
|
[apiUrl, isLoading, namespace, onError, onReply, projectId, setMessages]
|
|
@@ -2461,6 +2669,13 @@ function useRagChat(projectId, options = {}) {
|
|
|
2461
2669
|
});
|
|
2462
2670
|
}
|
|
2463
2671
|
}, [sendMessage]);
|
|
2672
|
+
const stop = (0, import_react10.useCallback)(() => {
|
|
2673
|
+
if (abortControllerRef.current) {
|
|
2674
|
+
abortControllerRef.current.abort();
|
|
2675
|
+
abortControllerRef.current = null;
|
|
2676
|
+
}
|
|
2677
|
+
setIsLoading(false);
|
|
2678
|
+
}, []);
|
|
2464
2679
|
return {
|
|
2465
2680
|
messages,
|
|
2466
2681
|
isLoading,
|
|
@@ -2468,7 +2683,8 @@ function useRagChat(projectId, options = {}) {
|
|
|
2468
2683
|
send: sendMessage,
|
|
2469
2684
|
clear,
|
|
2470
2685
|
retry,
|
|
2471
|
-
setMessages
|
|
2686
|
+
setMessages,
|
|
2687
|
+
stop
|
|
2472
2688
|
};
|
|
2473
2689
|
}
|
|
2474
2690
|
|
|
@@ -2494,7 +2710,7 @@ function ChatWindow({
|
|
|
2494
2710
|
const windowRef = (0, import_react11.useRef)(null);
|
|
2495
2711
|
const bottomRef = (0, import_react11.useRef)(null);
|
|
2496
2712
|
const inputRef = (0, import_react11.useRef)(null);
|
|
2497
|
-
const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
|
|
2713
|
+
const { messages, send, clear, isLoading, error, stop } = useRagChat(projectId, {
|
|
2498
2714
|
namespace: projectId
|
|
2499
2715
|
});
|
|
2500
2716
|
const [suggestions, setSuggestions] = (0, import_react11.useState)([]);
|
|
@@ -2858,14 +3074,22 @@ function ChatWindow({
|
|
|
2858
3074
|
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Paperclip, { className: "w-4 h-4" })
|
|
2859
3075
|
}
|
|
2860
3076
|
),
|
|
2861
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3077
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3078
|
+
"button",
|
|
3079
|
+
{
|
|
3080
|
+
onClick: stop,
|
|
3081
|
+
className: "flex-shrink-0 w-9 h-9 rounded-xl flex items-center justify-center transition-all hover:scale-105 active:scale-95 shadow-md bg-rose-500 hover:bg-rose-600 text-white cursor-pointer",
|
|
3082
|
+
title: "Stop generating",
|
|
3083
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "w-3.5 h-3.5 bg-white rounded-[2px]" })
|
|
3084
|
+
}
|
|
3085
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2862
3086
|
"button",
|
|
2863
3087
|
{
|
|
2864
3088
|
onClick: sendMessage,
|
|
2865
|
-
disabled: !input.trim()
|
|
3089
|
+
disabled: !input.trim(),
|
|
2866
3090
|
className: "flex-shrink-0 w-9 h-9 rounded-xl flex items-center justify-center transition-all disabled:opacity-30 disabled:cursor-not-allowed hover:scale-105 active:scale-95 shadow-md",
|
|
2867
3091
|
style: {
|
|
2868
|
-
background: input.trim()
|
|
3092
|
+
background: input.trim() ? `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` : "rgba(148, 163, 184, 0.2)"
|
|
2869
3093
|
// slate-400/20 for light mode disabled
|
|
2870
3094
|
},
|
|
2871
3095
|
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.ArrowUp, { className: "w-4 h-4 text-white" })
|