@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.mjs
CHANGED
|
@@ -123,7 +123,7 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
|
|
|
123
123
|
};
|
|
124
124
|
if (!products || products.length === 0) return null;
|
|
125
125
|
if (products.length === 1) {
|
|
126
|
-
return /* @__PURE__ */ React3.createElement("div", { className: "my-4 w-[
|
|
126
|
+
return /* @__PURE__ */ React3.createElement("div", { className: "my-4 w-[min(88%,18rem)] min-w-0 max-w-full animate-fade-in-up" }, /* @__PURE__ */ React3.createElement(ProductCard, { product: products[0], primaryColor, onAddToCart }));
|
|
127
127
|
}
|
|
128
128
|
return /* @__PURE__ */ React3.createElement("div", { className: "relative w-full my-4 group/carousel animate-fade-in-up" }, canScroll && /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.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__ */ React3.createElement(
|
|
129
129
|
"button",
|
|
@@ -158,7 +158,7 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
|
|
|
158
158
|
"div",
|
|
159
159
|
{
|
|
160
160
|
key: product.id,
|
|
161
|
-
className: "snap-start flex-shrink-0 w-[
|
|
161
|
+
className: "snap-start flex-shrink-0 w-[min(88%,18rem)] min-w-[11rem] max-w-full"
|
|
162
162
|
},
|
|
163
163
|
/* @__PURE__ */ React3.createElement(ProductCard, { product, primaryColor, onAddToCart })
|
|
164
164
|
))
|
|
@@ -183,9 +183,20 @@ import {
|
|
|
183
183
|
ResponsiveContainer
|
|
184
184
|
} from "recharts";
|
|
185
185
|
var DEFAULT_COLORS = ["#6366f1", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#ec4899"];
|
|
186
|
-
function DynamicChart({
|
|
186
|
+
function DynamicChart({
|
|
187
|
+
config,
|
|
188
|
+
primaryColor = "#6366f1",
|
|
189
|
+
accentColor = "#8b5cf6",
|
|
190
|
+
viewportSize = "large"
|
|
191
|
+
}) {
|
|
187
192
|
const { type, data } = config;
|
|
188
193
|
const colors = config.colors || [primaryColor, accentColor, ...DEFAULT_COLORS];
|
|
194
|
+
const isCompact = viewportSize === "compact";
|
|
195
|
+
const isMedium = viewportSize === "medium";
|
|
196
|
+
const chartHeightClass = isCompact ? "h-56 min-h-[220px]" : isMedium ? "h-64 min-h-[250px]" : "h-72 min-h-[280px]";
|
|
197
|
+
const pieOuterRadius = isCompact ? 56 : isMedium ? 68 : 80;
|
|
198
|
+
const pieLabel = ({ name, percent }) => isCompact ? `${name}` : `${name} ${((percent != null ? percent : 0) * 100).toFixed(0)}%`;
|
|
199
|
+
const axisTick = { fontSize: isCompact ? 10 : 12, fill: "#64748b" };
|
|
189
200
|
const sanitizedData = React4.useMemo(() => {
|
|
190
201
|
if (!data) return [];
|
|
191
202
|
return data.map((item) => {
|
|
@@ -233,9 +244,59 @@ function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6
|
|
|
233
244
|
}).slice(0, 5);
|
|
234
245
|
const finalXKey = String(resolvedXKey);
|
|
235
246
|
const finalDataKeys = resolvedDataKeys.map(String).filter((k) => k !== "undefined");
|
|
247
|
+
const pieDataKey = finalDataKeys[0] || "value";
|
|
248
|
+
const stockAwareColor = (entry, index) => {
|
|
249
|
+
var _a, _b, _c;
|
|
250
|
+
const stockStatus = String(
|
|
251
|
+
(_c = (_b = (_a = entry.stockStatus) != null ? _a : entry.status) != null ? _b : entry.availability) != null ? _c : ""
|
|
252
|
+
).toLowerCase();
|
|
253
|
+
const inStockCount = typeof entry.inStockCount === "number" ? entry.inStockCount : void 0;
|
|
254
|
+
const outOfStockCount = typeof entry.outOfStockCount === "number" ? entry.outOfStockCount : void 0;
|
|
255
|
+
const inStockFlag = entry.inStock;
|
|
256
|
+
if (stockStatus.includes("in stock")) return "#10b981";
|
|
257
|
+
if (stockStatus.includes("out of stock")) return "#f97316";
|
|
258
|
+
if (typeof inStockFlag === "string" && inStockFlag.toLowerCase() === "true") return "#10b981";
|
|
259
|
+
if (inStockFlag === 1) return "#10b981";
|
|
260
|
+
if (inStockFlag === 0) return "#f97316";
|
|
261
|
+
if (typeof inStockCount === "number" || typeof outOfStockCount === "number") {
|
|
262
|
+
const inCount = inStockCount != null ? inStockCount : 0;
|
|
263
|
+
const outCount = outOfStockCount != null ? outOfStockCount : 0;
|
|
264
|
+
if (inCount > outCount) return "#10b981";
|
|
265
|
+
if (outCount > inCount) return "#f97316";
|
|
266
|
+
}
|
|
267
|
+
return colors[index % colors.length];
|
|
268
|
+
};
|
|
269
|
+
const tooltipLabelMap = {
|
|
270
|
+
value: "Value",
|
|
271
|
+
count: "Count",
|
|
272
|
+
inStock: "In stock",
|
|
273
|
+
inStockCount: "In stock",
|
|
274
|
+
outOfStockCount: "Out of stock",
|
|
275
|
+
stockStatus: "Stock status",
|
|
276
|
+
category: "Category",
|
|
277
|
+
label: "Label",
|
|
278
|
+
name: "Name"
|
|
279
|
+
};
|
|
280
|
+
const renderTooltip = (row, label) => {
|
|
281
|
+
var _a, _b;
|
|
282
|
+
if (!row) return null;
|
|
283
|
+
return /* @__PURE__ */ React4.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__ */ React4.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]) => {
|
|
284
|
+
var _a2;
|
|
285
|
+
if (value === null || value === void 0 || key === finalXKey) return null;
|
|
286
|
+
if (typeof value === "object") return null;
|
|
287
|
+
return /* @__PURE__ */ React4.createElement("div", { key, className: "flex items-center justify-between gap-3 text-slate-600 dark:text-white/70" }, /* @__PURE__ */ React4.createElement("span", null, (_a2 = tooltipLabelMap[key]) != null ? _a2 : key), /* @__PURE__ */ React4.createElement("span", { className: "font-medium text-slate-900 dark:text-white/90" }, String(value)));
|
|
288
|
+
}));
|
|
289
|
+
};
|
|
290
|
+
const getTooltipRow = (payload) => {
|
|
291
|
+
if (!Array.isArray(payload) || payload.length === 0) return null;
|
|
292
|
+
const first = payload[0];
|
|
293
|
+
if (!first || typeof first !== "object" || !("payload" in first)) return null;
|
|
294
|
+
const row = first.payload;
|
|
295
|
+
if (!row || typeof row !== "object" || Array.isArray(row)) return null;
|
|
296
|
+
return row;
|
|
297
|
+
};
|
|
236
298
|
if (type === "pie") {
|
|
237
|
-
|
|
238
|
-
return /* @__PURE__ */ React4.createElement("div", { className: "w-full h-72 min-h-[280px] mt-4 mb-2 select-none overflow-hidden" }, /* @__PURE__ */ React4.createElement(ResponsiveContainer, { width: "99%", height: "100%" }, /* @__PURE__ */ React4.createElement(PieChart, null, /* @__PURE__ */ React4.createElement(
|
|
299
|
+
return /* @__PURE__ */ React4.createElement("div", { className: `w-full ${chartHeightClass} mt-4 mb-2 select-none overflow-hidden` }, /* @__PURE__ */ React4.createElement(ResponsiveContainer, { width: "99%", height: "100%" }, /* @__PURE__ */ React4.createElement(PieChart, null, /* @__PURE__ */ React4.createElement(
|
|
239
300
|
Pie,
|
|
240
301
|
{
|
|
241
302
|
data: sanitizedData,
|
|
@@ -243,47 +304,31 @@ function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6
|
|
|
243
304
|
nameKey: finalXKey,
|
|
244
305
|
cx: "50%",
|
|
245
306
|
cy: "50%",
|
|
246
|
-
outerRadius:
|
|
247
|
-
label:
|
|
307
|
+
outerRadius: pieOuterRadius,
|
|
308
|
+
label: pieLabel
|
|
248
309
|
},
|
|
249
|
-
|
|
250
|
-
), /* @__PURE__ */ React4.createElement(
|
|
251
|
-
Tooltip,
|
|
252
|
-
{
|
|
253
|
-
contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" }
|
|
254
|
-
}
|
|
255
|
-
), /* @__PURE__ */ React4.createElement(Legend, null))));
|
|
310
|
+
sanitizedData.map((entry, index) => /* @__PURE__ */ React4.createElement(Cell, { key: `cell-${index}`, fill: stockAwareColor(entry, index) }))
|
|
311
|
+
), /* @__PURE__ */ React4.createElement(Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }), /* @__PURE__ */ React4.createElement(Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }))));
|
|
256
312
|
}
|
|
257
|
-
return /* @__PURE__ */ React4.createElement("div", { className:
|
|
258
|
-
Tooltip,
|
|
259
|
-
{
|
|
260
|
-
contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" },
|
|
261
|
-
cursor: { fill: "#f1f5f9" }
|
|
262
|
-
}
|
|
263
|
-
), /* @__PURE__ */ React4.createElement(Legend, { wrapperStyle: { fontSize: 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ React4.createElement(
|
|
313
|
+
return /* @__PURE__ */ React4.createElement("div", { className: `w-full ${chartHeightClass} mt-4 mb-2 select-none overflow-hidden` }, /* @__PURE__ */ React4.createElement(ResponsiveContainer, { width: "99%", height: "100%" }, type === "bar" ? /* @__PURE__ */ React4.createElement(BarChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ React4.createElement(CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ React4.createElement(XAxis, { dataKey: finalXKey, tick: axisTick, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ React4.createElement(YAxis, { tick: axisTick, tickLine: false, axisLine: false }), /* @__PURE__ */ React4.createElement(Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0), cursor: { fill: "#f1f5f9" } }), /* @__PURE__ */ React4.createElement(Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ React4.createElement(
|
|
264
314
|
Bar,
|
|
265
315
|
{
|
|
266
316
|
key,
|
|
267
317
|
dataKey: key,
|
|
268
318
|
fill: colors[index % colors.length],
|
|
269
319
|
radius: [4, 4, 0, 0],
|
|
270
|
-
barSize: Math.max(20, 60 / data.length)
|
|
320
|
+
barSize: isCompact ? Math.max(14, 42 / data.length) : Math.max(20, 60 / data.length)
|
|
271
321
|
}
|
|
272
|
-
))) : /* @__PURE__ */ React4.createElement(LineChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ React4.createElement(CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ React4.createElement(XAxis, { dataKey: finalXKey, tick:
|
|
273
|
-
Tooltip,
|
|
274
|
-
{
|
|
275
|
-
contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" }
|
|
276
|
-
}
|
|
277
|
-
), /* @__PURE__ */ React4.createElement(Legend, { wrapperStyle: { fontSize: 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ React4.createElement(
|
|
322
|
+
))) : /* @__PURE__ */ React4.createElement(LineChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ React4.createElement(CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ React4.createElement(XAxis, { dataKey: finalXKey, tick: axisTick, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ React4.createElement(YAxis, { tick: axisTick, tickLine: false, axisLine: false }), /* @__PURE__ */ React4.createElement(Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }), /* @__PURE__ */ React4.createElement(Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ React4.createElement(
|
|
278
323
|
Line,
|
|
279
324
|
{
|
|
280
325
|
key,
|
|
281
326
|
type: "monotone",
|
|
282
327
|
dataKey: key,
|
|
283
328
|
stroke: colors[index % colors.length],
|
|
284
|
-
strokeWidth: 3,
|
|
285
|
-
dot: { r: 4, strokeWidth: 2 },
|
|
286
|
-
activeDot: { r: 6 }
|
|
329
|
+
strokeWidth: isCompact ? 2 : 3,
|
|
330
|
+
dot: { r: isCompact ? 3 : 4, strokeWidth: 2 },
|
|
331
|
+
activeDot: { r: isCompact ? 5 : 6 }
|
|
287
332
|
}
|
|
288
333
|
)))));
|
|
289
334
|
}
|
|
@@ -342,6 +387,14 @@ function sanitizeJson(raw) {
|
|
|
342
387
|
}
|
|
343
388
|
return s;
|
|
344
389
|
}
|
|
390
|
+
function extractLikelyJsonBlock(raw) {
|
|
391
|
+
const trimmed = raw.trim();
|
|
392
|
+
const objectStart = trimmed.indexOf("{");
|
|
393
|
+
const arrayStart = trimmed.indexOf("[");
|
|
394
|
+
const starts = [objectStart, arrayStart].filter((index) => index >= 0);
|
|
395
|
+
if (starts.length === 0) return trimmed;
|
|
396
|
+
return trimmed.slice(Math.min(...starts));
|
|
397
|
+
}
|
|
345
398
|
function resolveImage(data) {
|
|
346
399
|
for (const key of ["image", "img", "thumbnail"]) {
|
|
347
400
|
const v = data[key];
|
|
@@ -358,7 +411,9 @@ function normaliseChild(children) {
|
|
|
358
411
|
}
|
|
359
412
|
return children;
|
|
360
413
|
}
|
|
361
|
-
function DataTable({ config }) {
|
|
414
|
+
function DataTable({ config, viewportSize = "large" }) {
|
|
415
|
+
const isCompact = viewportSize === "compact";
|
|
416
|
+
const isMedium = viewportSize === "medium";
|
|
362
417
|
const keys = React5.useMemo(() => {
|
|
363
418
|
if (Array.isArray(config.columns) && config.columns.length) {
|
|
364
419
|
return config.columns;
|
|
@@ -380,11 +435,11 @@ function DataTable({ config }) {
|
|
|
380
435
|
if (typeof val === "boolean") return val ? "\u2713" : "\u2717";
|
|
381
436
|
return String(val);
|
|
382
437
|
};
|
|
383
|
-
return /* @__PURE__ */ React5.createElement("div", { className: "my-4 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden" }, config.title && /* @__PURE__ */ React5.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__ */ React5.createElement("p", { className: "text-xs font-semibold text-slate-600 dark:text-white/70 uppercase tracking-wide" }, config.title)), /* @__PURE__ */ React5.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React5.createElement("table", { className:
|
|
438
|
+
return /* @__PURE__ */ React5.createElement("div", { className: "my-4 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden" }, config.title && /* @__PURE__ */ React5.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__ */ React5.createElement("p", { className: "text-xs font-semibold text-slate-600 dark:text-white/70 uppercase tracking-wide" }, config.title)), /* @__PURE__ */ React5.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React5.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__ */ React5.createElement("thead", { className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ React5.createElement("tr", null, keys.map((k) => /* @__PURE__ */ React5.createElement(
|
|
384
439
|
"th",
|
|
385
440
|
{
|
|
386
441
|
key: k,
|
|
387
|
-
className: "px-4 py-3 font-semibold text-slate-700 dark:text-white/90 whitespace-nowrap
|
|
442
|
+
className: `${isCompact ? "px-2.5 py-2" : "px-4 py-3"} font-semibold text-slate-700 dark:text-white/90 whitespace-nowrap`
|
|
388
443
|
},
|
|
389
444
|
k
|
|
390
445
|
)))), /* @__PURE__ */ React5.createElement("tbody", null, config.data.map((row, ri) => /* @__PURE__ */ React5.createElement(
|
|
@@ -397,33 +452,54 @@ function DataTable({ config }) {
|
|
|
397
452
|
"td",
|
|
398
453
|
{
|
|
399
454
|
key: k,
|
|
400
|
-
className: "px-4 py-3 text-slate-600 dark:text-white/70 whitespace-nowrap
|
|
455
|
+
className: `${isCompact ? "px-2.5 py-2" : "px-4 py-3"} text-slate-600 dark:text-white/70 whitespace-nowrap`
|
|
401
456
|
},
|
|
402
457
|
formatCell(row[k])
|
|
403
458
|
))
|
|
404
459
|
))))), /* @__PURE__ */ React5.createElement("div", { className: "px-4 py-2 bg-slate-50 dark:bg-white/5 border-t border-slate-100 dark:border-white/5" }, /* @__PURE__ */ React5.createElement("p", { className: "text-[11px] text-slate-400 dark:text-white/30" }, config.data.length, " row", config.data.length !== 1 ? "s" : "")));
|
|
405
460
|
}
|
|
406
|
-
function
|
|
461
|
+
function normalizeTabularRows(rows, columns) {
|
|
462
|
+
if (!Array.isArray(rows)) return [];
|
|
463
|
+
return rows.map((row) => {
|
|
464
|
+
if (Array.isArray(row)) {
|
|
465
|
+
const keys = Array.isArray(columns) && columns.length > 0 ? columns : row.map((_, index) => `column_${index + 1}`);
|
|
466
|
+
return keys.reduce((acc, key, index) => {
|
|
467
|
+
acc[key] = row[index];
|
|
468
|
+
return acc;
|
|
469
|
+
}, {});
|
|
470
|
+
}
|
|
471
|
+
if (row && typeof row === "object") {
|
|
472
|
+
return row;
|
|
473
|
+
}
|
|
474
|
+
return { value: row };
|
|
475
|
+
}).filter((row) => Object.keys(row).length > 0);
|
|
476
|
+
}
|
|
477
|
+
function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAddToCart, viewportSize = "large" }) {
|
|
478
|
+
var _a;
|
|
407
479
|
const result = React5.useMemo(() => {
|
|
408
480
|
if (isStreaming) return { loading: true };
|
|
409
481
|
try {
|
|
410
482
|
const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
|
|
411
|
-
const parsed = JSON.parse(sanitizeJson(clean));
|
|
483
|
+
const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
|
|
412
484
|
const config2 = __spreadValues({}, parsed);
|
|
413
485
|
if (!config2.view) {
|
|
414
486
|
if (config2.type === "products" || Array.isArray(config2.items)) {
|
|
415
487
|
config2.view = "carousel";
|
|
416
488
|
config2.data = config2.data || config2.items || [];
|
|
417
|
-
} else if (["pie", "bar", "line"].includes(config2.type) || ["pie", "bar", "line"].includes(config2.chartType)) {
|
|
489
|
+
} else if (typeof config2.type === "string" && ["pie", "bar", "line"].includes(config2.type) || typeof config2.chartType === "string" && ["pie", "bar", "line"].includes(config2.chartType)) {
|
|
490
|
+
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";
|
|
418
491
|
config2.view = "chart";
|
|
419
|
-
config2.chartType =
|
|
492
|
+
config2.chartType = resolvedChartType;
|
|
420
493
|
config2.data = config2.data || [];
|
|
421
494
|
} else {
|
|
422
495
|
config2.view = "table";
|
|
423
496
|
config2.data = Array.isArray(config2.data) ? config2.data : Array.isArray(config2) ? config2 : [];
|
|
424
497
|
}
|
|
425
498
|
}
|
|
426
|
-
|
|
499
|
+
const normalizedConfig = __spreadProps(__spreadValues({}, config2), {
|
|
500
|
+
data: normalizeTabularRows(config2.data, config2.columns)
|
|
501
|
+
});
|
|
502
|
+
return { config: normalizedConfig };
|
|
427
503
|
} catch (err) {
|
|
428
504
|
return { error: String(err) };
|
|
429
505
|
}
|
|
@@ -435,28 +511,50 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming }) {
|
|
|
435
511
|
return /* @__PURE__ */ React5.createElement("pre", { className: "p-4 my-2 bg-slate-900 text-slate-100 rounded-lg text-[10px] overflow-auto max-h-40" }, /* @__PURE__ */ React5.createElement("code", null, rawContent));
|
|
436
512
|
}
|
|
437
513
|
const { config } = result;
|
|
514
|
+
const isCompact = viewportSize === "compact";
|
|
515
|
+
const hasInsights = Array.isArray(config.insights) && config.insights.length > 0;
|
|
516
|
+
const hasDescription = typeof config.description === "string" && config.description.trim().length > 0;
|
|
438
517
|
switch (config.view) {
|
|
439
518
|
case "chart":
|
|
440
|
-
return /* @__PURE__ */ React5.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
|
|
519
|
+
return /* @__PURE__ */ React5.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__ */ React5.createElement("h4", { className: `${isCompact ? "text-[11px] mb-3" : "text-xs mb-4"} font-semibold text-slate-500 px-2` }, config.title), hasDescription && /* @__PURE__ */ React5.createElement("p", { className: `px-2 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ React5.createElement(
|
|
441
520
|
DynamicChart,
|
|
442
521
|
{
|
|
443
522
|
config: {
|
|
444
523
|
type: config.chartType || "bar",
|
|
445
|
-
data: config.data
|
|
524
|
+
data: config.data,
|
|
525
|
+
xAxisKey: config.xAxisKey,
|
|
526
|
+
dataKeys: config.dataKeys,
|
|
527
|
+
colors: config.colors
|
|
446
528
|
},
|
|
447
529
|
primaryColor,
|
|
448
|
-
accentColor
|
|
530
|
+
accentColor,
|
|
531
|
+
viewportSize
|
|
449
532
|
}
|
|
450
|
-
))
|
|
533
|
+
), hasInsights && /* @__PURE__ */ React5.createElement("div", { className: "mt-4 flex flex-wrap gap-2 px-2" }, (_a = config.insights) == null ? void 0 : _a.map((insight) => /* @__PURE__ */ React5.createElement(
|
|
534
|
+
"span",
|
|
535
|
+
{
|
|
536
|
+
key: insight,
|
|
537
|
+
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`
|
|
538
|
+
},
|
|
539
|
+
insight
|
|
540
|
+
))));
|
|
451
541
|
case "carousel":
|
|
452
|
-
return /* @__PURE__ */ React5.createElement("div", { className: "my-4" }, /* @__PURE__ */ React5.createElement(ProductCarousel, { products: config.data.map((item) => {
|
|
453
|
-
var
|
|
542
|
+
return /* @__PURE__ */ React5.createElement("div", { className: "my-4" }, config.title && /* @__PURE__ */ React5.createElement("h4", { className: `${isCompact ? "mb-1.5 text-[11px]" : "mb-2 text-xs"} font-semibold text-slate-500` }, config.title), hasDescription && /* @__PURE__ */ React5.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ React5.createElement(ProductCarousel, { products: config.data.map((item) => {
|
|
543
|
+
var _a2;
|
|
454
544
|
return __spreadProps(__spreadValues({}, item), {
|
|
455
|
-
image: (
|
|
545
|
+
image: (_a2 = item.image) != null ? _a2 : typeof resolveImage === "function" ? resolveImage(item) : void 0
|
|
456
546
|
});
|
|
457
|
-
}) }));
|
|
547
|
+
}), primaryColor, onAddToCart }));
|
|
458
548
|
case "table":
|
|
459
|
-
return /* @__PURE__ */ React5.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
|
|
549
|
+
return /* @__PURE__ */ React5.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__ */ React5.createElement("h4", { className: `${isCompact ? "text-[11px]" : "text-xs"} font-semibold text-slate-500 mb-2` }, config.title), hasDescription && /* @__PURE__ */ React5.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ React5.createElement(DataTable, { config: {
|
|
550
|
+
type: "table",
|
|
551
|
+
title: config.title,
|
|
552
|
+
description: config.description,
|
|
553
|
+
columns: config.columns,
|
|
554
|
+
dataKeys: config.dataKeys,
|
|
555
|
+
xAxisKey: config.xAxisKey,
|
|
556
|
+
data: config.data
|
|
557
|
+
}, viewportSize }));
|
|
460
558
|
default:
|
|
461
559
|
return null;
|
|
462
560
|
}
|
|
@@ -467,10 +565,17 @@ function MessageBubble({
|
|
|
467
565
|
isStreaming = false,
|
|
468
566
|
primaryColor = "#6366f1",
|
|
469
567
|
accentColor = "#8b5cf6",
|
|
470
|
-
onAddToCart
|
|
568
|
+
onAddToCart,
|
|
569
|
+
viewportSize = "large"
|
|
471
570
|
}) {
|
|
472
571
|
const isUser = message.role === "user";
|
|
572
|
+
const isCompact = viewportSize === "compact";
|
|
573
|
+
const isMedium = viewportSize === "medium";
|
|
473
574
|
const [showSources, setShowSources] = React5.useState(false);
|
|
575
|
+
const hasStructuredProductBlock = React5.useMemo(
|
|
576
|
+
() => /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|type)"\s*:\s*"(?:carousel|products)"/i.test(message.content),
|
|
577
|
+
[message.content]
|
|
578
|
+
);
|
|
474
579
|
const productsFromSources = React5.useMemo(() => {
|
|
475
580
|
if (isUser || !sources) return [];
|
|
476
581
|
return sources.filter((s) => {
|
|
@@ -641,7 +746,9 @@ ${match.trim()}
|
|
|
641
746
|
rawContent: String(children != null ? children : "").trim(),
|
|
642
747
|
primaryColor,
|
|
643
748
|
accentColor,
|
|
644
|
-
isStreaming
|
|
749
|
+
isStreaming,
|
|
750
|
+
onAddToCart,
|
|
751
|
+
viewportSize
|
|
645
752
|
}
|
|
646
753
|
);
|
|
647
754
|
}
|
|
@@ -654,7 +761,9 @@ ${match.trim()}
|
|
|
654
761
|
rawContent: content,
|
|
655
762
|
primaryColor,
|
|
656
763
|
accentColor,
|
|
657
|
-
isStreaming
|
|
764
|
+
isStreaming,
|
|
765
|
+
onAddToCart,
|
|
766
|
+
viewportSize
|
|
658
767
|
}
|
|
659
768
|
);
|
|
660
769
|
}
|
|
@@ -665,23 +774,23 @@ ${match.trim()}
|
|
|
665
774
|
return /* @__PURE__ */ React5.createElement("code", __spreadValues({ className }, props), typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children));
|
|
666
775
|
}
|
|
667
776
|
}),
|
|
668
|
-
[primaryColor, accentColor, isStreaming]
|
|
777
|
+
[primaryColor, accentColor, isStreaming, onAddToCart, viewportSize]
|
|
669
778
|
);
|
|
670
|
-
return /* @__PURE__ */ React5.createElement("div", { className: `flex gap-3 ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ React5.createElement(
|
|
779
|
+
return /* @__PURE__ */ React5.createElement("div", { className: `flex ${isCompact ? "gap-2" : "gap-3"} ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ React5.createElement(
|
|
671
780
|
"div",
|
|
672
781
|
{
|
|
673
|
-
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"}`,
|
|
782
|
+
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"}`,
|
|
674
783
|
style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
|
|
675
784
|
},
|
|
676
|
-
isUser ? /* @__PURE__ */ React5.createElement(User, { className: "w-4 h-4 text-white
|
|
677
|
-
), /* @__PURE__ */ React5.createElement("div", { className: `flex flex-col gap-1 max-w-[90%] ${isUser ? "items-end" : "items-start"}` }, /* @__PURE__ */ React5.createElement(
|
|
785
|
+
isUser ? /* @__PURE__ */ React5.createElement(User, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"} text-white` }) : /* @__PURE__ */ React5.createElement(Bot, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"}` })
|
|
786
|
+
), /* @__PURE__ */ React5.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__ */ React5.createElement(
|
|
678
787
|
"div",
|
|
679
788
|
{
|
|
680
|
-
className: `relative px-4 py-3 rounded-2xl
|
|
789
|
+
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"}`,
|
|
681
790
|
style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
|
|
682
791
|
},
|
|
683
|
-
isStreaming && !message.content ? /* @__PURE__ */ React5.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }), /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }), /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })) : /* @__PURE__ */ React5.createElement("div", { className: `prose prose-sm max-w-none ${isUser ? "prose-invert" : "dark:prose-invert"}` }, /* @__PURE__ */ React5.createElement(ReactMarkdown, { remarkPlugins: [remarkGfm], components: markdownComponents }, processedMarkdown), isStreaming && message.content && /* @__PURE__ */ React5.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
|
|
684
|
-
), !isUser && allProducts.length > 0 && /* @__PURE__ */ React5.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ React5.createElement(
|
|
792
|
+
isStreaming && !message.content ? /* @__PURE__ */ React5.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }), /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }), /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })) : /* @__PURE__ */ React5.createElement("div", { className: `prose ${isCompact ? "prose-xs" : "prose-sm"} max-w-none break-words ${isUser ? "prose-invert" : "dark:prose-invert"}` }, /* @__PURE__ */ React5.createElement(ReactMarkdown, { remarkPlugins: [remarkGfm], components: markdownComponents }, processedMarkdown), isStreaming && message.content && /* @__PURE__ */ React5.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
|
|
793
|
+
), !isUser && !hasStructuredProductBlock && allProducts.length > 0 && /* @__PURE__ */ React5.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ React5.createElement(
|
|
685
794
|
ProductCarousel,
|
|
686
795
|
{
|
|
687
796
|
products: allProducts,
|
|
@@ -963,6 +1072,8 @@ function ChatWindow({
|
|
|
963
1072
|
const { ui, projectId } = useConfig();
|
|
964
1073
|
const [input, setInput] = useState4("");
|
|
965
1074
|
const [mounted, setMounted] = useState4(false);
|
|
1075
|
+
const [viewportSize, setViewportSize] = useState4("large");
|
|
1076
|
+
const windowRef = useRef3(null);
|
|
966
1077
|
const bottomRef = useRef3(null);
|
|
967
1078
|
const inputRef = useRef3(null);
|
|
968
1079
|
const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
|
|
@@ -1021,6 +1132,22 @@ function ChatWindow({
|
|
|
1021
1132
|
useEffect4(() => {
|
|
1022
1133
|
setMounted(true);
|
|
1023
1134
|
}, []);
|
|
1135
|
+
useEffect4(() => {
|
|
1136
|
+
const element = windowRef.current;
|
|
1137
|
+
if (!element || typeof ResizeObserver === "undefined") return;
|
|
1138
|
+
const resolveViewportSize = (width) => {
|
|
1139
|
+
if (width < 420) return "compact";
|
|
1140
|
+
if (width < 640) return "medium";
|
|
1141
|
+
return "large";
|
|
1142
|
+
};
|
|
1143
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
1144
|
+
if (!entry) return;
|
|
1145
|
+
setViewportSize(resolveViewportSize(entry.contentRect.width));
|
|
1146
|
+
});
|
|
1147
|
+
setViewportSize(resolveViewportSize(element.getBoundingClientRect().width));
|
|
1148
|
+
observer.observe(element);
|
|
1149
|
+
return () => observer.disconnect();
|
|
1150
|
+
}, []);
|
|
1024
1151
|
useEffect4(() => {
|
|
1025
1152
|
var _a2;
|
|
1026
1153
|
if (messages.length > 0 || isLoading) {
|
|
@@ -1084,6 +1211,7 @@ function ChatWindow({
|
|
|
1084
1211
|
return /* @__PURE__ */ React8.createElement(
|
|
1085
1212
|
"div",
|
|
1086
1213
|
{
|
|
1214
|
+
ref: windowRef,
|
|
1087
1215
|
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}`,
|
|
1088
1216
|
style: __spreadValues({ "--primary": ui.primaryColor, "--accent": ui.accentColor }, style)
|
|
1089
1217
|
},
|
|
@@ -1180,7 +1308,8 @@ function ChatWindow({
|
|
|
1180
1308
|
isStreaming: isLoading && index === messages.length - 1 && msg.role === "assistant",
|
|
1181
1309
|
primaryColor: ui.primaryColor,
|
|
1182
1310
|
accentColor: ui.accentColor,
|
|
1183
|
-
onAddToCart
|
|
1311
|
+
onAddToCart,
|
|
1312
|
+
viewportSize
|
|
1184
1313
|
}
|
|
1185
1314
|
)), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */ React8.createElement(
|
|
1186
1315
|
MessageBubble,
|
|
@@ -1189,7 +1318,8 @@ function ChatWindow({
|
|
|
1189
1318
|
isStreaming: true,
|
|
1190
1319
|
primaryColor: ui.primaryColor,
|
|
1191
1320
|
accentColor: ui.accentColor,
|
|
1192
|
-
onAddToCart
|
|
1321
|
+
onAddToCart,
|
|
1322
|
+
viewportSize
|
|
1193
1323
|
}
|
|
1194
1324
|
), error && /* @__PURE__ */ React8.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__ */ React8.createElement(TriangleAlert, { className: "w-4 h-4 flex-shrink-0" }), /* @__PURE__ */ React8.createElement("span", null, error)), /* @__PURE__ */ React8.createElement("div", { ref: bottomRef })),
|
|
1195
1325
|
/* @__PURE__ */ React8.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__ */ React8.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__ */ React8.createElement(
|
package/dist/server.js
CHANGED
|
@@ -3913,23 +3913,70 @@ var Pipeline = class {
|
|
|
3913
3913
|
async initialize() {
|
|
3914
3914
|
var _a, _b;
|
|
3915
3915
|
if (this.initialised) return;
|
|
3916
|
-
const CHART_MARKER = "<!--
|
|
3916
|
+
const CHART_MARKER = "<!-- UI_PROTOCOL_V5 -->";
|
|
3917
3917
|
const chartInstruction = `
|
|
3918
3918
|
|
|
3919
3919
|
${CHART_MARKER}
|
|
3920
|
-
### UNIVERSAL UI PROTOCOL
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
- "
|
|
3925
|
-
- "
|
|
3926
|
-
|
|
3920
|
+
### UNIVERSAL UI PROTOCOL
|
|
3921
|
+
When the user asks for a visual representation, comparison, distribution, breakdown, table, list, catalog, products, carousel, stock view, or category summary, you MUST include exactly one \`\`\`ui\`\`\` block.
|
|
3922
|
+
|
|
3923
|
+
1. VIEW SELECTION
|
|
3924
|
+
- Use "chart" for distributions, percentages, counts, comparisons, trends, or "show me in a chart".
|
|
3925
|
+
- Use "carousel" for browseable product recommendations or when the user asks to see products/items/cards.
|
|
3926
|
+
- Use "table" for tabular/raw detail, explicit table/list requests, or when there are many attributes to compare.
|
|
3927
|
+
|
|
3928
|
+
2. REQUIRED JSON SHAPE
|
|
3927
3929
|
{
|
|
3928
3930
|
"view": "chart" | "carousel" | "table",
|
|
3929
|
-
"
|
|
3930
|
-
"
|
|
3931
|
+
"title": "Short heading",
|
|
3932
|
+
"description": "One sentence describing the view",
|
|
3933
|
+
"chartType": "pie" | "bar" | "line",
|
|
3934
|
+
"xAxisKey": "label",
|
|
3935
|
+
"dataKeys": ["value"],
|
|
3936
|
+
"columns": ["name", "category", "price", "stockStatus"],
|
|
3937
|
+
"insights": ["Short takeaway 1", "Short takeaway 2"],
|
|
3938
|
+
"data": []
|
|
3931
3939
|
}
|
|
3932
|
-
|
|
3940
|
+
|
|
3941
|
+
3. DATA RULES
|
|
3942
|
+
- Build the UI payload from retrieved context only. Do not invent products, categories, or stock values.
|
|
3943
|
+
- Aggregate raw product rows when the user asks for a chart.
|
|
3944
|
+
- For charts, every row in "data" must be flat JSON with primitive values only.
|
|
3945
|
+
- Prefer { "label": "...", "value": number } for pie charts.
|
|
3946
|
+
- If stock information exists, preserve it in each row with fields like "inStock", "inStockCount", "outOfStockCount", or "stockStatus".
|
|
3947
|
+
- If the user asks to highlight what is in stock, include those stock-related fields in the chart data and mention the pattern in "insights".
|
|
3948
|
+
- For carousel rows, include product-friendly fields such as id, name, brand, price, image, link, category, stockStatus.
|
|
3949
|
+
- For tables, keep "data" row-oriented and include "columns" when possible.
|
|
3950
|
+
|
|
3951
|
+
4. FORMAT RULES
|
|
3952
|
+
- Never use ASCII art, markdown tables as the primary answer, or text-only fake charts when a UI block is requested.
|
|
3953
|
+
- Put any short natural-language explanation before or after the \`\`\`ui\`\`\` block, but keep it concise.
|
|
3954
|
+
- Return valid JSON inside the \`\`\`ui\`\`\` block.
|
|
3955
|
+
- If the user explicitly asks for a pie chart, return "view": "chart" with "chartType": "pie", not a table fallback.
|
|
3956
|
+
- Do not prefix the JSON with labels like "Table View", "Alternative", or explanatory text inside the code block.
|
|
3957
|
+
|
|
3958
|
+
5. EXAMPLE
|
|
3959
|
+
User: "provide me the distribution of products across categories and highlight which ones are in stock in a pie chart"
|
|
3960
|
+
Assistant:
|
|
3961
|
+
\`\`\`ui
|
|
3962
|
+
{
|
|
3963
|
+
"view": "chart",
|
|
3964
|
+
"title": "Product Distribution Across Categories",
|
|
3965
|
+
"description": "Pie chart showing product count by category with stock signals preserved per slice.",
|
|
3966
|
+
"chartType": "pie",
|
|
3967
|
+
"xAxisKey": "label",
|
|
3968
|
+
"dataKeys": ["value"],
|
|
3969
|
+
"insights": [
|
|
3970
|
+
"Beauty has the highest product count.",
|
|
3971
|
+
"Electronics has the largest number of in-stock products."
|
|
3972
|
+
],
|
|
3973
|
+
"data": [
|
|
3974
|
+
{ "label": "Beauty", "value": 12, "inStockCount": 9, "outOfStockCount": 3 },
|
|
3975
|
+
{ "label": "Electronics", "value": 8, "inStockCount": 7, "outOfStockCount": 1 },
|
|
3976
|
+
{ "label": "Home", "value": 5, "inStockCount": 2, "outOfStockCount": 3 }
|
|
3977
|
+
]
|
|
3978
|
+
}
|
|
3979
|
+
\`\`\``;
|
|
3933
3980
|
if (!((_a = this.config.llm.systemPrompt) == null ? void 0 : _a.includes(CHART_MARKER))) {
|
|
3934
3981
|
this.config.llm.systemPrompt = (this.config.llm.systemPrompt || "") + chartInstruction;
|
|
3935
3982
|
}
|
package/dist/server.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retrivora-ai/rag-engine",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.6",
|
|
4
4
|
"description": "Retrivora AI is a plug-and-play AI engine for RAG chat experiences — generic vector DB + LLM provider, embeddable or standalone.",
|
|
5
5
|
"author": "Abhinav Alkuchi",
|
|
6
6
|
"license": "MIT",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createStreamHandler } from '@/handlers';
|
|
2
2
|
import { getRagConfig } from '@/config/serverConfig';
|
|
3
3
|
|
|
4
|
-
export const POST =
|
|
4
|
+
export const POST = createStreamHandler(getRagConfig());
|
|
@@ -65,6 +65,8 @@ export function ChatWindow({
|
|
|
65
65
|
const { ui, projectId } = useConfig();
|
|
66
66
|
const [input, setInput] = useState('');
|
|
67
67
|
const [mounted, setMounted] = useState(false);
|
|
68
|
+
const [viewportSize, setViewportSize] = useState<'compact' | 'medium' | 'large'>('large');
|
|
69
|
+
const windowRef = useRef<HTMLDivElement>(null);
|
|
68
70
|
const bottomRef = useRef<HTMLDivElement>(null);
|
|
69
71
|
const inputRef = useRef<HTMLTextAreaElement>(null);
|
|
70
72
|
const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
|
|
@@ -136,6 +138,27 @@ export function ChatWindow({
|
|
|
136
138
|
setMounted(true);
|
|
137
139
|
}, []);
|
|
138
140
|
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
const element = windowRef.current;
|
|
143
|
+
if (!element || typeof ResizeObserver === 'undefined') return;
|
|
144
|
+
|
|
145
|
+
const resolveViewportSize = (width: number) => {
|
|
146
|
+
if (width < 420) return 'compact';
|
|
147
|
+
if (width < 640) return 'medium';
|
|
148
|
+
return 'large';
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
152
|
+
if (!entry) return;
|
|
153
|
+
setViewportSize(resolveViewportSize(entry.contentRect.width));
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
setViewportSize(resolveViewportSize(element.getBoundingClientRect().width));
|
|
157
|
+
observer.observe(element);
|
|
158
|
+
|
|
159
|
+
return () => observer.disconnect();
|
|
160
|
+
}, []);
|
|
161
|
+
|
|
139
162
|
// Scroll to bottom on new message (but not on initial mount with empty messages)
|
|
140
163
|
useEffect(() => {
|
|
141
164
|
if (messages.length > 0 || isLoading) {
|
|
@@ -206,6 +229,7 @@ export function ChatWindow({
|
|
|
206
229
|
|
|
207
230
|
return (
|
|
208
231
|
<div
|
|
232
|
+
ref={windowRef}
|
|
209
233
|
className={`relative flex flex-col border border-slate-200 dark:border-white/10 shadow-2xl transition-all duration-300 ${currentRadius} ${
|
|
210
234
|
isGlass
|
|
211
235
|
? 'bg-white/90 dark:bg-[#0f0f1a]/90 backdrop-blur-xl'
|
|
@@ -344,6 +368,7 @@ export function ChatWindow({
|
|
|
344
368
|
primaryColor={ui.primaryColor}
|
|
345
369
|
accentColor={ui.accentColor}
|
|
346
370
|
onAddToCart={onAddToCart}
|
|
371
|
+
viewportSize={viewportSize}
|
|
347
372
|
/>
|
|
348
373
|
))
|
|
349
374
|
)}
|
|
@@ -356,6 +381,7 @@ export function ChatWindow({
|
|
|
356
381
|
primaryColor={ui.primaryColor}
|
|
357
382
|
accentColor={ui.accentColor}
|
|
358
383
|
onAddToCart={onAddToCart}
|
|
384
|
+
viewportSize={viewportSize}
|
|
359
385
|
/>
|
|
360
386
|
)}
|
|
361
387
|
|