@retrivora-ai/rag-engine 1.5.4 → 1.5.6
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/{chunk-BLLMNP77.mjs → chunk-ID2Q4CF7.mjs} +58 -11
- package/dist/handlers/index.js +58 -11
- package/dist/handlers/index.mjs +1 -1
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +192 -62
- package/dist/index.mjs +192 -62
- package/dist/server.js +58 -11
- package/dist/server.mjs +1 -1
- package/package.json +1 -1
- package/src/app/api/chat/route.ts +2 -2
- package/src/components/ChatWindow.tsx +26 -0
- package/src/components/DynamicChart.tsx +113 -30
- package/src/components/MessageBubble.tsx +143 -26
- package/src/components/ProductCarousel.tsx +2 -2
- package/src/core/Pipeline.ts +58 -11
- package/src/types/props.ts +3 -0
package/dist/index.js
CHANGED
|
@@ -174,7 +174,7 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
|
|
|
174
174
|
};
|
|
175
175
|
if (!products || products.length === 0) return null;
|
|
176
176
|
if (products.length === 1) {
|
|
177
|
-
return /* @__PURE__ */ import_react3.default.createElement("div", { className: "my-4 w-[
|
|
177
|
+
return /* @__PURE__ */ import_react3.default.createElement("div", { className: "my-4 w-[min(88%,18rem)] min-w-0 max-w-full animate-fade-in-up" }, /* @__PURE__ */ import_react3.default.createElement(ProductCard, { product: products[0], primaryColor, onAddToCart }));
|
|
178
178
|
}
|
|
179
179
|
return /* @__PURE__ */ import_react3.default.createElement("div", { className: "relative w-full my-4 group/carousel animate-fade-in-up" }, canScroll && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("div", { className: "absolute -left-4 top-1/2 -translate-y-1/2 z-20 opacity-100 md:opacity-0 md:group-hover/carousel:opacity-100 transition-opacity" }, /* @__PURE__ */ import_react3.default.createElement(
|
|
180
180
|
"button",
|
|
@@ -209,7 +209,7 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
|
|
|
209
209
|
"div",
|
|
210
210
|
{
|
|
211
211
|
key: product.id,
|
|
212
|
-
className: "snap-start flex-shrink-0 w-[
|
|
212
|
+
className: "snap-start flex-shrink-0 w-[min(88%,18rem)] min-w-[11rem] max-w-full"
|
|
213
213
|
},
|
|
214
214
|
/* @__PURE__ */ import_react3.default.createElement(ProductCard, { product, primaryColor, onAddToCart })
|
|
215
215
|
))
|
|
@@ -220,9 +220,20 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
|
|
|
220
220
|
var import_react4 = __toESM(require("react"));
|
|
221
221
|
var import_recharts = require("recharts");
|
|
222
222
|
var DEFAULT_COLORS = ["#6366f1", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#ec4899"];
|
|
223
|
-
function DynamicChart({
|
|
223
|
+
function DynamicChart({
|
|
224
|
+
config,
|
|
225
|
+
primaryColor = "#6366f1",
|
|
226
|
+
accentColor = "#8b5cf6",
|
|
227
|
+
viewportSize = "large"
|
|
228
|
+
}) {
|
|
224
229
|
const { type, data } = config;
|
|
225
230
|
const colors = config.colors || [primaryColor, accentColor, ...DEFAULT_COLORS];
|
|
231
|
+
const isCompact = viewportSize === "compact";
|
|
232
|
+
const isMedium = viewportSize === "medium";
|
|
233
|
+
const chartHeightClass = isCompact ? "h-56 min-h-[220px]" : isMedium ? "h-64 min-h-[250px]" : "h-72 min-h-[280px]";
|
|
234
|
+
const pieOuterRadius = isCompact ? 56 : isMedium ? 68 : 80;
|
|
235
|
+
const pieLabel = ({ name, percent }) => isCompact ? `${name}` : `${name} ${((percent != null ? percent : 0) * 100).toFixed(0)}%`;
|
|
236
|
+
const axisTick = { fontSize: isCompact ? 10 : 12, fill: "#64748b" };
|
|
226
237
|
const sanitizedData = import_react4.default.useMemo(() => {
|
|
227
238
|
if (!data) return [];
|
|
228
239
|
return data.map((item) => {
|
|
@@ -270,9 +281,59 @@ function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6
|
|
|
270
281
|
}).slice(0, 5);
|
|
271
282
|
const finalXKey = String(resolvedXKey);
|
|
272
283
|
const finalDataKeys = resolvedDataKeys.map(String).filter((k) => k !== "undefined");
|
|
284
|
+
const pieDataKey = finalDataKeys[0] || "value";
|
|
285
|
+
const stockAwareColor = (entry, index) => {
|
|
286
|
+
var _a, _b, _c;
|
|
287
|
+
const stockStatus = String(
|
|
288
|
+
(_c = (_b = (_a = entry.stockStatus) != null ? _a : entry.status) != null ? _b : entry.availability) != null ? _c : ""
|
|
289
|
+
).toLowerCase();
|
|
290
|
+
const inStockCount = typeof entry.inStockCount === "number" ? entry.inStockCount : void 0;
|
|
291
|
+
const outOfStockCount = typeof entry.outOfStockCount === "number" ? entry.outOfStockCount : void 0;
|
|
292
|
+
const inStockFlag = entry.inStock;
|
|
293
|
+
if (stockStatus.includes("in stock")) return "#10b981";
|
|
294
|
+
if (stockStatus.includes("out of stock")) return "#f97316";
|
|
295
|
+
if (typeof inStockFlag === "string" && inStockFlag.toLowerCase() === "true") return "#10b981";
|
|
296
|
+
if (inStockFlag === 1) return "#10b981";
|
|
297
|
+
if (inStockFlag === 0) return "#f97316";
|
|
298
|
+
if (typeof inStockCount === "number" || typeof outOfStockCount === "number") {
|
|
299
|
+
const inCount = inStockCount != null ? inStockCount : 0;
|
|
300
|
+
const outCount = outOfStockCount != null ? outOfStockCount : 0;
|
|
301
|
+
if (inCount > outCount) return "#10b981";
|
|
302
|
+
if (outCount > inCount) return "#f97316";
|
|
303
|
+
}
|
|
304
|
+
return colors[index % colors.length];
|
|
305
|
+
};
|
|
306
|
+
const tooltipLabelMap = {
|
|
307
|
+
value: "Value",
|
|
308
|
+
count: "Count",
|
|
309
|
+
inStock: "In stock",
|
|
310
|
+
inStockCount: "In stock",
|
|
311
|
+
outOfStockCount: "Out of stock",
|
|
312
|
+
stockStatus: "Stock status",
|
|
313
|
+
category: "Category",
|
|
314
|
+
label: "Label",
|
|
315
|
+
name: "Name"
|
|
316
|
+
};
|
|
317
|
+
const renderTooltip = (row, label) => {
|
|
318
|
+
var _a, _b;
|
|
319
|
+
if (!row) return null;
|
|
320
|
+
return /* @__PURE__ */ import_react4.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" }, /* @__PURE__ */ import_react4.default.createElement("p", { className: "mb-2 font-semibold text-slate-800 dark:text-white/90" }, String((_b = (_a = row[finalXKey]) != null ? _a : label) != null ? _b : "Details")), Object.entries(row).map(([key, value]) => {
|
|
321
|
+
var _a2;
|
|
322
|
+
if (value === null || value === void 0 || key === finalXKey) return null;
|
|
323
|
+
if (typeof value === "object") return null;
|
|
324
|
+
return /* @__PURE__ */ import_react4.default.createElement("div", { key, className: "flex items-center justify-between gap-3 text-slate-600 dark:text-white/70" }, /* @__PURE__ */ import_react4.default.createElement("span", null, (_a2 = tooltipLabelMap[key]) != null ? _a2 : key), /* @__PURE__ */ import_react4.default.createElement("span", { className: "font-medium text-slate-900 dark:text-white/90" }, String(value)));
|
|
325
|
+
}));
|
|
326
|
+
};
|
|
327
|
+
const getTooltipRow = (payload) => {
|
|
328
|
+
if (!Array.isArray(payload) || payload.length === 0) return null;
|
|
329
|
+
const first = payload[0];
|
|
330
|
+
if (!first || typeof first !== "object" || !("payload" in first)) return null;
|
|
331
|
+
const row = first.payload;
|
|
332
|
+
if (!row || typeof row !== "object" || Array.isArray(row)) return null;
|
|
333
|
+
return row;
|
|
334
|
+
};
|
|
273
335
|
if (type === "pie") {
|
|
274
|
-
|
|
275
|
-
return /* @__PURE__ */ import_react4.default.createElement("div", { className: "w-full h-72 min-h-[280px] mt-4 mb-2 select-none overflow-hidden" }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.ResponsiveContainer, { width: "99%", height: "100%" }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.PieChart, null, /* @__PURE__ */ import_react4.default.createElement(
|
|
336
|
+
return /* @__PURE__ */ import_react4.default.createElement("div", { className: `w-full ${chartHeightClass} mt-4 mb-2 select-none overflow-hidden` }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.ResponsiveContainer, { width: "99%", height: "100%" }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.PieChart, null, /* @__PURE__ */ import_react4.default.createElement(
|
|
276
337
|
import_recharts.Pie,
|
|
277
338
|
{
|
|
278
339
|
data: sanitizedData,
|
|
@@ -280,47 +341,31 @@ function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6
|
|
|
280
341
|
nameKey: finalXKey,
|
|
281
342
|
cx: "50%",
|
|
282
343
|
cy: "50%",
|
|
283
|
-
outerRadius:
|
|
284
|
-
label:
|
|
344
|
+
outerRadius: pieOuterRadius,
|
|
345
|
+
label: pieLabel
|
|
285
346
|
},
|
|
286
|
-
|
|
287
|
-
), /* @__PURE__ */ import_react4.default.createElement(
|
|
288
|
-
import_recharts.Tooltip,
|
|
289
|
-
{
|
|
290
|
-
contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" }
|
|
291
|
-
}
|
|
292
|
-
), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, null))));
|
|
347
|
+
sanitizedData.map((entry, index) => /* @__PURE__ */ import_react4.default.createElement(import_recharts.Cell, { key: `cell-${index}`, fill: stockAwareColor(entry, index) }))
|
|
348
|
+
), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }))));
|
|
293
349
|
}
|
|
294
|
-
return /* @__PURE__ */ import_react4.default.createElement("div", { className:
|
|
295
|
-
import_recharts.Tooltip,
|
|
296
|
-
{
|
|
297
|
-
contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" },
|
|
298
|
-
cursor: { fill: "#f1f5f9" }
|
|
299
|
-
}
|
|
300
|
-
), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ import_react4.default.createElement(
|
|
350
|
+
return /* @__PURE__ */ import_react4.default.createElement("div", { className: `w-full ${chartHeightClass} mt-4 mb-2 select-none overflow-hidden` }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.ResponsiveContainer, { width: "99%", height: "100%" }, type === "bar" ? /* @__PURE__ */ import_react4.default.createElement(import_recharts.BarChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.XAxis, { dataKey: finalXKey, tick: axisTick, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.YAxis, { tick: axisTick, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0), cursor: { fill: "#f1f5f9" } }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ import_react4.default.createElement(
|
|
301
351
|
import_recharts.Bar,
|
|
302
352
|
{
|
|
303
353
|
key,
|
|
304
354
|
dataKey: key,
|
|
305
355
|
fill: colors[index % colors.length],
|
|
306
356
|
radius: [4, 4, 0, 0],
|
|
307
|
-
barSize: Math.max(20, 60 / data.length)
|
|
357
|
+
barSize: isCompact ? Math.max(14, 42 / data.length) : Math.max(20, 60 / data.length)
|
|
308
358
|
}
|
|
309
|
-
))) : /* @__PURE__ */ import_react4.default.createElement(import_recharts.LineChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.XAxis, { dataKey: finalXKey, tick:
|
|
310
|
-
import_recharts.Tooltip,
|
|
311
|
-
{
|
|
312
|
-
contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" }
|
|
313
|
-
}
|
|
314
|
-
), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ import_react4.default.createElement(
|
|
359
|
+
))) : /* @__PURE__ */ import_react4.default.createElement(import_recharts.LineChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.XAxis, { dataKey: finalXKey, tick: axisTick, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.YAxis, { tick: axisTick, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ import_react4.default.createElement(
|
|
315
360
|
import_recharts.Line,
|
|
316
361
|
{
|
|
317
362
|
key,
|
|
318
363
|
type: "monotone",
|
|
319
364
|
dataKey: key,
|
|
320
365
|
stroke: colors[index % colors.length],
|
|
321
|
-
strokeWidth: 3,
|
|
322
|
-
dot: { r: 4, strokeWidth: 2 },
|
|
323
|
-
activeDot: { r: 6 }
|
|
366
|
+
strokeWidth: isCompact ? 2 : 3,
|
|
367
|
+
dot: { r: isCompact ? 3 : 4, strokeWidth: 2 },
|
|
368
|
+
activeDot: { r: isCompact ? 5 : 6 }
|
|
324
369
|
}
|
|
325
370
|
)))));
|
|
326
371
|
}
|
|
@@ -379,6 +424,14 @@ function sanitizeJson(raw) {
|
|
|
379
424
|
}
|
|
380
425
|
return s;
|
|
381
426
|
}
|
|
427
|
+
function extractLikelyJsonBlock(raw) {
|
|
428
|
+
const trimmed = raw.trim();
|
|
429
|
+
const objectStart = trimmed.indexOf("{");
|
|
430
|
+
const arrayStart = trimmed.indexOf("[");
|
|
431
|
+
const starts = [objectStart, arrayStart].filter((index) => index >= 0);
|
|
432
|
+
if (starts.length === 0) return trimmed;
|
|
433
|
+
return trimmed.slice(Math.min(...starts));
|
|
434
|
+
}
|
|
382
435
|
function resolveImage(data) {
|
|
383
436
|
for (const key of ["image", "img", "thumbnail"]) {
|
|
384
437
|
const v = data[key];
|
|
@@ -395,7 +448,9 @@ function normaliseChild(children) {
|
|
|
395
448
|
}
|
|
396
449
|
return children;
|
|
397
450
|
}
|
|
398
|
-
function DataTable({ config }) {
|
|
451
|
+
function DataTable({ config, viewportSize = "large" }) {
|
|
452
|
+
const isCompact = viewportSize === "compact";
|
|
453
|
+
const isMedium = viewportSize === "medium";
|
|
399
454
|
const keys = import_react5.default.useMemo(() => {
|
|
400
455
|
if (Array.isArray(config.columns) && config.columns.length) {
|
|
401
456
|
return config.columns;
|
|
@@ -417,11 +472,11 @@ function DataTable({ config }) {
|
|
|
417
472
|
if (typeof val === "boolean") return val ? "\u2713" : "\u2717";
|
|
418
473
|
return String(val);
|
|
419
474
|
};
|
|
420
|
-
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-4 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden" }, config.title && /* @__PURE__ */ import_react5.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_react5.default.createElement("p", { className: "text-xs font-semibold text-slate-600 dark:text-white/70 uppercase tracking-wide" }, config.title)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ import_react5.default.createElement("table", { className:
|
|
475
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-4 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden" }, config.title && /* @__PURE__ */ import_react5.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_react5.default.createElement("p", { className: "text-xs font-semibold text-slate-600 dark:text-white/70 uppercase tracking-wide" }, config.title)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ import_react5.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_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, keys.map((k) => /* @__PURE__ */ import_react5.default.createElement(
|
|
421
476
|
"th",
|
|
422
477
|
{
|
|
423
478
|
key: k,
|
|
424
|
-
className: "px-4 py-3 font-semibold text-slate-700 dark:text-white/90 whitespace-nowrap
|
|
479
|
+
className: `${isCompact ? "px-2.5 py-2" : "px-4 py-3"} font-semibold text-slate-700 dark:text-white/90 whitespace-nowrap`
|
|
425
480
|
},
|
|
426
481
|
k
|
|
427
482
|
)))), /* @__PURE__ */ import_react5.default.createElement("tbody", null, config.data.map((row, ri) => /* @__PURE__ */ import_react5.default.createElement(
|
|
@@ -434,33 +489,54 @@ function DataTable({ config }) {
|
|
|
434
489
|
"td",
|
|
435
490
|
{
|
|
436
491
|
key: k,
|
|
437
|
-
className: "px-4 py-3 text-slate-600 dark:text-white/70 whitespace-nowrap
|
|
492
|
+
className: `${isCompact ? "px-2.5 py-2" : "px-4 py-3"} text-slate-600 dark:text-white/70 whitespace-nowrap`
|
|
438
493
|
},
|
|
439
494
|
formatCell(row[k])
|
|
440
495
|
))
|
|
441
496
|
))))), /* @__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" }, config.data.length, " row", config.data.length !== 1 ? "s" : "")));
|
|
442
497
|
}
|
|
443
|
-
function
|
|
498
|
+
function normalizeTabularRows(rows, columns) {
|
|
499
|
+
if (!Array.isArray(rows)) return [];
|
|
500
|
+
return rows.map((row) => {
|
|
501
|
+
if (Array.isArray(row)) {
|
|
502
|
+
const keys = Array.isArray(columns) && columns.length > 0 ? columns : row.map((_, index) => `column_${index + 1}`);
|
|
503
|
+
return keys.reduce((acc, key, index) => {
|
|
504
|
+
acc[key] = row[index];
|
|
505
|
+
return acc;
|
|
506
|
+
}, {});
|
|
507
|
+
}
|
|
508
|
+
if (row && typeof row === "object") {
|
|
509
|
+
return row;
|
|
510
|
+
}
|
|
511
|
+
return { value: row };
|
|
512
|
+
}).filter((row) => Object.keys(row).length > 0);
|
|
513
|
+
}
|
|
514
|
+
function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAddToCart, viewportSize = "large" }) {
|
|
515
|
+
var _a;
|
|
444
516
|
const result = import_react5.default.useMemo(() => {
|
|
445
517
|
if (isStreaming) return { loading: true };
|
|
446
518
|
try {
|
|
447
519
|
const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
|
|
448
|
-
const parsed = JSON.parse(sanitizeJson(clean));
|
|
520
|
+
const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
|
|
449
521
|
const config2 = __spreadValues({}, parsed);
|
|
450
522
|
if (!config2.view) {
|
|
451
523
|
if (config2.type === "products" || Array.isArray(config2.items)) {
|
|
452
524
|
config2.view = "carousel";
|
|
453
525
|
config2.data = config2.data || config2.items || [];
|
|
454
|
-
} else if (["pie", "bar", "line"].includes(config2.type) || ["pie", "bar", "line"].includes(config2.chartType)) {
|
|
526
|
+
} else if (typeof config2.type === "string" && ["pie", "bar", "line"].includes(config2.type) || typeof config2.chartType === "string" && ["pie", "bar", "line"].includes(config2.chartType)) {
|
|
527
|
+
const resolvedChartType = config2.chartType === "pie" || config2.chartType === "bar" || config2.chartType === "line" ? config2.chartType : config2.type === "pie" || config2.type === "bar" || config2.type === "line" ? config2.type : "bar";
|
|
455
528
|
config2.view = "chart";
|
|
456
|
-
config2.chartType =
|
|
529
|
+
config2.chartType = resolvedChartType;
|
|
457
530
|
config2.data = config2.data || [];
|
|
458
531
|
} else {
|
|
459
532
|
config2.view = "table";
|
|
460
533
|
config2.data = Array.isArray(config2.data) ? config2.data : Array.isArray(config2) ? config2 : [];
|
|
461
534
|
}
|
|
462
535
|
}
|
|
463
|
-
|
|
536
|
+
const normalizedConfig = __spreadProps(__spreadValues({}, config2), {
|
|
537
|
+
data: normalizeTabularRows(config2.data, config2.columns)
|
|
538
|
+
});
|
|
539
|
+
return { config: normalizedConfig };
|
|
464
540
|
} catch (err) {
|
|
465
541
|
return { error: String(err) };
|
|
466
542
|
}
|
|
@@ -472,28 +548,50 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming }) {
|
|
|
472
548
|
return /* @__PURE__ */ import_react5.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_react5.default.createElement("code", null, rawContent));
|
|
473
549
|
}
|
|
474
550
|
const { config } = result;
|
|
551
|
+
const isCompact = viewportSize === "compact";
|
|
552
|
+
const hasInsights = Array.isArray(config.insights) && config.insights.length > 0;
|
|
553
|
+
const hasDescription = typeof config.description === "string" && config.description.trim().length > 0;
|
|
475
554
|
switch (config.view) {
|
|
476
555
|
case "chart":
|
|
477
|
-
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-6 p-4 bg-white dark:bg-slate-900 rounded-2xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden
|
|
556
|
+
return /* @__PURE__ */ import_react5.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_react5.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_react5.default.createElement("p", { className: `px-2 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react5.default.createElement(
|
|
478
557
|
DynamicChart,
|
|
479
558
|
{
|
|
480
559
|
config: {
|
|
481
560
|
type: config.chartType || "bar",
|
|
482
|
-
data: config.data
|
|
561
|
+
data: config.data,
|
|
562
|
+
xAxisKey: config.xAxisKey,
|
|
563
|
+
dataKeys: config.dataKeys,
|
|
564
|
+
colors: config.colors
|
|
483
565
|
},
|
|
484
566
|
primaryColor,
|
|
485
|
-
accentColor
|
|
567
|
+
accentColor,
|
|
568
|
+
viewportSize
|
|
486
569
|
}
|
|
487
|
-
))
|
|
570
|
+
), hasInsights && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mt-4 flex flex-wrap gap-2 px-2" }, (_a = config.insights) == null ? void 0 : _a.map((insight) => /* @__PURE__ */ import_react5.default.createElement(
|
|
571
|
+
"span",
|
|
572
|
+
{
|
|
573
|
+
key: insight,
|
|
574
|
+
className: `rounded-full border border-emerald-200 bg-emerald-50 ${isCompact ? "px-2.5 py-1 text-[10px]" : "px-3 py-1 text-[11px]"} font-medium text-emerald-700 dark:border-emerald-500/20 dark:bg-emerald-500/10 dark:text-emerald-300`
|
|
575
|
+
},
|
|
576
|
+
insight
|
|
577
|
+
))));
|
|
488
578
|
case "carousel":
|
|
489
|
-
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-4" }, /* @__PURE__ */ import_react5.default.createElement(ProductCarousel, { products: config.data.map((item) => {
|
|
490
|
-
var
|
|
579
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-4" }, config.title && /* @__PURE__ */ import_react5.default.createElement("h4", { className: `${isCompact ? "mb-1.5 text-[11px]" : "mb-2 text-xs"} font-semibold text-slate-500` }, config.title), hasDescription && /* @__PURE__ */ import_react5.default.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react5.default.createElement(ProductCarousel, { products: config.data.map((item) => {
|
|
580
|
+
var _a2;
|
|
491
581
|
return __spreadProps(__spreadValues({}, item), {
|
|
492
|
-
image: (
|
|
582
|
+
image: (_a2 = item.image) != null ? _a2 : typeof resolveImage === "function" ? resolveImage(item) : void 0
|
|
493
583
|
});
|
|
494
|
-
}) }));
|
|
584
|
+
}), primaryColor, onAddToCart }));
|
|
495
585
|
case "table":
|
|
496
|
-
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-4 p-4 bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-auto
|
|
586
|
+
return /* @__PURE__ */ import_react5.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_react5.default.createElement("h4", { className: `${isCompact ? "text-[11px]" : "text-xs"} font-semibold text-slate-500 mb-2` }, config.title), hasDescription && /* @__PURE__ */ import_react5.default.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react5.default.createElement(DataTable, { config: {
|
|
587
|
+
type: "table",
|
|
588
|
+
title: config.title,
|
|
589
|
+
description: config.description,
|
|
590
|
+
columns: config.columns,
|
|
591
|
+
dataKeys: config.dataKeys,
|
|
592
|
+
xAxisKey: config.xAxisKey,
|
|
593
|
+
data: config.data
|
|
594
|
+
}, viewportSize }));
|
|
497
595
|
default:
|
|
498
596
|
return null;
|
|
499
597
|
}
|
|
@@ -504,10 +602,17 @@ function MessageBubble({
|
|
|
504
602
|
isStreaming = false,
|
|
505
603
|
primaryColor = "#6366f1",
|
|
506
604
|
accentColor = "#8b5cf6",
|
|
507
|
-
onAddToCart
|
|
605
|
+
onAddToCart,
|
|
606
|
+
viewportSize = "large"
|
|
508
607
|
}) {
|
|
509
608
|
const isUser = message.role === "user";
|
|
609
|
+
const isCompact = viewportSize === "compact";
|
|
610
|
+
const isMedium = viewportSize === "medium";
|
|
510
611
|
const [showSources, setShowSources] = import_react5.default.useState(false);
|
|
612
|
+
const hasStructuredProductBlock = import_react5.default.useMemo(
|
|
613
|
+
() => /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|type)"\s*:\s*"(?:carousel|products)"/i.test(message.content),
|
|
614
|
+
[message.content]
|
|
615
|
+
);
|
|
511
616
|
const productsFromSources = import_react5.default.useMemo(() => {
|
|
512
617
|
if (isUser || !sources) return [];
|
|
513
618
|
return sources.filter((s) => {
|
|
@@ -678,7 +783,9 @@ ${match.trim()}
|
|
|
678
783
|
rawContent: String(children != null ? children : "").trim(),
|
|
679
784
|
primaryColor,
|
|
680
785
|
accentColor,
|
|
681
|
-
isStreaming
|
|
786
|
+
isStreaming,
|
|
787
|
+
onAddToCart,
|
|
788
|
+
viewportSize
|
|
682
789
|
}
|
|
683
790
|
);
|
|
684
791
|
}
|
|
@@ -691,7 +798,9 @@ ${match.trim()}
|
|
|
691
798
|
rawContent: content,
|
|
692
799
|
primaryColor,
|
|
693
800
|
accentColor,
|
|
694
|
-
isStreaming
|
|
801
|
+
isStreaming,
|
|
802
|
+
onAddToCart,
|
|
803
|
+
viewportSize
|
|
695
804
|
}
|
|
696
805
|
);
|
|
697
806
|
}
|
|
@@ -702,23 +811,23 @@ ${match.trim()}
|
|
|
702
811
|
return /* @__PURE__ */ import_react5.default.createElement("code", __spreadValues({ className }, props), typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children));
|
|
703
812
|
}
|
|
704
813
|
}),
|
|
705
|
-
[primaryColor, accentColor, isStreaming]
|
|
814
|
+
[primaryColor, accentColor, isStreaming, onAddToCart, viewportSize]
|
|
706
815
|
);
|
|
707
|
-
return /* @__PURE__ */ import_react5.default.createElement("div", { className: `flex gap-3 ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ import_react5.default.createElement(
|
|
816
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: `flex ${isCompact ? "gap-2" : "gap-3"} ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ import_react5.default.createElement(
|
|
708
817
|
"div",
|
|
709
818
|
{
|
|
710
|
-
className: `flex-shrink-0 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"}`,
|
|
819
|
+
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"}`,
|
|
711
820
|
style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
|
|
712
821
|
},
|
|
713
|
-
isUser ? /* @__PURE__ */ import_react5.default.createElement(import_lucide_react4.User, { className: "w-4 h-4 text-white
|
|
714
|
-
), /* @__PURE__ */ import_react5.default.createElement("div", { className: `flex flex-col gap-1 max-w-[90%] ${isUser ? "items-end" : "items-start"}` }, /* @__PURE__ */ import_react5.default.createElement(
|
|
822
|
+
isUser ? /* @__PURE__ */ import_react5.default.createElement(import_lucide_react4.User, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"} text-white` }) : /* @__PURE__ */ import_react5.default.createElement(import_lucide_react4.Bot, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"}` })
|
|
823
|
+
), /* @__PURE__ */ import_react5.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_react5.default.createElement(
|
|
715
824
|
"div",
|
|
716
825
|
{
|
|
717
|
-
className: `relative px-4 py-3 rounded-2xl
|
|
826
|
+
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"}`,
|
|
718
827
|
style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
|
|
719
828
|
},
|
|
720
|
-
isStreaming && !message.content ? /* @__PURE__ */ import_react5.default.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ import_react5.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_react5.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_react5.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_react5.default.createElement("div", { className: `prose prose-sm max-w-none ${isUser ? "prose-invert" : "dark:prose-invert"}` }, /* @__PURE__ */ import_react5.default.createElement(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default], components: markdownComponents }, processedMarkdown), isStreaming && message.content && /* @__PURE__ */ import_react5.default.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
|
|
721
|
-
), !isUser && allProducts.length > 0 && /* @__PURE__ */ import_react5.default.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ import_react5.default.createElement(
|
|
829
|
+
isStreaming && !message.content ? /* @__PURE__ */ import_react5.default.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ import_react5.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_react5.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_react5.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_react5.default.createElement("div", { className: `prose ${isCompact ? "prose-xs" : "prose-sm"} max-w-none break-words ${isUser ? "prose-invert" : "dark:prose-invert"}` }, /* @__PURE__ */ import_react5.default.createElement(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default], components: markdownComponents }, processedMarkdown), isStreaming && message.content && /* @__PURE__ */ import_react5.default.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
|
|
830
|
+
), !isUser && !hasStructuredProductBlock && allProducts.length > 0 && /* @__PURE__ */ import_react5.default.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ import_react5.default.createElement(
|
|
722
831
|
ProductCarousel,
|
|
723
832
|
{
|
|
724
833
|
products: allProducts,
|
|
@@ -1014,6 +1123,8 @@ function ChatWindow({
|
|
|
1014
1123
|
const { ui, projectId } = useConfig();
|
|
1015
1124
|
const [input, setInput] = (0, import_react8.useState)("");
|
|
1016
1125
|
const [mounted, setMounted] = (0, import_react8.useState)(false);
|
|
1126
|
+
const [viewportSize, setViewportSize] = (0, import_react8.useState)("large");
|
|
1127
|
+
const windowRef = (0, import_react8.useRef)(null);
|
|
1017
1128
|
const bottomRef = (0, import_react8.useRef)(null);
|
|
1018
1129
|
const inputRef = (0, import_react8.useRef)(null);
|
|
1019
1130
|
const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
|
|
@@ -1072,6 +1183,22 @@ function ChatWindow({
|
|
|
1072
1183
|
(0, import_react8.useEffect)(() => {
|
|
1073
1184
|
setMounted(true);
|
|
1074
1185
|
}, []);
|
|
1186
|
+
(0, import_react8.useEffect)(() => {
|
|
1187
|
+
const element = windowRef.current;
|
|
1188
|
+
if (!element || typeof ResizeObserver === "undefined") return;
|
|
1189
|
+
const resolveViewportSize = (width) => {
|
|
1190
|
+
if (width < 420) return "compact";
|
|
1191
|
+
if (width < 640) return "medium";
|
|
1192
|
+
return "large";
|
|
1193
|
+
};
|
|
1194
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
1195
|
+
if (!entry) return;
|
|
1196
|
+
setViewportSize(resolveViewportSize(entry.contentRect.width));
|
|
1197
|
+
});
|
|
1198
|
+
setViewportSize(resolveViewportSize(element.getBoundingClientRect().width));
|
|
1199
|
+
observer.observe(element);
|
|
1200
|
+
return () => observer.disconnect();
|
|
1201
|
+
}, []);
|
|
1075
1202
|
(0, import_react8.useEffect)(() => {
|
|
1076
1203
|
var _a2;
|
|
1077
1204
|
if (messages.length > 0 || isLoading) {
|
|
@@ -1135,6 +1262,7 @@ function ChatWindow({
|
|
|
1135
1262
|
return /* @__PURE__ */ import_react8.default.createElement(
|
|
1136
1263
|
"div",
|
|
1137
1264
|
{
|
|
1265
|
+
ref: windowRef,
|
|
1138
1266
|
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}`,
|
|
1139
1267
|
style: __spreadValues({ "--primary": ui.primaryColor, "--accent": ui.accentColor }, style)
|
|
1140
1268
|
},
|
|
@@ -1231,7 +1359,8 @@ function ChatWindow({
|
|
|
1231
1359
|
isStreaming: isLoading && index === messages.length - 1 && msg.role === "assistant",
|
|
1232
1360
|
primaryColor: ui.primaryColor,
|
|
1233
1361
|
accentColor: ui.accentColor,
|
|
1234
|
-
onAddToCart
|
|
1362
|
+
onAddToCart,
|
|
1363
|
+
viewportSize
|
|
1235
1364
|
}
|
|
1236
1365
|
)), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */ import_react8.default.createElement(
|
|
1237
1366
|
MessageBubble,
|
|
@@ -1240,7 +1369,8 @@ function ChatWindow({
|
|
|
1240
1369
|
isStreaming: true,
|
|
1241
1370
|
primaryColor: ui.primaryColor,
|
|
1242
1371
|
accentColor: ui.accentColor,
|
|
1243
|
-
onAddToCart
|
|
1372
|
+
onAddToCart,
|
|
1373
|
+
viewportSize
|
|
1244
1374
|
}
|
|
1245
1375
|
), error && /* @__PURE__ */ import_react8.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_react8.default.createElement(import_lucide_react5.TriangleAlert, { className: "w-4 h-4 flex-shrink-0" }), /* @__PURE__ */ import_react8.default.createElement("span", null, error)), /* @__PURE__ */ import_react8.default.createElement("div", { ref: bottomRef })),
|
|
1246
1376
|
/* @__PURE__ */ import_react8.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_react8.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_react8.default.createElement(
|