@retrivora-ai/rag-engine 1.8.2 → 1.8.3
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/handlers/index.js +142 -16
- package/dist/handlers/index.mjs +5848 -17
- package/dist/index.d.mts +9 -15
- package/dist/index.d.ts +9 -15
- package/dist/index.js +1355 -919
- package/dist/index.mjs +1437 -896
- package/dist/server.d.mts +6 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.js +171 -17
- package/dist/server.mjs +5923 -68
- package/package.json +6 -6
- package/src/app/globals.css +35 -11
- package/src/components/ChatWidget.tsx +0 -1
- package/src/components/MarkdownComponents.tsx +3 -0
- package/src/components/MessageBubble.tsx +3 -2
- package/src/components/ObservabilityPanel.tsx +1 -1
- package/src/components/UIDispatcher.tsx +0 -3
- package/src/config/ConfigBuilder.ts +38 -1
- package/src/core/LangChainAgent.ts +1 -4
- package/src/core/Pipeline.ts +31 -18
- package/src/core/QueryProcessor.ts +65 -0
- package/src/rag/Reranker.ts +99 -6
- package/src/utils/ProductExtractor.ts +3 -3
- package/dist/ChromaDBProvider-MIDOR4FW.mjs +0 -8
- package/dist/MilvusProvider-U7SKC27V.mjs +0 -8
- package/dist/MongoDBProvider-YNKC7EJ6.mjs +0 -8
- package/dist/MultiTablePostgresProvider-ZLGSKTJR.mjs +0 -8
- package/dist/PineconeProvider-QZNRKTN2.mjs +0 -8
- package/dist/QdrantProvider-RLJTNGPY.mjs +0 -8
- package/dist/RedisProvider-SR65SCKV.mjs +0 -8
- package/dist/SimpleGraphProvider-SLOXO4M7.mjs +0 -62
- package/dist/UniversalVectorProvider-IN67OS56.mjs +0 -9
- package/dist/WeaviateProvider-5FWDFITI.mjs +0 -8
- package/dist/chunk-5AJ4XHLW.mjs +0 -201
- package/dist/chunk-5YGUXK7Z.mjs +0 -80
- package/dist/chunk-CFVEZTBJ.mjs +0 -102
- package/dist/chunk-ICKRMZQK.mjs +0 -76
- package/dist/chunk-IMP6FUCY.mjs +0 -30
- package/dist/chunk-LR3VMDVK.mjs +0 -157
- package/dist/chunk-LZVVLSDN.mjs +0 -4077
- package/dist/chunk-M6JSPGAR.mjs +0 -117
- package/dist/chunk-OZFBG4BA.mjs +0 -291
- package/dist/chunk-PSFPZXHX.mjs +0 -245
- package/dist/chunk-U55XRW3U.mjs +0 -96
- package/dist/chunk-VUQJVIJT.mjs +0 -148
- package/dist/chunk-X4TOT24V.mjs +0 -89
- package/dist/chunk-YLTMFW4M.mjs +0 -49
package/dist/index.js
CHANGED
|
@@ -73,19 +73,19 @@ __export(index_exports, {
|
|
|
73
73
|
module.exports = __toCommonJS(index_exports);
|
|
74
74
|
|
|
75
75
|
// src/components/ChatWidget.tsx
|
|
76
|
-
var
|
|
76
|
+
var import_react12 = require("react");
|
|
77
77
|
var import_lucide_react8 = require("lucide-react");
|
|
78
78
|
|
|
79
79
|
// src/components/ChatWindow.tsx
|
|
80
|
-
var
|
|
80
|
+
var import_react11 = require("react");
|
|
81
81
|
var import_lucide_react7 = require("lucide-react");
|
|
82
82
|
|
|
83
83
|
// src/components/DocumentUpload.tsx
|
|
84
|
-
var import_react2 =
|
|
84
|
+
var import_react2 = require("react");
|
|
85
85
|
var import_lucide_react = require("lucide-react");
|
|
86
86
|
|
|
87
87
|
// src/components/ConfigProvider.tsx
|
|
88
|
-
var import_react =
|
|
88
|
+
var import_react = require("react");
|
|
89
89
|
|
|
90
90
|
// src/utils/templateUtils.ts
|
|
91
91
|
function mergeDefined(base, override) {
|
|
@@ -137,6 +137,7 @@ var CHAT_SUGGESTIONS = [
|
|
|
137
137
|
];
|
|
138
138
|
|
|
139
139
|
// src/components/ConfigProvider.tsx
|
|
140
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
140
141
|
var ConfigContext = (0, import_react.createContext)(DEFAULT_CONFIG);
|
|
141
142
|
function ConfigProvider({
|
|
142
143
|
config,
|
|
@@ -147,13 +148,14 @@ function ConfigProvider({
|
|
|
147
148
|
ui: mergeDefined(DEFAULT_CONFIG.ui, config == null ? void 0 : config.ui),
|
|
148
149
|
embedding: config == null ? void 0 : config.embedding
|
|
149
150
|
};
|
|
150
|
-
return /* @__PURE__ */
|
|
151
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConfigContext.Provider, { value: merged, children });
|
|
151
152
|
}
|
|
152
153
|
function useConfig() {
|
|
153
154
|
return (0, import_react.useContext)(ConfigContext);
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
// src/components/DocumentUpload.tsx
|
|
158
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
157
159
|
function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
|
|
158
160
|
var _a;
|
|
159
161
|
const { ui, embedding } = useConfig();
|
|
@@ -224,92 +226,129 @@ function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
|
|
|
224
226
|
};
|
|
225
227
|
const isUploading = fileStates.some((s) => s.status === "uploading");
|
|
226
228
|
const hasIdle = fileStates.some((s) => s.status === "idle");
|
|
227
|
-
return /* @__PURE__ */
|
|
229
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
228
230
|
"div",
|
|
229
231
|
{
|
|
230
232
|
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}`,
|
|
231
233
|
onDragOver,
|
|
232
234
|
onDragLeave,
|
|
233
|
-
onDrop
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
235
|
+
onDrop,
|
|
236
|
+
children: [
|
|
237
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col items-center justify-center text-center", children: [
|
|
238
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
239
|
+
"div",
|
|
240
|
+
{
|
|
241
|
+
className: "w-12 h-12 rounded-full flex items-center justify-center mb-4 shadow-sm",
|
|
242
|
+
style: { background: `linear-gradient(135deg, ${ui.primaryColor}20, ${ui.accentColor}20)` },
|
|
243
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Upload, { className: "w-6 h-6", style: { color: ui.primaryColor } })
|
|
244
|
+
}
|
|
245
|
+
),
|
|
246
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "text-slate-900 dark:text-white font-semibold mb-1", children: "Upload Documents" }),
|
|
247
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-slate-500 dark:text-white/40 text-sm mb-6 max-w-xs", children: "Drag and drop PDF, DOCX, TXT, or JSON files to train your AI on your own data." }),
|
|
248
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
249
|
+
"button",
|
|
250
|
+
{
|
|
251
|
+
onClick: () => {
|
|
252
|
+
var _a2;
|
|
253
|
+
return (_a2 = fileInputRef.current) == null ? void 0 : _a2.click();
|
|
254
|
+
},
|
|
255
|
+
disabled: isUploading,
|
|
256
|
+
className: "px-4 py-2 rounded-lg text-sm font-medium transition-all hover:scale-105 active:scale-95 disabled:opacity-50",
|
|
257
|
+
style: {
|
|
258
|
+
backgroundColor: `${ui.primaryColor}15`,
|
|
259
|
+
color: ui.primaryColor,
|
|
260
|
+
border: `1px solid ${ui.primaryColor}30`
|
|
261
|
+
},
|
|
262
|
+
children: "Select Files"
|
|
263
|
+
}
|
|
264
|
+
),
|
|
265
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
266
|
+
"input",
|
|
267
|
+
{
|
|
268
|
+
ref: fileInputRef,
|
|
269
|
+
type: "file",
|
|
270
|
+
multiple: true,
|
|
271
|
+
onChange: onFileSelect,
|
|
272
|
+
className: "hidden",
|
|
273
|
+
accept: ".pdf,.docx,.txt,.md,.json,.csv"
|
|
274
|
+
}
|
|
275
|
+
),
|
|
276
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mt-6 flex flex-col items-center gap-2 text-sm", children: [
|
|
277
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "text-slate-600 dark:text-white/60 font-medium", children: "Embedding Dimension" }),
|
|
278
|
+
isChangeable ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
279
|
+
"select",
|
|
280
|
+
{
|
|
281
|
+
value: dimension,
|
|
282
|
+
onChange: (e) => setDimension(Number(e.target.value)),
|
|
283
|
+
disabled: isUploading,
|
|
284
|
+
className: "px-3 py-1.5 rounded-lg bg-slate-50 dark:bg-white/5 border border-slate-200 dark:border-white/10 text-slate-800 dark:text-white/90 outline-none focus:border-emerald-500 transition-colors",
|
|
285
|
+
children: availableDimensions.map((dim) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: dim, className: "bg-white dark:bg-slate-900", children: dim }, dim))
|
|
286
|
+
}
|
|
287
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "px-3 py-1.5 rounded-lg bg-slate-100 dark:bg-white/10 border border-slate-200 dark:border-white/10 text-slate-500 dark:text-white/50 cursor-not-allowed text-xs", children: [
|
|
288
|
+
dimension,
|
|
289
|
+
" (Fixed for ",
|
|
290
|
+
currentModel,
|
|
291
|
+
")"
|
|
292
|
+
] })
|
|
293
|
+
] })
|
|
294
|
+
] }),
|
|
295
|
+
fileStates.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mt-8 space-y-3", children: [
|
|
296
|
+
fileStates.map((state, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
297
|
+
"div",
|
|
298
|
+
{
|
|
299
|
+
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",
|
|
300
|
+
children: [
|
|
301
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-3 overflow-hidden", children: [
|
|
302
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "w-8 h-8 rounded-lg bg-white dark:bg-white/10 flex items-center justify-center shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.File, { className: "w-4 h-4 text-slate-400" }) }),
|
|
303
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "truncate", children: [
|
|
304
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs font-medium text-slate-700 dark:text-white/80 truncate", children: state.file.name }),
|
|
305
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "text-[10px] text-slate-400", children: [
|
|
306
|
+
(state.file.size / 1024).toFixed(1),
|
|
307
|
+
" KB"
|
|
308
|
+
] })
|
|
309
|
+
] })
|
|
310
|
+
] }),
|
|
311
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
312
|
+
state.status === "uploading" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Loader2, { className: "w-4 h-4 text-slate-400 animate-spin" }),
|
|
313
|
+
state.status === "success" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.CheckCircle, { className: "w-4 h-4 text-emerald-500" }),
|
|
314
|
+
state.status === "error" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { title: state.error, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.AlertCircle, { className: "w-4 h-4 text-rose-500" }) }),
|
|
315
|
+
state.status !== "uploading" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
316
|
+
"button",
|
|
317
|
+
{
|
|
318
|
+
onClick: () => removeFile(i),
|
|
319
|
+
className: "p-1 rounded-md hover:bg-slate-200 dark:hover:bg-white/10 transition-colors",
|
|
320
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.X, { className: "w-3.5 h-3.5 text-slate-400" })
|
|
321
|
+
}
|
|
322
|
+
)
|
|
323
|
+
] })
|
|
324
|
+
]
|
|
325
|
+
},
|
|
326
|
+
i
|
|
327
|
+
)),
|
|
328
|
+
hasIdle && !isUploading && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
329
|
+
"button",
|
|
330
|
+
{
|
|
331
|
+
onClick: uploadFiles,
|
|
332
|
+
className: "w-full mt-4 py-2.5 rounded-xl text-sm font-semibold text-white shadow-lg transition-all hover:scale-[1.02] active:scale-[0.98]",
|
|
333
|
+
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` },
|
|
334
|
+
children: "Start Upload"
|
|
335
|
+
}
|
|
336
|
+
)
|
|
337
|
+
] })
|
|
338
|
+
]
|
|
339
|
+
}
|
|
302
340
|
);
|
|
303
341
|
}
|
|
304
342
|
|
|
305
343
|
// src/components/MessageBubble.tsx
|
|
306
|
-
var
|
|
344
|
+
var import_react9 = __toESM(require("react"));
|
|
307
345
|
var import_lucide_react6 = require("lucide-react");
|
|
308
346
|
var import_react_markdown = __toESM(require("react-markdown"));
|
|
309
347
|
|
|
310
348
|
// src/components/SourceCard.tsx
|
|
311
349
|
var import_react3 = __toESM(require("react"));
|
|
312
350
|
var import_lucide_react2 = require("lucide-react");
|
|
351
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
313
352
|
function SourceCard({ source, index }) {
|
|
314
353
|
var _a, _b;
|
|
315
354
|
const [expanded, setExpanded] = import_react3.default.useState(false);
|
|
@@ -318,62 +357,98 @@ function SourceCard({ source, index }) {
|
|
|
318
357
|
const scoreBg = source.score >= 0.8 ? "bg-emerald-50 border-emerald-100 dark:bg-emerald-400/10 dark:border-emerald-400/20" : source.score >= 0.6 ? "bg-amber-50 border-amber-100 dark:bg-amber-400/10 dark:border-amber-400/20" : "bg-rose-50 border-rose-100 dark:bg-rose-400/10 dark:border-rose-400/20";
|
|
319
358
|
const preview = source.content.slice(0, 120);
|
|
320
359
|
const hasMore = source.content.length > 120;
|
|
321
|
-
return /* @__PURE__ */
|
|
360
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
322
361
|
"div",
|
|
323
362
|
{
|
|
324
363
|
className: `rounded-xl border backdrop-blur-sm p-3 transition-all duration-200 hover:scale-[1.01] cursor-pointer ${scoreBg}`,
|
|
325
|
-
onClick: () => setExpanded((e) => !e)
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
364
|
+
onClick: () => setExpanded((e) => !e),
|
|
365
|
+
children: [
|
|
366
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-start justify-between gap-2", children: [
|
|
367
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
368
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "flex-shrink-0 w-5 h-5 rounded-full bg-slate-200 dark:bg-white/10 flex items-center justify-center text-[10px] font-bold text-slate-500 dark:text-white/60", children: index + 1 }),
|
|
369
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-xs text-slate-500 dark:text-white/50 truncate font-mono", children: (_b = (_a = source.metadata) == null ? void 0 : _a.docId) != null ? _b : source.id })
|
|
370
|
+
] }),
|
|
371
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: `flex-shrink-0 text-xs font-semibold ${scoreColor} tabular-nums`, children: [
|
|
372
|
+
scorePercent,
|
|
373
|
+
"%"
|
|
374
|
+
] })
|
|
375
|
+
] }),
|
|
376
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mt-2 text-xs text-slate-600 dark:text-white/70 leading-relaxed", children: expanded ? source.content : `${preview}${hasMore && !expanded ? "\u2026" : ""}` }),
|
|
377
|
+
hasMore && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { className: "mt-1 text-[10px] text-indigo-400 hover:text-indigo-300 transition-colors flex items-center gap-0.5", children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
378
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.ChevronUp, { className: "w-3 h-3" }),
|
|
379
|
+
" Show less"
|
|
380
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
381
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.ChevronDown, { className: "w-3 h-3" }),
|
|
382
|
+
" Show more"
|
|
383
|
+
] }) })
|
|
384
|
+
]
|
|
385
|
+
}
|
|
330
386
|
);
|
|
331
387
|
}
|
|
332
388
|
|
|
333
389
|
// src/components/ProductCarousel.tsx
|
|
334
|
-
var
|
|
390
|
+
var import_react4 = require("react");
|
|
335
391
|
var import_lucide_react4 = require("lucide-react");
|
|
336
392
|
|
|
337
393
|
// src/components/ProductCard.tsx
|
|
338
|
-
var import_react4 = __toESM(require("react"));
|
|
339
394
|
var import_image = __toESM(require("next/image"));
|
|
340
395
|
var import_lucide_react3 = require("lucide-react");
|
|
396
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
341
397
|
function ProductCard({ product, primaryColor = "#6366f1", onAddToCart }) {
|
|
342
|
-
return /* @__PURE__ */
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
398
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex-shrink-0 w-full bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 rounded-xl overflow-hidden shadow-sm hover:shadow-md transition-all duration-300 group", children: [
|
|
399
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "relative h-40 w-full bg-slate-100 dark:bg-white/5 flex items-center justify-center overflow-hidden", children: [
|
|
400
|
+
product.image ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
401
|
+
import_image.default,
|
|
402
|
+
{
|
|
403
|
+
src: product.image,
|
|
404
|
+
alt: product.name,
|
|
405
|
+
fill: true,
|
|
406
|
+
unoptimized: true,
|
|
407
|
+
className: "object-cover group-hover:scale-105 transition-transform duration-500"
|
|
408
|
+
}
|
|
409
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "text-slate-400 dark:text-white/20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react3.ShoppingCart, { className: "w-12 h-12" }) }),
|
|
410
|
+
product.brand && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "absolute top-2 left-2 px-2 py-1 bg-white/90 dark:bg-black/60 backdrop-blur-md rounded-md text-[10px] font-bold uppercase tracking-wider text-slate-700 dark:text-white/90 shadow-sm", children: product.brand })
|
|
411
|
+
] }),
|
|
412
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "p-4 flex flex-col gap-2", children: [
|
|
413
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex justify-between items-start gap-2", children: [
|
|
414
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { className: "text-sm font-semibold text-slate-800 dark:text-white/90 line-clamp-1", children: product.name }),
|
|
415
|
+
product.price && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-sm font-bold", style: { color: primaryColor }, children: typeof product.price === "number" ? `$${product.price}` : String(product.price).match(/^[\d.]/) ? `$${product.price}` : product.price })
|
|
416
|
+
] }),
|
|
417
|
+
product.description && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "text-[11px] text-slate-500 dark:text-white/50 line-clamp-2 leading-relaxed", children: product.description }),
|
|
418
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mt-2 flex gap-2", children: [
|
|
419
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
420
|
+
"button",
|
|
421
|
+
{
|
|
422
|
+
onClick: () => onAddToCart == null ? void 0 : onAddToCart(product),
|
|
423
|
+
className: "flex-1 py-2 px-3 rounded-lg text-[11px] font-medium text-white shadow-sm hover:opacity-90 transition-opacity flex items-center justify-center gap-1.5",
|
|
424
|
+
style: { background: primaryColor },
|
|
425
|
+
children: [
|
|
426
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react3.ShoppingCart, { className: "w-3 h-3" }),
|
|
427
|
+
"Add to Cart"
|
|
428
|
+
]
|
|
429
|
+
}
|
|
430
|
+
),
|
|
431
|
+
product.link && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
432
|
+
"a",
|
|
433
|
+
{
|
|
434
|
+
href: product.link,
|
|
435
|
+
target: "_blank",
|
|
436
|
+
rel: "noopener noreferrer",
|
|
437
|
+
className: "p-2 rounded-lg bg-slate-100 dark:bg-white/10 text-slate-600 dark:text-white/70 hover:bg-slate-200 dark:hover:bg-white/20 transition-colors",
|
|
438
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react3.ExternalLink, { className: "w-3.5 h-3.5" })
|
|
439
|
+
}
|
|
440
|
+
)
|
|
441
|
+
] })
|
|
442
|
+
] })
|
|
443
|
+
] });
|
|
370
444
|
}
|
|
371
445
|
|
|
372
446
|
// src/components/ProductCarousel.tsx
|
|
447
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
373
448
|
function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
|
|
374
|
-
const scrollRef = (0,
|
|
375
|
-
const [canScroll, setCanScroll] = (0,
|
|
376
|
-
(0,
|
|
449
|
+
const scrollRef = (0, import_react4.useRef)(null);
|
|
450
|
+
const [canScroll, setCanScroll] = (0, import_react4.useState)(false);
|
|
451
|
+
(0, import_react4.useEffect)(() => {
|
|
377
452
|
const checkScroll = () => {
|
|
378
453
|
if (scrollRef.current) {
|
|
379
454
|
const hasOverflow = scrollRef.current.scrollWidth > scrollRef.current.clientWidth;
|
|
@@ -397,55 +472,61 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
|
|
|
397
472
|
};
|
|
398
473
|
if (!products || products.length === 0) return null;
|
|
399
474
|
if (products.length === 1) {
|
|
400
|
-
return /* @__PURE__ */
|
|
475
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "my-4 w-[min(88%,18rem)] min-w-0 max-w-full animate-fade-in-up", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ProductCard, { product: products[0], primaryColor, onAddToCart }) });
|
|
401
476
|
}
|
|
402
|
-
return /* @__PURE__ */
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
},
|
|
431
|
-
products.map((product) => /* @__PURE__ */ import_react5.default.createElement(
|
|
477
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "relative w-full my-4 group/carousel animate-fade-in-up", children: [
|
|
478
|
+
canScroll && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
479
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
480
|
+
"button",
|
|
481
|
+
{
|
|
482
|
+
onClick: (e) => {
|
|
483
|
+
e.stopPropagation();
|
|
484
|
+
scroll("left");
|
|
485
|
+
},
|
|
486
|
+
className: "p-2 rounded-full bg-white dark:bg-slate-800 shadow-xl border border-slate-200 dark:border-white/10 text-slate-600 dark:text-white/80 hover:text-indigo-500 dark:hover:text-indigo-400 transition-all hover:scale-110 active:scale-95",
|
|
487
|
+
"aria-label": "Scroll left",
|
|
488
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react4.ChevronLeft, { className: "w-5 h-5" })
|
|
489
|
+
}
|
|
490
|
+
) }),
|
|
491
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "absolute -right-4 top-1/2 -translate-y-1/2 z-20 opacity-100 md:opacity-0 md:group-hover/carousel:opacity-100 transition-opacity", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
492
|
+
"button",
|
|
493
|
+
{
|
|
494
|
+
onClick: (e) => {
|
|
495
|
+
e.stopPropagation();
|
|
496
|
+
scroll("right");
|
|
497
|
+
},
|
|
498
|
+
className: "p-2 rounded-full bg-white dark:bg-slate-800 shadow-xl border border-slate-200 dark:border-white/10 text-slate-600 dark:text-white/80 hover:text-indigo-500 dark:hover:text-indigo-400 transition-all hover:scale-110 active:scale-95",
|
|
499
|
+
"aria-label": "Scroll right",
|
|
500
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react4.ChevronRight, { className: "w-5 h-5" })
|
|
501
|
+
}
|
|
502
|
+
) })
|
|
503
|
+
] }),
|
|
504
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
432
505
|
"div",
|
|
433
506
|
{
|
|
434
|
-
|
|
435
|
-
className: "
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
507
|
+
ref: scrollRef,
|
|
508
|
+
className: "flex gap-4 overflow-x-auto pb-4 px-1 scrollbar-hide snap-x snap-mandatory",
|
|
509
|
+
style: { scrollbarWidth: "none", msOverflowStyle: "none" },
|
|
510
|
+
children: products.map((product) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
511
|
+
"div",
|
|
512
|
+
{
|
|
513
|
+
className: "snap-start flex-shrink-0 w-[min(88%,18rem)] min-w-[11rem] max-w-full",
|
|
514
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ProductCard, { product, primaryColor, onAddToCart })
|
|
515
|
+
},
|
|
516
|
+
product.id
|
|
517
|
+
))
|
|
518
|
+
}
|
|
519
|
+
)
|
|
520
|
+
] });
|
|
440
521
|
}
|
|
441
522
|
|
|
442
523
|
// src/components/VisualizationRenderer.tsx
|
|
443
|
-
var import_react7 = __toESM(require("react"));
|
|
444
524
|
var import_recharts2 = require("recharts");
|
|
445
525
|
|
|
446
526
|
// src/components/DynamicChart.tsx
|
|
447
|
-
var
|
|
527
|
+
var import_react5 = __toESM(require("react"));
|
|
448
528
|
var import_recharts = require("recharts");
|
|
529
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
449
530
|
var CHART_COLORS = ["#6366f1", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#ec4899"];
|
|
450
531
|
function DynamicChart({
|
|
451
532
|
config,
|
|
@@ -456,9 +537,9 @@ function DynamicChart({
|
|
|
456
537
|
}) {
|
|
457
538
|
const { type, data } = config;
|
|
458
539
|
const colors = config.colors || [primaryColor, accentColor, ...CHART_COLORS];
|
|
459
|
-
const containerRef =
|
|
460
|
-
const [containerWidth, setContainerWidth] =
|
|
461
|
-
|
|
540
|
+
const containerRef = import_react5.default.useRef(null);
|
|
541
|
+
const [containerWidth, setContainerWidth] = import_react5.default.useState(0);
|
|
542
|
+
import_react5.default.useEffect(() => {
|
|
462
543
|
const element = containerRef.current;
|
|
463
544
|
if (!element || typeof ResizeObserver === "undefined") return;
|
|
464
545
|
const updateWidth = (width) => {
|
|
@@ -484,7 +565,7 @@ function DynamicChart({
|
|
|
484
565
|
return text.length > maxLength ? `${text.slice(0, maxLength)}\u2026` : text;
|
|
485
566
|
};
|
|
486
567
|
const chartMargin = isTiny ? { top: 8, right: 4, left: -28, bottom: 0 } : isCompact ? { top: 10, right: 6, left: -24, bottom: 0 } : { top: 10, right: 10, left: -20, bottom: 0 };
|
|
487
|
-
const sanitizedData =
|
|
568
|
+
const sanitizedData = import_react5.default.useMemo(() => {
|
|
488
569
|
if (!data) return [];
|
|
489
570
|
return data.map((item) => {
|
|
490
571
|
const newItem = {};
|
|
@@ -518,17 +599,17 @@ function DynamicChart({
|
|
|
518
599
|
}, [data]);
|
|
519
600
|
if (isStreaming) {
|
|
520
601
|
const bars = type === "pie" ? 6 : 5;
|
|
521
|
-
return /* @__PURE__ */
|
|
602
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "w-full mt-4 mb-2 animate-pulse", children: type === "pie" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mx-auto w-40 h-40 rounded-full bg-slate-100 dark:bg-white/10" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex items-end gap-2 h-32 px-2", children: Array.from({ length: bars }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
522
603
|
"div",
|
|
523
604
|
{
|
|
524
|
-
key: i,
|
|
525
605
|
className: "flex-1 rounded-t-md bg-slate-100 dark:bg-white/10",
|
|
526
606
|
style: { height: `${40 + i % 3 * 25}%` }
|
|
527
|
-
}
|
|
528
|
-
|
|
607
|
+
},
|
|
608
|
+
i
|
|
609
|
+
)) }) });
|
|
529
610
|
}
|
|
530
611
|
if (!data || data.length === 0) {
|
|
531
|
-
return /* @__PURE__ */
|
|
612
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "p-4 text-sm text-slate-500", children: "No data available for chart." });
|
|
532
613
|
}
|
|
533
614
|
const firstItem = sanitizedData[0];
|
|
534
615
|
const allKeys = Object.keys(firstItem);
|
|
@@ -553,14 +634,20 @@ function DynamicChart({
|
|
|
553
634
|
const renderTooltip = (row, label) => {
|
|
554
635
|
var _a, _b;
|
|
555
636
|
if (!row) return null;
|
|
556
|
-
return /* @__PURE__ */
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
637
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("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", children: [
|
|
638
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mb-2 font-semibold text-slate-800 dark:text-white/90", children: String((_b = (_a = row[finalXKey]) != null ? _a : label) != null ? _b : "Details") }),
|
|
639
|
+
Object.entries(row).map(([key, value]) => {
|
|
640
|
+
var _a2;
|
|
641
|
+
if (value === null || value === void 0 || key === finalXKey) return null;
|
|
642
|
+
if (typeof value === "object") return null;
|
|
643
|
+
const forbiddenKeys = ["fill", "color", "payload", "percent", "stroke", "inStock"];
|
|
644
|
+
if (forbiddenKeys.includes(key)) return null;
|
|
645
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center justify-between gap-3 text-slate-600 dark:text-white/70", children: [
|
|
646
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: (_a2 = tooltipLabelMap[key]) != null ? _a2 : key }),
|
|
647
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "font-medium text-slate-900 dark:text-white/90", children: String(value) })
|
|
648
|
+
] }, key);
|
|
649
|
+
})
|
|
650
|
+
] });
|
|
564
651
|
};
|
|
565
652
|
const getTooltipRow = (payload) => {
|
|
566
653
|
if (!Array.isArray(payload) || payload.length === 0) return null;
|
|
@@ -571,45 +658,64 @@ function DynamicChart({
|
|
|
571
658
|
return row;
|
|
572
659
|
};
|
|
573
660
|
if (type === "pie") {
|
|
574
|
-
return /* @__PURE__ */
|
|
575
|
-
|
|
661
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref: containerRef, className: "w-full min-w-0 mt-4 mb-2 select-none overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mx-auto w-full max-w-full aspect-square", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_recharts.PieChart, { children: [
|
|
662
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
663
|
+
import_recharts.Pie,
|
|
664
|
+
{
|
|
665
|
+
data: sanitizedData,
|
|
666
|
+
dataKey: pieDataKey,
|
|
667
|
+
nameKey: finalXKey,
|
|
668
|
+
cx: "50%",
|
|
669
|
+
cy: "50%",
|
|
670
|
+
outerRadius: pieOuterRadius,
|
|
671
|
+
label: false,
|
|
672
|
+
labelLine: false,
|
|
673
|
+
children: sanitizedData.map((_entry, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_recharts.Cell, { fill: colors[index % colors.length] }, `cell-${index}`))
|
|
674
|
+
}
|
|
675
|
+
),
|
|
676
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_recharts.Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }),
|
|
677
|
+
showLegend && !isCompact && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_recharts.Legend, { wrapperStyle: { fontSize: 12 }, verticalAlign: "bottom" })
|
|
678
|
+
] }) }) }) });
|
|
679
|
+
}
|
|
680
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref: containerRef, className: "w-full min-w-0 mt-4 mb-2 select-none overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "w-full aspect-[4/3]", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_recharts.ResponsiveContainer, { width: "100%", height: "100%", children: type === "bar" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_recharts.BarChart, { data: sanitizedData, margin: chartMargin, children: [
|
|
681
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }),
|
|
682
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_recharts.XAxis, { dataKey: finalXKey, tick: axisTick, tickFormatter: truncateAxisLabel, tickLine: false, axisLine: { stroke: "#cbd5e1" }, interval: 0, minTickGap: isTiny ? 2 : isCompact ? 6 : 12 }),
|
|
683
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_recharts.YAxis, { tick: axisTick, tickLine: false, axisLine: false }),
|
|
684
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_recharts.Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0), cursor: { fill: "#f1f5f9" } }),
|
|
685
|
+
showLegend && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_recharts.Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }),
|
|
686
|
+
finalDataKeys.map((key, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
687
|
+
import_recharts.Bar,
|
|
576
688
|
{
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
cy: "50%",
|
|
582
|
-
outerRadius: pieOuterRadius,
|
|
583
|
-
label: false,
|
|
584
|
-
labelLine: false
|
|
689
|
+
dataKey: key,
|
|
690
|
+
fill: colors[index % colors.length],
|
|
691
|
+
radius: [4, 4, 0, 0],
|
|
692
|
+
barSize: isTiny ? Math.max(10, 28 / data.length) : isCompact ? Math.max(14, 42 / data.length) : Math.max(20, 60 / data.length)
|
|
585
693
|
},
|
|
586
|
-
|
|
587
|
-
)
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
import_recharts.
|
|
591
|
-
{
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
activeDot: { r: isTiny ? 4 : isCompact ? 5 : 6 }
|
|
608
|
-
}
|
|
609
|
-
))))));
|
|
694
|
+
key
|
|
695
|
+
))
|
|
696
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_recharts.LineChart, { data: sanitizedData, margin: chartMargin, children: [
|
|
697
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }),
|
|
698
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_recharts.XAxis, { dataKey: finalXKey, tick: axisTick, tickFormatter: truncateAxisLabel, tickLine: false, axisLine: { stroke: "#cbd5e1" }, interval: 0, minTickGap: isTiny ? 2 : isCompact ? 6 : 12 }),
|
|
699
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_recharts.YAxis, { tick: axisTick, tickLine: false, axisLine: false }),
|
|
700
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_recharts.Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }),
|
|
701
|
+
showLegend && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_recharts.Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }),
|
|
702
|
+
finalDataKeys.map((key, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
703
|
+
import_recharts.Line,
|
|
704
|
+
{
|
|
705
|
+
type: "monotone",
|
|
706
|
+
dataKey: key,
|
|
707
|
+
stroke: colors[index % colors.length],
|
|
708
|
+
strokeWidth: isTiny ? 1.75 : isCompact ? 2 : 3,
|
|
709
|
+
dot: { r: isTiny ? 2.5 : isCompact ? 3 : 4, strokeWidth: 2 },
|
|
710
|
+
activeDot: { r: isTiny ? 4 : isCompact ? 5 : 6 }
|
|
711
|
+
},
|
|
712
|
+
key
|
|
713
|
+
))
|
|
714
|
+
] }) }) }) });
|
|
610
715
|
}
|
|
611
716
|
|
|
612
717
|
// src/components/VisualizationRenderer.tsx
|
|
718
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
613
719
|
function getColor(index) {
|
|
614
720
|
return CHART_COLORS[index % CHART_COLORS.length];
|
|
615
721
|
}
|
|
@@ -619,13 +725,22 @@ function CustomTooltip({
|
|
|
619
725
|
label
|
|
620
726
|
}) {
|
|
621
727
|
if (!active || !payload || payload.length === 0) return null;
|
|
622
|
-
return /* @__PURE__ */
|
|
623
|
-
"
|
|
624
|
-
{
|
|
625
|
-
className: "
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
728
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("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", children: [
|
|
729
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "mb-2 font-semibold text-slate-800 dark:text-white/90", children: label }),
|
|
730
|
+
payload.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center justify-between gap-3 text-slate-600 dark:text-white/70", children: [
|
|
731
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "flex items-center gap-1.5", children: [
|
|
732
|
+
entry.color && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
733
|
+
"span",
|
|
734
|
+
{
|
|
735
|
+
className: "inline-block w-2 h-2 rounded-full flex-shrink-0",
|
|
736
|
+
style: { background: entry.color }
|
|
737
|
+
}
|
|
738
|
+
),
|
|
739
|
+
entry.name
|
|
740
|
+
] }),
|
|
741
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "font-medium text-slate-900 dark:text-white/90", children: entry.value })
|
|
742
|
+
] }, i))
|
|
743
|
+
] });
|
|
629
744
|
}
|
|
630
745
|
function VisualizationRenderer({
|
|
631
746
|
data,
|
|
@@ -636,72 +751,86 @@ function VisualizationRenderer({
|
|
|
636
751
|
}) {
|
|
637
752
|
var _a;
|
|
638
753
|
if (!data) {
|
|
639
|
-
return /* @__PURE__ */
|
|
754
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: `p-4 text-gray-500 ${className}`, children: "No data available for visualization" });
|
|
640
755
|
}
|
|
641
|
-
return /* @__PURE__ */
|
|
756
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `space-y-4 ${className}`, children: [
|
|
757
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-1", children: [
|
|
758
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { className: "text-sm font-semibold text-slate-900 dark:text-white", children: data.title }),
|
|
759
|
+
data.description && data.description !== ((_a = data.data) == null ? void 0 : _a.content) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-xs text-slate-500 dark:text-slate-400", children: data.description })
|
|
760
|
+
] }),
|
|
761
|
+
renderVisualization(data.type, data.data, onAddToCart, primaryColor, isStreaming)
|
|
762
|
+
] });
|
|
642
763
|
}
|
|
643
764
|
function renderVisualization(type, data, onAddToCart, primaryColor, isStreaming) {
|
|
644
765
|
try {
|
|
645
766
|
switch (type) {
|
|
646
767
|
case "pie_chart":
|
|
647
|
-
return /* @__PURE__ */
|
|
768
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PieChartView, { data, isStreaming });
|
|
648
769
|
case "bar_chart":
|
|
649
|
-
return /* @__PURE__ */
|
|
770
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(BarChartView, { data, primaryColor, isStreaming });
|
|
650
771
|
case "line_chart":
|
|
651
|
-
return /* @__PURE__ */
|
|
772
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(LineChartView, { data, primaryColor, isStreaming });
|
|
652
773
|
case "radar_chart":
|
|
653
|
-
return /* @__PURE__ */
|
|
774
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RadarChartView, { data, isStreaming });
|
|
654
775
|
case "table":
|
|
655
|
-
return /* @__PURE__ */
|
|
776
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TableView, { data, isStreaming });
|
|
656
777
|
case "product_carousel":
|
|
657
778
|
case "carousel":
|
|
658
|
-
return /* @__PURE__ */
|
|
779
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CarouselView, { data, onAddToCart, primaryColor });
|
|
659
780
|
case "text":
|
|
660
781
|
default:
|
|
661
|
-
return /* @__PURE__ */
|
|
782
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TextView, { data });
|
|
662
783
|
}
|
|
663
784
|
} catch (error) {
|
|
664
785
|
console.warn("[VisualizationRenderer] Rendering failed, falling back to text:", error);
|
|
665
|
-
return /* @__PURE__ */
|
|
786
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TextView, { data: { content: "Unable to render the requested visualization." } });
|
|
666
787
|
}
|
|
667
788
|
}
|
|
668
789
|
function ChartSkeleton({ type }) {
|
|
669
790
|
if (type === "pie") {
|
|
670
|
-
return /* @__PURE__ */
|
|
791
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "w-full mt-4 mb-2 animate-pulse", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mx-auto w-40 h-40 rounded-full bg-slate-100 dark:bg-white/10" }) });
|
|
671
792
|
}
|
|
672
793
|
if (type === "table") {
|
|
673
|
-
return /* @__PURE__ */
|
|
794
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "w-full mt-4 mb-2 animate-pulse space-y-2", children: [
|
|
795
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "h-8 bg-slate-100 dark:bg-white/10 rounded" }),
|
|
796
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "h-8 bg-slate-100 dark:bg-white/10 rounded" }),
|
|
797
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "h-8 bg-slate-100 dark:bg-white/10 rounded" })
|
|
798
|
+
] });
|
|
674
799
|
}
|
|
675
|
-
return /* @__PURE__ */
|
|
800
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "w-full mt-4 mb-2 animate-pulse flex items-end gap-2 h-32 px-2", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex-1 rounded-t-md bg-slate-100 dark:bg-white/10", style: { height: `${40 + i % 3 * 25}%` } }, i)) });
|
|
676
801
|
}
|
|
677
802
|
function PieChartView({ data, isStreaming }) {
|
|
678
|
-
if (isStreaming) return /* @__PURE__ */
|
|
803
|
+
if (isStreaming) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChartSkeleton, { type: "pie" });
|
|
679
804
|
if (!Array.isArray(data) || data.length === 0) {
|
|
680
|
-
return /* @__PURE__ */
|
|
805
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs text-red-500", children: "Invalid pie chart data" });
|
|
681
806
|
}
|
|
682
807
|
const chartData = data.map((item) => ({
|
|
683
808
|
name: item.label,
|
|
684
809
|
value: item.value
|
|
685
810
|
}));
|
|
686
|
-
return /* @__PURE__ */
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
811
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.ResponsiveContainer, { width: "100%", height: 280, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_recharts2.PieChart, { children: [
|
|
812
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
813
|
+
import_recharts2.Pie,
|
|
814
|
+
{
|
|
815
|
+
data: chartData,
|
|
816
|
+
dataKey: "value",
|
|
817
|
+
nameKey: "name",
|
|
818
|
+
cx: "50%",
|
|
819
|
+
cy: "50%",
|
|
820
|
+
outerRadius: "68%",
|
|
821
|
+
label: false,
|
|
822
|
+
labelLine: false,
|
|
823
|
+
children: chartData.map((_entry, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Cell, { fill: getColor(index) }, `cell-${index}`))
|
|
824
|
+
}
|
|
825
|
+
),
|
|
826
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Tooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CustomTooltip, {}) }),
|
|
827
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Legend, { wrapperStyle: { fontSize: 12 }, verticalAlign: "bottom" })
|
|
828
|
+
] }) }) });
|
|
700
829
|
}
|
|
701
830
|
function BarChartView({ data, primaryColor, isStreaming }) {
|
|
702
|
-
if (isStreaming) return /* @__PURE__ */
|
|
831
|
+
if (isStreaming) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChartSkeleton, { type: "bar" });
|
|
703
832
|
if (!Array.isArray(data) || data.length === 0) {
|
|
704
|
-
return /* @__PURE__ */
|
|
833
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs text-red-500", children: "Invalid bar chart data" });
|
|
705
834
|
}
|
|
706
835
|
const chartData = data.map((item) => __spreadValues(__spreadValues({
|
|
707
836
|
category: item.category,
|
|
@@ -709,20 +838,30 @@ function BarChartView({ data, primaryColor, isStreaming }) {
|
|
|
709
838
|
}, item.inStockCount !== void 0 && { inStockCount: item.inStockCount }), item.outOfStockCount !== void 0 && { outOfStockCount: item.outOfStockCount }));
|
|
710
839
|
const barColor = primaryColor != null ? primaryColor : getColor(0);
|
|
711
840
|
const hasStock = chartData.some((d) => "inStockCount" in d);
|
|
712
|
-
return /* @__PURE__ */
|
|
713
|
-
import_recharts2.
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
841
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.ResponsiveContainer, { width: "100%", height: 260, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_recharts2.BarChart, { data: chartData, margin: { top: 10, right: 10, left: -20, bottom: 0 }, children: [
|
|
842
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }),
|
|
843
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
844
|
+
import_recharts2.XAxis,
|
|
845
|
+
{
|
|
846
|
+
dataKey: "category",
|
|
847
|
+
tick: { fontSize: 11, fill: "#64748b" },
|
|
848
|
+
tickLine: false,
|
|
849
|
+
axisLine: { stroke: "#cbd5e1" }
|
|
850
|
+
}
|
|
851
|
+
),
|
|
852
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.YAxis, { tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: false }),
|
|
853
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Tooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CustomTooltip, {}), cursor: { fill: "#f1f5f9" } }),
|
|
854
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Legend, { wrapperStyle: { fontSize: 12 } }),
|
|
855
|
+
hasStock ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
856
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Bar, { dataKey: "inStockCount", name: "In Stock", fill: getColor(1), radius: [4, 4, 0, 0] }),
|
|
857
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Bar, { dataKey: "outOfStockCount", name: "Out of Stock", fill: getColor(3), radius: [4, 4, 0, 0] })
|
|
858
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Bar, { dataKey: "value", name: "Value", fill: barColor, radius: [4, 4, 0, 0] })
|
|
859
|
+
] }) }) });
|
|
721
860
|
}
|
|
722
861
|
function LineChartView({ data, primaryColor, isStreaming }) {
|
|
723
|
-
if (isStreaming) return /* @__PURE__ */
|
|
862
|
+
if (isStreaming) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChartSkeleton, { type: "bar" });
|
|
724
863
|
if (!Array.isArray(data) || data.length === 0) {
|
|
725
|
-
return /* @__PURE__ */
|
|
864
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs text-red-500", children: "Invalid line chart data" });
|
|
726
865
|
}
|
|
727
866
|
const chartData = data.map((point) => {
|
|
728
867
|
var _a;
|
|
@@ -732,74 +871,97 @@ function LineChartView({ data, primaryColor, isStreaming }) {
|
|
|
732
871
|
};
|
|
733
872
|
});
|
|
734
873
|
const lineColor = primaryColor != null ? primaryColor : getColor(0);
|
|
735
|
-
return /* @__PURE__ */
|
|
736
|
-
import_recharts2.
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
874
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.ResponsiveContainer, { width: "100%", height: 260, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_recharts2.LineChart, { data: chartData, margin: { top: 10, right: 10, left: -20, bottom: 0 }, children: [
|
|
875
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }),
|
|
876
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
877
|
+
import_recharts2.XAxis,
|
|
878
|
+
{
|
|
879
|
+
dataKey: "label",
|
|
880
|
+
tick: { fontSize: 11, fill: "#64748b" },
|
|
881
|
+
tickLine: false,
|
|
882
|
+
axisLine: { stroke: "#cbd5e1" }
|
|
883
|
+
}
|
|
884
|
+
),
|
|
885
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.YAxis, { tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: false }),
|
|
886
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Tooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CustomTooltip, {}) }),
|
|
887
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
888
|
+
import_recharts2.Line,
|
|
889
|
+
{
|
|
890
|
+
type: "monotone",
|
|
891
|
+
dataKey: "value",
|
|
892
|
+
name: "Value",
|
|
893
|
+
stroke: lineColor,
|
|
894
|
+
strokeWidth: 2.5,
|
|
895
|
+
dot: { r: 3.5, strokeWidth: 2, fill: lineColor },
|
|
896
|
+
activeDot: { r: 5 }
|
|
897
|
+
}
|
|
898
|
+
)
|
|
899
|
+
] }) }) });
|
|
755
900
|
}
|
|
756
901
|
function RadarChartView({ data, isStreaming }) {
|
|
757
|
-
if (isStreaming) return /* @__PURE__ */
|
|
902
|
+
if (isStreaming) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChartSkeleton, { type: "pie" });
|
|
758
903
|
if (!Array.isArray(data) || data.length === 0) {
|
|
759
|
-
return /* @__PURE__ */
|
|
904
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs text-red-500", children: "Invalid radar chart data" });
|
|
760
905
|
}
|
|
761
906
|
const productNames = Array.from(
|
|
762
907
|
new Set(data.flatMap((item) => Object.keys(item).filter((key) => key !== "attribute")))
|
|
763
908
|
);
|
|
764
|
-
return /* @__PURE__ */
|
|
765
|
-
import_recharts2.
|
|
766
|
-
{
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
909
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.ResponsiveContainer, { width: "100%", height: 300, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_recharts2.RadarChart, { cx: "50%", cy: "50%", outerRadius: "80%", data, children: [
|
|
910
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.PolarGrid, { stroke: "#e2e8f0" }),
|
|
911
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.PolarAngleAxis, { dataKey: "attribute", tick: { fontSize: 11, fill: "#64748b" } }),
|
|
912
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.PolarRadiusAxis, { tick: { fontSize: 10, fill: "#64748b" } }),
|
|
913
|
+
productNames.map((productName, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
914
|
+
import_recharts2.Radar,
|
|
915
|
+
{
|
|
916
|
+
name: productName,
|
|
917
|
+
dataKey: productName,
|
|
918
|
+
stroke: getColor(index),
|
|
919
|
+
fill: getColor(index),
|
|
920
|
+
fillOpacity: 0.4
|
|
921
|
+
},
|
|
922
|
+
productName
|
|
923
|
+
)),
|
|
924
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Tooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CustomTooltip, {}) }),
|
|
925
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_recharts2.Legend, { wrapperStyle: { fontSize: 12 } })
|
|
926
|
+
] }) }) });
|
|
775
927
|
}
|
|
776
928
|
function TableView({ data, isStreaming }) {
|
|
777
|
-
if (isStreaming) return /* @__PURE__ */
|
|
929
|
+
if (isStreaming) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChartSkeleton, { type: "table" });
|
|
778
930
|
if (!(data == null ? void 0 : data.columns) || !(data == null ? void 0 : data.rows)) {
|
|
779
|
-
return /* @__PURE__ */
|
|
931
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs text-red-500", children: "Invalid table data" });
|
|
780
932
|
}
|
|
781
|
-
return /* @__PURE__ */
|
|
782
|
-
"
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
933
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden", children: [
|
|
934
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("table", { className: "w-full text-sm border-collapse", children: [
|
|
935
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("thead", { className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tr", { children: data.columns.map((col, idx) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
936
|
+
"th",
|
|
937
|
+
{
|
|
938
|
+
className: "px-4 py-3 text-left text-xs font-semibold text-slate-700 dark:text-white/90 whitespace-nowrap uppercase tracking-wider",
|
|
939
|
+
children: col
|
|
940
|
+
},
|
|
941
|
+
idx
|
|
942
|
+
)) }) }),
|
|
943
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tbody", { className: "divide-y divide-slate-100 dark:divide-white/5", children: data.rows.map((row, rowIdx) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
944
|
+
"tr",
|
|
945
|
+
{
|
|
946
|
+
className: "hover:bg-slate-50/60 dark:hover:bg-white/5 transition-colors",
|
|
947
|
+
children: row.map((cell, cellIdx) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
948
|
+
"td",
|
|
949
|
+
{
|
|
950
|
+
className: "px-4 py-3 text-slate-600 dark:text-white/70 text-sm",
|
|
951
|
+
children: String(cell)
|
|
952
|
+
},
|
|
953
|
+
cellIdx
|
|
954
|
+
))
|
|
955
|
+
},
|
|
956
|
+
rowIdx
|
|
957
|
+
)) })
|
|
958
|
+
] }) }),
|
|
959
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "px-4 py-2 bg-slate-50 dark:bg-white/5 border-t border-slate-100 dark:border-white/5", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "text-[11px] text-slate-400 dark:text-white/30", children: [
|
|
960
|
+
data.rows.length,
|
|
961
|
+
" row",
|
|
962
|
+
data.rows.length !== 1 ? "s" : ""
|
|
963
|
+
] }) })
|
|
964
|
+
] });
|
|
803
965
|
}
|
|
804
966
|
function CarouselView({
|
|
805
967
|
data,
|
|
@@ -807,7 +969,7 @@ function CarouselView({
|
|
|
807
969
|
primaryColor
|
|
808
970
|
}) {
|
|
809
971
|
if (!Array.isArray(data)) {
|
|
810
|
-
return /* @__PURE__ */
|
|
972
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs text-red-500", children: "Invalid carousel data" });
|
|
811
973
|
}
|
|
812
974
|
const products = data.map((product) => ({
|
|
813
975
|
id: product.id,
|
|
@@ -819,23 +981,24 @@ function CarouselView({
|
|
|
819
981
|
description: product.description,
|
|
820
982
|
inStock: product.inStock
|
|
821
983
|
}));
|
|
822
|
-
return /* @__PURE__ */
|
|
984
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "w-full", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
823
985
|
ProductCarousel,
|
|
824
986
|
{
|
|
825
987
|
products,
|
|
826
988
|
primaryColor: primaryColor != null ? primaryColor : "#6366f1",
|
|
827
989
|
onAddToCart: (p) => onAddToCart == null ? void 0 : onAddToCart(p)
|
|
828
990
|
}
|
|
829
|
-
));
|
|
991
|
+
) });
|
|
830
992
|
}
|
|
831
993
|
function TextView({ data }) {
|
|
832
994
|
const content = (data == null ? void 0 : data.content) || String(data != null ? data : "");
|
|
833
|
-
return /* @__PURE__ */
|
|
995
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-sm text-slate-700 dark:text-slate-300 whitespace-pre-wrap leading-relaxed", children: content }) });
|
|
834
996
|
}
|
|
835
997
|
|
|
836
998
|
// src/components/ObservabilityPanel.tsx
|
|
837
|
-
var
|
|
999
|
+
var import_react6 = __toESM(require("react"));
|
|
838
1000
|
var import_lucide_react5 = require("lucide-react");
|
|
1001
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
839
1002
|
function fmtMs(ms) {
|
|
840
1003
|
return ms >= 1e3 ? `${(ms / 1e3).toFixed(2)}s` : `${Math.round(ms)}ms`;
|
|
841
1004
|
}
|
|
@@ -845,25 +1008,55 @@ function fmtTokens(n) {
|
|
|
845
1008
|
function ScoreBadge({ score }) {
|
|
846
1009
|
const pct = Math.round(score * 100);
|
|
847
1010
|
const color = pct <= 20 ? "text-emerald-600 bg-emerald-50 border-emerald-200 dark:text-emerald-400 dark:bg-emerald-500/10 dark:border-emerald-500/20" : pct <= 50 ? "text-amber-600 bg-amber-50 border-amber-200 dark:text-amber-400 dark:bg-amber-500/10 dark:border-amber-500/20" : "text-red-600 bg-red-50 border-red-200 dark:text-red-400 dark:bg-red-500/10 dark:border-red-500/20";
|
|
848
|
-
return /* @__PURE__ */
|
|
1011
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: `inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[11px] font-semibold border ${color}`, children: [
|
|
1012
|
+
pct <= 20 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react5.CheckCircle, { className: "w-3 h-3" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react5.AlertCircle, { className: "w-3 h-3" }),
|
|
1013
|
+
pct,
|
|
1014
|
+
"% hallucination risk"
|
|
1015
|
+
] });
|
|
849
1016
|
}
|
|
850
1017
|
function RetrievalTab({ trace }) {
|
|
851
|
-
return /* @__PURE__ */
|
|
852
|
-
"
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
1018
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-2", children: [
|
|
1019
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { className: "text-[11px] text-slate-500 dark:text-white/40", children: [
|
|
1020
|
+
trace.chunks.length,
|
|
1021
|
+
" chunk",
|
|
1022
|
+
trace.chunks.length !== 1 ? "s" : "",
|
|
1023
|
+
" retrieved",
|
|
1024
|
+
trace.rewrittenQuery && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "ml-2 italic", children: [
|
|
1025
|
+
"(query rewritten: ",
|
|
1026
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("em", { className: "text-indigo-500", children: trace.rewrittenQuery }),
|
|
1027
|
+
")"
|
|
1028
|
+
] })
|
|
1029
|
+
] }),
|
|
1030
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "space-y-1.5 max-h-56 overflow-y-auto pr-1 custom-scrollbar", children: trace.chunks.map((chunk, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
859
1031
|
"div",
|
|
860
1032
|
{
|
|
861
|
-
className: "
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
1033
|
+
className: "rounded-lg border border-slate-100 dark:border-white/8 bg-slate-50 dark:bg-white/3 p-2.5",
|
|
1034
|
+
children: [
|
|
1035
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center justify-between mb-1", children: [
|
|
1036
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "text-[10px] font-mono text-slate-400 dark:text-white/30", children: [
|
|
1037
|
+
"[",
|
|
1038
|
+
i + 1,
|
|
1039
|
+
"] ",
|
|
1040
|
+
String(chunk.id).slice(0, 20)
|
|
1041
|
+
] }),
|
|
1042
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "text-[10px] font-semibold text-indigo-600 dark:text-indigo-400", children: [
|
|
1043
|
+
"score: ",
|
|
1044
|
+
chunk.score.toFixed(3)
|
|
1045
|
+
] })
|
|
1046
|
+
] }),
|
|
1047
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "h-1 rounded-full bg-slate-200 dark:bg-white/10 mb-2 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1048
|
+
"div",
|
|
1049
|
+
{
|
|
1050
|
+
className: "h-full rounded-full bg-indigo-500 dark:bg-indigo-400 transition-all",
|
|
1051
|
+
style: { width: `${Math.min(100, chunk.score * 100)}%` }
|
|
1052
|
+
}
|
|
1053
|
+
) }),
|
|
1054
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-[11px] text-slate-600 dark:text-white/60 line-clamp-2 leading-relaxed", children: chunk.content })
|
|
1055
|
+
]
|
|
1056
|
+
},
|
|
1057
|
+
String(chunk.id)
|
|
1058
|
+
)) })
|
|
1059
|
+
] });
|
|
867
1060
|
}
|
|
868
1061
|
function LatencyTab({ trace }) {
|
|
869
1062
|
const { latency } = trace;
|
|
@@ -874,73 +1067,153 @@ function LatencyTab({ trace }) {
|
|
|
874
1067
|
{ label: "Generate", ms: latency.generateMs, color: "#8b5cf6" }
|
|
875
1068
|
];
|
|
876
1069
|
const maxMs = Math.max(...bars.map((b) => b.ms), 1);
|
|
877
|
-
return /* @__PURE__ */
|
|
878
|
-
"div",
|
|
879
|
-
|
|
880
|
-
className: "
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
1070
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-3", children: [
|
|
1071
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
1072
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-[11px] text-slate-500 dark:text-white/40", children: "Pipeline stages" }),
|
|
1073
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "text-[11px] font-semibold text-slate-700 dark:text-white/70", children: [
|
|
1074
|
+
"Total: ",
|
|
1075
|
+
fmtMs(latency.totalMs)
|
|
1076
|
+
] })
|
|
1077
|
+
] }),
|
|
1078
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "space-y-2", children: bars.map((bar) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-0.5", children: [
|
|
1079
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
1080
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-[11px] text-slate-600 dark:text-white/60", children: bar.label }),
|
|
1081
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-[11px] font-mono text-slate-500 dark:text-white/40", children: fmtMs(bar.ms) })
|
|
1082
|
+
] }),
|
|
1083
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "h-2 rounded-full bg-slate-100 dark:bg-white/8 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1084
|
+
"div",
|
|
1085
|
+
{
|
|
1086
|
+
className: "h-full rounded-full transition-all duration-700",
|
|
1087
|
+
style: {
|
|
1088
|
+
width: `${bar.ms / maxMs * 100}%`,
|
|
1089
|
+
background: bar.color,
|
|
1090
|
+
opacity: 0.85
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
) })
|
|
1094
|
+
] }, bar.label)) })
|
|
1095
|
+
] });
|
|
888
1096
|
}
|
|
889
1097
|
function TokensTab({ trace }) {
|
|
890
1098
|
const { tokens } = trace;
|
|
891
1099
|
if (!tokens) {
|
|
892
|
-
return /* @__PURE__ */
|
|
1100
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-[11px] text-slate-400 dark:text-white/30 italic", children: "Token data not available." });
|
|
893
1101
|
}
|
|
894
1102
|
const stats = [
|
|
895
1103
|
{ label: "Prompt Tokens", value: fmtTokens(tokens.promptTokens), color: "text-indigo-600 dark:text-indigo-400" },
|
|
896
1104
|
{ label: "Completion Tokens", value: fmtTokens(tokens.completionTokens), color: "text-emerald-600 dark:text-emerald-400" },
|
|
897
1105
|
{ label: "Total Tokens", value: fmtTokens(tokens.totalTokens), color: "text-slate-700 dark:text-white/80" }
|
|
898
1106
|
];
|
|
899
|
-
return /* @__PURE__ */
|
|
900
|
-
"div",
|
|
901
|
-
|
|
902
|
-
className: "
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
1107
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-3", children: [
|
|
1108
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "grid grid-cols-3 gap-2", children: stats.map((s) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rounded-lg border border-slate-100 dark:border-white/8 bg-slate-50 dark:bg-white/3 p-2.5 text-center", children: [
|
|
1109
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: `text-lg font-bold ${s.color}`, children: s.value }),
|
|
1110
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-[10px] text-slate-400 dark:text-white/30 mt-0.5", children: s.label })
|
|
1111
|
+
] }, s.label)) }),
|
|
1112
|
+
tokens.estimatedCostUsd != null && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center justify-between rounded-lg border border-emerald-100 dark:border-emerald-500/20 bg-emerald-50 dark:bg-emerald-500/10 px-3 py-2", children: [
|
|
1113
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-[11px] text-emerald-700 dark:text-emerald-400 font-medium", children: "Estimated Cost" }),
|
|
1114
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "text-[11px] font-bold text-emerald-700 dark:text-emerald-400", children: [
|
|
1115
|
+
"$",
|
|
1116
|
+
tokens.estimatedCostUsd < 1e-4 ? tokens.estimatedCostUsd.toExponential(2) : tokens.estimatedCostUsd.toFixed(5),
|
|
1117
|
+
" USD"
|
|
1118
|
+
] })
|
|
1119
|
+
] }),
|
|
1120
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "h-2 rounded-full overflow-hidden flex", children: [
|
|
1121
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1122
|
+
"div",
|
|
1123
|
+
{
|
|
1124
|
+
className: "h-full bg-indigo-500 dark:bg-indigo-400",
|
|
1125
|
+
style: { width: `${tokens.promptTokens / tokens.totalTokens * 100}%` },
|
|
1126
|
+
title: "Prompt tokens"
|
|
1127
|
+
}
|
|
1128
|
+
),
|
|
1129
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1130
|
+
"div",
|
|
1131
|
+
{
|
|
1132
|
+
className: "h-full bg-emerald-500 dark:bg-emerald-400",
|
|
1133
|
+
style: { width: `${tokens.completionTokens / tokens.totalTokens * 100}%` },
|
|
1134
|
+
title: "Completion tokens"
|
|
1135
|
+
}
|
|
1136
|
+
)
|
|
1137
|
+
] }),
|
|
1138
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex gap-3 text-[10px] text-slate-400 dark:text-white/30", children: [
|
|
1139
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex items-center gap-1", children: [
|
|
1140
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "inline-block w-2 h-2 rounded-full bg-indigo-500" }),
|
|
1141
|
+
" Prompt"
|
|
1142
|
+
] }),
|
|
1143
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex items-center gap-1", children: [
|
|
1144
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "inline-block w-2 h-2 rounded-full bg-emerald-500" }),
|
|
1145
|
+
" Completion"
|
|
1146
|
+
] })
|
|
1147
|
+
] })
|
|
1148
|
+
] });
|
|
914
1149
|
}
|
|
915
1150
|
function HallucinationTab({ trace }) {
|
|
916
1151
|
if (trace.hallucinationScore == null) {
|
|
917
|
-
return /* @__PURE__ */
|
|
1152
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-[11px] text-slate-400 dark:text-white/30 italic", children: "Hallucination scoring not available for this response." });
|
|
918
1153
|
}
|
|
919
1154
|
const score = trace.hallucinationScore;
|
|
920
1155
|
const pct = Math.round(score * 100);
|
|
921
1156
|
const barColor = pct <= 20 ? "#10b981" : pct <= 50 ? "#f59e0b" : "#ef4444";
|
|
922
|
-
return /* @__PURE__ */
|
|
923
|
-
"div",
|
|
924
|
-
|
|
925
|
-
className: "
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
1157
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-3", children: [
|
|
1158
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
1159
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ScoreBadge, { score }),
|
|
1160
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "text-[11px] font-mono text-slate-500 dark:text-white/40", children: [
|
|
1161
|
+
pct,
|
|
1162
|
+
"/100"
|
|
1163
|
+
] })
|
|
1164
|
+
] }),
|
|
1165
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "h-3 rounded-full bg-slate-100 dark:bg-white/8 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1166
|
+
"div",
|
|
1167
|
+
{
|
|
1168
|
+
className: "h-full rounded-full transition-all duration-700",
|
|
1169
|
+
style: { width: `${pct}%`, background: barColor }
|
|
1170
|
+
}
|
|
1171
|
+
) }),
|
|
1172
|
+
trace.hallucinationReason && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rounded-lg border border-slate-100 dark:border-white/8 bg-slate-50 dark:bg-white/3 p-2.5", children: [
|
|
1173
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-[11px] text-slate-500 dark:text-white/40 font-medium mb-0.5", children: "AI self-assessment" }),
|
|
1174
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-[11px] text-slate-700 dark:text-white/70 leading-relaxed", children: trace.hallucinationReason })
|
|
1175
|
+
] }),
|
|
1176
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex gap-2 text-[10px] text-slate-400 dark:text-white/30", children: [
|
|
1177
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex items-center gap-1", children: [
|
|
1178
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "inline-block w-2 h-2 rounded-full bg-emerald-500" }),
|
|
1179
|
+
" 0\u201320%: Grounded"
|
|
1180
|
+
] }),
|
|
1181
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex items-center gap-1", children: [
|
|
1182
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "inline-block w-2 h-2 rounded-full bg-amber-500" }),
|
|
1183
|
+
" 21\u201350%: Uncertain"
|
|
1184
|
+
] }),
|
|
1185
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex items-center gap-1", children: [
|
|
1186
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "inline-block w-2 h-2 rounded-full bg-red-500" }),
|
|
1187
|
+
" 51\u2013100%: Risk"
|
|
1188
|
+
] })
|
|
1189
|
+
] })
|
|
1190
|
+
] });
|
|
929
1191
|
}
|
|
930
1192
|
function PromptTab({ trace }) {
|
|
931
|
-
const [showSystem, setShowSystem] =
|
|
932
|
-
return /* @__PURE__ */
|
|
933
|
-
"
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1193
|
+
const [showSystem, setShowSystem] = import_react6.default.useState(false);
|
|
1194
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-3", children: [
|
|
1195
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
1196
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1197
|
+
"button",
|
|
1198
|
+
{
|
|
1199
|
+
onClick: () => setShowSystem((s) => !s),
|
|
1200
|
+
className: "flex items-center gap-1.5 text-[11px] font-semibold text-slate-600 dark:text-white/60 hover:text-slate-900 dark:hover:text-white/80 transition-colors mb-1.5",
|
|
1201
|
+
children: [
|
|
1202
|
+
showSystem ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react5.ChevronDown, { className: "w-3 h-3" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react5.ChevronRight, { className: "w-3 h-3" }),
|
|
1203
|
+
"System Prompt"
|
|
1204
|
+
]
|
|
1205
|
+
}
|
|
1206
|
+
),
|
|
1207
|
+
showSystem && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("pre", { className: "text-[10px] font-mono text-slate-600 dark:text-white/60 bg-slate-900 dark:bg-black/30 rounded-lg p-3 overflow-auto max-h-40 whitespace-pre-wrap leading-relaxed", children: trace.systemPrompt || "(empty)" })
|
|
1208
|
+
] }),
|
|
1209
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
1210
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-[11px] font-semibold text-slate-600 dark:text-white/60 mb-1.5", children: "User Prompt" }),
|
|
1211
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("pre", { className: "text-[10px] font-mono text-slate-600 dark:text-white/60 bg-slate-900 dark:bg-black/30 rounded-lg p-3 overflow-auto max-h-40 whitespace-pre-wrap leading-relaxed", children: trace.userPrompt })
|
|
1212
|
+
] })
|
|
1213
|
+
] });
|
|
941
1214
|
}
|
|
942
1215
|
function ChunksTab({ trace }) {
|
|
943
|
-
const [expanded, setExpanded] =
|
|
1216
|
+
const [expanded, setExpanded] = import_react6.default.useState(/* @__PURE__ */ new Set());
|
|
944
1217
|
const toggle = (i) => setExpanded((prev) => {
|
|
945
1218
|
const next = new Set(prev);
|
|
946
1219
|
if (next.has(i)) {
|
|
@@ -950,74 +1223,111 @@ function ChunksTab({ trace }) {
|
|
|
950
1223
|
}
|
|
951
1224
|
return next;
|
|
952
1225
|
});
|
|
953
|
-
return /* @__PURE__ */
|
|
1226
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "space-y-1.5 max-h-64 overflow-y-auto pr-1 custom-scrollbar", children: trace.chunks.map((chunk, i) => {
|
|
954
1227
|
const isOpen = expanded.has(i);
|
|
955
|
-
return /* @__PURE__ */
|
|
1228
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
956
1229
|
"div",
|
|
957
1230
|
{
|
|
958
|
-
|
|
959
|
-
|
|
1231
|
+
className: "rounded-lg border border-slate-100 dark:border-white/8 bg-slate-50 dark:bg-white/3 overflow-hidden",
|
|
1232
|
+
children: [
|
|
1233
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1234
|
+
"button",
|
|
1235
|
+
{
|
|
1236
|
+
onClick: () => toggle(i),
|
|
1237
|
+
className: "w-full flex items-center justify-between px-3 py-2 text-left hover:bg-slate-100 dark:hover:bg-white/5 transition-colors",
|
|
1238
|
+
children: [
|
|
1239
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1240
|
+
isOpen ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react5.ChevronDown, { className: "w-3 h-3 text-slate-400" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react5.ChevronRight, { className: "w-3 h-3 text-slate-400" }),
|
|
1241
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "text-[11px] font-medium text-slate-700 dark:text-white/70", children: [
|
|
1242
|
+
"Chunk ",
|
|
1243
|
+
i + 1
|
|
1244
|
+
] }),
|
|
1245
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-[10px] font-mono text-slate-400 dark:text-white/30", children: String(chunk.id).slice(0, 16) })
|
|
1246
|
+
] }),
|
|
1247
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-[10px] font-semibold text-indigo-600 dark:text-indigo-400", children: chunk.score.toFixed(3) })
|
|
1248
|
+
]
|
|
1249
|
+
}
|
|
1250
|
+
),
|
|
1251
|
+
isOpen && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "px-3 pb-3 space-y-2 border-t border-slate-100 dark:border-white/5 pt-2", children: [
|
|
1252
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
1253
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-[10px] text-slate-400 dark:text-white/30 font-semibold uppercase tracking-wider mb-1", children: "Content" }),
|
|
1254
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-[11px] text-slate-600 dark:text-white/60 leading-relaxed whitespace-pre-wrap", children: chunk.content })
|
|
1255
|
+
] }),
|
|
1256
|
+
Object.keys(chunk.metadata).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
1257
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-[10px] text-slate-400 dark:text-white/30 font-semibold uppercase tracking-wider mb-1", children: "Metadata" }),
|
|
1258
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("pre", { className: "text-[10px] font-mono text-slate-500 dark:text-white/40 bg-slate-900 dark:bg-black/30 rounded-md p-2 overflow-auto max-h-24", children: JSON.stringify(chunk.metadata, null, 2) })
|
|
1259
|
+
] })
|
|
1260
|
+
] })
|
|
1261
|
+
]
|
|
960
1262
|
},
|
|
961
|
-
|
|
962
|
-
"button",
|
|
963
|
-
{
|
|
964
|
-
onClick: () => toggle(i),
|
|
965
|
-
className: "w-full flex items-center justify-between px-3 py-2 text-left hover:bg-slate-100 dark:hover:bg-white/5 transition-colors"
|
|
966
|
-
},
|
|
967
|
-
/* @__PURE__ */ import_react8.default.createElement("div", { className: "flex items-center gap-2" }, isOpen ? /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.ChevronDown, { className: "w-3 h-3 text-slate-400" }) : /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.ChevronRight, { className: "w-3 h-3 text-slate-400" }), /* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[11px] font-medium text-slate-700 dark:text-white/70" }, "Chunk ", i + 1), /* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[10px] font-mono text-slate-400 dark:text-white/30" }, String(chunk.id).slice(0, 16))),
|
|
968
|
-
/* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[10px] font-semibold text-indigo-600 dark:text-indigo-400" }, chunk.score.toFixed(3))
|
|
969
|
-
),
|
|
970
|
-
isOpen && /* @__PURE__ */ import_react8.default.createElement("div", { className: "px-3 pb-3 space-y-2 border-t border-slate-100 dark:border-white/5 pt-2" }, /* @__PURE__ */ import_react8.default.createElement("div", null, /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-[10px] text-slate-400 dark:text-white/30 font-semibold uppercase tracking-wider mb-1" }, "Content"), /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-[11px] text-slate-600 dark:text-white/60 leading-relaxed whitespace-pre-wrap" }, chunk.content)), Object.keys(chunk.metadata).length > 0 && /* @__PURE__ */ import_react8.default.createElement("div", null, /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-[10px] text-slate-400 dark:text-white/30 font-semibold uppercase tracking-wider mb-1" }, "Metadata"), /* @__PURE__ */ import_react8.default.createElement("pre", { className: "text-[10px] font-mono text-slate-500 dark:text-white/40 bg-slate-900 dark:bg-black/30 rounded-md p-2 overflow-auto max-h-24" }, JSON.stringify(chunk.metadata, null, 2))))
|
|
1263
|
+
String(chunk.id)
|
|
971
1264
|
);
|
|
972
|
-
}));
|
|
1265
|
+
}) });
|
|
973
1266
|
}
|
|
974
1267
|
var TABS = [
|
|
975
|
-
{ id: "retrieval", label: "Retrieval", icon: /* @__PURE__ */
|
|
976
|
-
{ id: "latency", label: "Latency", icon: /* @__PURE__ */
|
|
977
|
-
{ id: "tokens", label: "Tokens", icon: /* @__PURE__ */
|
|
978
|
-
{ id: "hallucination", label: "Grounding", icon: /* @__PURE__ */
|
|
979
|
-
{ id: "prompt", label: "Prompt", icon: /* @__PURE__ */
|
|
980
|
-
{ id: "chunks", label: "Chunks", icon: /* @__PURE__ */
|
|
1268
|
+
{ id: "retrieval", label: "Retrieval", icon: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react5.Layers, { className: "w-3 h-3" }) },
|
|
1269
|
+
{ id: "latency", label: "Latency", icon: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react5.Clock, { className: "w-3 h-3" }) },
|
|
1270
|
+
{ id: "tokens", label: "Tokens", icon: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react5.Cpu, { className: "w-3 h-3" }) },
|
|
1271
|
+
{ id: "hallucination", label: "Grounding", icon: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react5.AlertTriangle, { className: "w-3 h-3" }) },
|
|
1272
|
+
{ id: "prompt", label: "Prompt", icon: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react5.FileText, { className: "w-3 h-3" }) },
|
|
1273
|
+
{ id: "chunks", label: "Chunks", icon: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react5.Zap, { className: "w-3 h-3" }) }
|
|
981
1274
|
];
|
|
982
1275
|
function ObservabilityPanel({ trace, primaryColor = "#6366f1" }) {
|
|
983
|
-
const [activeTab, setActiveTab] =
|
|
984
|
-
return /* @__PURE__ */
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
className: "flex items-center gap-2 px-3 py-2 border-b border-slate-100 dark:border-white/8",
|
|
988
|
-
style: { background: `${primaryColor}08` }
|
|
989
|
-
},
|
|
990
|
-
/* @__PURE__ */ import_react8.default.createElement(
|
|
991
|
-
"span",
|
|
1276
|
+
const [activeTab, setActiveTab] = import_react6.default.useState("retrieval");
|
|
1277
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "mt-2 w-[500px] max-w-full rounded-xl border border-slate-200 dark:border-white/8 bg-white dark:bg-slate-900/60 shadow-sm overflow-hidden text-[12px]", children: [
|
|
1278
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1279
|
+
"div",
|
|
992
1280
|
{
|
|
993
|
-
className: "
|
|
994
|
-
style: {
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
1281
|
+
className: "flex items-center gap-2 px-3 py-2 border-b border-slate-100 dark:border-white/8",
|
|
1282
|
+
style: { background: `${primaryColor}08` },
|
|
1283
|
+
children: [
|
|
1284
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1285
|
+
"span",
|
|
1286
|
+
{
|
|
1287
|
+
className: "inline-flex items-center gap-1 text-[10px] font-bold uppercase tracking-wider",
|
|
1288
|
+
style: { color: primaryColor },
|
|
1289
|
+
children: [
|
|
1290
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react5.Zap, { className: "w-3 h-3" }),
|
|
1291
|
+
"Observability Trace"
|
|
1292
|
+
]
|
|
1293
|
+
}
|
|
1294
|
+
),
|
|
1295
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-[10px] text-slate-400 dark:text-white/30 ml-auto font-mono", children: trace.requestId })
|
|
1296
|
+
]
|
|
1297
|
+
}
|
|
998
1298
|
),
|
|
999
|
-
/* @__PURE__ */
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1299
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex border-b border-slate-100 dark:border-white/8 overflow-x-auto", children: TABS.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1300
|
+
"button",
|
|
1301
|
+
{
|
|
1302
|
+
onClick: () => setActiveTab(tab.id),
|
|
1303
|
+
className: `flex items-center gap-1.5 px-3 py-2 text-[10px] font-semibold whitespace-nowrap transition-colors border-b-2 ${activeTab === tab.id ? "border-b-2 text-indigo-600 dark:text-indigo-400" : "border-transparent text-slate-400 dark:text-white/30 hover:text-slate-600 dark:hover:text-white/60"}`,
|
|
1304
|
+
style: activeTab === tab.id ? { borderBottomColor: primaryColor, color: primaryColor } : {},
|
|
1305
|
+
children: [
|
|
1306
|
+
tab.icon,
|
|
1307
|
+
tab.label
|
|
1308
|
+
]
|
|
1309
|
+
},
|
|
1310
|
+
tab.id
|
|
1311
|
+
)) }),
|
|
1312
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "p-3", children: [
|
|
1313
|
+
activeTab === "retrieval" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(RetrievalTab, { trace }),
|
|
1314
|
+
activeTab === "latency" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(LatencyTab, { trace }),
|
|
1315
|
+
activeTab === "tokens" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TokensTab, { trace }),
|
|
1316
|
+
activeTab === "hallucination" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(HallucinationTab, { trace }),
|
|
1317
|
+
activeTab === "prompt" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PromptTab, { trace }),
|
|
1318
|
+
activeTab === "chunks" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ChunksTab, { trace })
|
|
1319
|
+
] })
|
|
1320
|
+
] });
|
|
1011
1321
|
}
|
|
1012
1322
|
|
|
1013
1323
|
// src/components/HourglassLoader.tsx
|
|
1014
|
-
var
|
|
1324
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1015
1325
|
var HourglassLoader = ({
|
|
1016
1326
|
size = 16,
|
|
1017
1327
|
primaryColor = "#10b981",
|
|
1018
1328
|
glow = false
|
|
1019
1329
|
}) => {
|
|
1020
|
-
return /* @__PURE__ */
|
|
1330
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1021
1331
|
"svg",
|
|
1022
1332
|
{
|
|
1023
1333
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -1028,58 +1338,64 @@ var HourglassLoader = ({
|
|
|
1028
1338
|
height: size,
|
|
1029
1339
|
background: "transparent",
|
|
1030
1340
|
filter: glow ? `drop-shadow(0 0 4px ${primaryColor})` : "none"
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1341
|
+
},
|
|
1342
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("g", { children: [
|
|
1343
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1344
|
+
"animateTransform",
|
|
1345
|
+
{
|
|
1346
|
+
attributeName: "transform",
|
|
1347
|
+
type: "rotate",
|
|
1348
|
+
calcMode: "spline",
|
|
1349
|
+
values: "0 50 50; 0 50 50; 180 50 50",
|
|
1350
|
+
keyTimes: "0; 0.8; 1",
|
|
1351
|
+
keySplines: "0 0 1 1; 0.4 0 0.2 1",
|
|
1352
|
+
dur: "2s",
|
|
1353
|
+
repeatCount: "indefinite"
|
|
1354
|
+
}
|
|
1355
|
+
),
|
|
1356
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1357
|
+
"path",
|
|
1358
|
+
{
|
|
1359
|
+
d: "M 25 15 L 75 15 L 75 20 L 55 50 L 75 80 L 75 85 L 25 85 L 25 80 L 45 50 L 25 20 Z",
|
|
1360
|
+
fill: "none",
|
|
1361
|
+
stroke: primaryColor,
|
|
1362
|
+
strokeWidth: "5",
|
|
1363
|
+
strokeLinejoin: "round",
|
|
1364
|
+
strokeLinecap: "round"
|
|
1365
|
+
}
|
|
1366
|
+
),
|
|
1367
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { fill: primaryColor, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1368
|
+
"animate",
|
|
1369
|
+
{
|
|
1370
|
+
attributeName: "d",
|
|
1371
|
+
values: "M 30 20 L 70 20 L 50 50 L 50 50 Z; M 50 50 L 50 50 L 50 50 L 50 50 Z; M 50 50 L 50 50 L 50 50 L 50 50 Z",
|
|
1372
|
+
keyTimes: "0; 0.8; 1",
|
|
1373
|
+
dur: "2s",
|
|
1374
|
+
repeatCount: "indefinite"
|
|
1375
|
+
}
|
|
1376
|
+
) }),
|
|
1377
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { fill: primaryColor, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1378
|
+
"animate",
|
|
1379
|
+
{
|
|
1380
|
+
attributeName: "d",
|
|
1381
|
+
values: "M 30 80 L 70 80 L 70 80 L 30 80 Z; M 30 80 L 70 80 L 50 50 L 50 50 Z; M 30 80 L 70 80 L 50 50 L 50 50 Z",
|
|
1382
|
+
keyTimes: "0; 0.8; 1",
|
|
1383
|
+
dur: "2s",
|
|
1384
|
+
repeatCount: "indefinite"
|
|
1385
|
+
}
|
|
1386
|
+
) }),
|
|
1387
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "50", y1: "50", x2: "50", y2: "80", stroke: primaryColor, strokeWidth: "3", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1388
|
+
"animate",
|
|
1389
|
+
{
|
|
1390
|
+
attributeName: "opacity",
|
|
1391
|
+
values: "0; 1; 1; 0; 0",
|
|
1392
|
+
keyTimes: "0; 0.1; 0.7; 0.8; 1",
|
|
1393
|
+
dur: "2s",
|
|
1394
|
+
repeatCount: "indefinite"
|
|
1395
|
+
}
|
|
1396
|
+
) })
|
|
1397
|
+
] })
|
|
1398
|
+
}
|
|
1083
1399
|
);
|
|
1084
1400
|
};
|
|
1085
1401
|
var HourglassLoader_default = HourglassLoader;
|
|
@@ -1332,7 +1648,6 @@ function extractProductsFromSources(sources, isUser) {
|
|
|
1332
1648
|
const brand = resolveMetadataValue(m, "brand");
|
|
1333
1649
|
const price = resolveMetadataValue(m, "price");
|
|
1334
1650
|
const description = resolveMetadataValue(m, "description");
|
|
1335
|
-
console.log("\u{1F680} ~ extractProductsFromSources ~ description:", s);
|
|
1336
1651
|
return {
|
|
1337
1652
|
id: s.id,
|
|
1338
1653
|
name: (_b = name != null ? name : s.content.split("\n")[0]) != null ? _b : "Unknown Product",
|
|
@@ -1345,7 +1660,7 @@ function extractProductsFromSources(sources, isUser) {
|
|
|
1345
1660
|
};
|
|
1346
1661
|
});
|
|
1347
1662
|
}
|
|
1348
|
-
function extractProductsFromContent(content, payloadText, payloadCandidates, productsFromSources) {
|
|
1663
|
+
function extractProductsFromContent(content, payloadText, payloadCandidates, productsFromSources, isStreaming = false) {
|
|
1349
1664
|
var _a, _b;
|
|
1350
1665
|
const jsonRegex = /```(?:json|ui)?\s*([\s\S]*?)\s*```/g;
|
|
1351
1666
|
const products = [];
|
|
@@ -1388,7 +1703,7 @@ function extractProductsFromContent(content, payloadText, payloadCandidates, pro
|
|
|
1388
1703
|
}
|
|
1389
1704
|
const bulletRegex = /^[ \t]*(?:[•*-]|\d+\.)\s+(?:\*\*)?([^\n\-\$–—\(]+?)(?:\*\*)?(?:\s*\(?Price\s*[:\-–—]?\s*)?(?:\s*[:\-–—]\s*|\s+)\$?([\d,.]+)(?:\s*USD)?/gim;
|
|
1390
1705
|
const matches = Array.from(cleanContent.matchAll(bulletRegex));
|
|
1391
|
-
if (matches.length >= 2) {
|
|
1706
|
+
if (!isStreaming && matches.length >= 2) {
|
|
1392
1707
|
const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1393
1708
|
for (const match of matches) {
|
|
1394
1709
|
let name = ((_a = match[1]) == null ? void 0 : _a.trim()) || "";
|
|
@@ -1440,10 +1755,11 @@ function deduplicateProducts(productsFromSources, productsFromContent, messageCo
|
|
|
1440
1755
|
}
|
|
1441
1756
|
|
|
1442
1757
|
// src/components/MarkdownComponents.tsx
|
|
1443
|
-
var
|
|
1758
|
+
var import_react8 = __toESM(require("react"));
|
|
1444
1759
|
|
|
1445
1760
|
// src/components/UIDispatcher.tsx
|
|
1446
|
-
var
|
|
1761
|
+
var import_react7 = __toESM(require("react"));
|
|
1762
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1447
1763
|
function normalizeTabularRows(rows, columns) {
|
|
1448
1764
|
if (!Array.isArray(rows)) return [];
|
|
1449
1765
|
const SYNONYMS = {
|
|
@@ -1511,7 +1827,7 @@ function resolveStructuredRows(config) {
|
|
|
1511
1827
|
}
|
|
1512
1828
|
function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAddToCart, viewportSize = "large" }) {
|
|
1513
1829
|
var _a;
|
|
1514
|
-
const result =
|
|
1830
|
+
const result = import_react7.default.useMemo(() => {
|
|
1515
1831
|
try {
|
|
1516
1832
|
const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
|
|
1517
1833
|
const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
|
|
@@ -1556,72 +1872,87 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
1556
1872
|
}
|
|
1557
1873
|
}, [rawContent, isStreaming]);
|
|
1558
1874
|
if ("loading" in result) {
|
|
1559
|
-
return /* @__PURE__ */
|
|
1875
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("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", children: [
|
|
1876
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "w-5 h-5 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }),
|
|
1877
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-xs text-slate-500 font-medium italic", children: "Preparing view..." })
|
|
1878
|
+
] });
|
|
1560
1879
|
}
|
|
1561
1880
|
if ("error" in result) {
|
|
1562
|
-
return /* @__PURE__ */
|
|
1881
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("pre", { className: "p-4 my-2 bg-slate-900 text-slate-100 rounded-lg text-[10px] overflow-auto max-h-40", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("code", { children: rawContent }) });
|
|
1563
1882
|
}
|
|
1564
1883
|
const { config } = result;
|
|
1565
1884
|
const isCompact = viewportSize === "compact";
|
|
1566
1885
|
const hasInsights = Array.isArray(config.insights) && config.insights.length > 0;
|
|
1567
1886
|
const hasDescription = typeof config.description === "string" && config.description.trim().length > 0;
|
|
1568
|
-
console.log("\u{1F680} ~ UIDispatcher ~ description:", config.description);
|
|
1569
|
-
console.log("\u{1F680} ~ UIDispatcher ~ hasDescription:", hasDescription);
|
|
1570
1887
|
switch (config.view) {
|
|
1571
1888
|
case "chart":
|
|
1572
|
-
return /* @__PURE__ */
|
|
1573
|
-
|
|
1574
|
-
{
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1889
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("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`, children: [
|
|
1890
|
+
config.title && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h4", { className: `${isCompact ? "text-[11px] mb-3" : "text-xs mb-4"} font-semibold text-slate-500 px-2`, children: config.title }),
|
|
1891
|
+
hasDescription && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: `px-2 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60`, children: config.description }),
|
|
1892
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1893
|
+
DynamicChart,
|
|
1894
|
+
{
|
|
1895
|
+
config: {
|
|
1896
|
+
type: config.chartType || "bar",
|
|
1897
|
+
data: config.data,
|
|
1898
|
+
xAxisKey: config.xAxisKey,
|
|
1899
|
+
dataKeys: config.dataKeys,
|
|
1900
|
+
colors: config.colors
|
|
1901
|
+
},
|
|
1902
|
+
primaryColor,
|
|
1903
|
+
accentColor,
|
|
1904
|
+
viewportSize,
|
|
1905
|
+
isStreaming
|
|
1906
|
+
}
|
|
1907
|
+
),
|
|
1908
|
+
hasInsights && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-4 flex flex-wrap gap-2 px-2", children: (_a = config.insights) == null ? void 0 : _a.map((insight, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1909
|
+
"span",
|
|
1910
|
+
{
|
|
1911
|
+
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`,
|
|
1912
|
+
children: String(insight)
|
|
1581
1913
|
},
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
isStreaming
|
|
1586
|
-
}
|
|
1587
|
-
), hasInsights && /* @__PURE__ */ import_react10.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_react10.default.createElement(
|
|
1588
|
-
"span",
|
|
1589
|
-
{
|
|
1590
|
-
key: `insight-${i}`,
|
|
1591
|
-
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`
|
|
1592
|
-
},
|
|
1593
|
-
String(insight)
|
|
1594
|
-
))));
|
|
1914
|
+
`insight-${i}`
|
|
1915
|
+
)) })
|
|
1916
|
+
] });
|
|
1595
1917
|
case "carousel":
|
|
1596
|
-
return /* @__PURE__ */
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1918
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "my-4", children: [
|
|
1919
|
+
config.title && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h4", { className: `${isCompact ? "mb-1.5 text-[11px]" : "mb-2 text-xs"} font-semibold text-slate-500`, children: config.title }),
|
|
1920
|
+
hasDescription && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60`, children: config.description }),
|
|
1921
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ProductCarousel, { products: config.data.map((item) => {
|
|
1922
|
+
var _a2;
|
|
1923
|
+
return __spreadProps(__spreadValues({}, item), {
|
|
1924
|
+
image: (_a2 = item.image) != null ? _a2 : typeof resolveImage === "function" ? resolveImage(item) : void 0
|
|
1925
|
+
});
|
|
1926
|
+
}), primaryColor, onAddToCart })
|
|
1927
|
+
] });
|
|
1602
1928
|
case "table":
|
|
1603
|
-
return /* @__PURE__ */
|
|
1604
|
-
|
|
1605
|
-
{
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
description: config.description,
|
|
1929
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("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`, children: [
|
|
1930
|
+
config.title && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h4", { className: `${isCompact ? "text-[11px]" : "text-xs"} font-semibold text-slate-500 mb-2`, children: config.title }),
|
|
1931
|
+
hasDescription && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60`, children: config.description }),
|
|
1932
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1933
|
+
VisualizationRenderer,
|
|
1934
|
+
{
|
|
1610
1935
|
data: {
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1936
|
+
type: "table",
|
|
1937
|
+
title: config.title || "",
|
|
1938
|
+
description: config.description,
|
|
1939
|
+
data: {
|
|
1940
|
+
columns: config.columns || Object.keys(config.data[0] || {}),
|
|
1941
|
+
rows: config.data.map((row) => Object.values(row))
|
|
1942
|
+
}
|
|
1943
|
+
},
|
|
1944
|
+
primaryColor,
|
|
1945
|
+
isStreaming
|
|
1946
|
+
}
|
|
1947
|
+
)
|
|
1948
|
+
] });
|
|
1619
1949
|
default:
|
|
1620
1950
|
return null;
|
|
1621
1951
|
}
|
|
1622
1952
|
}
|
|
1623
1953
|
|
|
1624
1954
|
// src/components/MarkdownComponents.tsx
|
|
1955
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1625
1956
|
function createMarkdownComponents({
|
|
1626
1957
|
primaryColor,
|
|
1627
1958
|
accentColor,
|
|
@@ -1630,66 +1961,75 @@ function createMarkdownComponents({
|
|
|
1630
1961
|
viewportSize
|
|
1631
1962
|
}) {
|
|
1632
1963
|
return {
|
|
1633
|
-
|
|
1964
|
+
p: (_a) => {
|
|
1634
1965
|
var props = __objRest(_a, []);
|
|
1966
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", __spreadValues({ className: "whitespace-pre-line" }, props));
|
|
1967
|
+
},
|
|
1968
|
+
table: (_b) => {
|
|
1969
|
+
var props = __objRest(_b, []);
|
|
1635
1970
|
if (isStreaming) {
|
|
1636
|
-
return /* @__PURE__ */
|
|
1971
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "my-5 p-6 bg-slate-50 dark:bg-white/5 rounded-xl border border-dashed border-slate-300 dark:border-white/10 flex items-center justify-center gap-3 select-none", children: [
|
|
1972
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "w-4 h-4 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }),
|
|
1973
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-xs text-slate-500 font-medium italic animate-pulse", children: "Generating data table..." })
|
|
1974
|
+
] });
|
|
1637
1975
|
}
|
|
1638
|
-
return /* @__PURE__ */
|
|
1976
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1639
1977
|
"table",
|
|
1640
1978
|
__spreadValues({
|
|
1641
1979
|
className: "!table w-full text-left border-collapse min-w-[400px] text-sm"
|
|
1642
1980
|
}, props)
|
|
1643
|
-
)));
|
|
1981
|
+
) }) });
|
|
1644
1982
|
},
|
|
1645
|
-
thead: (
|
|
1646
|
-
var props = __objRest(
|
|
1647
|
-
return /* @__PURE__ */
|
|
1983
|
+
thead: (_c) => {
|
|
1984
|
+
var props = __objRest(_c, []);
|
|
1985
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1648
1986
|
"thead",
|
|
1649
1987
|
__spreadValues({
|
|
1650
1988
|
className: "!table-header-group bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10"
|
|
1651
1989
|
}, props)
|
|
1652
1990
|
);
|
|
1653
1991
|
},
|
|
1654
|
-
tbody: (
|
|
1655
|
-
var props = __objRest(_c, []);
|
|
1656
|
-
return /* @__PURE__ */ import_react11.default.createElement("tbody", __spreadValues({ className: "!table-row-group divide-y divide-slate-100 dark:divide-white/5" }, props));
|
|
1657
|
-
},
|
|
1658
|
-
tr: (_d) => {
|
|
1992
|
+
tbody: (_d) => {
|
|
1659
1993
|
var props = __objRest(_d, []);
|
|
1660
|
-
return /* @__PURE__ */
|
|
1994
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tbody", __spreadValues({ className: "!table-row-group divide-y divide-slate-100 dark:divide-white/5" }, props));
|
|
1995
|
+
},
|
|
1996
|
+
tr: (_e) => {
|
|
1997
|
+
var props = __objRest(_e, []);
|
|
1998
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1661
1999
|
"tr",
|
|
1662
2000
|
__spreadValues({
|
|
1663
2001
|
className: "!table-row hover:bg-slate-50/70 dark:hover:bg-white/5 transition-colors"
|
|
1664
2002
|
}, props)
|
|
1665
2003
|
);
|
|
1666
2004
|
},
|
|
1667
|
-
th: (
|
|
1668
|
-
var
|
|
1669
|
-
return /* @__PURE__ */
|
|
2005
|
+
th: (_f) => {
|
|
2006
|
+
var _g = _f, { children } = _g, props = __objRest(_g, ["children"]);
|
|
2007
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1670
2008
|
"th",
|
|
1671
|
-
__spreadValues({
|
|
2009
|
+
__spreadProps(__spreadValues({
|
|
1672
2010
|
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"
|
|
1673
|
-
}, props),
|
|
1674
|
-
|
|
2011
|
+
}, props), {
|
|
2012
|
+
children: normaliseChild(children)
|
|
2013
|
+
})
|
|
1675
2014
|
);
|
|
1676
2015
|
},
|
|
1677
|
-
td: (
|
|
1678
|
-
var
|
|
1679
|
-
return /* @__PURE__ */
|
|
2016
|
+
td: (_h) => {
|
|
2017
|
+
var _i = _h, { children } = _i, props = __objRest(_i, ["children"]);
|
|
2018
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1680
2019
|
"td",
|
|
1681
|
-
__spreadValues({
|
|
2020
|
+
__spreadProps(__spreadValues({
|
|
1682
2021
|
className: "!table-cell px-4 py-3 text-slate-600 dark:text-white/70 whitespace-nowrap text-sm"
|
|
1683
|
-
}, props),
|
|
1684
|
-
|
|
2022
|
+
}, props), {
|
|
2023
|
+
children: normaliseChild(children)
|
|
2024
|
+
})
|
|
1685
2025
|
);
|
|
1686
2026
|
},
|
|
1687
|
-
code(
|
|
1688
|
-
var
|
|
2027
|
+
code(_j) {
|
|
2028
|
+
var _k = _j, {
|
|
1689
2029
|
inline,
|
|
1690
2030
|
className,
|
|
1691
2031
|
children
|
|
1692
|
-
} =
|
|
2032
|
+
} = _k, props = __objRest(_k, [
|
|
1693
2033
|
"inline",
|
|
1694
2034
|
"className",
|
|
1695
2035
|
"children"
|
|
@@ -1698,7 +2038,7 @@ function createMarkdownComponents({
|
|
|
1698
2038
|
const lang = (_a = /language-(\w+)/.exec(className != null ? className : "")) == null ? void 0 : _a[1];
|
|
1699
2039
|
if (!inline && (lang === "ui" || lang === "chart" || lang === "json")) {
|
|
1700
2040
|
const content = String(children != null ? children : "").trim();
|
|
1701
|
-
return /* @__PURE__ */
|
|
2041
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1702
2042
|
UIDispatcher,
|
|
1703
2043
|
{
|
|
1704
2044
|
rawContent: content,
|
|
@@ -1713,7 +2053,7 @@ function createMarkdownComponents({
|
|
|
1713
2053
|
if (!inline) {
|
|
1714
2054
|
const content = String(children != null ? children : "").trim();
|
|
1715
2055
|
if (content.startsWith("{") && content.endsWith("}")) {
|
|
1716
|
-
return /* @__PURE__ */
|
|
2056
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1717
2057
|
UIDispatcher,
|
|
1718
2058
|
{
|
|
1719
2059
|
rawContent: content,
|
|
@@ -1726,18 +2066,19 @@ function createMarkdownComponents({
|
|
|
1726
2066
|
);
|
|
1727
2067
|
}
|
|
1728
2068
|
}
|
|
1729
|
-
return /* @__PURE__ */
|
|
2069
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", __spreadProps(__spreadValues({ className }, props), { children: typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children) }));
|
|
1730
2070
|
}
|
|
1731
2071
|
};
|
|
1732
2072
|
}
|
|
1733
2073
|
function normaliseChild(children) {
|
|
1734
|
-
if (typeof children === "object" && children !== null && !Array.isArray(children) && !
|
|
2074
|
+
if (typeof children === "object" && children !== null && !Array.isArray(children) && !import_react8.default.isValidElement(children)) {
|
|
1735
2075
|
return JSON.stringify(children);
|
|
1736
2076
|
}
|
|
1737
2077
|
return children;
|
|
1738
2078
|
}
|
|
1739
2079
|
|
|
1740
2080
|
// src/components/MessageBubble.tsx
|
|
2081
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1741
2082
|
function MessageBubble({
|
|
1742
2083
|
message,
|
|
1743
2084
|
sources,
|
|
@@ -1750,13 +2091,13 @@ function MessageBubble({
|
|
|
1750
2091
|
const isUser = message.role === "user";
|
|
1751
2092
|
const isCompact = viewportSize === "compact";
|
|
1752
2093
|
const isMedium = viewportSize === "medium";
|
|
1753
|
-
const [showSources, setShowSources] =
|
|
1754
|
-
const [showTrace, setShowTrace] =
|
|
1755
|
-
const structuredContent =
|
|
2094
|
+
const [showSources, setShowSources] = import_react9.default.useState(false);
|
|
2095
|
+
const [showTrace, setShowTrace] = import_react9.default.useState(false);
|
|
2096
|
+
const structuredContent = import_react9.default.useMemo(
|
|
1756
2097
|
() => isUser ? { payload: null, text: message.content } : extractStructuredPayload(message.content),
|
|
1757
2098
|
[isUser, message.content]
|
|
1758
2099
|
);
|
|
1759
|
-
const hasRichUI =
|
|
2100
|
+
const hasRichUI = import_react9.default.useMemo(() => {
|
|
1760
2101
|
if (message.uiTransformation) {
|
|
1761
2102
|
const type = message.uiTransformation.type;
|
|
1762
2103
|
if (type && !["text", "table"].includes(type)) return true;
|
|
@@ -1767,10 +2108,10 @@ function MessageBubble({
|
|
|
1767
2108
|
return false;
|
|
1768
2109
|
}, [message.uiTransformation, structuredContent.payload]);
|
|
1769
2110
|
const shouldRenderStructuredOnly = !isUser && hasRichUI && isLikelyUiOnlyMessage(structuredContent.text);
|
|
1770
|
-
const productsFromSources =
|
|
2111
|
+
const productsFromSources = import_react9.default.useMemo(() => {
|
|
1771
2112
|
return extractProductsFromSources(sources, isUser);
|
|
1772
2113
|
}, [sources, isUser]);
|
|
1773
|
-
const { productsFromContent, cleanContent } =
|
|
2114
|
+
const { productsFromContent, cleanContent } = import_react9.default.useMemo(() => {
|
|
1774
2115
|
if (isUser) {
|
|
1775
2116
|
return { productsFromContent: [], cleanContent: message.content };
|
|
1776
2117
|
}
|
|
@@ -1782,13 +2123,14 @@ function MessageBubble({
|
|
|
1782
2123
|
message.content,
|
|
1783
2124
|
structuredContent.text,
|
|
1784
2125
|
payloadCandidates,
|
|
1785
|
-
productsFromSources
|
|
2126
|
+
productsFromSources,
|
|
2127
|
+
isStreaming
|
|
1786
2128
|
);
|
|
1787
|
-
}, [message.content, isUser, structuredContent, productsFromSources]);
|
|
1788
|
-
const allProducts =
|
|
2129
|
+
}, [message.content, isUser, structuredContent, productsFromSources, isStreaming]);
|
|
2130
|
+
const allProducts = import_react9.default.useMemo(() => {
|
|
1789
2131
|
return deduplicateProducts(productsFromSources, productsFromContent, message.content);
|
|
1790
2132
|
}, [productsFromSources, productsFromContent, message.content]);
|
|
1791
|
-
const processedMarkdown =
|
|
2133
|
+
const processedMarkdown = import_react9.default.useMemo(() => {
|
|
1792
2134
|
let raw = structuredContent.payload ? structuredContent.text : cleanContent || message.content;
|
|
1793
2135
|
const hasStructuredUiBlock = Boolean(structuredContent.payload) || /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|chartType|type|data|items|rows|products|results)"\s*:/i.test(raw);
|
|
1794
2136
|
raw = raw.replace(/([^\n])\n\|/g, "$1\n\n|").replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, "$1\n");
|
|
@@ -1811,93 +2153,123 @@ ${match.trim()}
|
|
|
1811
2153
|
}
|
|
1812
2154
|
return raw;
|
|
1813
2155
|
}, [cleanContent, message.content, isStreaming, structuredContent]);
|
|
1814
|
-
const markdownComponents =
|
|
2156
|
+
const markdownComponents = import_react9.default.useMemo(
|
|
1815
2157
|
() => createMarkdownComponents({ primaryColor, accentColor, isStreaming, onAddToCart, viewportSize }),
|
|
1816
2158
|
[primaryColor, accentColor, isStreaming, onAddToCart, viewportSize]
|
|
1817
2159
|
);
|
|
1818
|
-
return /* @__PURE__ */
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
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"}`,
|
|
1822
|
-
style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
|
|
1823
|
-
},
|
|
1824
|
-
isUser ? /* @__PURE__ */ import_react12.default.createElement(import_lucide_react6.User, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"} text-white` }) : /* @__PURE__ */ import_react12.default.createElement(import_lucide_react6.Bot, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"}` })
|
|
1825
|
-
), /* @__PURE__ */ import_react12.default.createElement("div", { className: `flex flex-col gap-1 min-w-0 ${isCompact ? "max-w-[94%]" : isMedium ? "max-w-[92%]" : "max-w-[90%]"} ${isUser ? "items-end" : "items-start"}` }, /* @__PURE__ */ import_react12.default.createElement(
|
|
1826
|
-
"div",
|
|
1827
|
-
{
|
|
1828
|
-
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"}`,
|
|
1829
|
-
style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
|
|
1830
|
-
},
|
|
1831
|
-
isStreaming && !message.content ? /* @__PURE__ */ import_react12.default.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ import_react12.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_react12.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_react12.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_react12.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_react12.default.createElement(
|
|
1832
|
-
UIDispatcher,
|
|
1833
|
-
{
|
|
1834
|
-
rawContent: structuredContent.payload,
|
|
1835
|
-
primaryColor,
|
|
1836
|
-
accentColor,
|
|
1837
|
-
isStreaming,
|
|
1838
|
-
onAddToCart,
|
|
1839
|
-
viewportSize
|
|
1840
|
-
}
|
|
1841
|
-
), !shouldRenderStructuredOnly && /* @__PURE__ */ import_react12.default.createElement(import_react_markdown.default, { components: markdownComponents }, processedMarkdown), isStreaming && /* @__PURE__ */ import_react12.default.createElement("span", { className: "inline-flex items-center gap-1.5 ml-2 text-emerald-500 animate-pulse align-middle text-xs font-medium" }, /* @__PURE__ */ import_react12.default.createElement(
|
|
1842
|
-
HourglassLoader_default,
|
|
1843
|
-
{
|
|
1844
|
-
size: 18,
|
|
1845
|
-
primaryColor,
|
|
1846
|
-
accentColor,
|
|
1847
|
-
glow: false
|
|
1848
|
-
}
|
|
1849
|
-
), "Thinking..."))
|
|
1850
|
-
), (() => {
|
|
1851
|
-
var _a, _b;
|
|
1852
|
-
if (isUser || structuredContent.payload || !message.uiTransformation) return null;
|
|
1853
|
-
const ui = message.uiTransformation;
|
|
1854
|
-
const textContent = (_b = (_a = ui.data) == null ? void 0 : _a.content) != null ? _b : "";
|
|
1855
|
-
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());
|
|
1856
|
-
if (!shouldShow) return null;
|
|
1857
|
-
return /* @__PURE__ */ import_react12.default.createElement("div", { className: "w-full mt-3" }, /* @__PURE__ */ import_react12.default.createElement(
|
|
1858
|
-
VisualizationRenderer,
|
|
2160
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `flex ${isCompact ? "gap-2" : "gap-3"} ${isUser ? "flex-row-reverse" : "flex-row"} items-start`, children: [
|
|
2161
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2162
|
+
"div",
|
|
1859
2163
|
{
|
|
1860
|
-
|
|
1861
|
-
primaryColor,
|
|
1862
|
-
|
|
1863
|
-
className: "rounded-3xl border border-slate-200/60 dark:border-white/10 bg-white/90 dark:bg-slate-900/80 p-4",
|
|
1864
|
-
isStreaming
|
|
2164
|
+
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"}`,
|
|
2165
|
+
style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {},
|
|
2166
|
+
children: isUser ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react6.User, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"} text-white` }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react6.Bot, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"}` })
|
|
1865
2167
|
}
|
|
1866
|
-
)
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
2168
|
+
),
|
|
2169
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `flex flex-col gap-1 min-w-0 ${isCompact ? "max-w-[94%]" : isMedium ? "max-w-[92%]" : "max-w-[90%]"} ${isUser ? "items-end" : "items-start"}`, children: [
|
|
2170
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2171
|
+
"div",
|
|
2172
|
+
{
|
|
2173
|
+
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"}`,
|
|
2174
|
+
style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {},
|
|
2175
|
+
children: isStreaming && !message.content ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "flex items-center gap-1 py-1", children: [
|
|
2176
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }),
|
|
2177
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }),
|
|
2178
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })
|
|
2179
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `prose ${isCompact ? "prose-xs" : "prose-sm"} max-w-none break-words ${isUser ? "prose-invert" : "dark:prose-invert"}`, children: [
|
|
2180
|
+
!isUser && structuredContent.payload && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2181
|
+
UIDispatcher,
|
|
2182
|
+
{
|
|
2183
|
+
rawContent: structuredContent.payload,
|
|
2184
|
+
primaryColor,
|
|
2185
|
+
accentColor,
|
|
2186
|
+
isStreaming,
|
|
2187
|
+
onAddToCart,
|
|
2188
|
+
viewportSize
|
|
2189
|
+
}
|
|
2190
|
+
),
|
|
2191
|
+
!shouldRenderStructuredOnly && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_markdown.default, { components: markdownComponents, children: processedMarkdown }),
|
|
2192
|
+
isStreaming && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "inline-flex items-center gap-1.5 ml-2 text-emerald-500 animate-pulse align-middle text-xs font-medium", children: [
|
|
2193
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2194
|
+
HourglassLoader_default,
|
|
2195
|
+
{
|
|
2196
|
+
size: 18,
|
|
2197
|
+
primaryColor,
|
|
2198
|
+
accentColor,
|
|
2199
|
+
glow: false
|
|
2200
|
+
}
|
|
2201
|
+
),
|
|
2202
|
+
"Thinking..."
|
|
2203
|
+
] })
|
|
2204
|
+
] })
|
|
2205
|
+
}
|
|
2206
|
+
),
|
|
2207
|
+
(() => {
|
|
2208
|
+
var _a, _b;
|
|
2209
|
+
if (isUser || structuredContent.payload || !message.uiTransformation) return null;
|
|
2210
|
+
const ui = message.uiTransformation;
|
|
2211
|
+
const textContent = (_b = (_a = ui.data) == null ? void 0 : _a.content) != null ? _b : "";
|
|
2212
|
+
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());
|
|
2213
|
+
if (!shouldShow) return null;
|
|
2214
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "w-full mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2215
|
+
VisualizationRenderer,
|
|
2216
|
+
{
|
|
2217
|
+
data: ui,
|
|
2218
|
+
primaryColor,
|
|
2219
|
+
onAddToCart,
|
|
2220
|
+
className: "rounded-3xl border border-slate-200/60 dark:border-white/10 bg-white/90 dark:bg-slate-900/80 p-4",
|
|
2221
|
+
isStreaming
|
|
2222
|
+
}
|
|
2223
|
+
) });
|
|
2224
|
+
})(),
|
|
2225
|
+
!isUser && !hasRichUI && allProducts.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "w-full mt-1", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2226
|
+
ProductCarousel,
|
|
2227
|
+
{
|
|
2228
|
+
products: allProducts,
|
|
2229
|
+
primaryColor,
|
|
2230
|
+
onAddToCart
|
|
2231
|
+
}
|
|
2232
|
+
) }),
|
|
2233
|
+
!isUser && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-4 mt-1 w-full flex-wrap", children: [
|
|
2234
|
+
sources && sources.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
2235
|
+
"button",
|
|
2236
|
+
{
|
|
2237
|
+
onClick: () => setShowSources((s) => !s),
|
|
2238
|
+
className: "text-[11px] text-indigo-400 hover:text-indigo-300 transition-colors flex items-center gap-1",
|
|
2239
|
+
children: [
|
|
2240
|
+
showSources ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react6.ChevronDown, { className: "w-3 h-3" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react6.ChevronRight, { className: "w-3 h-3" }),
|
|
2241
|
+
sources.length,
|
|
2242
|
+
" source",
|
|
2243
|
+
sources.length !== 1 ? "s" : "",
|
|
2244
|
+
" used"
|
|
2245
|
+
]
|
|
2246
|
+
}
|
|
2247
|
+
),
|
|
2248
|
+
message.trace && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
2249
|
+
"button",
|
|
2250
|
+
{
|
|
2251
|
+
onClick: () => setShowTrace((t) => !t),
|
|
2252
|
+
className: "text-[11px] text-emerald-500 hover:text-emerald-400 transition-colors flex items-center gap-1",
|
|
2253
|
+
children: [
|
|
2254
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react6.Activity, { className: "w-3 h-3" }),
|
|
2255
|
+
showTrace ? "Hide Trace" : "Trace"
|
|
2256
|
+
]
|
|
2257
|
+
}
|
|
2258
|
+
)
|
|
2259
|
+
] }),
|
|
2260
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "w-full flex flex-col gap-2 min-w-0", children: [
|
|
2261
|
+
showSources && sources && sources.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mt-1 flex flex-col gap-2", children: sources.map((src, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SourceCard, { source: src, index: i }, src.id)) }),
|
|
2262
|
+
showTrace && message.trace && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ObservabilityPanel, { trace: message.trace, primaryColor })
|
|
2263
|
+
] })
|
|
2264
|
+
] })
|
|
2265
|
+
] });
|
|
1894
2266
|
}
|
|
1895
2267
|
|
|
1896
2268
|
// src/hooks/useRagChat.ts
|
|
1897
|
-
var
|
|
2269
|
+
var import_react10 = require("react");
|
|
1898
2270
|
|
|
1899
2271
|
// src/hooks/useStoredMessages.ts
|
|
1900
|
-
var
|
|
2272
|
+
var React10 = __toESM(require("react"));
|
|
1901
2273
|
function readStoredMessages(storageKey) {
|
|
1902
2274
|
if (typeof window === "undefined") {
|
|
1903
2275
|
return [];
|
|
@@ -1914,8 +2286,8 @@ function readStoredMessages(storageKey) {
|
|
|
1914
2286
|
}
|
|
1915
2287
|
}
|
|
1916
2288
|
function useStoredMessages(storageKey, persist) {
|
|
1917
|
-
const [messages, setMessages] =
|
|
1918
|
-
|
|
2289
|
+
const [messages, setMessages] = React10.useState(() => persist ? readStoredMessages(storageKey) : []);
|
|
2290
|
+
React10.useEffect(() => {
|
|
1919
2291
|
if (!persist || typeof window === "undefined") {
|
|
1920
2292
|
return;
|
|
1921
2293
|
}
|
|
@@ -1955,14 +2327,14 @@ function useRagChat(projectId, options = {}) {
|
|
|
1955
2327
|
} = options;
|
|
1956
2328
|
const storageKey = `rag_chat_${projectId}`;
|
|
1957
2329
|
const [messages, setMessages] = useStoredMessages(storageKey, persist);
|
|
1958
|
-
const [isLoading, setIsLoading] = (0,
|
|
1959
|
-
const [error, setError] = (0,
|
|
1960
|
-
const lastInputRef = (0,
|
|
1961
|
-
const messagesRef = (0,
|
|
1962
|
-
(0,
|
|
2330
|
+
const [isLoading, setIsLoading] = (0, import_react10.useState)(false);
|
|
2331
|
+
const [error, setError] = (0, import_react10.useState)(null);
|
|
2332
|
+
const lastInputRef = (0, import_react10.useRef)("");
|
|
2333
|
+
const messagesRef = (0, import_react10.useRef)(messages);
|
|
2334
|
+
(0, import_react10.useEffect)(() => {
|
|
1963
2335
|
messagesRef.current = messages;
|
|
1964
2336
|
}, [messages]);
|
|
1965
|
-
const sendMessage = (0,
|
|
2337
|
+
const sendMessage = (0, import_react10.useCallback)(
|
|
1966
2338
|
async (text, opts) => {
|
|
1967
2339
|
var _a, _b;
|
|
1968
2340
|
const trimmed = text.trim();
|
|
@@ -2075,12 +2447,12 @@ function useRagChat(projectId, options = {}) {
|
|
|
2075
2447
|
},
|
|
2076
2448
|
[apiUrl, isLoading, namespace, onError, onReply, projectId, setMessages]
|
|
2077
2449
|
);
|
|
2078
|
-
const clear = (0,
|
|
2450
|
+
const clear = (0, import_react10.useCallback)(() => {
|
|
2079
2451
|
setMessages([]);
|
|
2080
2452
|
setError(null);
|
|
2081
2453
|
if (persist) localStorage.removeItem(storageKey);
|
|
2082
2454
|
}, [persist, setMessages, storageKey]);
|
|
2083
|
-
const retry = (0,
|
|
2455
|
+
const retry = (0, import_react10.useCallback)(async () => {
|
|
2084
2456
|
if (lastInputRef.current) {
|
|
2085
2457
|
const latestMessage = messagesRef.current[messagesRef.current.length - 1];
|
|
2086
2458
|
await sendMessage(lastInputRef.current, {
|
|
@@ -2100,6 +2472,7 @@ function useRagChat(projectId, options = {}) {
|
|
|
2100
2472
|
}
|
|
2101
2473
|
|
|
2102
2474
|
// src/components/ChatWindow.tsx
|
|
2475
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2103
2476
|
function ChatWindow({
|
|
2104
2477
|
className = "",
|
|
2105
2478
|
style,
|
|
@@ -2114,21 +2487,21 @@ function ChatWindow({
|
|
|
2114
2487
|
}) {
|
|
2115
2488
|
var _a;
|
|
2116
2489
|
const { ui, projectId } = useConfig();
|
|
2117
|
-
const [input, setInput] = (0,
|
|
2118
|
-
const [mounted, setMounted] = (0,
|
|
2119
|
-
const [viewportSize, setViewportSize] = (0,
|
|
2120
|
-
const windowRef = (0,
|
|
2121
|
-
const bottomRef = (0,
|
|
2122
|
-
const inputRef = (0,
|
|
2490
|
+
const [input, setInput] = (0, import_react11.useState)("");
|
|
2491
|
+
const [mounted, setMounted] = (0, import_react11.useState)(false);
|
|
2492
|
+
const [viewportSize, setViewportSize] = (0, import_react11.useState)("large");
|
|
2493
|
+
const windowRef = (0, import_react11.useRef)(null);
|
|
2494
|
+
const bottomRef = (0, import_react11.useRef)(null);
|
|
2495
|
+
const inputRef = (0, import_react11.useRef)(null);
|
|
2123
2496
|
const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
|
|
2124
2497
|
namespace: projectId
|
|
2125
2498
|
});
|
|
2126
|
-
const [suggestions, setSuggestions] = (0,
|
|
2127
|
-
const [isSuggesting, setIsSuggesting] = (0,
|
|
2128
|
-
const [isListening, setIsListening] = (0,
|
|
2129
|
-
const [isUploadModalOpen, setIsUploadModalOpen] = (0,
|
|
2130
|
-
const recognitionRef = (0,
|
|
2131
|
-
(0,
|
|
2499
|
+
const [suggestions, setSuggestions] = (0, import_react11.useState)([]);
|
|
2500
|
+
const [isSuggesting, setIsSuggesting] = (0, import_react11.useState)(false);
|
|
2501
|
+
const [isListening, setIsListening] = (0, import_react11.useState)(false);
|
|
2502
|
+
const [isUploadModalOpen, setIsUploadModalOpen] = (0, import_react11.useState)(false);
|
|
2503
|
+
const recognitionRef = (0, import_react11.useRef)(null);
|
|
2504
|
+
(0, import_react11.useEffect)(() => {
|
|
2132
2505
|
if (typeof window !== "undefined") {
|
|
2133
2506
|
const win = window;
|
|
2134
2507
|
const SpeechRecognition = win.SpeechRecognition || win.webkitSpeechRecognition;
|
|
@@ -2174,10 +2547,10 @@ function ChatWindow({
|
|
|
2174
2547
|
}
|
|
2175
2548
|
}
|
|
2176
2549
|
};
|
|
2177
|
-
(0,
|
|
2550
|
+
(0, import_react11.useEffect)(() => {
|
|
2178
2551
|
setMounted(true);
|
|
2179
2552
|
}, []);
|
|
2180
|
-
(0,
|
|
2553
|
+
(0, import_react11.useEffect)(() => {
|
|
2181
2554
|
const element = windowRef.current;
|
|
2182
2555
|
if (!element || typeof ResizeObserver === "undefined") return;
|
|
2183
2556
|
const resolveViewportSize = (width) => {
|
|
@@ -2193,13 +2566,13 @@ function ChatWindow({
|
|
|
2193
2566
|
observer.observe(element);
|
|
2194
2567
|
return () => observer.disconnect();
|
|
2195
2568
|
}, []);
|
|
2196
|
-
(0,
|
|
2569
|
+
(0, import_react11.useEffect)(() => {
|
|
2197
2570
|
var _a2;
|
|
2198
2571
|
if (messages.length > 0 || isLoading) {
|
|
2199
2572
|
(_a2 = bottomRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth" });
|
|
2200
2573
|
}
|
|
2201
2574
|
}, [messages, isLoading]);
|
|
2202
|
-
const sendMessage = (0,
|
|
2575
|
+
const sendMessage = (0, import_react11.useCallback)(async () => {
|
|
2203
2576
|
var _a2;
|
|
2204
2577
|
const text = input.trim();
|
|
2205
2578
|
if (!text || isLoading) return;
|
|
@@ -2229,7 +2602,7 @@ function ChatWindow({
|
|
|
2229
2602
|
const isEmpty = messages.length === 0;
|
|
2230
2603
|
const currentRadius = BORDER_RADIUS_MAP[ui.borderRadius || "xl"];
|
|
2231
2604
|
const isGlass = ui.visualStyle !== "solid";
|
|
2232
|
-
(0,
|
|
2605
|
+
(0, import_react11.useEffect)(() => {
|
|
2233
2606
|
if (input.trim().length < 3) {
|
|
2234
2607
|
return;
|
|
2235
2608
|
}
|
|
@@ -2253,217 +2626,273 @@ function ChatWindow({
|
|
|
2253
2626
|
}, 800);
|
|
2254
2627
|
return () => clearTimeout(timer);
|
|
2255
2628
|
}, [input, projectId]);
|
|
2256
|
-
return /* @__PURE__ */
|
|
2629
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
2257
2630
|
"div",
|
|
2258
2631
|
{
|
|
2259
2632
|
ref: windowRef,
|
|
2260
2633
|
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}`,
|
|
2261
|
-
style: __spreadValues({ "--primary": ui.primaryColor, "--accent": ui.accentColor }, style)
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
{
|
|
2266
|
-
onMouseDown: onResizeStart,
|
|
2267
|
-
className: "absolute top-0 left-0 w-6 h-6 cursor-nw-resize z-[100] group flex items-start justify-start p-1",
|
|
2268
|
-
title: "Drag to resize"
|
|
2269
|
-
},
|
|
2270
|
-
/* @__PURE__ */ import_react14.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]" })
|
|
2271
|
-
),
|
|
2272
|
-
/* @__PURE__ */ import_react14.default.createElement(
|
|
2273
|
-
"div",
|
|
2274
|
-
{
|
|
2275
|
-
className: "flex items-center justify-between px-5 py-4 border-b border-slate-200 dark:border-white/10",
|
|
2276
|
-
style: { background: `linear-gradient(135deg, ${ui.primaryColor}15, ${ui.accentColor}10)` }
|
|
2277
|
-
},
|
|
2278
|
-
/* @__PURE__ */ import_react14.default.createElement("div", { className: "flex items-center gap-3" }, ui.logoUrl ? (
|
|
2279
|
-
// eslint-disable-next-line @next/next/no-img-element
|
|
2280
|
-
/* @__PURE__ */ import_react14.default.createElement("img", { src: ui.logoUrl, alt: "logo", className: "w-8 h-8 rounded-lg object-cover" })
|
|
2281
|
-
) : /* @__PURE__ */ import_react14.default.createElement(
|
|
2282
|
-
"div",
|
|
2283
|
-
{
|
|
2284
|
-
className: `w-9 h-9 flex items-center justify-center shadow-md ${ui.borderRadius === "full" ? "rounded-full" : "rounded-xl"}`,
|
|
2285
|
-
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` }
|
|
2286
|
-
},
|
|
2287
|
-
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Bot, { className: "w-5 h-5 text-white" })
|
|
2288
|
-
), /* @__PURE__ */ import_react14.default.createElement("div", null, /* @__PURE__ */ import_react14.default.createElement("h2", { className: "text-slate-900 dark:text-white font-semibold text-sm leading-tight" }, ui.title), ui.poweredBy && /* @__PURE__ */ import_react14.default.createElement("p", { className: "text-slate-500 dark:text-white/40 text-[11px] leading-tight" }, `Powered by ${ui.poweredBy}`))),
|
|
2289
|
-
/* @__PURE__ */ import_react14.default.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ import_react14.default.createElement("span", { className: "flex items-center gap-1 text-[10px] text-emerald-500 dark:text-emerald-400 mr-2" }, /* @__PURE__ */ import_react14.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500 dark:bg-emerald-400 animate-pulse" }), "Online"), /* @__PURE__ */ import_react14.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_react14.default.createElement(
|
|
2290
|
-
"button",
|
|
2291
|
-
{
|
|
2292
|
-
onClick: clearHistory,
|
|
2293
|
-
title: "Clear conversation",
|
|
2294
|
-
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"
|
|
2295
|
-
},
|
|
2296
|
-
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Trash2, { className: "w-3.5 h-3.5" })
|
|
2297
|
-
), isResized && onResetResize && /* @__PURE__ */ import_react14.default.createElement(
|
|
2298
|
-
"button",
|
|
2299
|
-
{
|
|
2300
|
-
onClick: onResetResize,
|
|
2301
|
-
title: "Reset to default size",
|
|
2302
|
-
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"
|
|
2303
|
-
},
|
|
2304
|
-
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.RotateCcw, { className: "w-3.5 h-3.5" })
|
|
2305
|
-
), onMaximize && /* @__PURE__ */ import_react14.default.createElement(
|
|
2306
|
-
"button",
|
|
2307
|
-
{
|
|
2308
|
-
onClick: onMaximize,
|
|
2309
|
-
title: isMaximized ? "Minimize" : "Maximize",
|
|
2310
|
-
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"
|
|
2311
|
-
},
|
|
2312
|
-
isMaximized ? /* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Minimize2, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Maximize2, { className: "w-3.5 h-3.5" })
|
|
2313
|
-
), showClose && onClose && /* @__PURE__ */ import_react14.default.createElement(
|
|
2314
|
-
"button",
|
|
2315
|
-
{
|
|
2316
|
-
onClick: onClose,
|
|
2317
|
-
title: "Close chat",
|
|
2318
|
-
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"
|
|
2319
|
-
},
|
|
2320
|
-
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.X, { className: "w-4 h-4" })
|
|
2321
|
-
)))
|
|
2322
|
-
),
|
|
2323
|
-
/* @__PURE__ */ import_react14.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 ? (
|
|
2324
|
-
/* Welcome state */
|
|
2325
|
-
/* @__PURE__ */ import_react14.default.createElement("div", { className: "h-full flex flex-col items-center justify-center text-center gap-4 px-6 py-12" }, /* @__PURE__ */ import_react14.default.createElement(
|
|
2326
|
-
"div",
|
|
2327
|
-
{
|
|
2328
|
-
className: `w-16 h-16 flex items-center justify-center shadow-lg ${ui.borderRadius === "full" ? "rounded-full" : "rounded-2xl"}`,
|
|
2329
|
-
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` }
|
|
2330
|
-
},
|
|
2331
|
-
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Sparkles, { className: "w-8 h-8 text-white" })
|
|
2332
|
-
), /* @__PURE__ */ import_react14.default.createElement("div", null, /* @__PURE__ */ import_react14.default.createElement("p", { className: "text-slate-800 dark:text-white/80 font-medium leading-relaxed" }, ui.welcomeMessage), /* @__PURE__ */ import_react14.default.createElement("p", { className: "text-slate-500 dark:text-white/30 text-sm mt-2" }, "Ask a question to get started")), /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex flex-wrap gap-2 justify-center mt-2" }, CHAT_SUGGESTIONS.map(
|
|
2333
|
-
(suggestion) => /* @__PURE__ */ import_react14.default.createElement(
|
|
2334
|
-
"button",
|
|
2634
|
+
style: __spreadValues({ "--primary": ui.primaryColor, "--accent": ui.accentColor }, style),
|
|
2635
|
+
children: [
|
|
2636
|
+
onResizeStart && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2637
|
+
"div",
|
|
2335
2638
|
{
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
(_a2 = inputRef.current) == null ? void 0 : _a2.focus();
|
|
2341
|
-
},
|
|
2342
|
-
className: "px-3 py-1.5 rounded-full text-xs border border-slate-200 dark:border-white/10 text-slate-600 dark:text-white/50 hover:text-slate-900 dark:hover:text-white/80 hover:border-slate-300 dark:hover:border-white/20 hover:bg-slate-100 dark:hover:bg-white/5 transition-all"
|
|
2343
|
-
},
|
|
2344
|
-
suggestion
|
|
2345
|
-
)
|
|
2346
|
-
)))
|
|
2347
|
-
) : messages.map((msg, index) => /* @__PURE__ */ import_react14.default.createElement(
|
|
2348
|
-
MessageBubble,
|
|
2349
|
-
{
|
|
2350
|
-
key: msg.id,
|
|
2351
|
-
message: msg,
|
|
2352
|
-
sources: msg.sources,
|
|
2353
|
-
isStreaming: isLoading && index === messages.length - 1 && msg.role === "assistant",
|
|
2354
|
-
primaryColor: ui.primaryColor,
|
|
2355
|
-
accentColor: ui.accentColor,
|
|
2356
|
-
onAddToCart,
|
|
2357
|
-
viewportSize
|
|
2358
|
-
}
|
|
2359
|
-
)), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */ import_react14.default.createElement(
|
|
2360
|
-
MessageBubble,
|
|
2361
|
-
{
|
|
2362
|
-
message: { id: "loading", role: "assistant", content: "", createdAt: (/* @__PURE__ */ new Date()).toISOString() },
|
|
2363
|
-
isStreaming: true,
|
|
2364
|
-
primaryColor: ui.primaryColor,
|
|
2365
|
-
accentColor: ui.accentColor,
|
|
2366
|
-
onAddToCart,
|
|
2367
|
-
viewportSize
|
|
2368
|
-
}
|
|
2369
|
-
), error && /* @__PURE__ */ import_react14.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_react14.default.createElement(import_lucide_react7.TriangleAlert, { className: "w-4 h-4 flex-shrink-0" }), /* @__PURE__ */ import_react14.default.createElement("span", null, error)), /* @__PURE__ */ import_react14.default.createElement("div", { ref: bottomRef })),
|
|
2370
|
-
isUploadModalOpen && /* @__PURE__ */ import_react14.default.createElement("div", { className: "absolute inset-0 z-50 flex items-center justify-center p-4 bg-slate-900/50 backdrop-blur-sm rounded-inherit" }, /* @__PURE__ */ import_react14.default.createElement("div", { className: "relative w-full max-w-md bg-white dark:bg-[#0f0f1a] rounded-2xl shadow-2xl overflow-hidden animate-in zoom-in-95 duration-200" }, /* @__PURE__ */ import_react14.default.createElement(
|
|
2371
|
-
"button",
|
|
2372
|
-
{
|
|
2373
|
-
onClick: () => setIsUploadModalOpen(false),
|
|
2374
|
-
className: "absolute top-4 right-4 p-1.5 rounded-lg text-slate-400 hover:text-slate-600 hover:bg-slate-100 dark:hover:text-white/80 dark:hover:bg-white/10 transition-colors z-10"
|
|
2375
|
-
},
|
|
2376
|
-
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.X, { className: "w-5 h-5" })
|
|
2377
|
-
), /* @__PURE__ */ import_react14.default.createElement(
|
|
2378
|
-
DocumentUpload,
|
|
2379
|
-
{
|
|
2380
|
-
namespace: projectId,
|
|
2381
|
-
onUploadComplete: () => setIsUploadModalOpen(false)
|
|
2382
|
-
}
|
|
2383
|
-
))),
|
|
2384
|
-
/* @__PURE__ */ import_react14.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_react14.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_react14.default.createElement(
|
|
2385
|
-
"button",
|
|
2386
|
-
{
|
|
2387
|
-
key: suggestion,
|
|
2388
|
-
onClick: () => {
|
|
2389
|
-
var _a2;
|
|
2390
|
-
setInput(suggestion);
|
|
2391
|
-
setSuggestions([]);
|
|
2392
|
-
(_a2 = inputRef.current) == null ? void 0 : _a2.focus();
|
|
2393
|
-
},
|
|
2394
|
-
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"
|
|
2395
|
-
},
|
|
2396
|
-
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Sparkles, { className: "w-3 h-3 text-amber-400" }),
|
|
2397
|
-
suggestion
|
|
2398
|
-
)), isSuggesting && suggestions.length === 0 && /* @__PURE__ */ import_react14.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_react14.default.createElement(import_lucide_react7.Sparkles, { className: "w-3 h-3" }), "Thinking...")), /* @__PURE__ */ import_react14.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_react14.default.createElement(
|
|
2399
|
-
"textarea",
|
|
2400
|
-
{
|
|
2401
|
-
ref: inputRef,
|
|
2402
|
-
value: input,
|
|
2403
|
-
onChange: (e) => {
|
|
2404
|
-
const val = e.target.value;
|
|
2405
|
-
setInput(val);
|
|
2406
|
-
if (val.trim().length < 3) {
|
|
2407
|
-
setSuggestions([]);
|
|
2639
|
+
onMouseDown: onResizeStart,
|
|
2640
|
+
className: "absolute top-0 left-0 w-6 h-6 cursor-nw-resize z-[100] group flex items-start justify-start p-1",
|
|
2641
|
+
title: "Drag to resize",
|
|
2642
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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]" })
|
|
2408
2643
|
}
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2644
|
+
),
|
|
2645
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
2646
|
+
"div",
|
|
2647
|
+
{
|
|
2648
|
+
className: "flex items-center justify-between px-5 py-4 border-b border-slate-200 dark:border-white/10",
|
|
2649
|
+
style: { background: `linear-gradient(135deg, ${ui.primaryColor}15, ${ui.accentColor}10)` },
|
|
2650
|
+
children: [
|
|
2651
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
2652
|
+
ui.logoUrl ? (
|
|
2653
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
2654
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: ui.logoUrl, alt: "logo", className: "w-8 h-8 rounded-lg object-cover" })
|
|
2655
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2656
|
+
"div",
|
|
2657
|
+
{
|
|
2658
|
+
className: `w-9 h-9 flex items-center justify-center shadow-md ${ui.borderRadius === "full" ? "rounded-full" : "rounded-xl"}`,
|
|
2659
|
+
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` },
|
|
2660
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Bot, { className: "w-5 h-5 text-white" })
|
|
2661
|
+
}
|
|
2662
|
+
),
|
|
2663
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
|
|
2664
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { className: "text-slate-900 dark:text-white font-semibold text-sm leading-tight", children: ui.title }),
|
|
2665
|
+
ui.poweredBy && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-slate-500 dark:text-white/40 text-[11px] leading-tight", children: `Powered by ${ui.poweredBy}` })
|
|
2666
|
+
] })
|
|
2667
|
+
] }),
|
|
2668
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
2669
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "flex items-center gap-1 text-[10px] text-emerald-500 dark:text-emerald-400 mr-2", children: [
|
|
2670
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500 dark:bg-emerald-400 animate-pulse" }),
|
|
2671
|
+
"Online"
|
|
2672
|
+
] }),
|
|
2673
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("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", children: [
|
|
2674
|
+
mounted && messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2675
|
+
"button",
|
|
2676
|
+
{
|
|
2677
|
+
onClick: clearHistory,
|
|
2678
|
+
title: "Clear conversation",
|
|
2679
|
+
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",
|
|
2680
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Trash2, { className: "w-3.5 h-3.5" })
|
|
2681
|
+
}
|
|
2682
|
+
),
|
|
2683
|
+
isResized && onResetResize && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2684
|
+
"button",
|
|
2685
|
+
{
|
|
2686
|
+
onClick: onResetResize,
|
|
2687
|
+
title: "Reset to default size",
|
|
2688
|
+
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",
|
|
2689
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.RotateCcw, { className: "w-3.5 h-3.5" })
|
|
2690
|
+
}
|
|
2691
|
+
),
|
|
2692
|
+
onMaximize && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2693
|
+
"button",
|
|
2694
|
+
{
|
|
2695
|
+
onClick: onMaximize,
|
|
2696
|
+
title: isMaximized ? "Minimize" : "Maximize",
|
|
2697
|
+
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",
|
|
2698
|
+
children: isMaximized ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Minimize2, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Maximize2, { className: "w-3.5 h-3.5" })
|
|
2699
|
+
}
|
|
2700
|
+
),
|
|
2701
|
+
showClose && onClose && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2702
|
+
"button",
|
|
2703
|
+
{
|
|
2704
|
+
onClick: onClose,
|
|
2705
|
+
title: "Close chat",
|
|
2706
|
+
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",
|
|
2707
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.X, { className: "w-4 h-4" })
|
|
2708
|
+
}
|
|
2709
|
+
)
|
|
2710
|
+
] })
|
|
2711
|
+
] })
|
|
2712
|
+
]
|
|
2713
|
+
}
|
|
2714
|
+
),
|
|
2715
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("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", children: [
|
|
2716
|
+
!mounted || isEmpty ? (
|
|
2717
|
+
/* Welcome state */
|
|
2718
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "h-full flex flex-col items-center justify-center text-center gap-4 px-6 py-12", children: [
|
|
2719
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2720
|
+
"div",
|
|
2721
|
+
{
|
|
2722
|
+
className: `w-16 h-16 flex items-center justify-center shadow-lg ${ui.borderRadius === "full" ? "rounded-full" : "rounded-2xl"}`,
|
|
2723
|
+
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` },
|
|
2724
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Sparkles, { className: "w-8 h-8 text-white" })
|
|
2725
|
+
}
|
|
2726
|
+
),
|
|
2727
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
|
|
2728
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-slate-800 dark:text-white/80 font-medium leading-relaxed", children: ui.welcomeMessage }),
|
|
2729
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-slate-500 dark:text-white/30 text-sm mt-2", children: "Ask a question to get started" })
|
|
2730
|
+
] }),
|
|
2731
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex flex-wrap gap-2 justify-center mt-2", children: CHAT_SUGGESTIONS.map(
|
|
2732
|
+
(suggestion) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2733
|
+
"button",
|
|
2734
|
+
{
|
|
2735
|
+
onClick: () => {
|
|
2736
|
+
var _a2;
|
|
2737
|
+
setInput(suggestion);
|
|
2738
|
+
(_a2 = inputRef.current) == null ? void 0 : _a2.focus();
|
|
2739
|
+
},
|
|
2740
|
+
className: "px-3 py-1.5 rounded-full text-xs border border-slate-200 dark:border-white/10 text-slate-600 dark:text-white/50 hover:text-slate-900 dark:hover:text-white/80 hover:border-slate-300 dark:hover:border-white/20 hover:bg-slate-100 dark:hover:bg-white/5 transition-all",
|
|
2741
|
+
children: suggestion
|
|
2742
|
+
},
|
|
2743
|
+
suggestion
|
|
2744
|
+
)
|
|
2745
|
+
) })
|
|
2746
|
+
] })
|
|
2747
|
+
) : messages.map((msg, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2748
|
+
MessageBubble,
|
|
2749
|
+
{
|
|
2750
|
+
message: msg,
|
|
2751
|
+
sources: msg.sources,
|
|
2752
|
+
isStreaming: isLoading && index === messages.length - 1 && msg.role === "assistant",
|
|
2753
|
+
primaryColor: ui.primaryColor,
|
|
2754
|
+
accentColor: ui.accentColor,
|
|
2755
|
+
onAddToCart,
|
|
2756
|
+
viewportSize
|
|
2757
|
+
},
|
|
2758
|
+
msg.id
|
|
2759
|
+
)),
|
|
2760
|
+
isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2761
|
+
MessageBubble,
|
|
2762
|
+
{
|
|
2763
|
+
message: { id: "loading", role: "assistant", content: "", createdAt: (/* @__PURE__ */ new Date()).toISOString() },
|
|
2764
|
+
isStreaming: true,
|
|
2765
|
+
primaryColor: ui.primaryColor,
|
|
2766
|
+
accentColor: ui.accentColor,
|
|
2767
|
+
onAddToCart,
|
|
2768
|
+
viewportSize
|
|
2769
|
+
}
|
|
2770
|
+
),
|
|
2771
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("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", children: [
|
|
2772
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.TriangleAlert, { className: "w-4 h-4 flex-shrink-0" }),
|
|
2773
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: error })
|
|
2774
|
+
] }),
|
|
2775
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { ref: bottomRef })
|
|
2776
|
+
] }),
|
|
2777
|
+
isUploadModalOpen && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute inset-0 z-50 flex items-center justify-center p-4 bg-slate-900/50 backdrop-blur-sm rounded-inherit", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "relative w-full max-w-md bg-white dark:bg-[#0f0f1a] rounded-2xl shadow-2xl overflow-hidden animate-in zoom-in-95 duration-200", children: [
|
|
2778
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2779
|
+
"button",
|
|
2780
|
+
{
|
|
2781
|
+
onClick: () => setIsUploadModalOpen(false),
|
|
2782
|
+
className: "absolute top-4 right-4 p-1.5 rounded-lg text-slate-400 hover:text-slate-600 hover:bg-slate-100 dark:hover:text-white/80 dark:hover:bg-white/10 transition-colors z-10",
|
|
2783
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.X, { className: "w-5 h-5" })
|
|
2784
|
+
}
|
|
2785
|
+
),
|
|
2786
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2787
|
+
DocumentUpload,
|
|
2788
|
+
{
|
|
2789
|
+
namespace: projectId,
|
|
2790
|
+
onUploadComplete: () => setIsUploadModalOpen(false)
|
|
2791
|
+
}
|
|
2792
|
+
)
|
|
2793
|
+
] }) }),
|
|
2794
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("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]"}`, children: [
|
|
2795
|
+
(suggestions.length > 0 || isSuggesting) && !isLoading && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "mb-3 flex flex-wrap gap-2 animate-in fade-in slide-in-from-bottom-2 duration-300", children: [
|
|
2796
|
+
suggestions.map((suggestion) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
2797
|
+
"button",
|
|
2798
|
+
{
|
|
2799
|
+
onClick: () => {
|
|
2800
|
+
var _a2;
|
|
2801
|
+
setInput(suggestion);
|
|
2802
|
+
setSuggestions([]);
|
|
2803
|
+
(_a2 = inputRef.current) == null ? void 0 : _a2.focus();
|
|
2804
|
+
},
|
|
2805
|
+
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",
|
|
2806
|
+
children: [
|
|
2807
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Sparkles, { className: "w-3 h-3 text-amber-400" }),
|
|
2808
|
+
suggestion
|
|
2809
|
+
]
|
|
2810
|
+
},
|
|
2811
|
+
suggestion
|
|
2812
|
+
)),
|
|
2813
|
+
isSuggesting && suggestions.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("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", children: [
|
|
2814
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Sparkles, { className: "w-3 h-3" }),
|
|
2815
|
+
"Thinking..."
|
|
2816
|
+
] })
|
|
2817
|
+
] }),
|
|
2818
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("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"}`, children: [
|
|
2819
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2820
|
+
"textarea",
|
|
2821
|
+
{
|
|
2822
|
+
ref: inputRef,
|
|
2823
|
+
value: input,
|
|
2824
|
+
onChange: (e) => {
|
|
2825
|
+
const val = e.target.value;
|
|
2826
|
+
setInput(val);
|
|
2827
|
+
if (val.trim().length < 3) {
|
|
2828
|
+
setSuggestions([]);
|
|
2829
|
+
}
|
|
2830
|
+
},
|
|
2831
|
+
onKeyDown: handleKeyDown,
|
|
2832
|
+
placeholder: ui.placeholder,
|
|
2833
|
+
rows: 1,
|
|
2834
|
+
disabled: isLoading,
|
|
2835
|
+
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",
|
|
2836
|
+
style: { scrollbarWidth: "none" }
|
|
2837
|
+
}
|
|
2838
|
+
),
|
|
2839
|
+
ui.enableVoiceInput !== false && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2840
|
+
"button",
|
|
2841
|
+
{
|
|
2842
|
+
type: "button",
|
|
2843
|
+
onClick: toggleListening,
|
|
2844
|
+
disabled: isLoading,
|
|
2845
|
+
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"}`,
|
|
2846
|
+
title: isListening ? "Stop listening" : "Start voice input",
|
|
2847
|
+
children: isListening ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.MicOff, { className: "w-4 h-4" }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Mic, { className: "w-4 h-4" })
|
|
2848
|
+
}
|
|
2849
|
+
),
|
|
2850
|
+
ui.allowUpload !== false && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2851
|
+
"button",
|
|
2852
|
+
{
|
|
2853
|
+
type: "button",
|
|
2854
|
+
onClick: () => setIsUploadModalOpen(true),
|
|
2855
|
+
className: "flex-shrink-0 w-9 h-9 rounded-xl flex items-center justify-center transition-all hover:scale-105 active:scale-95 text-slate-400 dark:text-white/40 hover:bg-slate-200 dark:hover:bg-white/10",
|
|
2856
|
+
title: "Upload Document",
|
|
2857
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Paperclip, { className: "w-4 h-4" })
|
|
2858
|
+
}
|
|
2859
|
+
),
|
|
2860
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2861
|
+
"button",
|
|
2862
|
+
{
|
|
2863
|
+
onClick: sendMessage,
|
|
2864
|
+
disabled: !input.trim() || isLoading,
|
|
2865
|
+
className: "flex-shrink-0 w-9 h-9 rounded-xl flex items-center justify-center transition-all disabled:opacity-30 disabled:cursor-not-allowed hover:scale-105 active:scale-95 shadow-md",
|
|
2866
|
+
style: {
|
|
2867
|
+
background: input.trim() && !isLoading ? `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` : "rgba(148, 163, 184, 0.2)"
|
|
2868
|
+
// slate-400/20 for light mode disabled
|
|
2869
|
+
},
|
|
2870
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.ArrowUp, { className: "w-4 h-4 text-white" })
|
|
2871
|
+
}
|
|
2872
|
+
)
|
|
2873
|
+
] }),
|
|
2874
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-center text-[10px] text-slate-400 dark:text-white/20 mt-2", children: "Press Enter to send \xB7 Shift+Enter for new line" })
|
|
2875
|
+
] })
|
|
2876
|
+
]
|
|
2877
|
+
}
|
|
2449
2878
|
);
|
|
2450
2879
|
}
|
|
2451
2880
|
|
|
2452
2881
|
// src/components/ChatWidget.tsx
|
|
2882
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2453
2883
|
var DEFAULT_DIMENSIONS = { width: 380, height: 600 };
|
|
2454
2884
|
function ChatWidget({ position = "bottom-right", onAddToCart }) {
|
|
2455
2885
|
const { ui } = useConfig();
|
|
2456
|
-
const [isOpen, setIsOpen] = (0,
|
|
2457
|
-
const [hasUnread, setHasUnread] = (0,
|
|
2458
|
-
const [dimensions, setDimensions] = (0,
|
|
2459
|
-
const [isResizing, setIsResizing] = (0,
|
|
2460
|
-
const [isMaximized, setIsMaximized] = (0,
|
|
2461
|
-
const [prevDimensions, setPrevDimensions] = (0,
|
|
2886
|
+
const [isOpen, setIsOpen] = (0, import_react12.useState)(false);
|
|
2887
|
+
const [hasUnread, setHasUnread] = (0, import_react12.useState)(false);
|
|
2888
|
+
const [dimensions, setDimensions] = (0, import_react12.useState)(DEFAULT_DIMENSIONS);
|
|
2889
|
+
const [isResizing, setIsResizing] = (0, import_react12.useState)(false);
|
|
2890
|
+
const [isMaximized, setIsMaximized] = (0, import_react12.useState)(false);
|
|
2891
|
+
const [prevDimensions, setPrevDimensions] = (0, import_react12.useState)(DEFAULT_DIMENSIONS);
|
|
2462
2892
|
if (ui.showWidget === false) return null;
|
|
2463
2893
|
const positionClass = position === "bottom-left" ? "bottom-6 left-6" : "bottom-6 right-6";
|
|
2464
2894
|
const windowPositionClass = position === "bottom-left" ? "bottom-20 left-6" : "bottom-20 right-6";
|
|
2465
2895
|
const handleOpen = () => {
|
|
2466
|
-
console.log("ChatWidget: Opening...");
|
|
2467
2896
|
setIsOpen(true);
|
|
2468
2897
|
setHasUnread(false);
|
|
2469
2898
|
};
|
|
@@ -2508,60 +2937,67 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
|
|
|
2508
2937
|
}
|
|
2509
2938
|
};
|
|
2510
2939
|
const isResized = dimensions.width !== DEFAULT_DIMENSIONS.width || dimensions.height !== DEFAULT_DIMENSIONS.height;
|
|
2511
|
-
return /* @__PURE__ */
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
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"}`,
|
|
2515
|
-
style: {
|
|
2516
|
-
width: `${dimensions.width}px`,
|
|
2517
|
-
height: `${dimensions.height}px`,
|
|
2518
|
-
maxHeight: "calc(100vh - 6rem)"
|
|
2519
|
-
}
|
|
2520
|
-
},
|
|
2521
|
-
/* @__PURE__ */ import_react15.default.createElement(
|
|
2522
|
-
ChatWindow,
|
|
2940
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
2941
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
2942
|
+
"div",
|
|
2523
2943
|
{
|
|
2524
|
-
className: "
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2944
|
+
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"}`,
|
|
2945
|
+
style: {
|
|
2946
|
+
width: `${dimensions.width}px`,
|
|
2947
|
+
height: `${dimensions.height}px`,
|
|
2948
|
+
maxHeight: "calc(100vh - 6rem)"
|
|
2949
|
+
},
|
|
2950
|
+
children: [
|
|
2951
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2952
|
+
ChatWindow,
|
|
2953
|
+
{
|
|
2954
|
+
className: "h-full relative z-10",
|
|
2955
|
+
showClose: true,
|
|
2956
|
+
onClose: () => setIsOpen(false),
|
|
2957
|
+
onResizeStart: ui.allowResize !== false ? handleResizeStart : void 0,
|
|
2958
|
+
onResetResize: ui.allowResize !== false ? handleResetResize : void 0,
|
|
2959
|
+
isResized,
|
|
2960
|
+
onMaximize: ui.allowResize !== false ? handleMaximize : void 0,
|
|
2961
|
+
isMaximized,
|
|
2962
|
+
onAddToCart
|
|
2963
|
+
}
|
|
2964
|
+
),
|
|
2965
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2966
|
+
"div",
|
|
2967
|
+
{
|
|
2968
|
+
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"}`
|
|
2969
|
+
}
|
|
2970
|
+
)
|
|
2971
|
+
]
|
|
2533
2972
|
}
|
|
2534
2973
|
),
|
|
2535
|
-
/* @__PURE__ */
|
|
2536
|
-
"
|
|
2974
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
2975
|
+
"button",
|
|
2537
2976
|
{
|
|
2538
|
-
|
|
2977
|
+
onClick: isOpen ? () => setIsOpen(false) : handleOpen,
|
|
2978
|
+
className: `fixed z-[9999] w-14 h-14 shadow-2xl flex items-center justify-center transition-all duration-300 cursor-pointer hover:scale-110 active:scale-95 ${ui.borderRadius === "full" ? "rounded-full" : "rounded-2xl"} ${positionClass}`,
|
|
2979
|
+
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` },
|
|
2980
|
+
"aria-label": "Open chat",
|
|
2981
|
+
children: [
|
|
2982
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2983
|
+
"span",
|
|
2984
|
+
{
|
|
2985
|
+
className: "absolute inset-0 rounded-full animate-ping opacity-20",
|
|
2986
|
+
style: { background: ui.primaryColor }
|
|
2987
|
+
}
|
|
2988
|
+
),
|
|
2989
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2990
|
+
"span",
|
|
2991
|
+
{
|
|
2992
|
+
className: `transition-transform duration-300 ${isOpen ? "rotate-90 scale-90" : "rotate-0 scale-100"}`,
|
|
2993
|
+
children: isOpen ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react8.X, { className: "w-6 h-6 text-white" }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react8.MessageSquare, { className: "w-6 h-6 text-white" })
|
|
2994
|
+
}
|
|
2995
|
+
),
|
|
2996
|
+
hasUnread && !isOpen && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("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", children: "1" })
|
|
2997
|
+
]
|
|
2539
2998
|
}
|
|
2540
2999
|
)
|
|
2541
|
-
)
|
|
2542
|
-
"button",
|
|
2543
|
-
{
|
|
2544
|
-
onClick: isOpen ? () => setIsOpen(false) : handleOpen,
|
|
2545
|
-
className: `fixed z-[9999] w-14 h-14 shadow-2xl flex items-center justify-center transition-all duration-300 cursor-pointer hover:scale-110 active:scale-95 ${ui.borderRadius === "full" ? "rounded-full" : "rounded-2xl"} ${positionClass}`,
|
|
2546
|
-
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` },
|
|
2547
|
-
"aria-label": "Open chat"
|
|
2548
|
-
},
|
|
2549
|
-
/* @__PURE__ */ import_react15.default.createElement(
|
|
2550
|
-
"span",
|
|
2551
|
-
{
|
|
2552
|
-
className: "absolute inset-0 rounded-full animate-ping opacity-20",
|
|
2553
|
-
style: { background: ui.primaryColor }
|
|
2554
|
-
}
|
|
2555
|
-
),
|
|
2556
|
-
/* @__PURE__ */ import_react15.default.createElement(
|
|
2557
|
-
"span",
|
|
2558
|
-
{
|
|
2559
|
-
className: `transition-transform duration-300 ${isOpen ? "rotate-90 scale-90" : "rotate-0 scale-100"}`
|
|
2560
|
-
},
|
|
2561
|
-
isOpen ? /* @__PURE__ */ import_react15.default.createElement(import_lucide_react8.X, { className: "w-6 h-6 text-white" }) : /* @__PURE__ */ import_react15.default.createElement(import_lucide_react8.MessageSquare, { className: "w-6 h-6 text-white" })
|
|
2562
|
-
),
|
|
2563
|
-
hasUnread && !isOpen && /* @__PURE__ */ import_react15.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")
|
|
2564
|
-
));
|
|
3000
|
+
] });
|
|
2565
3001
|
}
|
|
2566
3002
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2567
3003
|
0 && (module.exports = {
|