@retrivora-ai/rag-engine 1.8.0 → 1.8.1
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/DocumentChunker-Dh9TvmGG.d.mts +45 -0
- package/dist/DocumentChunker-Dh9TvmGG.d.ts +45 -0
- package/dist/{index-DPsQodME.d.mts → ILLMProvider-BfRgI1Xh.d.mts} +58 -1
- package/dist/{index-DPsQodME.d.ts → ILLMProvider-BfRgI1Xh.d.ts} +58 -1
- package/dist/MultiTablePostgresProvider-YY7LPNJK.mjs +8 -0
- package/dist/{chunk-PV3MFHWU.mjs → chunk-BFYLQYQU.mjs} +808 -439
- package/dist/chunk-R3RGUMHE.mjs +218 -0
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +995 -603
- package/dist/handlers/index.mjs +1 -1
- package/dist/{index-Bb2yEopi.d.mts → index-1Z4GuYBi.d.ts} +7 -1
- package/dist/{index-CkbTzj9J.d.ts → index-BV0z5mb6.d.mts} +7 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +491 -316
- package/dist/index.mjs +411 -217
- package/dist/server.d.mts +35 -5
- package/dist/server.d.ts +35 -5
- package/dist/server.js +1146 -777
- package/dist/server.mjs +163 -176
- package/package.json +4 -2
- package/src/app/page.tsx +1 -2
- package/src/components/MessageBubble.tsx +211 -69
- package/src/components/ProductCard.tsx +2 -2
- package/src/components/VisualizationRenderer.tsx +347 -247
- package/src/config/RagConfig.ts +5 -0
- package/src/config/serverConfig.ts +3 -1
- package/src/core/Pipeline.ts +65 -206
- package/src/core/ProviderRegistry.ts +2 -2
- package/src/core/VectorPlugin.ts +9 -0
- package/src/handlers/index.ts +23 -7
- package/src/hooks/useRagChat.ts +2 -2
- package/src/llm/LLMFactory.ts +54 -2
- package/src/llm/providers/AnthropicProvider.ts +12 -8
- package/src/llm/providers/GeminiProvider.ts +188 -143
- package/src/llm/providers/OllamaProvider.ts +7 -3
- package/src/llm/providers/OpenAIProvider.ts +12 -8
- package/src/types/chat.ts +6 -0
- package/src/types/index.ts +80 -0
- package/src/utils/SchemaMapper.ts +129 -0
- package/src/utils/UITransformer.ts +491 -181
- package/dist/DocumentChunker-C1GEEosY.d.ts +0 -93
- package/dist/DocumentChunker-CFEiRopR.d.mts +0 -93
- package/dist/PostgreSQLProvider-BMOETDZA.mjs +0 -8
- package/dist/chunk-FLOSGE6A.mjs +0 -202
package/dist/index.js
CHANGED
|
@@ -71,18 +71,17 @@ __export(index_exports, {
|
|
|
71
71
|
module.exports = __toCommonJS(index_exports);
|
|
72
72
|
|
|
73
73
|
// src/components/ChatWidget.tsx
|
|
74
|
-
var
|
|
74
|
+
var import_react10 = __toESM(require("react"));
|
|
75
75
|
var import_lucide_react6 = require("lucide-react");
|
|
76
76
|
|
|
77
77
|
// src/components/ChatWindow.tsx
|
|
78
|
-
var
|
|
78
|
+
var import_react9 = __toESM(require("react"));
|
|
79
79
|
var import_lucide_react5 = require("lucide-react");
|
|
80
80
|
|
|
81
81
|
// src/components/MessageBubble.tsx
|
|
82
|
-
var
|
|
82
|
+
var import_react6 = __toESM(require("react"));
|
|
83
83
|
var import_lucide_react4 = require("lucide-react");
|
|
84
84
|
var import_react_markdown = __toESM(require("react-markdown"));
|
|
85
|
-
var import_remark_gfm = __toESM(require("remark-gfm"));
|
|
86
85
|
|
|
87
86
|
// src/components/SourceCard.tsx
|
|
88
87
|
var import_react = __toESM(require("react"));
|
|
@@ -371,175 +370,232 @@ function DynamicChart({
|
|
|
371
370
|
}
|
|
372
371
|
|
|
373
372
|
// src/components/VisualizationRenderer.tsx
|
|
374
|
-
var
|
|
373
|
+
var import_react5 = __toESM(require("react"));
|
|
374
|
+
var import_recharts2 = require("recharts");
|
|
375
|
+
var CHART_COLORS = [
|
|
376
|
+
"#6366f1",
|
|
377
|
+
// indigo
|
|
378
|
+
"#10b981",
|
|
379
|
+
// emerald
|
|
380
|
+
"#f59e0b",
|
|
381
|
+
// amber
|
|
382
|
+
"#ef4444",
|
|
383
|
+
// red
|
|
384
|
+
"#8b5cf6",
|
|
385
|
+
// purple
|
|
386
|
+
"#ec4899",
|
|
387
|
+
// pink
|
|
388
|
+
"#06b6d4",
|
|
389
|
+
// cyan
|
|
390
|
+
"#f97316"
|
|
391
|
+
// orange
|
|
392
|
+
];
|
|
393
|
+
function getColor(index) {
|
|
394
|
+
return CHART_COLORS[index % CHART_COLORS.length];
|
|
395
|
+
}
|
|
396
|
+
function CustomTooltip({
|
|
397
|
+
active,
|
|
398
|
+
payload,
|
|
399
|
+
label
|
|
400
|
+
}) {
|
|
401
|
+
if (!active || !payload || payload.length === 0) return null;
|
|
402
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "rounded-xl border border-slate-200 bg-white px-3 py-2 text-xs shadow-xl dark:border-white/10 dark:bg-slate-950" }, label && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mb-2 font-semibold text-slate-800 dark:text-white/90" }, label), payload.map((entry, i) => /* @__PURE__ */ import_react5.default.createElement("div", { key: i, className: "flex items-center justify-between gap-3 text-slate-600 dark:text-white/70" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "flex items-center gap-1.5" }, entry.color && /* @__PURE__ */ import_react5.default.createElement(
|
|
403
|
+
"span",
|
|
404
|
+
{
|
|
405
|
+
className: "inline-block w-2 h-2 rounded-full flex-shrink-0",
|
|
406
|
+
style: { background: entry.color }
|
|
407
|
+
}
|
|
408
|
+
), entry.name), /* @__PURE__ */ import_react5.default.createElement("span", { className: "font-medium text-slate-900 dark:text-white/90" }, entry.value))));
|
|
409
|
+
}
|
|
375
410
|
function VisualizationRenderer({
|
|
376
411
|
data,
|
|
377
|
-
className = ""
|
|
412
|
+
className = "",
|
|
413
|
+
primaryColor,
|
|
414
|
+
onAddToCart
|
|
378
415
|
}) {
|
|
416
|
+
var _a;
|
|
379
417
|
if (!data) {
|
|
380
|
-
return /* @__PURE__ */
|
|
418
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: `p-4 text-gray-500 ${className}` }, "No data available for visualization");
|
|
381
419
|
}
|
|
382
|
-
return /* @__PURE__ */
|
|
420
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: `space-y-4 ${className}` }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react5.default.createElement("h3", { className: "text-sm font-semibold text-slate-900 dark:text-white" }, data.title), data.description && data.description !== ((_a = data.data) == null ? void 0 : _a.content) && /* @__PURE__ */ import_react5.default.createElement("p", { className: "text-xs text-slate-500 dark:text-slate-400" }, data.description)), renderVisualization(data.type, data.data, onAddToCart, primaryColor));
|
|
383
421
|
}
|
|
384
|
-
function renderVisualization(type, data) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
422
|
+
function renderVisualization(type, data, onAddToCart, primaryColor) {
|
|
423
|
+
try {
|
|
424
|
+
switch (type) {
|
|
425
|
+
case "pie_chart":
|
|
426
|
+
return /* @__PURE__ */ import_react5.default.createElement(PieChartView, { data });
|
|
427
|
+
case "bar_chart":
|
|
428
|
+
return /* @__PURE__ */ import_react5.default.createElement(BarChartView, { data, primaryColor });
|
|
429
|
+
case "line_chart":
|
|
430
|
+
return /* @__PURE__ */ import_react5.default.createElement(LineChartView, { data, primaryColor });
|
|
431
|
+
case "radar_chart":
|
|
432
|
+
return /* @__PURE__ */ import_react5.default.createElement(RadarChartView, { data });
|
|
433
|
+
case "table":
|
|
434
|
+
return /* @__PURE__ */ import_react5.default.createElement(TableView, { data });
|
|
435
|
+
case "product_carousel":
|
|
436
|
+
case "carousel":
|
|
437
|
+
return /* @__PURE__ */ import_react5.default.createElement(CarouselView, { data, onAddToCart, primaryColor });
|
|
438
|
+
case "text":
|
|
439
|
+
default:
|
|
440
|
+
return /* @__PURE__ */ import_react5.default.createElement(TextView, { data });
|
|
441
|
+
}
|
|
442
|
+
} catch (error) {
|
|
443
|
+
console.warn("[VisualizationRenderer] Rendering failed, falling back to text:", error);
|
|
444
|
+
return /* @__PURE__ */ import_react5.default.createElement(TextView, { data: { content: "Unable to render the requested visualization." } });
|
|
399
445
|
}
|
|
400
446
|
}
|
|
401
|
-
function
|
|
402
|
-
if (!Array.isArray(data)) {
|
|
403
|
-
return /* @__PURE__ */
|
|
447
|
+
function PieChartView({ data }) {
|
|
448
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
449
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid pie chart data");
|
|
404
450
|
}
|
|
405
|
-
|
|
406
|
-
|
|
451
|
+
const chartData = data.map((item) => ({
|
|
452
|
+
name: item.label,
|
|
453
|
+
value: item.value
|
|
454
|
+
}));
|
|
455
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm" }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.ResponsiveContainer, { width: "100%", height: 280 }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.PieChart, null, /* @__PURE__ */ import_react5.default.createElement(
|
|
456
|
+
import_recharts2.Pie,
|
|
407
457
|
{
|
|
408
|
-
|
|
409
|
-
|
|
458
|
+
data: chartData,
|
|
459
|
+
dataKey: "value",
|
|
460
|
+
nameKey: "name",
|
|
461
|
+
cx: "50%",
|
|
462
|
+
cy: "50%",
|
|
463
|
+
outerRadius: "68%",
|
|
464
|
+
label: false,
|
|
465
|
+
labelLine: false
|
|
410
466
|
},
|
|
411
|
-
/* @__PURE__ */
|
|
412
|
-
|
|
413
|
-
{
|
|
414
|
-
className: "w-3 h-3 rounded-full",
|
|
415
|
-
style: { backgroundColor: generateColor(idx) }
|
|
416
|
-
}
|
|
417
|
-
),
|
|
418
|
-
/* @__PURE__ */ React.createElement("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300" }, item.label, ": ", item.value),
|
|
419
|
-
item.inStock !== void 0 && /* @__PURE__ */ React.createElement(
|
|
420
|
-
"span",
|
|
421
|
-
{
|
|
422
|
-
className: `text-xs px-2 py-1 rounded ${item.inStock ? "bg-green-100 text-green-800" : "bg-red-100 text-red-800"}`
|
|
423
|
-
},
|
|
424
|
-
item.inStock ? "In Stock" : "Out of Stock"
|
|
425
|
-
)
|
|
426
|
-
))));
|
|
467
|
+
chartData.map((_entry, index) => /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Cell, { key: `cell-${index}`, fill: getColor(index) }))
|
|
468
|
+
), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Tooltip, { content: /* @__PURE__ */ import_react5.default.createElement(CustomTooltip, null) }), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Legend, { wrapperStyle: { fontSize: 12 }, verticalAlign: "bottom" }))));
|
|
427
469
|
}
|
|
428
|
-
function
|
|
429
|
-
if (!Array.isArray(data)) {
|
|
430
|
-
return /* @__PURE__ */
|
|
470
|
+
function BarChartView({ data, primaryColor }) {
|
|
471
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
472
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid bar chart data");
|
|
431
473
|
}
|
|
432
|
-
|
|
433
|
-
|
|
474
|
+
const chartData = data.map((item) => __spreadValues(__spreadValues({
|
|
475
|
+
category: item.category,
|
|
476
|
+
value: item.value
|
|
477
|
+
}, item.inStockCount !== void 0 && { inStockCount: item.inStockCount }), item.outOfStockCount !== void 0 && { outOfStockCount: item.outOfStockCount }));
|
|
478
|
+
const barColor = primaryColor != null ? primaryColor : getColor(0);
|
|
479
|
+
const hasStock = chartData.some((d) => "inStockCount" in d);
|
|
480
|
+
return /* @__PURE__ */ import_react5.default.createElement("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" }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.ResponsiveContainer, { width: "100%", height: 260 }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.BarChart, { data: chartData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react5.default.createElement(
|
|
481
|
+
import_recharts2.XAxis,
|
|
434
482
|
{
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
}
|
|
483
|
+
dataKey: "category",
|
|
484
|
+
tick: { fontSize: 11, fill: "#64748b" },
|
|
485
|
+
tickLine: false,
|
|
486
|
+
axisLine: { stroke: "#cbd5e1" }
|
|
440
487
|
}
|
|
441
|
-
)),
|
|
442
|
-
"span",
|
|
443
|
-
{
|
|
444
|
-
className: `text-xs px-2 py-1 rounded inline-block ${item.inStock ? "bg-green-100 text-green-800" : "bg-red-100 text-red-800"}`
|
|
445
|
-
},
|
|
446
|
-
item.inStock ? "In Stock" : "Out of Stock"
|
|
447
|
-
)))));
|
|
488
|
+
), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.YAxis, { tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Tooltip, { content: /* @__PURE__ */ import_react5.default.createElement(CustomTooltip, null), cursor: { fill: "#f1f5f9" } }), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Legend, { wrapperStyle: { fontSize: 12 } }), hasStock ? /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Bar, { dataKey: "inStockCount", name: "In Stock", fill: getColor(1), radius: [4, 4, 0, 0] }), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Bar, { dataKey: "outOfStockCount", name: "Out of Stock", fill: getColor(3), radius: [4, 4, 0, 0] })) : /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Bar, { dataKey: "value", name: "Value", fill: barColor, radius: [4, 4, 0, 0] }))));
|
|
448
489
|
}
|
|
449
|
-
function
|
|
450
|
-
if (!Array.isArray(data)) {
|
|
451
|
-
return /* @__PURE__ */
|
|
490
|
+
function LineChartView({ data, primaryColor }) {
|
|
491
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
492
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid line chart data");
|
|
452
493
|
}
|
|
453
|
-
|
|
454
|
-
|
|
494
|
+
const chartData = data.map((point) => {
|
|
495
|
+
var _a;
|
|
496
|
+
return {
|
|
497
|
+
label: String((_a = point.label) != null ? _a : point.timestamp),
|
|
498
|
+
value: Number(point.value)
|
|
499
|
+
};
|
|
500
|
+
});
|
|
501
|
+
const lineColor = primaryColor != null ? primaryColor : getColor(0);
|
|
502
|
+
return /* @__PURE__ */ import_react5.default.createElement("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" }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.ResponsiveContainer, { width: "100%", height: 260 }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.LineChart, { data: chartData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react5.default.createElement(
|
|
503
|
+
import_recharts2.XAxis,
|
|
455
504
|
{
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
505
|
+
dataKey: "label",
|
|
506
|
+
tick: { fontSize: 11, fill: "#64748b" },
|
|
507
|
+
tickLine: false,
|
|
508
|
+
axisLine: { stroke: "#cbd5e1" }
|
|
509
|
+
}
|
|
510
|
+
), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.YAxis, { tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Tooltip, { content: /* @__PURE__ */ import_react5.default.createElement(CustomTooltip, null) }), /* @__PURE__ */ import_react5.default.createElement(
|
|
511
|
+
import_recharts2.Line,
|
|
512
|
+
{
|
|
513
|
+
type: "monotone",
|
|
514
|
+
dataKey: "value",
|
|
515
|
+
name: "Value",
|
|
516
|
+
stroke: lineColor,
|
|
517
|
+
strokeWidth: 2.5,
|
|
518
|
+
dot: { r: 3.5, strokeWidth: 2, fill: lineColor },
|
|
519
|
+
activeDot: { r: 5 }
|
|
520
|
+
}
|
|
461
521
|
))));
|
|
462
522
|
}
|
|
463
|
-
function
|
|
464
|
-
if (!data
|
|
465
|
-
return /* @__PURE__ */
|
|
523
|
+
function RadarChartView({ data }) {
|
|
524
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
525
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid radar chart data");
|
|
466
526
|
}
|
|
467
|
-
|
|
527
|
+
const productNames = Array.from(
|
|
528
|
+
new Set(data.flatMap((item) => Object.keys(item).filter((key) => key !== "attribute")))
|
|
529
|
+
);
|
|
530
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm" }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.ResponsiveContainer, { width: "100%", height: 300 }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.RadarChart, { cx: "50%", cy: "50%", outerRadius: "80%", data }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.PolarGrid, { stroke: "#e2e8f0" }), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.PolarAngleAxis, { dataKey: "attribute", tick: { fontSize: 11, fill: "#64748b" } }), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.PolarRadiusAxis, { tick: { fontSize: 10, fill: "#64748b" } }), productNames.map((productName, index) => /* @__PURE__ */ import_react5.default.createElement(
|
|
531
|
+
import_recharts2.Radar,
|
|
532
|
+
{
|
|
533
|
+
key: productName,
|
|
534
|
+
name: productName,
|
|
535
|
+
dataKey: productName,
|
|
536
|
+
stroke: getColor(index),
|
|
537
|
+
fill: getColor(index),
|
|
538
|
+
fillOpacity: 0.4
|
|
539
|
+
}
|
|
540
|
+
)), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Tooltip, { content: /* @__PURE__ */ import_react5.default.createElement(CustomTooltip, null) }), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Legend, { wrapperStyle: { fontSize: 12 } }))));
|
|
541
|
+
}
|
|
542
|
+
function TableView({ data }) {
|
|
543
|
+
if (!(data == null ? void 0 : data.columns) || !(data == null ? void 0 : data.rows)) {
|
|
544
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid table data");
|
|
545
|
+
}
|
|
546
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ import_react5.default.createElement("table", { className: "w-full text-sm border-collapse" }, /* @__PURE__ */ import_react5.default.createElement("thead", { className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ import_react5.default.createElement("tr", null, data.columns.map((col, idx) => /* @__PURE__ */ import_react5.default.createElement(
|
|
468
547
|
"th",
|
|
469
548
|
{
|
|
470
549
|
key: idx,
|
|
471
|
-
className: "px-4 py-
|
|
550
|
+
className: "px-4 py-3 text-left text-xs font-semibold text-slate-700 dark:text-white/90 whitespace-nowrap uppercase tracking-wider"
|
|
472
551
|
},
|
|
473
552
|
col
|
|
474
|
-
)))), /* @__PURE__ */
|
|
553
|
+
)))), /* @__PURE__ */ import_react5.default.createElement("tbody", { className: "divide-y divide-slate-100 dark:divide-white/5" }, data.rows.map((row, rowIdx) => /* @__PURE__ */ import_react5.default.createElement(
|
|
475
554
|
"tr",
|
|
476
555
|
{
|
|
477
556
|
key: rowIdx,
|
|
478
|
-
className: "hover:bg-
|
|
557
|
+
className: "hover:bg-slate-50/60 dark:hover:bg-white/5 transition-colors"
|
|
479
558
|
},
|
|
480
|
-
row.map((cell, cellIdx) => /* @__PURE__ */
|
|
559
|
+
row.map((cell, cellIdx) => /* @__PURE__ */ import_react5.default.createElement(
|
|
481
560
|
"td",
|
|
482
561
|
{
|
|
483
562
|
key: cellIdx,
|
|
484
|
-
className: "px-4 py-
|
|
563
|
+
className: "px-4 py-3 text-slate-600 dark:text-white/70 text-sm"
|
|
485
564
|
},
|
|
486
565
|
String(cell)
|
|
487
566
|
))
|
|
488
|
-
)))));
|
|
567
|
+
))))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "px-4 py-2 bg-slate-50 dark:bg-white/5 border-t border-slate-100 dark:border-white/5" }, /* @__PURE__ */ import_react5.default.createElement("p", { className: "text-[11px] text-slate-400 dark:text-white/30" }, data.rows.length, " row", data.rows.length !== 1 ? "s" : "")));
|
|
489
568
|
}
|
|
490
|
-
function
|
|
569
|
+
function CarouselView({
|
|
570
|
+
data,
|
|
571
|
+
onAddToCart,
|
|
572
|
+
primaryColor
|
|
573
|
+
}) {
|
|
491
574
|
if (!Array.isArray(data)) {
|
|
492
|
-
return /* @__PURE__ */
|
|
575
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid carousel data");
|
|
493
576
|
}
|
|
494
|
-
|
|
495
|
-
|
|
577
|
+
const products = data.map((product) => ({
|
|
578
|
+
id: product.id,
|
|
579
|
+
name: product.name,
|
|
580
|
+
brand: product.brand,
|
|
581
|
+
price: product.price,
|
|
582
|
+
image: product.image,
|
|
583
|
+
link: typeof product.link === "string" ? product.link : void 0,
|
|
584
|
+
description: product.description,
|
|
585
|
+
inStock: product.inStock
|
|
586
|
+
}));
|
|
587
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "w-full" }, /* @__PURE__ */ import_react5.default.createElement(
|
|
588
|
+
ProductCarousel,
|
|
496
589
|
{
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
{
|
|
503
|
-
src: product.image,
|
|
504
|
-
alt: product.name,
|
|
505
|
-
fill: true,
|
|
506
|
-
className: "object-cover",
|
|
507
|
-
sizes: "(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
|
508
|
-
}
|
|
509
|
-
)),
|
|
510
|
-
/* @__PURE__ */ React.createElement("div", { className: "p-4 space-y-2" }, /* @__PURE__ */ React.createElement("h4", { className: "font-semibold text-gray-900 dark:text-white line-clamp-2" }, product.name), product.brand && /* @__PURE__ */ React.createElement("p", { className: "text-xs text-gray-500 dark:text-gray-400" }, "Brand: ", product.brand), product.price && /* @__PURE__ */ React.createElement("p", { className: "text-lg font-bold text-gray-900 dark:text-white" }, "$", typeof product.price === "number" ? product.price.toFixed(2) : product.price), product.description && /* @__PURE__ */ React.createElement("p", { className: "text-sm text-gray-600 dark:text-gray-400 line-clamp-2" }, product.description), /* @__PURE__ */ React.createElement("div", { className: "flex gap-2 pt-2" }, /* @__PURE__ */ React.createElement(
|
|
511
|
-
"span",
|
|
512
|
-
{
|
|
513
|
-
className: `text-xs px-2 py-1 rounded flex-1 text-center ${product.inStock ? "bg-green-100 text-green-800" : "bg-red-100 text-red-800"}`
|
|
514
|
-
},
|
|
515
|
-
product.inStock ? "In Stock" : "Out of Stock"
|
|
516
|
-
)))
|
|
517
|
-
))));
|
|
518
|
-
}
|
|
519
|
-
function renderText(data) {
|
|
520
|
-
const content = (data == null ? void 0 : data.content) || String(data);
|
|
521
|
-
return /* @__PURE__ */ React.createElement("div", { className: "bg-white dark:bg-gray-800 p-4 rounded-lg shadow prose dark:prose-invert max-w-none" }, /* @__PURE__ */ React.createElement("p", { className: "text-gray-700 dark:text-gray-300 whitespace-pre-wrap" }, content));
|
|
590
|
+
products,
|
|
591
|
+
primaryColor: primaryColor != null ? primaryColor : "#6366f1",
|
|
592
|
+
onAddToCart: (p) => onAddToCart == null ? void 0 : onAddToCart(p)
|
|
593
|
+
}
|
|
594
|
+
));
|
|
522
595
|
}
|
|
523
|
-
function
|
|
524
|
-
const
|
|
525
|
-
|
|
526
|
-
// blue
|
|
527
|
-
"#10B981",
|
|
528
|
-
// green
|
|
529
|
-
"#F59E0B",
|
|
530
|
-
// amber
|
|
531
|
-
"#EF4444",
|
|
532
|
-
// red
|
|
533
|
-
"#8B5CF6",
|
|
534
|
-
// purple
|
|
535
|
-
"#EC4899",
|
|
536
|
-
// pink
|
|
537
|
-
"#06B6D4",
|
|
538
|
-
// cyan
|
|
539
|
-
"#F97316"
|
|
540
|
-
// orange
|
|
541
|
-
];
|
|
542
|
-
return colors[index % colors.length];
|
|
596
|
+
function TextView({ data }) {
|
|
597
|
+
const content = (data == null ? void 0 : data.content) || String(data != null ? data : "");
|
|
598
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm" }, /* @__PURE__ */ import_react5.default.createElement("p", { className: "text-sm text-slate-700 dark:text-slate-300 whitespace-pre-wrap leading-relaxed" }, content));
|
|
543
599
|
}
|
|
544
600
|
|
|
545
601
|
// src/components/MessageBubble.tsx
|
|
@@ -623,41 +679,51 @@ function stripStructuredUiLabels(raw) {
|
|
|
623
679
|
);
|
|
624
680
|
}
|
|
625
681
|
function extractBareJsonObject(raw) {
|
|
626
|
-
|
|
682
|
+
let start = raw.indexOf("{");
|
|
627
683
|
if (start === -1) return null;
|
|
628
|
-
let
|
|
629
|
-
let
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
if (
|
|
650
|
-
|
|
684
|
+
let bestJson = null;
|
|
685
|
+
let maxLen = 0;
|
|
686
|
+
while (start !== -1) {
|
|
687
|
+
let depth = 0;
|
|
688
|
+
let inString = false;
|
|
689
|
+
let escape = false;
|
|
690
|
+
for (let i = start; i < raw.length; i += 1) {
|
|
691
|
+
const ch = raw[i];
|
|
692
|
+
if (escape) {
|
|
693
|
+
escape = false;
|
|
694
|
+
continue;
|
|
695
|
+
}
|
|
696
|
+
if (ch === "\\" && inString) {
|
|
697
|
+
escape = true;
|
|
698
|
+
continue;
|
|
699
|
+
}
|
|
700
|
+
if (ch === '"') {
|
|
701
|
+
inString = !inString;
|
|
702
|
+
continue;
|
|
703
|
+
}
|
|
704
|
+
if (inString) continue;
|
|
705
|
+
if (ch === "{") depth += 1;
|
|
706
|
+
else if (ch === "}") {
|
|
707
|
+
depth -= 1;
|
|
708
|
+
if (depth === 0) {
|
|
709
|
+
const candidate = raw.slice(start, i + 1);
|
|
710
|
+
if (candidate.length > maxLen) {
|
|
711
|
+
maxLen = candidate.length;
|
|
712
|
+
bestJson = candidate;
|
|
713
|
+
}
|
|
714
|
+
break;
|
|
715
|
+
}
|
|
651
716
|
}
|
|
652
717
|
}
|
|
718
|
+
start = raw.indexOf("{", start + 1);
|
|
653
719
|
}
|
|
654
|
-
return
|
|
720
|
+
return bestJson;
|
|
655
721
|
}
|
|
656
722
|
function extractStructuredPayload(raw) {
|
|
657
723
|
var _a, _b;
|
|
658
724
|
let working = raw;
|
|
659
725
|
const fenceRegex = /```(?:[a-z]+)?\s*([\s\S]*?)```/gi;
|
|
660
|
-
for (const match of raw.matchAll(fenceRegex)) {
|
|
726
|
+
for (const match of Array.from(raw.matchAll(fenceRegex))) {
|
|
661
727
|
const body = (_b = (_a = match[1]) == null ? void 0 : _a.trim()) != null ? _b : "";
|
|
662
728
|
if (!looksLikeStructuredPayload(body)) continue;
|
|
663
729
|
working = working.replace(match[0], "");
|
|
@@ -681,21 +747,30 @@ function extractStructuredPayload(raw) {
|
|
|
681
747
|
}
|
|
682
748
|
function isLikelyUiOnlyMessage(text) {
|
|
683
749
|
const trimmed = text.trim();
|
|
684
|
-
return trimmed.length === 0 || /^(chart data|table data|visualization|visual representation|product catalog|product recommendations|catalog summary)\s*:?\s*$/i.test(trimmed);
|
|
750
|
+
return trimmed.length === 0 || trimmed.length < 30 || /^(chart data|table data|visualization|visual representation|product catalog|product recommendations|catalog summary|availability|inventory status|details)\s*:?\s*$/i.test(trimmed);
|
|
685
751
|
}
|
|
686
752
|
function resolveImage(data) {
|
|
687
753
|
const isPlaceholder = (val) => typeof val === "string" && (val === "..." || val === "" || val.toLowerCase() === "null" || val.toLowerCase() === "undefined");
|
|
688
|
-
for (const key of ["image", "img", "thumbnail"]) {
|
|
754
|
+
for (const key of ["image", "img", "thumbnail", "images", "product_image", "Image", "Thumbnail"]) {
|
|
689
755
|
const v = data[key];
|
|
690
756
|
if (typeof v === "string" && v && !isPlaceholder(v)) return v;
|
|
691
|
-
|
|
692
|
-
if (Array.isArray(data.images) && typeof data.images[0] === "string" && !isPlaceholder(data.images[0])) {
|
|
693
|
-
return data.images[0];
|
|
757
|
+
if (Array.isArray(v) && typeof v[0] === "string" && v[0] && !isPlaceholder(v[0])) return v[0];
|
|
694
758
|
}
|
|
695
759
|
return void 0;
|
|
696
760
|
}
|
|
761
|
+
function getMetadataValue(meta, keys) {
|
|
762
|
+
const searchKeys = keys.map((k) => k.toLowerCase());
|
|
763
|
+
const metaKeys = Object.keys(meta);
|
|
764
|
+
const foundKey = metaKeys.find((k) => searchKeys.includes(k.toLowerCase()));
|
|
765
|
+
if (foundKey) return meta[foundKey];
|
|
766
|
+
const partialKey = metaKeys.find((k) => {
|
|
767
|
+
const kLow = k.toLowerCase();
|
|
768
|
+
return searchKeys.some((sk) => kLow.includes(sk) || sk.includes(kLow));
|
|
769
|
+
});
|
|
770
|
+
return partialKey ? meta[partialKey] : void 0;
|
|
771
|
+
}
|
|
697
772
|
function normaliseChild(children) {
|
|
698
|
-
if (typeof children === "object" && children !== null && !Array.isArray(children) && !
|
|
773
|
+
if (typeof children === "object" && children !== null && !Array.isArray(children) && !import_react6.default.isValidElement(children)) {
|
|
699
774
|
return JSON.stringify(children);
|
|
700
775
|
}
|
|
701
776
|
return children;
|
|
@@ -709,7 +784,7 @@ function formatColumnLabel(value) {
|
|
|
709
784
|
function DataTable({ config, viewportSize = "large" }) {
|
|
710
785
|
const isCompact = viewportSize === "compact";
|
|
711
786
|
const isMedium = viewportSize === "medium";
|
|
712
|
-
const columns =
|
|
787
|
+
const columns = import_react6.default.useMemo(() => {
|
|
713
788
|
const rowKeys = Array.from(
|
|
714
789
|
new Set(
|
|
715
790
|
config.data.flatMap((row) => Object.keys(row))
|
|
@@ -739,27 +814,27 @@ function DataTable({ config, viewportSize = "large" }) {
|
|
|
739
814
|
return rowKeys.map((key) => ({ label: formatColumnLabel(key), accessor: key }));
|
|
740
815
|
}, [config]);
|
|
741
816
|
if (!config.data.length || !columns.length) {
|
|
742
|
-
return /* @__PURE__ */
|
|
817
|
+
return /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-xs text-slate-400 italic my-2" }, "No data to display.");
|
|
743
818
|
}
|
|
744
819
|
const formatCell = (val) => {
|
|
745
820
|
if (val === null || val === void 0) return "\u2014";
|
|
746
821
|
if (typeof val === "boolean") return val ? "\u2713" : "\u2717";
|
|
747
822
|
return String(val);
|
|
748
823
|
};
|
|
749
|
-
return /* @__PURE__ */
|
|
824
|
+
return /* @__PURE__ */ import_react6.default.createElement("div", { className: "my-4 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden" }, config.title && /* @__PURE__ */ import_react6.default.createElement("div", { className: "px-4 py-2.5 bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-xs font-semibold text-slate-600 dark:text-white/70 uppercase tracking-wide" }, config.title)), /* @__PURE__ */ import_react6.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ import_react6.default.createElement("table", { className: `w-full text-left border-collapse ${isCompact ? "min-w-[240px] text-xs" : isMedium ? "min-w-[280px] text-[13px]" : "min-w-[320px] text-sm"}` }, /* @__PURE__ */ import_react6.default.createElement("thead", { className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ import_react6.default.createElement("tr", null, columns.map((column) => /* @__PURE__ */ import_react6.default.createElement(
|
|
750
825
|
"th",
|
|
751
826
|
{
|
|
752
827
|
key: column.label,
|
|
753
828
|
className: `${isCompact ? "px-2.5 py-2" : "px-4 py-3"} font-semibold text-slate-700 dark:text-white/90 whitespace-nowrap`
|
|
754
829
|
},
|
|
755
830
|
column.label
|
|
756
|
-
)))), /* @__PURE__ */
|
|
831
|
+
)))), /* @__PURE__ */ import_react6.default.createElement("tbody", null, config.data.map((row, ri) => /* @__PURE__ */ import_react6.default.createElement(
|
|
757
832
|
"tr",
|
|
758
833
|
{
|
|
759
834
|
key: ri,
|
|
760
835
|
className: "border-b border-slate-100 dark:border-white/5 last:border-0 hover:bg-slate-50/60 dark:hover:bg-white/5 transition-colors"
|
|
761
836
|
},
|
|
762
|
-
columns.map((column) => /* @__PURE__ */
|
|
837
|
+
columns.map((column) => /* @__PURE__ */ import_react6.default.createElement(
|
|
763
838
|
"td",
|
|
764
839
|
{
|
|
765
840
|
key: column.label,
|
|
@@ -767,10 +842,17 @@ function DataTable({ config, viewportSize = "large" }) {
|
|
|
767
842
|
},
|
|
768
843
|
formatCell(row[column.accessor])
|
|
769
844
|
))
|
|
770
|
-
))))), /* @__PURE__ */
|
|
845
|
+
))))), /* @__PURE__ */ import_react6.default.createElement("div", { className: "px-4 py-2 bg-slate-50 dark:bg-white/5 border-t border-slate-100 dark:border-white/5" }, /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-[11px] text-slate-400 dark:text-white/30" }, config.data.length, " row", config.data.length !== 1 ? "s" : "")));
|
|
771
846
|
}
|
|
772
847
|
function normalizeTabularRows(rows, columns) {
|
|
773
848
|
if (!Array.isArray(rows)) return [];
|
|
849
|
+
const SYNONYMS = {
|
|
850
|
+
name: ["product", "item", "title", "label", "heading", "product name", "item name"],
|
|
851
|
+
price: ["cost", "amount", "msrp", "price", "rate", "value", "price_usd"],
|
|
852
|
+
brand: ["manufacturer", "vendor", "make", "company", "brand_name", "supplier"],
|
|
853
|
+
image: ["imageUrl", "thumbnail", "img", "url", "photo", "picture", "media"],
|
|
854
|
+
stock: ["inventory", "quantity", "count", "availability", "stock_level", "in stock", "status"]
|
|
855
|
+
};
|
|
774
856
|
return rows.map((row) => {
|
|
775
857
|
if (Array.isArray(row)) {
|
|
776
858
|
const keys = Array.isArray(columns) && columns.length > 0 ? columns : row.map((_, index) => `column_${index + 1}`);
|
|
@@ -780,7 +862,36 @@ function normalizeTabularRows(rows, columns) {
|
|
|
780
862
|
}, {});
|
|
781
863
|
}
|
|
782
864
|
if (row && typeof row === "object") {
|
|
783
|
-
|
|
865
|
+
const result = __spreadValues({}, row);
|
|
866
|
+
if (Array.isArray(columns)) {
|
|
867
|
+
columns.forEach((col) => {
|
|
868
|
+
if (result[col] !== void 0) return;
|
|
869
|
+
const rowKeys = Object.keys(row);
|
|
870
|
+
const colLower = col.toLowerCase().replace(/_/g, " ");
|
|
871
|
+
const foundKey = rowKeys.find((rk) => {
|
|
872
|
+
const rkLower = rk.toLowerCase().replace(/_/g, " ");
|
|
873
|
+
return rkLower === colLower || rkLower.includes(colLower) || colLower.includes(rkLower);
|
|
874
|
+
});
|
|
875
|
+
if (foundKey) {
|
|
876
|
+
result[col] = row[foundKey];
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
for (const [target, aliases] of Object.entries(SYNONYMS)) {
|
|
880
|
+
const isMatch = target === colLower || aliases.some((a) => colLower.includes(a) || a.includes(colLower));
|
|
881
|
+
if (isMatch) {
|
|
882
|
+
const mappedKey = rowKeys.find((rk) => {
|
|
883
|
+
const rkL = rk.toLowerCase();
|
|
884
|
+
return rkL === target || aliases.some((a) => rkL.includes(a) || a.includes(rkL));
|
|
885
|
+
});
|
|
886
|
+
if (mappedKey) {
|
|
887
|
+
result[col] = row[mappedKey];
|
|
888
|
+
break;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
return result;
|
|
784
895
|
}
|
|
785
896
|
return { value: row };
|
|
786
897
|
}).filter((row) => Object.keys(row).length > 0);
|
|
@@ -800,7 +911,7 @@ function resolveStructuredRows(config) {
|
|
|
800
911
|
}
|
|
801
912
|
function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAddToCart, viewportSize = "large" }) {
|
|
802
913
|
var _a;
|
|
803
|
-
const result =
|
|
914
|
+
const result = import_react6.default.useMemo(() => {
|
|
804
915
|
if (isStreaming) return { loading: true };
|
|
805
916
|
try {
|
|
806
917
|
const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
|
|
@@ -845,10 +956,10 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
845
956
|
}
|
|
846
957
|
}, [rawContent, isStreaming]);
|
|
847
958
|
if ("loading" in result) {
|
|
848
|
-
return /* @__PURE__ */
|
|
959
|
+
return /* @__PURE__ */ import_react6.default.createElement("div", { className: "my-4 p-8 bg-slate-50 dark:bg-white/5 rounded-xl border border-dashed border-slate-300 dark:border-white/10 flex flex-col items-center justify-center gap-3 animate-pulse" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-5 h-5 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-xs text-slate-500 font-medium italic" }, "Preparing view..."));
|
|
849
960
|
}
|
|
850
961
|
if ("error" in result) {
|
|
851
|
-
return /* @__PURE__ */
|
|
962
|
+
return /* @__PURE__ */ import_react6.default.createElement("pre", { className: "p-4 my-2 bg-slate-900 text-slate-100 rounded-lg text-[10px] overflow-auto max-h-40" }, /* @__PURE__ */ import_react6.default.createElement("code", null, rawContent));
|
|
852
963
|
}
|
|
853
964
|
const { config } = result;
|
|
854
965
|
const isCompact = viewportSize === "compact";
|
|
@@ -856,7 +967,7 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
856
967
|
const hasDescription = typeof config.description === "string" && config.description.trim().length > 0;
|
|
857
968
|
switch (config.view) {
|
|
858
969
|
case "chart":
|
|
859
|
-
return /* @__PURE__ */
|
|
970
|
+
return /* @__PURE__ */ import_react6.default.createElement("div", { className: `${isCompact ? "my-4 p-3" : "my-6 p-4"} bg-white dark:bg-slate-900 rounded-2xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden` }, config.title && /* @__PURE__ */ import_react6.default.createElement("h4", { className: `${isCompact ? "text-[11px] mb-3" : "text-xs mb-4"} font-semibold text-slate-500 px-2` }, config.title), hasDescription && /* @__PURE__ */ import_react6.default.createElement("p", { className: `px-2 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react6.default.createElement(
|
|
860
971
|
DynamicChart,
|
|
861
972
|
{
|
|
862
973
|
config: {
|
|
@@ -870,7 +981,7 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
870
981
|
accentColor,
|
|
871
982
|
viewportSize
|
|
872
983
|
}
|
|
873
|
-
), hasInsights && /* @__PURE__ */
|
|
984
|
+
), hasInsights && /* @__PURE__ */ import_react6.default.createElement("div", { className: "mt-4 flex flex-wrap gap-2 px-2" }, (_a = config.insights) == null ? void 0 : _a.map((insight, i) => /* @__PURE__ */ import_react6.default.createElement(
|
|
874
985
|
"span",
|
|
875
986
|
{
|
|
876
987
|
key: `insight-${i}`,
|
|
@@ -879,14 +990,14 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
879
990
|
String(insight)
|
|
880
991
|
))));
|
|
881
992
|
case "carousel":
|
|
882
|
-
return /* @__PURE__ */
|
|
993
|
+
return /* @__PURE__ */ import_react6.default.createElement("div", { className: "my-4" }, config.title && /* @__PURE__ */ import_react6.default.createElement("h4", { className: `${isCompact ? "mb-1.5 text-[11px]" : "mb-2 text-xs"} font-semibold text-slate-500` }, config.title), hasDescription && /* @__PURE__ */ import_react6.default.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react6.default.createElement(ProductCarousel, { products: config.data.map((item) => {
|
|
883
994
|
var _a2;
|
|
884
995
|
return __spreadProps(__spreadValues({}, item), {
|
|
885
996
|
image: (_a2 = item.image) != null ? _a2 : typeof resolveImage === "function" ? resolveImage(item) : void 0
|
|
886
997
|
});
|
|
887
998
|
}), primaryColor, onAddToCart }));
|
|
888
999
|
case "table":
|
|
889
|
-
return /* @__PURE__ */
|
|
1000
|
+
return /* @__PURE__ */ import_react6.default.createElement("div", { className: `${isCompact ? "my-3 p-3 max-h-[320px]" : "my-4 p-4 max-h-[400px]"} bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-auto` }, config.title && /* @__PURE__ */ import_react6.default.createElement("h4", { className: `${isCompact ? "text-[11px]" : "text-xs"} font-semibold text-slate-500 mb-2` }, config.title), hasDescription && /* @__PURE__ */ import_react6.default.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react6.default.createElement(DataTable, { config: {
|
|
890
1001
|
type: "table",
|
|
891
1002
|
title: config.title,
|
|
892
1003
|
description: config.description,
|
|
@@ -911,44 +1022,59 @@ function MessageBubble({
|
|
|
911
1022
|
const isUser = message.role === "user";
|
|
912
1023
|
const isCompact = viewportSize === "compact";
|
|
913
1024
|
const isMedium = viewportSize === "medium";
|
|
914
|
-
const [showSources, setShowSources] =
|
|
915
|
-
const
|
|
916
|
-
() => /```(?:ui|json|chart)\s*[\s\S]*?"?(?:view|type|data|products)"?\s*:\s*"?(?:carousel|products|table)"?/i.test(message.content) || /\{[\s\S]*?"?(?:view|type|data|products)"?\s*:\s*"?(?:carousel|products)"?[\s\S]*\}/i.test(message.content) && looksLikeStructuredPayload(message.content),
|
|
917
|
-
[message.content]
|
|
918
|
-
);
|
|
919
|
-
const structuredContent = import_react5.default.useMemo(
|
|
1025
|
+
const [showSources, setShowSources] = import_react6.default.useState(false);
|
|
1026
|
+
const structuredContent = import_react6.default.useMemo(
|
|
920
1027
|
() => isUser ? { payload: null, text: message.content } : extractStructuredPayload(message.content),
|
|
921
1028
|
[isUser, message.content]
|
|
922
1029
|
);
|
|
923
|
-
const
|
|
924
|
-
|
|
1030
|
+
const hasRichUI = import_react6.default.useMemo(() => {
|
|
1031
|
+
if (message.uiTransformation) {
|
|
1032
|
+
const type = message.uiTransformation.type;
|
|
1033
|
+
if (type && !["text", "table"].includes(type)) return true;
|
|
1034
|
+
}
|
|
1035
|
+
if (structuredContent.payload) {
|
|
1036
|
+
return /"?(?:view|type|chartType)"?\s*:\s*"?(?:chart|carousel|pie|bar|line|product_carousel)"?/i.test(structuredContent.payload);
|
|
1037
|
+
}
|
|
1038
|
+
return false;
|
|
1039
|
+
}, [message.uiTransformation, structuredContent.payload]);
|
|
1040
|
+
const shouldRenderStructuredOnly = !isUser && hasRichUI && isLikelyUiOnlyMessage(structuredContent.text);
|
|
1041
|
+
const productsFromSources = import_react6.default.useMemo(() => {
|
|
925
1042
|
if (isUser || !sources) return [];
|
|
926
1043
|
return sources.filter((s) => {
|
|
927
1044
|
var _a;
|
|
928
1045
|
const m = (_a = s.metadata) != null ? _a : {};
|
|
929
|
-
|
|
1046
|
+
const keys = Object.keys(m).map((k) => k.toLowerCase());
|
|
1047
|
+
const hasProductKey = keys.some(
|
|
1048
|
+
(k) => ["price", "image", "img", "thumbnail", "images", "brand", "product", "sku", "category", "model", "cost"].includes(k)
|
|
1049
|
+
);
|
|
1050
|
+
const hasPricePattern = /\$\s*\d+/.test(s.content);
|
|
1051
|
+
return hasProductKey || hasPricePattern || m.type === "product";
|
|
930
1052
|
}).map((s) => {
|
|
931
|
-
var _a, _b
|
|
1053
|
+
var _a, _b;
|
|
932
1054
|
const m = (_a = s.metadata) != null ? _a : {};
|
|
1055
|
+
const name = getMetadataValue(m, ["name", "product", "title", "label", "item"]);
|
|
1056
|
+
const brand = getMetadataValue(m, ["brand", "manufacturer", "vendor", "make"]);
|
|
1057
|
+
const price = getMetadataValue(m, ["price", "cost", "amount", "msrp", "rate"]);
|
|
933
1058
|
return {
|
|
934
1059
|
id: s.id,
|
|
935
|
-
name: (
|
|
936
|
-
brand
|
|
937
|
-
price
|
|
1060
|
+
name: (_b = name != null ? name : s.content.split("\n")[0]) != null ? _b : "Unknown Product",
|
|
1061
|
+
brand,
|
|
1062
|
+
price,
|
|
938
1063
|
image: resolveImage(m),
|
|
939
|
-
link: m
|
|
1064
|
+
link: getMetadataValue(m, ["link", "url", "product_url"]),
|
|
940
1065
|
description: s.content
|
|
941
1066
|
};
|
|
942
1067
|
});
|
|
943
1068
|
}, [sources, isUser]);
|
|
944
|
-
const { productsFromContent, cleanContent } =
|
|
1069
|
+
const { productsFromContent, cleanContent } = import_react6.default.useMemo(() => {
|
|
1070
|
+
var _a, _b;
|
|
945
1071
|
if (isUser) {
|
|
946
1072
|
return { productsFromContent: [], cleanContent: message.content };
|
|
947
1073
|
}
|
|
948
1074
|
const jsonRegex = /```(?:json|ui)?\s*([\s\S]*?)\s*```/g;
|
|
949
1075
|
const products = [];
|
|
950
1076
|
let content = structuredContent.text;
|
|
951
|
-
const payloadCandidates = [structuredContent.payload, ...content.matchAll(jsonRegex).map((match) => match[1])].filter(Boolean);
|
|
1077
|
+
const payloadCandidates = [structuredContent.payload, ...Array.from(content.matchAll(jsonRegex)).map((match) => match[1])].filter(Boolean);
|
|
952
1078
|
for (const candidate of payloadCandidates) {
|
|
953
1079
|
try {
|
|
954
1080
|
const data = JSON.parse(sanitizeJson(candidate));
|
|
@@ -956,9 +1082,9 @@ function MessageBubble({
|
|
|
956
1082
|
if ((data.type === "products" || data.view === "carousel" || data.view === "table" || Array.isArray(data.products)) && itemSet) {
|
|
957
1083
|
products.push(
|
|
958
1084
|
...itemSet.map((item) => {
|
|
959
|
-
var
|
|
1085
|
+
var _a2;
|
|
960
1086
|
return __spreadProps(__spreadValues({}, item), {
|
|
961
|
-
image: (
|
|
1087
|
+
image: (_a2 = item.image) != null ? _a2 : resolveImage(item)
|
|
962
1088
|
});
|
|
963
1089
|
})
|
|
964
1090
|
);
|
|
@@ -967,15 +1093,15 @@ function MessageBubble({
|
|
|
967
1093
|
}
|
|
968
1094
|
}
|
|
969
1095
|
if (content.includes('"type": "products"') || content.includes('"type":"products"')) {
|
|
970
|
-
for (const match of content.matchAll(jsonRegex)) {
|
|
1096
|
+
for (const match of Array.from(content.matchAll(jsonRegex))) {
|
|
971
1097
|
try {
|
|
972
1098
|
const data = JSON.parse(sanitizeJson(match[1]));
|
|
973
1099
|
if (data.type === "products" && Array.isArray(data.items)) {
|
|
974
1100
|
products.push(
|
|
975
1101
|
...data.items.map((item) => {
|
|
976
|
-
var
|
|
1102
|
+
var _a2;
|
|
977
1103
|
return __spreadProps(__spreadValues({}, item), {
|
|
978
|
-
image: (
|
|
1104
|
+
image: (_a2 = item.image) != null ? _a2 : resolveImage(item)
|
|
979
1105
|
});
|
|
980
1106
|
})
|
|
981
1107
|
);
|
|
@@ -985,9 +1111,42 @@ function MessageBubble({
|
|
|
985
1111
|
}
|
|
986
1112
|
}
|
|
987
1113
|
}
|
|
1114
|
+
const bulletRegex = /(?:[•*-]\s*)?([^•\n\-\$*–—\(]+?)(?:\s*\(?Price\s*[:\-–—]?\s*)?(?:\s*[:\-–—]\s*|\s+)\$?([\d,.]+)(?:\s*USD)?/gi;
|
|
1115
|
+
const matches = Array.from(content.matchAll(bulletRegex));
|
|
1116
|
+
if (matches.length >= 2) {
|
|
1117
|
+
const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1118
|
+
for (const match of matches) {
|
|
1119
|
+
let name = ((_a = match[1]) == null ? void 0 : _a.trim()) || "";
|
|
1120
|
+
name = name.replace(/\s*\(?Price\s*$/i, "").replace(/[:\-–—]\s*$/g, "").trim();
|
|
1121
|
+
let price = ((_b = match[2]) == null ? void 0 : _b.trim()) || "";
|
|
1122
|
+
price = price.replace(/[,\s]+$/, "").trim();
|
|
1123
|
+
if (name && price) {
|
|
1124
|
+
const newProduct = {
|
|
1125
|
+
id: `text-prod-${name}-${price}`,
|
|
1126
|
+
name,
|
|
1127
|
+
price: `$${price}`
|
|
1128
|
+
};
|
|
1129
|
+
const normName = normalize(name);
|
|
1130
|
+
const sourceMatch = productsFromSources.find((s) => {
|
|
1131
|
+
const sn = normalize(s.name);
|
|
1132
|
+
return sn.includes(normName) || normName.includes(sn);
|
|
1133
|
+
});
|
|
1134
|
+
if (sourceMatch) {
|
|
1135
|
+
newProduct.image = sourceMatch.image;
|
|
1136
|
+
newProduct.brand = sourceMatch.brand;
|
|
1137
|
+
newProduct.link = sourceMatch.link;
|
|
1138
|
+
newProduct.description = sourceMatch.description;
|
|
1139
|
+
}
|
|
1140
|
+
products.push(newProduct);
|
|
1141
|
+
content = content.replace(match[0], `
|
|
1142
|
+
**${name}** \u2014 $${price}`);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
content = content.replace(/\n{3,}/g, "\n\n").trim();
|
|
1146
|
+
}
|
|
988
1147
|
return { productsFromContent: products, cleanContent: content.trim() };
|
|
989
|
-
}, [message.content, isUser, structuredContent]);
|
|
990
|
-
const allProducts =
|
|
1148
|
+
}, [message.content, isUser, structuredContent, productsFromSources]);
|
|
1149
|
+
const allProducts = import_react6.default.useMemo(() => {
|
|
991
1150
|
if (productsFromContent.length > 0) return productsFromContent;
|
|
992
1151
|
const seen = /* @__PURE__ */ new Set();
|
|
993
1152
|
const contentLower = message.content.toLowerCase();
|
|
@@ -1003,7 +1162,7 @@ function MessageBubble({
|
|
|
1003
1162
|
return false;
|
|
1004
1163
|
});
|
|
1005
1164
|
}, [productsFromSources, productsFromContent, message.content]);
|
|
1006
|
-
const processedMarkdown =
|
|
1165
|
+
const processedMarkdown = import_react6.default.useMemo(() => {
|
|
1007
1166
|
let raw = structuredContent.payload ? structuredContent.text : cleanContent || message.content;
|
|
1008
1167
|
const hasStructuredUiBlock = Boolean(structuredContent.payload) || /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|chartType|type|data|items|rows|products|results)"\s*:/i.test(raw);
|
|
1009
1168
|
raw = raw.replace(/([^\n])\n\|/g, "$1\n\n|").replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, "$1\n");
|
|
@@ -1037,16 +1196,16 @@ ${match.trim()}
|
|
|
1037
1196
|
}
|
|
1038
1197
|
return raw;
|
|
1039
1198
|
}, [cleanContent, message.content, isStreaming, structuredContent]);
|
|
1040
|
-
const markdownComponents =
|
|
1199
|
+
const markdownComponents = import_react6.default.useMemo(
|
|
1041
1200
|
() => ({
|
|
1042
1201
|
// Wrap in not-prose so Tailwind Typography resets don't clobber our styles.
|
|
1043
1202
|
// prose applies display:block and padding:0 to table/th/td — not-prose opts out.
|
|
1044
1203
|
table: (_a) => {
|
|
1045
1204
|
var props = __objRest(_a, []);
|
|
1046
1205
|
if (isStreaming) {
|
|
1047
|
-
return /* @__PURE__ */
|
|
1206
|
+
return /* @__PURE__ */ import_react6.default.createElement("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" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-4 h-4 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-xs text-slate-500 font-medium italic animate-pulse" }, "Generating data table..."));
|
|
1048
1207
|
}
|
|
1049
|
-
return /* @__PURE__ */
|
|
1208
|
+
return /* @__PURE__ */ import_react6.default.createElement("div", { className: "not-prose overflow-hidden my-5 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm bg-white dark:bg-slate-900/50" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ import_react6.default.createElement(
|
|
1050
1209
|
"table",
|
|
1051
1210
|
__spreadValues({
|
|
1052
1211
|
className: "!table w-full text-left border-collapse min-w-[400px] text-sm"
|
|
@@ -1055,7 +1214,7 @@ ${match.trim()}
|
|
|
1055
1214
|
},
|
|
1056
1215
|
thead: (_b) => {
|
|
1057
1216
|
var props = __objRest(_b, []);
|
|
1058
|
-
return /* @__PURE__ */
|
|
1217
|
+
return /* @__PURE__ */ import_react6.default.createElement(
|
|
1059
1218
|
"thead",
|
|
1060
1219
|
__spreadValues({
|
|
1061
1220
|
className: "!table-header-group bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10"
|
|
@@ -1064,11 +1223,11 @@ ${match.trim()}
|
|
|
1064
1223
|
},
|
|
1065
1224
|
tbody: (_c) => {
|
|
1066
1225
|
var props = __objRest(_c, []);
|
|
1067
|
-
return /* @__PURE__ */
|
|
1226
|
+
return /* @__PURE__ */ import_react6.default.createElement("tbody", __spreadValues({ className: "!table-row-group divide-y divide-slate-100 dark:divide-white/5" }, props));
|
|
1068
1227
|
},
|
|
1069
1228
|
tr: (_d) => {
|
|
1070
1229
|
var props = __objRest(_d, []);
|
|
1071
|
-
return /* @__PURE__ */
|
|
1230
|
+
return /* @__PURE__ */ import_react6.default.createElement(
|
|
1072
1231
|
"tr",
|
|
1073
1232
|
__spreadValues({
|
|
1074
1233
|
className: "!table-row hover:bg-slate-50/70 dark:hover:bg-white/5 transition-colors"
|
|
@@ -1077,7 +1236,7 @@ ${match.trim()}
|
|
|
1077
1236
|
},
|
|
1078
1237
|
th: (_e) => {
|
|
1079
1238
|
var _f = _e, { children } = _f, props = __objRest(_f, ["children"]);
|
|
1080
|
-
return /* @__PURE__ */
|
|
1239
|
+
return /* @__PURE__ */ import_react6.default.createElement(
|
|
1081
1240
|
"th",
|
|
1082
1241
|
__spreadValues({
|
|
1083
1242
|
className: "!table-cell px-4 py-3 font-bold text-slate-700 dark:text-white/90 whitespace-nowrap text-[11px] uppercase tracking-wider text-left"
|
|
@@ -1087,7 +1246,7 @@ ${match.trim()}
|
|
|
1087
1246
|
},
|
|
1088
1247
|
td: (_g) => {
|
|
1089
1248
|
var _h = _g, { children } = _h, props = __objRest(_h, ["children"]);
|
|
1090
|
-
return /* @__PURE__ */
|
|
1249
|
+
return /* @__PURE__ */ import_react6.default.createElement(
|
|
1091
1250
|
"td",
|
|
1092
1251
|
__spreadValues({
|
|
1093
1252
|
className: "!table-cell px-4 py-3 text-slate-600 dark:text-white/70 whitespace-nowrap text-sm"
|
|
@@ -1108,7 +1267,7 @@ ${match.trim()}
|
|
|
1108
1267
|
var _a;
|
|
1109
1268
|
const lang = (_a = /language-(\w+)/.exec(className != null ? className : "")) == null ? void 0 : _a[1];
|
|
1110
1269
|
if (!inline && (lang === "ui" || lang === "chart")) {
|
|
1111
|
-
return /* @__PURE__ */
|
|
1270
|
+
return /* @__PURE__ */ import_react6.default.createElement(
|
|
1112
1271
|
UIDispatcher,
|
|
1113
1272
|
{
|
|
1114
1273
|
rawContent: String(children != null ? children : "").trim(),
|
|
@@ -1123,7 +1282,7 @@ ${match.trim()}
|
|
|
1123
1282
|
if (!inline && lang === "json") {
|
|
1124
1283
|
const content = String(children != null ? children : "").trim();
|
|
1125
1284
|
if (looksLikeStructuredPayload(content)) {
|
|
1126
|
-
return /* @__PURE__ */
|
|
1285
|
+
return /* @__PURE__ */ import_react6.default.createElement(
|
|
1127
1286
|
UIDispatcher,
|
|
1128
1287
|
{
|
|
1129
1288
|
rawContent: content,
|
|
@@ -1139,7 +1298,7 @@ ${match.trim()}
|
|
|
1139
1298
|
if (!inline) {
|
|
1140
1299
|
const content = String(children != null ? children : "").trim();
|
|
1141
1300
|
if (looksLikeStructuredPayload(content)) {
|
|
1142
|
-
return /* @__PURE__ */
|
|
1301
|
+
return /* @__PURE__ */ import_react6.default.createElement(
|
|
1143
1302
|
UIDispatcher,
|
|
1144
1303
|
{
|
|
1145
1304
|
rawContent: content,
|
|
@@ -1153,27 +1312,27 @@ ${match.trim()}
|
|
|
1153
1312
|
}
|
|
1154
1313
|
}
|
|
1155
1314
|
if (!inline && lang === "table-loading") {
|
|
1156
|
-
return /* @__PURE__ */
|
|
1315
|
+
return /* @__PURE__ */ import_react6.default.createElement("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" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-4 h-4 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-xs text-slate-500 font-medium italic animate-pulse" }, "Generating data table..."));
|
|
1157
1316
|
}
|
|
1158
|
-
return /* @__PURE__ */
|
|
1317
|
+
return /* @__PURE__ */ import_react6.default.createElement("code", __spreadValues({ className }, props), typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children));
|
|
1159
1318
|
}
|
|
1160
1319
|
}),
|
|
1161
1320
|
[primaryColor, accentColor, isStreaming, onAddToCart, viewportSize]
|
|
1162
1321
|
);
|
|
1163
|
-
return /* @__PURE__ */
|
|
1322
|
+
return /* @__PURE__ */ import_react6.default.createElement("div", { className: `flex ${isCompact ? "gap-2" : "gap-3"} ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ import_react6.default.createElement(
|
|
1164
1323
|
"div",
|
|
1165
1324
|
{
|
|
1166
1325
|
className: `flex-shrink-0 ${isCompact ? "w-7 h-7" : "w-8 h-8"} rounded-full flex items-center justify-center shadow-lg ${isUser ? "text-white" : "bg-slate-100 dark:bg-white/10 text-slate-700 dark:text-white/80"}`,
|
|
1167
1326
|
style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
|
|
1168
1327
|
},
|
|
1169
|
-
isUser ? /* @__PURE__ */
|
|
1170
|
-
), /* @__PURE__ */
|
|
1328
|
+
isUser ? /* @__PURE__ */ import_react6.default.createElement(import_lucide_react4.User, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"} text-white` }) : /* @__PURE__ */ import_react6.default.createElement(import_lucide_react4.Bot, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"}` })
|
|
1329
|
+
), /* @__PURE__ */ import_react6.default.createElement("div", { className: `flex flex-col gap-1 ${isCompact ? "max-w-[94%]" : isMedium ? "max-w-[92%]" : "max-w-[90%]"} ${isUser ? "items-end" : "items-start"}` }, /* @__PURE__ */ import_react6.default.createElement(
|
|
1171
1330
|
"div",
|
|
1172
1331
|
{
|
|
1173
1332
|
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"}`,
|
|
1174
1333
|
style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
|
|
1175
1334
|
},
|
|
1176
|
-
isStreaming && !message.content ? /* @__PURE__ */
|
|
1335
|
+
isStreaming && !message.content ? /* @__PURE__ */ import_react6.default.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }), /* @__PURE__ */ import_react6.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }), /* @__PURE__ */ import_react6.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })) : /* @__PURE__ */ import_react6.default.createElement("div", { className: `prose ${isCompact ? "prose-xs" : "prose-sm"} max-w-none break-words ${isUser ? "prose-invert" : "dark:prose-invert"}` }, !isUser && structuredContent.payload && /* @__PURE__ */ import_react6.default.createElement(
|
|
1177
1336
|
UIDispatcher,
|
|
1178
1337
|
{
|
|
1179
1338
|
rawContent: structuredContent.payload,
|
|
@@ -1183,30 +1342,46 @@ ${match.trim()}
|
|
|
1183
1342
|
onAddToCart,
|
|
1184
1343
|
viewportSize
|
|
1185
1344
|
}
|
|
1186
|
-
), !shouldRenderStructuredOnly && /* @__PURE__ */
|
|
1187
|
-
),
|
|
1345
|
+
), !shouldRenderStructuredOnly && /* @__PURE__ */ import_react6.default.createElement(import_react_markdown.default, { components: markdownComponents }, processedMarkdown), isStreaming && message.content && /* @__PURE__ */ import_react6.default.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
|
|
1346
|
+
), (() => {
|
|
1347
|
+
var _a, _b;
|
|
1348
|
+
if (isUser || structuredContent.payload || !message.uiTransformation) return null;
|
|
1349
|
+
const ui = message.uiTransformation;
|
|
1350
|
+
const textContent = (_b = (_a = ui.data) == null ? void 0 : _a.content) != null ? _b : "";
|
|
1351
|
+
const shouldShow = ui.type === "table" && allProducts.length === 0 || !["text", "table"].includes(ui.type) || ui.type === "text" && !hasRichUI && allProducts.length === 0 && textContent && !processedMarkdown.toLowerCase().includes(textContent.trim().toLowerCase());
|
|
1352
|
+
if (!shouldShow) return null;
|
|
1353
|
+
return /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-full mt-3" }, /* @__PURE__ */ import_react6.default.createElement(
|
|
1354
|
+
VisualizationRenderer,
|
|
1355
|
+
{
|
|
1356
|
+
data: ui,
|
|
1357
|
+
primaryColor,
|
|
1358
|
+
onAddToCart,
|
|
1359
|
+
className: "rounded-3xl border border-slate-200/60 dark:border-white/10 bg-white/90 dark:bg-slate-900/80 p-4"
|
|
1360
|
+
}
|
|
1361
|
+
));
|
|
1362
|
+
})(), !isUser && !hasRichUI && allProducts.length > 0 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ import_react6.default.createElement(
|
|
1188
1363
|
ProductCarousel,
|
|
1189
1364
|
{
|
|
1190
1365
|
products: allProducts,
|
|
1191
1366
|
primaryColor,
|
|
1192
1367
|
onAddToCart
|
|
1193
1368
|
}
|
|
1194
|
-
)), !isUser && sources && sources.length > 0 && /* @__PURE__ */
|
|
1369
|
+
)), !isUser && sources && sources.length > 0 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-full" }, /* @__PURE__ */ import_react6.default.createElement(
|
|
1195
1370
|
"button",
|
|
1196
1371
|
{
|
|
1197
1372
|
onClick: () => setShowSources((s) => !s),
|
|
1198
1373
|
className: "text-[11px] text-indigo-400 hover:text-indigo-300 transition-colors flex items-center gap-1 mt-1"
|
|
1199
1374
|
},
|
|
1200
|
-
showSources ? /* @__PURE__ */
|
|
1375
|
+
showSources ? /* @__PURE__ */ import_react6.default.createElement(import_lucide_react4.ChevronDown, { className: "w-3 h-3" }) : /* @__PURE__ */ import_react6.default.createElement(import_lucide_react4.ChevronRight, { className: "w-3 h-3" }),
|
|
1201
1376
|
sources.length,
|
|
1202
1377
|
" source",
|
|
1203
1378
|
sources.length !== 1 ? "s" : "",
|
|
1204
1379
|
" used"
|
|
1205
|
-
), showSources && /* @__PURE__ */
|
|
1380
|
+
), showSources && /* @__PURE__ */ import_react6.default.createElement("div", { className: "mt-2 flex flex-col gap-2" }, sources.map((src, i) => /* @__PURE__ */ import_react6.default.createElement(SourceCard, { key: src.id, source: src, index: i }))))));
|
|
1206
1381
|
}
|
|
1207
1382
|
|
|
1208
1383
|
// src/components/ConfigProvider.tsx
|
|
1209
|
-
var
|
|
1384
|
+
var import_react7 = __toESM(require("react"));
|
|
1210
1385
|
|
|
1211
1386
|
// src/utils/templateUtils.ts
|
|
1212
1387
|
function mergeDefined(base, override) {
|
|
@@ -1258,7 +1433,7 @@ var CHAT_SUGGESTIONS = [
|
|
|
1258
1433
|
];
|
|
1259
1434
|
|
|
1260
1435
|
// src/components/ConfigProvider.tsx
|
|
1261
|
-
var ConfigContext = (0,
|
|
1436
|
+
var ConfigContext = (0, import_react7.createContext)(DEFAULT_CONFIG);
|
|
1262
1437
|
function ConfigProvider({
|
|
1263
1438
|
config,
|
|
1264
1439
|
children
|
|
@@ -1267,14 +1442,14 @@ function ConfigProvider({
|
|
|
1267
1442
|
projectId: (config == null ? void 0 : config.projectId) || DEFAULT_CONFIG.projectId,
|
|
1268
1443
|
ui: mergeDefined(DEFAULT_CONFIG.ui, config == null ? void 0 : config.ui)
|
|
1269
1444
|
};
|
|
1270
|
-
return /* @__PURE__ */
|
|
1445
|
+
return /* @__PURE__ */ import_react7.default.createElement(ConfigContext.Provider, { value: merged }, children);
|
|
1271
1446
|
}
|
|
1272
1447
|
function useConfig() {
|
|
1273
|
-
return (0,
|
|
1448
|
+
return (0, import_react7.useContext)(ConfigContext);
|
|
1274
1449
|
}
|
|
1275
1450
|
|
|
1276
1451
|
// src/hooks/useRagChat.ts
|
|
1277
|
-
var
|
|
1452
|
+
var import_react8 = require("react");
|
|
1278
1453
|
|
|
1279
1454
|
// src/hooks/useStoredMessages.ts
|
|
1280
1455
|
var React8 = __toESM(require("react"));
|
|
@@ -1335,14 +1510,14 @@ function useRagChat(projectId, options = {}) {
|
|
|
1335
1510
|
} = options;
|
|
1336
1511
|
const storageKey = `rag_chat_${projectId}`;
|
|
1337
1512
|
const [messages, setMessages] = useStoredMessages(storageKey, persist);
|
|
1338
|
-
const [isLoading, setIsLoading] = (0,
|
|
1339
|
-
const [error, setError] = (0,
|
|
1340
|
-
const lastInputRef = (0,
|
|
1341
|
-
const messagesRef = (0,
|
|
1342
|
-
(0,
|
|
1513
|
+
const [isLoading, setIsLoading] = (0, import_react8.useState)(false);
|
|
1514
|
+
const [error, setError] = (0, import_react8.useState)(null);
|
|
1515
|
+
const lastInputRef = (0, import_react8.useRef)("");
|
|
1516
|
+
const messagesRef = (0, import_react8.useRef)(messages);
|
|
1517
|
+
(0, import_react8.useEffect)(() => {
|
|
1343
1518
|
messagesRef.current = messages;
|
|
1344
1519
|
}, [messages]);
|
|
1345
|
-
const sendMessage = (0,
|
|
1520
|
+
const sendMessage = (0, import_react8.useCallback)(
|
|
1346
1521
|
async (text, opts) => {
|
|
1347
1522
|
var _a, _b;
|
|
1348
1523
|
const trimmed = text.trim();
|
|
@@ -1402,7 +1577,7 @@ function useRagChat(projectId, options = {}) {
|
|
|
1402
1577
|
const complete = buffer.slice(0, lastBoundary + 2);
|
|
1403
1578
|
buffer = buffer.slice(lastBoundary + 2);
|
|
1404
1579
|
for (const frame of parseSseChunk(complete)) {
|
|
1405
|
-
if (frame.type === "text") {
|
|
1580
|
+
if (frame.type === "text" && frame.text) {
|
|
1406
1581
|
assistantContent += frame.text;
|
|
1407
1582
|
} else if (frame.type === "metadata") {
|
|
1408
1583
|
sources = (_a = frame.sources) != null ? _a : [];
|
|
@@ -1424,7 +1599,7 @@ function useRagChat(projectId, options = {}) {
|
|
|
1424
1599
|
}
|
|
1425
1600
|
if (buffer.trim()) {
|
|
1426
1601
|
for (const frame of parseSseChunk(buffer)) {
|
|
1427
|
-
if (frame.type === "text") assistantContent += frame.text;
|
|
1602
|
+
if (frame.type === "text" && frame.text) assistantContent += frame.text;
|
|
1428
1603
|
else if (frame.type === "metadata") sources = (_b = frame.sources) != null ? _b : [];
|
|
1429
1604
|
}
|
|
1430
1605
|
}
|
|
@@ -1447,12 +1622,12 @@ function useRagChat(projectId, options = {}) {
|
|
|
1447
1622
|
},
|
|
1448
1623
|
[apiUrl, isLoading, namespace, onError, onReply, projectId, setMessages]
|
|
1449
1624
|
);
|
|
1450
|
-
const clear = (0,
|
|
1625
|
+
const clear = (0, import_react8.useCallback)(() => {
|
|
1451
1626
|
setMessages([]);
|
|
1452
1627
|
setError(null);
|
|
1453
1628
|
if (persist) localStorage.removeItem(storageKey);
|
|
1454
1629
|
}, [persist, setMessages, storageKey]);
|
|
1455
|
-
const retry = (0,
|
|
1630
|
+
const retry = (0, import_react8.useCallback)(async () => {
|
|
1456
1631
|
if (lastInputRef.current) {
|
|
1457
1632
|
const latestMessage = messagesRef.current[messagesRef.current.length - 1];
|
|
1458
1633
|
await sendMessage(lastInputRef.current, {
|
|
@@ -1486,20 +1661,20 @@ function ChatWindow({
|
|
|
1486
1661
|
}) {
|
|
1487
1662
|
var _a;
|
|
1488
1663
|
const { ui, projectId } = useConfig();
|
|
1489
|
-
const [input, setInput] = (0,
|
|
1490
|
-
const [mounted, setMounted] = (0,
|
|
1491
|
-
const [viewportSize, setViewportSize] = (0,
|
|
1492
|
-
const windowRef = (0,
|
|
1493
|
-
const bottomRef = (0,
|
|
1494
|
-
const inputRef = (0,
|
|
1664
|
+
const [input, setInput] = (0, import_react9.useState)("");
|
|
1665
|
+
const [mounted, setMounted] = (0, import_react9.useState)(false);
|
|
1666
|
+
const [viewportSize, setViewportSize] = (0, import_react9.useState)("large");
|
|
1667
|
+
const windowRef = (0, import_react9.useRef)(null);
|
|
1668
|
+
const bottomRef = (0, import_react9.useRef)(null);
|
|
1669
|
+
const inputRef = (0, import_react9.useRef)(null);
|
|
1495
1670
|
const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
|
|
1496
1671
|
namespace: projectId
|
|
1497
1672
|
});
|
|
1498
|
-
const [suggestions, setSuggestions] = (0,
|
|
1499
|
-
const [isSuggesting, setIsSuggesting] = (0,
|
|
1500
|
-
const [isListening, setIsListening] = (0,
|
|
1501
|
-
const recognitionRef = (0,
|
|
1502
|
-
(0,
|
|
1673
|
+
const [suggestions, setSuggestions] = (0, import_react9.useState)([]);
|
|
1674
|
+
const [isSuggesting, setIsSuggesting] = (0, import_react9.useState)(false);
|
|
1675
|
+
const [isListening, setIsListening] = (0, import_react9.useState)(false);
|
|
1676
|
+
const recognitionRef = (0, import_react9.useRef)(null);
|
|
1677
|
+
(0, import_react9.useEffect)(() => {
|
|
1503
1678
|
if (typeof window !== "undefined") {
|
|
1504
1679
|
const win = window;
|
|
1505
1680
|
const SpeechRecognition = win.SpeechRecognition || win.webkitSpeechRecognition;
|
|
@@ -1545,10 +1720,10 @@ function ChatWindow({
|
|
|
1545
1720
|
}
|
|
1546
1721
|
}
|
|
1547
1722
|
};
|
|
1548
|
-
(0,
|
|
1723
|
+
(0, import_react9.useEffect)(() => {
|
|
1549
1724
|
setMounted(true);
|
|
1550
1725
|
}, []);
|
|
1551
|
-
(0,
|
|
1726
|
+
(0, import_react9.useEffect)(() => {
|
|
1552
1727
|
const element = windowRef.current;
|
|
1553
1728
|
if (!element || typeof ResizeObserver === "undefined") return;
|
|
1554
1729
|
const resolveViewportSize = (width) => {
|
|
@@ -1564,13 +1739,13 @@ function ChatWindow({
|
|
|
1564
1739
|
observer.observe(element);
|
|
1565
1740
|
return () => observer.disconnect();
|
|
1566
1741
|
}, []);
|
|
1567
|
-
(0,
|
|
1742
|
+
(0, import_react9.useEffect)(() => {
|
|
1568
1743
|
var _a2;
|
|
1569
1744
|
if (messages.length > 0 || isLoading) {
|
|
1570
1745
|
(_a2 = bottomRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth" });
|
|
1571
1746
|
}
|
|
1572
1747
|
}, [messages, isLoading]);
|
|
1573
|
-
const sendMessage = (0,
|
|
1748
|
+
const sendMessage = (0, import_react9.useCallback)(async () => {
|
|
1574
1749
|
var _a2;
|
|
1575
1750
|
const text = input.trim();
|
|
1576
1751
|
if (!text || isLoading) return;
|
|
@@ -1600,7 +1775,7 @@ function ChatWindow({
|
|
|
1600
1775
|
const isEmpty = messages.length === 0;
|
|
1601
1776
|
const currentRadius = BORDER_RADIUS_MAP[ui.borderRadius || "xl"];
|
|
1602
1777
|
const isGlass = ui.visualStyle !== "solid";
|
|
1603
|
-
(0,
|
|
1778
|
+
(0, import_react9.useEffect)(() => {
|
|
1604
1779
|
if (input.trim().length < 3) {
|
|
1605
1780
|
return;
|
|
1606
1781
|
}
|
|
@@ -1624,84 +1799,84 @@ function ChatWindow({
|
|
|
1624
1799
|
}, 800);
|
|
1625
1800
|
return () => clearTimeout(timer);
|
|
1626
1801
|
}, [input, projectId]);
|
|
1627
|
-
return /* @__PURE__ */
|
|
1802
|
+
return /* @__PURE__ */ import_react9.default.createElement(
|
|
1628
1803
|
"div",
|
|
1629
1804
|
{
|
|
1630
1805
|
ref: windowRef,
|
|
1631
1806
|
className: `relative flex flex-col border border-slate-200 dark:border-white/10 shadow-2xl transition-all duration-300 ${currentRadius} ${isGlass ? "bg-white/90 dark:bg-[#0f0f1a]/90 backdrop-blur-xl" : "bg-white dark:bg-[#0f0f1a]"} ${className}`,
|
|
1632
1807
|
style: __spreadValues({ "--primary": ui.primaryColor, "--accent": ui.accentColor }, style)
|
|
1633
1808
|
},
|
|
1634
|
-
onResizeStart && /* @__PURE__ */
|
|
1809
|
+
onResizeStart && /* @__PURE__ */ import_react9.default.createElement(
|
|
1635
1810
|
"div",
|
|
1636
1811
|
{
|
|
1637
1812
|
onMouseDown: onResizeStart,
|
|
1638
1813
|
className: "absolute top-0 left-0 w-6 h-6 cursor-nw-resize z-[100] group flex items-start justify-start p-1",
|
|
1639
1814
|
title: "Drag to resize"
|
|
1640
1815
|
},
|
|
1641
|
-
/* @__PURE__ */
|
|
1816
|
+
/* @__PURE__ */ import_react9.default.createElement("div", { className: "w-2.5 h-2.5 border-t-2 border-l-2 border-slate-300 dark:border-white/20 group-hover:border-slate-500 dark:group-hover:border-white/50 transition-colors rounded-tl-[2px]" })
|
|
1642
1817
|
),
|
|
1643
|
-
/* @__PURE__ */
|
|
1818
|
+
/* @__PURE__ */ import_react9.default.createElement(
|
|
1644
1819
|
"div",
|
|
1645
1820
|
{
|
|
1646
1821
|
className: "flex items-center justify-between px-5 py-4 border-b border-slate-200 dark:border-white/10",
|
|
1647
1822
|
style: { background: `linear-gradient(135deg, ${ui.primaryColor}15, ${ui.accentColor}10)` }
|
|
1648
1823
|
},
|
|
1649
|
-
/* @__PURE__ */
|
|
1824
|
+
/* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center gap-3" }, ui.logoUrl ? (
|
|
1650
1825
|
// eslint-disable-next-line @next/next/no-img-element
|
|
1651
|
-
/* @__PURE__ */
|
|
1652
|
-
) : /* @__PURE__ */
|
|
1826
|
+
/* @__PURE__ */ import_react9.default.createElement("img", { src: ui.logoUrl, alt: "logo", className: "w-8 h-8 rounded-lg object-cover" })
|
|
1827
|
+
) : /* @__PURE__ */ import_react9.default.createElement(
|
|
1653
1828
|
"div",
|
|
1654
1829
|
{
|
|
1655
1830
|
className: `w-9 h-9 flex items-center justify-center shadow-md ${ui.borderRadius === "full" ? "rounded-full" : "rounded-xl"}`,
|
|
1656
1831
|
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` }
|
|
1657
1832
|
},
|
|
1658
|
-
/* @__PURE__ */
|
|
1659
|
-
), /* @__PURE__ */
|
|
1660
|
-
/* @__PURE__ */
|
|
1833
|
+
/* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Bot, { className: "w-5 h-5 text-white" })
|
|
1834
|
+
), /* @__PURE__ */ import_react9.default.createElement("div", null, /* @__PURE__ */ import_react9.default.createElement("h2", { className: "text-slate-900 dark:text-white font-semibold text-sm leading-tight" }, ui.title), ui.poweredBy && /* @__PURE__ */ import_react9.default.createElement("p", { className: "text-slate-500 dark:text-white/40 text-[11px] leading-tight" }, `Powered by ${ui.poweredBy}`))),
|
|
1835
|
+
/* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ import_react9.default.createElement("span", { className: "flex items-center gap-1 text-[10px] text-emerald-500 dark:text-emerald-400 mr-2" }, /* @__PURE__ */ import_react9.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500 dark:bg-emerald-400 animate-pulse" }), "Online"), /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center bg-slate-100/50 dark:bg-white/5 rounded-lg p-0.5 border border-slate-200/50 dark:border-white/5" }, mounted && messages.length > 0 && /* @__PURE__ */ import_react9.default.createElement(
|
|
1661
1836
|
"button",
|
|
1662
1837
|
{
|
|
1663
1838
|
onClick: clearHistory,
|
|
1664
1839
|
title: "Clear conversation",
|
|
1665
1840
|
className: "w-7 h-7 rounded-md flex items-center justify-center text-slate-400 hover:text-rose-500 dark:text-white/40 dark:hover:text-rose-400 hover:bg-white dark:hover:bg-white/10 transition-all cursor-pointer"
|
|
1666
1841
|
},
|
|
1667
|
-
/* @__PURE__ */
|
|
1668
|
-
), isResized && onResetResize && /* @__PURE__ */
|
|
1842
|
+
/* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Trash2, { className: "w-3.5 h-3.5" })
|
|
1843
|
+
), isResized && onResetResize && /* @__PURE__ */ import_react9.default.createElement(
|
|
1669
1844
|
"button",
|
|
1670
1845
|
{
|
|
1671
1846
|
onClick: onResetResize,
|
|
1672
1847
|
title: "Reset to default size",
|
|
1673
1848
|
className: "w-7 h-7 rounded-md flex items-center justify-center text-slate-400 hover:text-blue-500 dark:text-white/40 dark:hover:text-blue-400 hover:bg-white dark:hover:bg-white/10 transition-all cursor-pointer"
|
|
1674
1849
|
},
|
|
1675
|
-
/* @__PURE__ */
|
|
1676
|
-
), onMaximize && /* @__PURE__ */
|
|
1850
|
+
/* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.RotateCcw, { className: "w-3.5 h-3.5" })
|
|
1851
|
+
), onMaximize && /* @__PURE__ */ import_react9.default.createElement(
|
|
1677
1852
|
"button",
|
|
1678
1853
|
{
|
|
1679
1854
|
onClick: onMaximize,
|
|
1680
1855
|
title: isMaximized ? "Minimize" : "Maximize",
|
|
1681
1856
|
className: "w-7 h-7 rounded-md flex items-center justify-center text-slate-400 hover:text-blue-500 dark:text-white/40 dark:hover:text-blue-400 hover:bg-white dark:hover:bg-white/10 transition-all cursor-pointer"
|
|
1682
1857
|
},
|
|
1683
|
-
isMaximized ? /* @__PURE__ */
|
|
1684
|
-
), showClose && onClose && /* @__PURE__ */
|
|
1858
|
+
isMaximized ? /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Minimize2, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Maximize2, { className: "w-3.5 h-3.5" })
|
|
1859
|
+
), showClose && onClose && /* @__PURE__ */ import_react9.default.createElement(
|
|
1685
1860
|
"button",
|
|
1686
1861
|
{
|
|
1687
1862
|
onClick: onClose,
|
|
1688
1863
|
title: "Close chat",
|
|
1689
1864
|
className: "w-7 h-7 rounded-md flex items-center justify-center text-slate-400 hover:text-slate-600 dark:text-white/40 dark:hover:text-white/70 hover:bg-white dark:hover:bg-white/10 transition-all cursor-pointer"
|
|
1690
1865
|
},
|
|
1691
|
-
/* @__PURE__ */
|
|
1866
|
+
/* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.X, { className: "w-4 h-4" })
|
|
1692
1867
|
)))
|
|
1693
1868
|
),
|
|
1694
|
-
/* @__PURE__ */
|
|
1869
|
+
/* @__PURE__ */ import_react9.default.createElement("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5 scrollbar-thin scrollbar-thumb-slate-200 dark:scrollbar-thumb-white/10 scrollbar-track-transparent min-h-0 bg-slate-50 dark:bg-transparent" }, !mounted || isEmpty ? (
|
|
1695
1870
|
/* Welcome state */
|
|
1696
|
-
/* @__PURE__ */
|
|
1871
|
+
/* @__PURE__ */ import_react9.default.createElement("div", { className: "h-full flex flex-col items-center justify-center text-center gap-4 px-6 py-12" }, /* @__PURE__ */ import_react9.default.createElement(
|
|
1697
1872
|
"div",
|
|
1698
1873
|
{
|
|
1699
1874
|
className: `w-16 h-16 flex items-center justify-center shadow-lg ${ui.borderRadius === "full" ? "rounded-full" : "rounded-2xl"}`,
|
|
1700
1875
|
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` }
|
|
1701
1876
|
},
|
|
1702
|
-
/* @__PURE__ */
|
|
1703
|
-
), /* @__PURE__ */
|
|
1704
|
-
(suggestion) => /* @__PURE__ */
|
|
1877
|
+
/* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Sparkles, { className: "w-8 h-8 text-white" })
|
|
1878
|
+
), /* @__PURE__ */ import_react9.default.createElement("div", null, /* @__PURE__ */ import_react9.default.createElement("p", { className: "text-slate-800 dark:text-white/80 font-medium leading-relaxed" }, ui.welcomeMessage), /* @__PURE__ */ import_react9.default.createElement("p", { className: "text-slate-500 dark:text-white/30 text-sm mt-2" }, "Ask a question to get started")), /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex flex-wrap gap-2 justify-center mt-2" }, CHAT_SUGGESTIONS.map(
|
|
1879
|
+
(suggestion) => /* @__PURE__ */ import_react9.default.createElement(
|
|
1705
1880
|
"button",
|
|
1706
1881
|
{
|
|
1707
1882
|
key: suggestion,
|
|
@@ -1715,7 +1890,7 @@ function ChatWindow({
|
|
|
1715
1890
|
suggestion
|
|
1716
1891
|
)
|
|
1717
1892
|
)))
|
|
1718
|
-
) : messages.map((msg, index) => /* @__PURE__ */
|
|
1893
|
+
) : messages.map((msg, index) => /* @__PURE__ */ import_react9.default.createElement(
|
|
1719
1894
|
MessageBubble,
|
|
1720
1895
|
{
|
|
1721
1896
|
key: msg.id,
|
|
@@ -1727,7 +1902,7 @@ function ChatWindow({
|
|
|
1727
1902
|
onAddToCart,
|
|
1728
1903
|
viewportSize
|
|
1729
1904
|
}
|
|
1730
|
-
)), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */
|
|
1905
|
+
)), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */ import_react9.default.createElement(
|
|
1731
1906
|
MessageBubble,
|
|
1732
1907
|
{
|
|
1733
1908
|
message: { id: "loading", role: "assistant", content: "", createdAt: (/* @__PURE__ */ new Date()).toISOString() },
|
|
@@ -1737,8 +1912,8 @@ function ChatWindow({
|
|
|
1737
1912
|
onAddToCart,
|
|
1738
1913
|
viewportSize
|
|
1739
1914
|
}
|
|
1740
|
-
), error && /* @__PURE__ */
|
|
1741
|
-
/* @__PURE__ */
|
|
1915
|
+
), error && /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center gap-2 text-rose-500 dark:text-rose-400 text-sm bg-rose-50 dark:bg-rose-400/10 border border-rose-200 dark:border-rose-400/20 rounded-xl px-4 py-3" }, /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.TriangleAlert, { className: "w-4 h-4 flex-shrink-0" }), /* @__PURE__ */ import_react9.default.createElement("span", null, error)), /* @__PURE__ */ import_react9.default.createElement("div", { ref: bottomRef })),
|
|
1916
|
+
/* @__PURE__ */ import_react9.default.createElement("div", { className: `px-4 pb-4 pt-2 border-t border-slate-200 dark:border-white/10 ${isGlass ? "bg-transparent" : "bg-white dark:bg-[#0f0f1a]"}` }, (suggestions.length > 0 || isSuggesting) && !isLoading && /* @__PURE__ */ import_react9.default.createElement("div", { className: "mb-3 flex flex-wrap gap-2 animate-in fade-in slide-in-from-bottom-2 duration-300" }, suggestions.map((suggestion) => /* @__PURE__ */ import_react9.default.createElement(
|
|
1742
1917
|
"button",
|
|
1743
1918
|
{
|
|
1744
1919
|
key: suggestion,
|
|
@@ -1750,9 +1925,9 @@ function ChatWindow({
|
|
|
1750
1925
|
},
|
|
1751
1926
|
className: "flex items-center gap-1.5 px-3 py-1.5 rounded-xl text-[11px] font-medium bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 text-slate-600 dark:text-white/60 hover:text-slate-900 dark:hover:text-white/90 hover:border-slate-300 dark:hover:border-white/20 transition-all shadow-sm cursor-pointer group"
|
|
1752
1927
|
},
|
|
1753
|
-
/* @__PURE__ */
|
|
1928
|
+
/* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Sparkles, { className: "w-3 h-3 text-amber-400" }),
|
|
1754
1929
|
suggestion
|
|
1755
|
-
)), isSuggesting && suggestions.length === 0 && /* @__PURE__ */
|
|
1930
|
+
)), isSuggesting && suggestions.length === 0 && /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center gap-1.5 px-3 py-1.5 rounded-xl text-[11px] font-medium text-slate-400 dark:text-white/30 animate-pulse" }, /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Sparkles, { className: "w-3 h-3" }), "Thinking...")), /* @__PURE__ */ import_react9.default.createElement("div", { className: `flex items-end gap-2 bg-slate-50 dark:bg-white/5 border border-slate-200 dark:border-white/10 p-2 focus-within:border-slate-300 dark:focus-within:border-white/20 transition-all ${ui.borderRadius === "full" ? "rounded-3xl" : "rounded-2xl"}` }, /* @__PURE__ */ import_react9.default.createElement(
|
|
1756
1931
|
"textarea",
|
|
1757
1932
|
{
|
|
1758
1933
|
ref: inputRef,
|
|
@@ -1771,7 +1946,7 @@ function ChatWindow({
|
|
|
1771
1946
|
className: "flex-1 bg-transparent text-slate-900 dark:text-white/90 placeholder-slate-400 dark:placeholder-white/30 text-sm resize-none outline-none py-1.5 px-2 max-h-32 leading-relaxed disabled:opacity-50",
|
|
1772
1947
|
style: { scrollbarWidth: "none" }
|
|
1773
1948
|
}
|
|
1774
|
-
), ui.enableVoiceInput !== false && /* @__PURE__ */
|
|
1949
|
+
), ui.enableVoiceInput !== false && /* @__PURE__ */ import_react9.default.createElement(
|
|
1775
1950
|
"button",
|
|
1776
1951
|
{
|
|
1777
1952
|
type: "button",
|
|
@@ -1780,8 +1955,8 @@ function ChatWindow({
|
|
|
1780
1955
|
className: `flex-shrink-0 w-9 h-9 rounded-xl flex items-center justify-center transition-all hover:scale-105 active:scale-95 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100 disabled:active:scale-100 ${isListening ? "bg-rose-500 text-white animate-pulse shadow-md shadow-rose-500/20" : "text-slate-400 dark:text-white/40 hover:bg-slate-200 dark:hover:bg-white/10"}`,
|
|
1781
1956
|
title: isListening ? "Stop listening" : "Start voice input"
|
|
1782
1957
|
},
|
|
1783
|
-
isListening ? /* @__PURE__ */
|
|
1784
|
-
), /* @__PURE__ */
|
|
1958
|
+
isListening ? /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.MicOff, { className: "w-4 h-4" }) : /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Mic, { className: "w-4 h-4" })
|
|
1959
|
+
), /* @__PURE__ */ import_react9.default.createElement(
|
|
1785
1960
|
"button",
|
|
1786
1961
|
{
|
|
1787
1962
|
onClick: sendMessage,
|
|
@@ -1792,8 +1967,8 @@ function ChatWindow({
|
|
|
1792
1967
|
// slate-400/20 for light mode disabled
|
|
1793
1968
|
}
|
|
1794
1969
|
},
|
|
1795
|
-
/* @__PURE__ */
|
|
1796
|
-
)), /* @__PURE__ */
|
|
1970
|
+
/* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.ArrowUp, { className: "w-4 h-4 text-white" })
|
|
1971
|
+
)), /* @__PURE__ */ import_react9.default.createElement("p", { className: "text-center text-[10px] text-slate-400 dark:text-white/20 mt-2" }, "Press Enter to send \xB7 Shift+Enter for new line"))
|
|
1797
1972
|
);
|
|
1798
1973
|
}
|
|
1799
1974
|
|
|
@@ -1801,12 +1976,12 @@ function ChatWindow({
|
|
|
1801
1976
|
var DEFAULT_DIMENSIONS = { width: 380, height: 600 };
|
|
1802
1977
|
function ChatWidget({ position = "bottom-right", onAddToCart }) {
|
|
1803
1978
|
const { ui } = useConfig();
|
|
1804
|
-
const [isOpen, setIsOpen] = (0,
|
|
1805
|
-
const [hasUnread, setHasUnread] = (0,
|
|
1806
|
-
const [dimensions, setDimensions] = (0,
|
|
1807
|
-
const [isResizing, setIsResizing] = (0,
|
|
1808
|
-
const [isMaximized, setIsMaximized] = (0,
|
|
1809
|
-
const [prevDimensions, setPrevDimensions] = (0,
|
|
1979
|
+
const [isOpen, setIsOpen] = (0, import_react10.useState)(false);
|
|
1980
|
+
const [hasUnread, setHasUnread] = (0, import_react10.useState)(false);
|
|
1981
|
+
const [dimensions, setDimensions] = (0, import_react10.useState)(DEFAULT_DIMENSIONS);
|
|
1982
|
+
const [isResizing, setIsResizing] = (0, import_react10.useState)(false);
|
|
1983
|
+
const [isMaximized, setIsMaximized] = (0, import_react10.useState)(false);
|
|
1984
|
+
const [prevDimensions, setPrevDimensions] = (0, import_react10.useState)(DEFAULT_DIMENSIONS);
|
|
1810
1985
|
if (ui.showWidget === false) return null;
|
|
1811
1986
|
const positionClass = position === "bottom-left" ? "bottom-6 left-6" : "bottom-6 right-6";
|
|
1812
1987
|
const windowPositionClass = position === "bottom-left" ? "bottom-20 left-6" : "bottom-20 right-6";
|
|
@@ -1856,7 +2031,7 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
|
|
|
1856
2031
|
}
|
|
1857
2032
|
};
|
|
1858
2033
|
const isResized = dimensions.width !== DEFAULT_DIMENSIONS.width || dimensions.height !== DEFAULT_DIMENSIONS.height;
|
|
1859
|
-
return /* @__PURE__ */
|
|
2034
|
+
return /* @__PURE__ */ import_react10.default.createElement(import_react10.default.Fragment, null, /* @__PURE__ */ import_react10.default.createElement(
|
|
1860
2035
|
"div",
|
|
1861
2036
|
{
|
|
1862
2037
|
className: `fixed z-[9998] max-w-[calc(100vw-3rem)] ease-in-out ${windowPositionClass} ${isOpen ? "opacity-100 translate-y-0 pointer-events-auto" : "opacity-0 translate-y-4 pointer-events-none"} ${isResizing ? "" : "transition-all duration-300"}`,
|
|
@@ -1866,7 +2041,7 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
|
|
|
1866
2041
|
maxHeight: "calc(100vh - 6rem)"
|
|
1867
2042
|
}
|
|
1868
2043
|
},
|
|
1869
|
-
/* @__PURE__ */
|
|
2044
|
+
/* @__PURE__ */ import_react10.default.createElement(
|
|
1870
2045
|
ChatWindow,
|
|
1871
2046
|
{
|
|
1872
2047
|
className: "h-full relative z-10",
|
|
@@ -1880,13 +2055,13 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
|
|
|
1880
2055
|
onAddToCart
|
|
1881
2056
|
}
|
|
1882
2057
|
),
|
|
1883
|
-
/* @__PURE__ */
|
|
2058
|
+
/* @__PURE__ */ import_react10.default.createElement(
|
|
1884
2059
|
"div",
|
|
1885
2060
|
{
|
|
1886
2061
|
className: `absolute -bottom-1.5 w-4 h-4 rotate-45 border-r border-b border-slate-200 dark:border-white/10 z-0 ${ui.visualStyle === "solid" ? "bg-white dark:bg-[#0f0f1a]" : "bg-white/90 dark:bg-[#0f0f1a]/90 backdrop-blur-xl"} ${position === "bottom-left" ? "left-5" : "right-5"}`
|
|
1887
2062
|
}
|
|
1888
2063
|
)
|
|
1889
|
-
), /* @__PURE__ */
|
|
2064
|
+
), /* @__PURE__ */ import_react10.default.createElement(
|
|
1890
2065
|
"button",
|
|
1891
2066
|
{
|
|
1892
2067
|
onClick: isOpen ? () => setIsOpen(false) : handleOpen,
|
|
@@ -1894,32 +2069,32 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
|
|
|
1894
2069
|
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` },
|
|
1895
2070
|
"aria-label": "Open chat"
|
|
1896
2071
|
},
|
|
1897
|
-
/* @__PURE__ */
|
|
2072
|
+
/* @__PURE__ */ import_react10.default.createElement(
|
|
1898
2073
|
"span",
|
|
1899
2074
|
{
|
|
1900
2075
|
className: "absolute inset-0 rounded-full animate-ping opacity-20",
|
|
1901
2076
|
style: { background: ui.primaryColor }
|
|
1902
2077
|
}
|
|
1903
2078
|
),
|
|
1904
|
-
/* @__PURE__ */
|
|
2079
|
+
/* @__PURE__ */ import_react10.default.createElement(
|
|
1905
2080
|
"span",
|
|
1906
2081
|
{
|
|
1907
2082
|
className: `transition-transform duration-300 ${isOpen ? "rotate-90 scale-90" : "rotate-0 scale-100"}`
|
|
1908
2083
|
},
|
|
1909
|
-
isOpen ? /* @__PURE__ */
|
|
2084
|
+
isOpen ? /* @__PURE__ */ import_react10.default.createElement(import_lucide_react6.X, { className: "w-6 h-6 text-white" }) : /* @__PURE__ */ import_react10.default.createElement(import_lucide_react6.MessageSquare, { className: "w-6 h-6 text-white" })
|
|
1910
2085
|
),
|
|
1911
|
-
hasUnread && !isOpen && /* @__PURE__ */
|
|
2086
|
+
hasUnread && !isOpen && /* @__PURE__ */ import_react10.default.createElement("span", { className: "absolute top-0 right-0 w-4 h-4 bg-rose-500 rounded-full border-2 border-white flex items-center justify-center text-[9px] font-bold text-white" }, "1")
|
|
1912
2087
|
));
|
|
1913
2088
|
}
|
|
1914
2089
|
|
|
1915
2090
|
// src/components/DocumentUpload.tsx
|
|
1916
|
-
var
|
|
2091
|
+
var import_react11 = __toESM(require("react"));
|
|
1917
2092
|
var import_lucide_react7 = require("lucide-react");
|
|
1918
2093
|
function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
|
|
1919
2094
|
const { ui } = useConfig();
|
|
1920
|
-
const [fileStates, setFileStates] = (0,
|
|
1921
|
-
const [isDragging, setIsDragging] = (0,
|
|
1922
|
-
const fileInputRef = (0,
|
|
2095
|
+
const [fileStates, setFileStates] = (0, import_react11.useState)([]);
|
|
2096
|
+
const [isDragging, setIsDragging] = (0, import_react11.useState)(false);
|
|
2097
|
+
const fileInputRef = (0, import_react11.useRef)(null);
|
|
1923
2098
|
const addFiles = (files) => {
|
|
1924
2099
|
const newStates = files.map((file) => ({ file, status: "idle" }));
|
|
1925
2100
|
setFileStates((prev) => [...prev, ...newStates]);
|
|
@@ -1969,7 +2144,7 @@ function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
|
|
|
1969
2144
|
};
|
|
1970
2145
|
const isUploading = fileStates.some((s) => s.status === "uploading");
|
|
1971
2146
|
const hasIdle = fileStates.some((s) => s.status === "idle");
|
|
1972
|
-
return /* @__PURE__ */
|
|
2147
|
+
return /* @__PURE__ */ import_react11.default.createElement(
|
|
1973
2148
|
"div",
|
|
1974
2149
|
{
|
|
1975
2150
|
className: `p-6 border-2 border-dashed transition-all duration-300 rounded-2xl ${isDragging ? "border-emerald-500 bg-emerald-50/50 dark:bg-emerald-500/5" : "border-slate-200 dark:border-white/10 bg-white dark:bg-white/5"} ${className}`,
|
|
@@ -1977,14 +2152,14 @@ function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
|
|
|
1977
2152
|
onDragLeave,
|
|
1978
2153
|
onDrop
|
|
1979
2154
|
},
|
|
1980
|
-
/* @__PURE__ */
|
|
2155
|
+
/* @__PURE__ */ import_react11.default.createElement("div", { className: "flex flex-col items-center justify-center text-center" }, /* @__PURE__ */ import_react11.default.createElement(
|
|
1981
2156
|
"div",
|
|
1982
2157
|
{
|
|
1983
2158
|
className: "w-12 h-12 rounded-full flex items-center justify-center mb-4 shadow-sm",
|
|
1984
2159
|
style: { background: `linear-gradient(135deg, ${ui.primaryColor}20, ${ui.accentColor}20)` }
|
|
1985
2160
|
},
|
|
1986
|
-
/* @__PURE__ */
|
|
1987
|
-
), /* @__PURE__ */
|
|
2161
|
+
/* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.Upload, { className: "w-6 h-6", style: { color: ui.primaryColor } })
|
|
2162
|
+
), /* @__PURE__ */ import_react11.default.createElement("h3", { className: "text-slate-900 dark:text-white font-semibold mb-1" }, "Upload Documents"), /* @__PURE__ */ import_react11.default.createElement("p", { className: "text-slate-500 dark:text-white/40 text-sm mb-6 max-w-xs" }, "Drag and drop PDF, DOCX, TXT, or JSON files to train your AI on your own data."), /* @__PURE__ */ import_react11.default.createElement(
|
|
1988
2163
|
"button",
|
|
1989
2164
|
{
|
|
1990
2165
|
onClick: () => {
|
|
@@ -2000,7 +2175,7 @@ function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
|
|
|
2000
2175
|
}
|
|
2001
2176
|
},
|
|
2002
2177
|
"Select Files"
|
|
2003
|
-
), /* @__PURE__ */
|
|
2178
|
+
), /* @__PURE__ */ import_react11.default.createElement(
|
|
2004
2179
|
"input",
|
|
2005
2180
|
{
|
|
2006
2181
|
ref: fileInputRef,
|
|
@@ -2011,22 +2186,22 @@ function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
|
|
|
2011
2186
|
accept: ".pdf,.docx,.txt,.md,.json,.csv"
|
|
2012
2187
|
}
|
|
2013
2188
|
)),
|
|
2014
|
-
fileStates.length > 0 && /* @__PURE__ */
|
|
2189
|
+
fileStates.length > 0 && /* @__PURE__ */ import_react11.default.createElement("div", { className: "mt-8 space-y-3" }, fileStates.map((state, i) => /* @__PURE__ */ import_react11.default.createElement(
|
|
2015
2190
|
"div",
|
|
2016
2191
|
{
|
|
2017
2192
|
key: i,
|
|
2018
2193
|
className: "flex items-center justify-between p-3 rounded-xl bg-slate-50 dark:bg-white/5 border border-slate-100 dark:border-white/10"
|
|
2019
2194
|
},
|
|
2020
|
-
/* @__PURE__ */
|
|
2021
|
-
/* @__PURE__ */
|
|
2195
|
+
/* @__PURE__ */ import_react11.default.createElement("div", { className: "flex items-center gap-3 overflow-hidden" }, /* @__PURE__ */ import_react11.default.createElement("div", { className: "w-8 h-8 rounded-lg bg-white dark:bg-white/10 flex items-center justify-center shadow-sm" }, /* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.File, { className: "w-4 h-4 text-slate-400" })), /* @__PURE__ */ import_react11.default.createElement("div", { className: "truncate" }, /* @__PURE__ */ import_react11.default.createElement("p", { className: "text-xs font-medium text-slate-700 dark:text-white/80 truncate" }, state.file.name), /* @__PURE__ */ import_react11.default.createElement("p", { className: "text-[10px] text-slate-400" }, (state.file.size / 1024).toFixed(1), " KB"))),
|
|
2196
|
+
/* @__PURE__ */ import_react11.default.createElement("div", { className: "flex items-center gap-2" }, state.status === "uploading" && /* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.Loader2, { className: "w-4 h-4 text-slate-400 animate-spin" }), state.status === "success" && /* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.CheckCircle, { className: "w-4 h-4 text-emerald-500" }), state.status === "error" && /* @__PURE__ */ import_react11.default.createElement("div", { title: state.error }, /* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.AlertCircle, { className: "w-4 h-4 text-rose-500" })), state.status !== "uploading" && /* @__PURE__ */ import_react11.default.createElement(
|
|
2022
2197
|
"button",
|
|
2023
2198
|
{
|
|
2024
2199
|
onClick: () => removeFile(i),
|
|
2025
2200
|
className: "p-1 rounded-md hover:bg-slate-200 dark:hover:bg-white/10 transition-colors"
|
|
2026
2201
|
},
|
|
2027
|
-
/* @__PURE__ */
|
|
2202
|
+
/* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.X, { className: "w-3.5 h-3.5 text-slate-400" })
|
|
2028
2203
|
))
|
|
2029
|
-
)), hasIdle && !isUploading && /* @__PURE__ */
|
|
2204
|
+
)), hasIdle && !isUploading && /* @__PURE__ */ import_react11.default.createElement(
|
|
2030
2205
|
"button",
|
|
2031
2206
|
{
|
|
2032
2207
|
onClick: uploadFiles,
|