@retrivora-ai/rag-engine 1.8.1 → 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/{ILLMProvider-BfRgI1Xh.d.mts → ILLMProvider-BOJFz3Na.d.mts} +47 -1
- package/dist/{ILLMProvider-BfRgI1Xh.d.ts → ILLMProvider-BOJFz3Na.d.ts} +47 -1
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +509 -162
- package/dist/handlers/index.mjs +5849 -15
- package/dist/{index-1Z4GuYBi.d.ts → index-BwpcaziY.d.ts} +4 -2
- package/dist/{index-BV0z5mb6.d.mts → index-D3V9Et2M.d.mts} +4 -2
- package/dist/index.d.mts +30 -16
- package/dist/index.d.ts +30 -16
- package/dist/index.js +1999 -1210
- package/dist/index.mjs +2041 -1205
- package/dist/server.d.mts +21 -25
- package/dist/server.d.ts +21 -25
- package/dist/server.js +536 -163
- package/dist/server.mjs +5923 -67
- package/package.json +9 -7
- package/src/app/api/upload/route.ts +4 -0
- package/src/app/constants.tsx +2 -2
- package/src/app/globals.css +35 -11
- package/src/app/page.tsx +12 -321
- package/src/components/AmbientBackground.tsx +29 -0
- package/src/components/ArchitectureCard.tsx +17 -0
- package/src/components/ArchitectureCardsSection.tsx +15 -0
- package/src/components/ChatWidget.tsx +0 -1
- package/src/components/ChatWindow.tsx +32 -0
- package/src/components/CodeViewer.tsx +51 -0
- package/src/components/ConfigProvider.tsx +1 -0
- package/src/components/DocViewer.tsx +37 -0
- package/src/components/DocumentUpload.tsx +44 -1
- package/src/components/Documentation.tsx +58 -0
- package/src/components/DynamicChart.tsx +27 -2
- package/src/components/Hero.tsx +59 -0
- package/src/components/HourglassLoader.tsx +87 -0
- package/src/components/Lifecycle.tsx +37 -0
- package/src/components/MarkdownComponents.tsx +143 -0
- package/src/components/MessageBubble.tsx +91 -1012
- package/src/components/Navbar.tsx +55 -0
- package/src/components/ObservabilityPanel.tsx +374 -0
- package/src/components/ProductCard.tsx +3 -1
- package/src/components/UIDispatcher.tsx +341 -0
- package/src/components/VisualizationRenderer.tsx +48 -26
- package/src/config/ConfigBuilder.ts +38 -1
- package/src/core/LangChainAgent.ts +1 -4
- package/src/core/Pipeline.ts +209 -86
- package/src/core/QueryProcessor.ts +65 -0
- package/src/handlers/index.ts +72 -12
- package/src/hooks/useRagChat.ts +19 -9
- package/src/index.ts +9 -1
- package/src/providers/vectordb/MultiTablePostgresProvider.ts +150 -64
- package/src/rag/Reranker.ts +99 -6
- package/src/types/chat.ts +2 -0
- package/src/types/index.ts +52 -0
- package/src/types/props.ts +9 -1
- package/src/utils/ProductExtractor.ts +347 -0
- package/src/utils/UITransformer.ts +4 -53
- package/src/utils/synonyms.ts +78 -0
- package/dist/ChromaDBProvider-MIDOR4FW.mjs +0 -8
- package/dist/MilvusProvider-U7SKC27V.mjs +0 -8
- package/dist/MongoDBProvider-YNKC7EJ6.mjs +0 -8
- package/dist/MultiTablePostgresProvider-YY7LPNJK.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-BFYLQYQU.mjs +0 -3985
- package/dist/chunk-CFVEZTBJ.mjs +0 -102
- package/dist/chunk-IMP6FUCY.mjs +0 -30
- package/dist/chunk-LR3VMDVK.mjs +0 -157
- package/dist/chunk-M6JSPGAR.mjs +0 -117
- package/dist/chunk-PSFPZXHX.mjs +0 -245
- package/dist/chunk-R3RGUMHE.mjs +0 -218
- 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
|
@@ -64,92 +64,391 @@ __export(index_exports, {
|
|
|
64
64
|
ConfigProvider: () => ConfigProvider,
|
|
65
65
|
DocumentUpload: () => DocumentUpload,
|
|
66
66
|
MessageBubble: () => MessageBubble,
|
|
67
|
+
ObservabilityPanel: () => ObservabilityPanel,
|
|
67
68
|
SourceCard: () => SourceCard,
|
|
69
|
+
addSynonyms: () => addSynonyms,
|
|
68
70
|
useConfig: () => useConfig,
|
|
69
71
|
useRagChat: () => useRagChat
|
|
70
72
|
});
|
|
71
73
|
module.exports = __toCommonJS(index_exports);
|
|
72
74
|
|
|
73
75
|
// src/components/ChatWidget.tsx
|
|
74
|
-
var
|
|
75
|
-
var
|
|
76
|
+
var import_react12 = require("react");
|
|
77
|
+
var import_lucide_react8 = require("lucide-react");
|
|
76
78
|
|
|
77
79
|
// src/components/ChatWindow.tsx
|
|
78
|
-
var
|
|
79
|
-
var
|
|
80
|
+
var import_react11 = require("react");
|
|
81
|
+
var import_lucide_react7 = require("lucide-react");
|
|
82
|
+
|
|
83
|
+
// src/components/DocumentUpload.tsx
|
|
84
|
+
var import_react2 = require("react");
|
|
85
|
+
var import_lucide_react = require("lucide-react");
|
|
86
|
+
|
|
87
|
+
// src/components/ConfigProvider.tsx
|
|
88
|
+
var import_react = require("react");
|
|
89
|
+
|
|
90
|
+
// src/utils/templateUtils.ts
|
|
91
|
+
function mergeDefined(base, override) {
|
|
92
|
+
const merged = __spreadValues({}, base || {});
|
|
93
|
+
if (!override) {
|
|
94
|
+
return merged;
|
|
95
|
+
}
|
|
96
|
+
for (const [key, value] of Object.entries(override)) {
|
|
97
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
98
|
+
merged[key] = value;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return merged;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/config/uiConstants.ts
|
|
105
|
+
var DEFAULT_CONFIG = {
|
|
106
|
+
projectId: "default",
|
|
107
|
+
ui: {
|
|
108
|
+
title: "AI Assistant",
|
|
109
|
+
subtitle: "Powered by RAG",
|
|
110
|
+
primaryColor: "#6366f1",
|
|
111
|
+
accentColor: "#8b5cf6",
|
|
112
|
+
logoUrl: "",
|
|
113
|
+
placeholder: "Ask me anything\u2026",
|
|
114
|
+
showSources: true,
|
|
115
|
+
welcomeMessage: "Hello! I'm your AI assistant. Ask me anything about your documents.",
|
|
116
|
+
showWidget: true,
|
|
117
|
+
poweredBy: "RAG",
|
|
118
|
+
visualStyle: "glass",
|
|
119
|
+
borderRadius: "xl",
|
|
120
|
+
allowUpload: true,
|
|
121
|
+
allowResize: true,
|
|
122
|
+
enableVoiceInput: true
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
var BORDER_RADIUS_MAP = {
|
|
126
|
+
none: "rounded-none",
|
|
127
|
+
sm: "rounded-sm",
|
|
128
|
+
md: "rounded-md",
|
|
129
|
+
lg: "rounded-lg",
|
|
130
|
+
xl: "rounded-xl",
|
|
131
|
+
full: "rounded-3xl"
|
|
132
|
+
};
|
|
133
|
+
var CHAT_SUGGESTIONS = [
|
|
134
|
+
"What can you help me with?",
|
|
135
|
+
"Summarise the key topics",
|
|
136
|
+
"Show me an example"
|
|
137
|
+
];
|
|
138
|
+
|
|
139
|
+
// src/components/ConfigProvider.tsx
|
|
140
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
141
|
+
var ConfigContext = (0, import_react.createContext)(DEFAULT_CONFIG);
|
|
142
|
+
function ConfigProvider({
|
|
143
|
+
config,
|
|
144
|
+
children
|
|
145
|
+
}) {
|
|
146
|
+
const merged = {
|
|
147
|
+
projectId: (config == null ? void 0 : config.projectId) || DEFAULT_CONFIG.projectId,
|
|
148
|
+
ui: mergeDefined(DEFAULT_CONFIG.ui, config == null ? void 0 : config.ui),
|
|
149
|
+
embedding: config == null ? void 0 : config.embedding
|
|
150
|
+
};
|
|
151
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConfigContext.Provider, { value: merged, children });
|
|
152
|
+
}
|
|
153
|
+
function useConfig() {
|
|
154
|
+
return (0, import_react.useContext)(ConfigContext);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// src/components/DocumentUpload.tsx
|
|
158
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
159
|
+
function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
|
|
160
|
+
var _a;
|
|
161
|
+
const { ui, embedding } = useConfig();
|
|
162
|
+
const [fileStates, setFileStates] = (0, import_react2.useState)([]);
|
|
163
|
+
const [isDragging, setIsDragging] = (0, import_react2.useState)(false);
|
|
164
|
+
const fileInputRef = (0, import_react2.useRef)(null);
|
|
165
|
+
const MULTI_DIMENSION_MODELS = {
|
|
166
|
+
"text-embedding-3-small": [512, 1536],
|
|
167
|
+
"text-embedding-3-large": [256, 1024, 3072],
|
|
168
|
+
"nomic-embed-text": [64, 128, 256, 512, 768]
|
|
169
|
+
};
|
|
170
|
+
const COMMON_DIMENSIONS = [64, 128, 256, 384, 512, 768, 1024, 1536, 3072];
|
|
171
|
+
const currentModel = (embedding == null ? void 0 : embedding.model) || "unknown";
|
|
172
|
+
const defaultDimension = (embedding == null ? void 0 : embedding.dimensions) || 1536;
|
|
173
|
+
let availableDimensions = (_a = Object.entries(MULTI_DIMENSION_MODELS).find(([k]) => currentModel.includes(k))) == null ? void 0 : _a[1];
|
|
174
|
+
if (!availableDimensions) {
|
|
175
|
+
availableDimensions = COMMON_DIMENSIONS.includes(defaultDimension) ? COMMON_DIMENSIONS : [...COMMON_DIMENSIONS, defaultDimension].sort((a, b) => a - b);
|
|
176
|
+
}
|
|
177
|
+
const isChangeable = true;
|
|
178
|
+
const [dimension, setDimension] = (0, import_react2.useState)(defaultDimension);
|
|
179
|
+
const addFiles = (files) => {
|
|
180
|
+
const newStates = files.map((file) => ({ file, status: "idle" }));
|
|
181
|
+
setFileStates((prev) => [...prev, ...newStates]);
|
|
182
|
+
};
|
|
183
|
+
const removeFile = (index) => {
|
|
184
|
+
setFileStates((prev) => prev.filter((_, i) => i !== index));
|
|
185
|
+
};
|
|
186
|
+
const onDragOver = (e) => {
|
|
187
|
+
e.preventDefault();
|
|
188
|
+
setIsDragging(true);
|
|
189
|
+
};
|
|
190
|
+
const onDragLeave = () => {
|
|
191
|
+
setIsDragging(false);
|
|
192
|
+
};
|
|
193
|
+
const onDrop = (e) => {
|
|
194
|
+
e.preventDefault();
|
|
195
|
+
setIsDragging(false);
|
|
196
|
+
if (e.dataTransfer.files) {
|
|
197
|
+
addFiles(Array.from(e.dataTransfer.files));
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
const onFileSelect = (e) => {
|
|
201
|
+
if (e.target.files) {
|
|
202
|
+
addFiles(Array.from(e.target.files));
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
const uploadFiles = async () => {
|
|
206
|
+
const idleFiles = fileStates.filter((s) => s.status === "idle");
|
|
207
|
+
if (idleFiles.length === 0) return;
|
|
208
|
+
setFileStates((prev) => prev.map((s) => s.status === "idle" ? __spreadProps(__spreadValues({}, s), { status: "uploading" }) : s));
|
|
209
|
+
const formData = new FormData();
|
|
210
|
+
idleFiles.forEach((s) => formData.append("files", s.file));
|
|
211
|
+
if (namespace) formData.append("namespace", namespace);
|
|
212
|
+
formData.append("dimension", dimension.toString());
|
|
213
|
+
try {
|
|
214
|
+
const response = await fetch("/api/upload", {
|
|
215
|
+
method: "POST",
|
|
216
|
+
body: formData
|
|
217
|
+
});
|
|
218
|
+
const result = await response.json();
|
|
219
|
+
if (!response.ok) throw new Error(result.error || "Upload failed");
|
|
220
|
+
setFileStates((prev) => prev.map((s) => s.status === "uploading" ? __spreadProps(__spreadValues({}, s), { status: "success" }) : s));
|
|
221
|
+
if (onUploadComplete) onUploadComplete(result);
|
|
222
|
+
} catch (err) {
|
|
223
|
+
const message = err instanceof Error ? err.message : "Upload failed";
|
|
224
|
+
setFileStates((prev) => prev.map((s) => s.status === "uploading" ? __spreadProps(__spreadValues({}, s), { status: "error", error: message }) : s));
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
const isUploading = fileStates.some((s) => s.status === "uploading");
|
|
228
|
+
const hasIdle = fileStates.some((s) => s.status === "idle");
|
|
229
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
230
|
+
"div",
|
|
231
|
+
{
|
|
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}`,
|
|
233
|
+
onDragOver,
|
|
234
|
+
onDragLeave,
|
|
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
|
+
}
|
|
340
|
+
);
|
|
341
|
+
}
|
|
80
342
|
|
|
81
343
|
// src/components/MessageBubble.tsx
|
|
82
|
-
var
|
|
83
|
-
var
|
|
344
|
+
var import_react9 = __toESM(require("react"));
|
|
345
|
+
var import_lucide_react6 = require("lucide-react");
|
|
84
346
|
var import_react_markdown = __toESM(require("react-markdown"));
|
|
85
347
|
|
|
86
348
|
// src/components/SourceCard.tsx
|
|
87
|
-
var
|
|
88
|
-
var
|
|
349
|
+
var import_react3 = __toESM(require("react"));
|
|
350
|
+
var import_lucide_react2 = require("lucide-react");
|
|
351
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
89
352
|
function SourceCard({ source, index }) {
|
|
90
353
|
var _a, _b;
|
|
91
|
-
const [expanded, setExpanded] =
|
|
354
|
+
const [expanded, setExpanded] = import_react3.default.useState(false);
|
|
92
355
|
const scorePercent = Math.round(source.score * 100);
|
|
93
356
|
const scoreColor = source.score >= 0.8 ? "text-emerald-400" : source.score >= 0.6 ? "text-amber-400" : "text-rose-400";
|
|
94
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";
|
|
95
358
|
const preview = source.content.slice(0, 120);
|
|
96
359
|
const hasMore = source.content.length > 120;
|
|
97
|
-
return /* @__PURE__ */
|
|
360
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
98
361
|
"div",
|
|
99
362
|
{
|
|
100
363
|
className: `rounded-xl border backdrop-blur-sm p-3 transition-all duration-200 hover:scale-[1.01] cursor-pointer ${scoreBg}`,
|
|
101
|
-
onClick: () => setExpanded((e) => !e)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
+
}
|
|
106
386
|
);
|
|
107
387
|
}
|
|
108
388
|
|
|
109
389
|
// src/components/ProductCarousel.tsx
|
|
110
|
-
var
|
|
111
|
-
var
|
|
390
|
+
var import_react4 = require("react");
|
|
391
|
+
var import_lucide_react4 = require("lucide-react");
|
|
112
392
|
|
|
113
393
|
// src/components/ProductCard.tsx
|
|
114
|
-
var import_react2 = __toESM(require("react"));
|
|
115
394
|
var import_image = __toESM(require("next/image"));
|
|
116
|
-
var
|
|
395
|
+
var import_lucide_react3 = require("lucide-react");
|
|
396
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
117
397
|
function ProductCard({ product, primaryColor = "#6366f1", onAddToCart }) {
|
|
118
|
-
return /* @__PURE__ */
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
+
] });
|
|
146
444
|
}
|
|
147
445
|
|
|
148
446
|
// src/components/ProductCarousel.tsx
|
|
447
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
149
448
|
function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
|
|
150
|
-
const scrollRef = (0,
|
|
151
|
-
const [canScroll, setCanScroll] = (0,
|
|
152
|
-
(0,
|
|
449
|
+
const scrollRef = (0, import_react4.useRef)(null);
|
|
450
|
+
const [canScroll, setCanScroll] = (0, import_react4.useState)(false);
|
|
451
|
+
(0, import_react4.useEffect)(() => {
|
|
153
452
|
const checkScroll = () => {
|
|
154
453
|
if (scrollRef.current) {
|
|
155
454
|
const hasOverflow = scrollRef.current.scrollWidth > scrollRef.current.clientWidth;
|
|
@@ -173,63 +472,74 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
|
|
|
173
472
|
};
|
|
174
473
|
if (!products || products.length === 0) return null;
|
|
175
474
|
if (products.length === 1) {
|
|
176
|
-
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 }) });
|
|
177
476
|
}
|
|
178
|
-
return /* @__PURE__ */
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
},
|
|
207
|
-
products.map((product) => /* @__PURE__ */ import_react3.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)(
|
|
208
505
|
"div",
|
|
209
506
|
{
|
|
210
|
-
|
|
211
|
-
className: "
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
+
] });
|
|
216
521
|
}
|
|
217
522
|
|
|
523
|
+
// src/components/VisualizationRenderer.tsx
|
|
524
|
+
var import_recharts2 = require("recharts");
|
|
525
|
+
|
|
218
526
|
// src/components/DynamicChart.tsx
|
|
219
|
-
var
|
|
527
|
+
var import_react5 = __toESM(require("react"));
|
|
220
528
|
var import_recharts = require("recharts");
|
|
221
|
-
var
|
|
529
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
530
|
+
var CHART_COLORS = ["#6366f1", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#ec4899"];
|
|
222
531
|
function DynamicChart({
|
|
223
532
|
config,
|
|
224
533
|
primaryColor = "#6366f1",
|
|
225
534
|
accentColor = "#8b5cf6",
|
|
226
|
-
viewportSize = "large"
|
|
535
|
+
viewportSize = "large",
|
|
536
|
+
isStreaming = false
|
|
227
537
|
}) {
|
|
228
538
|
const { type, data } = config;
|
|
229
|
-
const colors = config.colors || [primaryColor, accentColor, ...
|
|
230
|
-
const containerRef =
|
|
231
|
-
const [containerWidth, setContainerWidth] =
|
|
232
|
-
|
|
539
|
+
const colors = config.colors || [primaryColor, accentColor, ...CHART_COLORS];
|
|
540
|
+
const containerRef = import_react5.default.useRef(null);
|
|
541
|
+
const [containerWidth, setContainerWidth] = import_react5.default.useState(0);
|
|
542
|
+
import_react5.default.useEffect(() => {
|
|
233
543
|
const element = containerRef.current;
|
|
234
544
|
if (!element || typeof ResizeObserver === "undefined") return;
|
|
235
545
|
const updateWidth = (width) => {
|
|
@@ -255,7 +565,7 @@ function DynamicChart({
|
|
|
255
565
|
return text.length > maxLength ? `${text.slice(0, maxLength)}\u2026` : text;
|
|
256
566
|
};
|
|
257
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 };
|
|
258
|
-
const sanitizedData =
|
|
568
|
+
const sanitizedData = import_react5.default.useMemo(() => {
|
|
259
569
|
if (!data) return [];
|
|
260
570
|
return data.map((item) => {
|
|
261
571
|
const newItem = {};
|
|
@@ -287,8 +597,19 @@ function DynamicChart({
|
|
|
287
597
|
return newItem;
|
|
288
598
|
});
|
|
289
599
|
}, [data]);
|
|
600
|
+
if (isStreaming) {
|
|
601
|
+
const bars = type === "pie" ? 6 : 5;
|
|
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)(
|
|
603
|
+
"div",
|
|
604
|
+
{
|
|
605
|
+
className: "flex-1 rounded-t-md bg-slate-100 dark:bg-white/10",
|
|
606
|
+
style: { height: `${40 + i % 3 * 25}%` }
|
|
607
|
+
},
|
|
608
|
+
i
|
|
609
|
+
)) }) });
|
|
610
|
+
}
|
|
290
611
|
if (!data || data.length === 0) {
|
|
291
|
-
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." });
|
|
292
613
|
}
|
|
293
614
|
const firstItem = sanitizedData[0];
|
|
294
615
|
const allKeys = Object.keys(firstItem);
|
|
@@ -313,14 +634,20 @@ function DynamicChart({
|
|
|
313
634
|
const renderTooltip = (row, label) => {
|
|
314
635
|
var _a, _b;
|
|
315
636
|
if (!row) return null;
|
|
316
|
-
return /* @__PURE__ */
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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
|
+
] });
|
|
324
651
|
};
|
|
325
652
|
const getTooltipRow = (payload) => {
|
|
326
653
|
if (!Array.isArray(payload) || payload.length === 0) return null;
|
|
@@ -331,65 +658,64 @@ function DynamicChart({
|
|
|
331
658
|
return row;
|
|
332
659
|
};
|
|
333
660
|
if (type === "pie") {
|
|
334
|
-
return /* @__PURE__ */
|
|
335
|
-
|
|
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,
|
|
336
688
|
{
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
cy: "50%",
|
|
342
|
-
outerRadius: pieOuterRadius,
|
|
343
|
-
label: false,
|
|
344
|
-
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)
|
|
345
693
|
},
|
|
346
|
-
|
|
347
|
-
)
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
import_recharts.
|
|
351
|
-
{
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
activeDot: { r: isTiny ? 4 : isCompact ? 5 : 6 }
|
|
368
|
-
}
|
|
369
|
-
))))));
|
|
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
|
+
] }) }) }) });
|
|
370
715
|
}
|
|
371
716
|
|
|
372
717
|
// src/components/VisualizationRenderer.tsx
|
|
373
|
-
var
|
|
374
|
-
var import_recharts2 = require("recharts");
|
|
375
|
-
var CHART_COLORS = [
|
|
376
|
-
"#6366f1",
|
|
377
|
-
// indigo
|
|
378
|
-
"#10b981",
|
|
379
|
-
// emerald
|
|
380
|
-
"#f59e0b",
|
|
381
|
-
// amber
|
|
382
|
-
"#ef4444",
|
|
383
|
-
// red
|
|
384
|
-
"#8b5cf6",
|
|
385
|
-
// purple
|
|
386
|
-
"#ec4899",
|
|
387
|
-
// pink
|
|
388
|
-
"#06b6d4",
|
|
389
|
-
// cyan
|
|
390
|
-
"#f97316"
|
|
391
|
-
// orange
|
|
392
|
-
];
|
|
718
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
393
719
|
function getColor(index) {
|
|
394
720
|
return CHART_COLORS[index % CHART_COLORS.length];
|
|
395
721
|
}
|
|
@@ -399,77 +725,112 @@ function CustomTooltip({
|
|
|
399
725
|
label
|
|
400
726
|
}) {
|
|
401
727
|
if (!active || !payload || payload.length === 0) return null;
|
|
402
|
-
return /* @__PURE__ */
|
|
403
|
-
"
|
|
404
|
-
{
|
|
405
|
-
className: "
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
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
|
+
] });
|
|
409
744
|
}
|
|
410
745
|
function VisualizationRenderer({
|
|
411
746
|
data,
|
|
412
747
|
className = "",
|
|
413
748
|
primaryColor,
|
|
414
|
-
onAddToCart
|
|
749
|
+
onAddToCart,
|
|
750
|
+
isStreaming
|
|
415
751
|
}) {
|
|
416
752
|
var _a;
|
|
417
753
|
if (!data) {
|
|
418
|
-
return /* @__PURE__ */
|
|
754
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: `p-4 text-gray-500 ${className}`, children: "No data available for visualization" });
|
|
419
755
|
}
|
|
420
|
-
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
|
+
] });
|
|
421
763
|
}
|
|
422
|
-
function renderVisualization(type, data, onAddToCart, primaryColor) {
|
|
764
|
+
function renderVisualization(type, data, onAddToCart, primaryColor, isStreaming) {
|
|
423
765
|
try {
|
|
424
766
|
switch (type) {
|
|
425
767
|
case "pie_chart":
|
|
426
|
-
return /* @__PURE__ */
|
|
768
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PieChartView, { data, isStreaming });
|
|
427
769
|
case "bar_chart":
|
|
428
|
-
return /* @__PURE__ */
|
|
770
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(BarChartView, { data, primaryColor, isStreaming });
|
|
429
771
|
case "line_chart":
|
|
430
|
-
return /* @__PURE__ */
|
|
772
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(LineChartView, { data, primaryColor, isStreaming });
|
|
431
773
|
case "radar_chart":
|
|
432
|
-
return /* @__PURE__ */
|
|
774
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RadarChartView, { data, isStreaming });
|
|
433
775
|
case "table":
|
|
434
|
-
return /* @__PURE__ */
|
|
776
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TableView, { data, isStreaming });
|
|
435
777
|
case "product_carousel":
|
|
436
778
|
case "carousel":
|
|
437
|
-
return /* @__PURE__ */
|
|
779
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CarouselView, { data, onAddToCart, primaryColor });
|
|
438
780
|
case "text":
|
|
439
781
|
default:
|
|
440
|
-
return /* @__PURE__ */
|
|
782
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TextView, { data });
|
|
441
783
|
}
|
|
442
784
|
} catch (error) {
|
|
443
785
|
console.warn("[VisualizationRenderer] Rendering failed, falling back to text:", error);
|
|
444
|
-
return /* @__PURE__ */
|
|
786
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TextView, { data: { content: "Unable to render the requested visualization." } });
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
function ChartSkeleton({ type }) {
|
|
790
|
+
if (type === "pie") {
|
|
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" }) });
|
|
445
792
|
}
|
|
793
|
+
if (type === "table") {
|
|
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
|
+
] });
|
|
799
|
+
}
|
|
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)) });
|
|
446
801
|
}
|
|
447
|
-
function PieChartView({ data }) {
|
|
802
|
+
function PieChartView({ data, isStreaming }) {
|
|
803
|
+
if (isStreaming) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChartSkeleton, { type: "pie" });
|
|
448
804
|
if (!Array.isArray(data) || data.length === 0) {
|
|
449
|
-
return /* @__PURE__ */
|
|
805
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs text-red-500", children: "Invalid pie chart data" });
|
|
450
806
|
}
|
|
451
807
|
const chartData = data.map((item) => ({
|
|
452
808
|
name: item.label,
|
|
453
809
|
value: item.value
|
|
454
810
|
}));
|
|
455
|
-
return /* @__PURE__ */
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
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
|
+
] }) }) });
|
|
469
829
|
}
|
|
470
|
-
function BarChartView({ data, primaryColor }) {
|
|
830
|
+
function BarChartView({ data, primaryColor, isStreaming }) {
|
|
831
|
+
if (isStreaming) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChartSkeleton, { type: "bar" });
|
|
471
832
|
if (!Array.isArray(data) || data.length === 0) {
|
|
472
|
-
return /* @__PURE__ */
|
|
833
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs text-red-500", children: "Invalid bar chart data" });
|
|
473
834
|
}
|
|
474
835
|
const chartData = data.map((item) => __spreadValues(__spreadValues({
|
|
475
836
|
category: item.category,
|
|
@@ -477,19 +838,30 @@ function BarChartView({ data, primaryColor }) {
|
|
|
477
838
|
}, item.inStockCount !== void 0 && { inStockCount: item.inStockCount }), item.outOfStockCount !== void 0 && { outOfStockCount: item.outOfStockCount }));
|
|
478
839
|
const barColor = primaryColor != null ? primaryColor : getColor(0);
|
|
479
840
|
const hasStock = chartData.some((d) => "inStockCount" in d);
|
|
480
|
-
return /* @__PURE__ */
|
|
481
|
-
import_recharts2.
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
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
|
+
] }) }) });
|
|
489
860
|
}
|
|
490
|
-
function LineChartView({ data, primaryColor }) {
|
|
861
|
+
function LineChartView({ data, primaryColor, isStreaming }) {
|
|
862
|
+
if (isStreaming) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChartSkeleton, { type: "bar" });
|
|
491
863
|
if (!Array.isArray(data) || data.length === 0) {
|
|
492
|
-
return /* @__PURE__ */
|
|
864
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs text-red-500", children: "Invalid line chart data" });
|
|
493
865
|
}
|
|
494
866
|
const chartData = data.map((point) => {
|
|
495
867
|
var _a;
|
|
@@ -499,72 +871,97 @@ function LineChartView({ data, primaryColor }) {
|
|
|
499
871
|
};
|
|
500
872
|
});
|
|
501
873
|
const lineColor = primaryColor != null ? primaryColor : getColor(0);
|
|
502
|
-
return /* @__PURE__ */
|
|
503
|
-
import_recharts2.
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
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
|
+
] }) }) });
|
|
900
|
+
}
|
|
901
|
+
function RadarChartView({ data, isStreaming }) {
|
|
902
|
+
if (isStreaming) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChartSkeleton, { type: "pie" });
|
|
903
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
904
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs text-red-500", children: "Invalid radar chart data" });
|
|
905
|
+
}
|
|
906
|
+
const productNames = Array.from(
|
|
528
907
|
new Set(data.flatMap((item) => Object.keys(item).filter((key) => key !== "attribute")))
|
|
529
908
|
);
|
|
530
|
-
return /* @__PURE__ */
|
|
531
|
-
import_recharts2.
|
|
532
|
-
{
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
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
|
+
] }) }) });
|
|
541
927
|
}
|
|
542
|
-
function TableView({ data }) {
|
|
928
|
+
function TableView({ data, isStreaming }) {
|
|
929
|
+
if (isStreaming) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChartSkeleton, { type: "table" });
|
|
543
930
|
if (!(data == null ? void 0 : data.columns) || !(data == null ? void 0 : data.rows)) {
|
|
544
|
-
return /* @__PURE__ */
|
|
931
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs text-red-500", children: "Invalid table data" });
|
|
545
932
|
}
|
|
546
|
-
return /* @__PURE__ */
|
|
547
|
-
"
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
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
|
+
] });
|
|
568
965
|
}
|
|
569
966
|
function CarouselView({
|
|
570
967
|
data,
|
|
@@ -572,7 +969,7 @@ function CarouselView({
|
|
|
572
969
|
primaryColor
|
|
573
970
|
}) {
|
|
574
971
|
if (!Array.isArray(data)) {
|
|
575
|
-
return /* @__PURE__ */
|
|
972
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs text-red-500", children: "Invalid carousel data" });
|
|
576
973
|
}
|
|
577
974
|
const products = data.map((product) => ({
|
|
578
975
|
id: product.id,
|
|
@@ -584,21 +981,498 @@ function CarouselView({
|
|
|
584
981
|
description: product.description,
|
|
585
982
|
inStock: product.inStock
|
|
586
983
|
}));
|
|
587
|
-
return /* @__PURE__ */
|
|
984
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "w-full", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
588
985
|
ProductCarousel,
|
|
589
986
|
{
|
|
590
987
|
products,
|
|
591
988
|
primaryColor: primaryColor != null ? primaryColor : "#6366f1",
|
|
592
989
|
onAddToCart: (p) => onAddToCart == null ? void 0 : onAddToCart(p)
|
|
593
990
|
}
|
|
594
|
-
));
|
|
991
|
+
) });
|
|
595
992
|
}
|
|
596
993
|
function TextView({ data }) {
|
|
597
994
|
const content = (data == null ? void 0 : data.content) || String(data != null ? data : "");
|
|
598
|
-
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 }) });
|
|
599
996
|
}
|
|
600
997
|
|
|
601
|
-
// src/components/
|
|
998
|
+
// src/components/ObservabilityPanel.tsx
|
|
999
|
+
var import_react6 = __toESM(require("react"));
|
|
1000
|
+
var import_lucide_react5 = require("lucide-react");
|
|
1001
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1002
|
+
function fmtMs(ms) {
|
|
1003
|
+
return ms >= 1e3 ? `${(ms / 1e3).toFixed(2)}s` : `${Math.round(ms)}ms`;
|
|
1004
|
+
}
|
|
1005
|
+
function fmtTokens(n) {
|
|
1006
|
+
return n >= 1e3 ? `${(n / 1e3).toFixed(1)}k` : String(n);
|
|
1007
|
+
}
|
|
1008
|
+
function ScoreBadge({ score }) {
|
|
1009
|
+
const pct = Math.round(score * 100);
|
|
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";
|
|
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
|
+
] });
|
|
1016
|
+
}
|
|
1017
|
+
function RetrievalTab({ trace }) {
|
|
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)(
|
|
1031
|
+
"div",
|
|
1032
|
+
{
|
|
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
|
+
] });
|
|
1060
|
+
}
|
|
1061
|
+
function LatencyTab({ trace }) {
|
|
1062
|
+
const { latency } = trace;
|
|
1063
|
+
const bars = [
|
|
1064
|
+
{ label: "Embed", ms: latency.embedMs, color: "#6366f1" },
|
|
1065
|
+
{ label: "Retrieve", ms: latency.retrieveMs, color: "#10b981" },
|
|
1066
|
+
...latency.rerankMs != null ? [{ label: "Rerank", ms: latency.rerankMs, color: "#f59e0b" }] : [],
|
|
1067
|
+
{ label: "Generate", ms: latency.generateMs, color: "#8b5cf6" }
|
|
1068
|
+
];
|
|
1069
|
+
const maxMs = Math.max(...bars.map((b) => b.ms), 1);
|
|
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
|
+
] });
|
|
1096
|
+
}
|
|
1097
|
+
function TokensTab({ trace }) {
|
|
1098
|
+
const { tokens } = trace;
|
|
1099
|
+
if (!tokens) {
|
|
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." });
|
|
1101
|
+
}
|
|
1102
|
+
const stats = [
|
|
1103
|
+
{ label: "Prompt Tokens", value: fmtTokens(tokens.promptTokens), color: "text-indigo-600 dark:text-indigo-400" },
|
|
1104
|
+
{ label: "Completion Tokens", value: fmtTokens(tokens.completionTokens), color: "text-emerald-600 dark:text-emerald-400" },
|
|
1105
|
+
{ label: "Total Tokens", value: fmtTokens(tokens.totalTokens), color: "text-slate-700 dark:text-white/80" }
|
|
1106
|
+
];
|
|
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
|
+
] });
|
|
1149
|
+
}
|
|
1150
|
+
function HallucinationTab({ trace }) {
|
|
1151
|
+
if (trace.hallucinationScore == null) {
|
|
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." });
|
|
1153
|
+
}
|
|
1154
|
+
const score = trace.hallucinationScore;
|
|
1155
|
+
const pct = Math.round(score * 100);
|
|
1156
|
+
const barColor = pct <= 20 ? "#10b981" : pct <= 50 ? "#f59e0b" : "#ef4444";
|
|
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
|
+
] });
|
|
1191
|
+
}
|
|
1192
|
+
function PromptTab({ trace }) {
|
|
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
|
+
] });
|
|
1214
|
+
}
|
|
1215
|
+
function ChunksTab({ trace }) {
|
|
1216
|
+
const [expanded, setExpanded] = import_react6.default.useState(/* @__PURE__ */ new Set());
|
|
1217
|
+
const toggle = (i) => setExpanded((prev) => {
|
|
1218
|
+
const next = new Set(prev);
|
|
1219
|
+
if (next.has(i)) {
|
|
1220
|
+
next.delete(i);
|
|
1221
|
+
} else {
|
|
1222
|
+
next.add(i);
|
|
1223
|
+
}
|
|
1224
|
+
return next;
|
|
1225
|
+
});
|
|
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) => {
|
|
1227
|
+
const isOpen = expanded.has(i);
|
|
1228
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1229
|
+
"div",
|
|
1230
|
+
{
|
|
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
|
+
]
|
|
1262
|
+
},
|
|
1263
|
+
String(chunk.id)
|
|
1264
|
+
);
|
|
1265
|
+
}) });
|
|
1266
|
+
}
|
|
1267
|
+
var TABS = [
|
|
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" }) }
|
|
1274
|
+
];
|
|
1275
|
+
function ObservabilityPanel({ trace, primaryColor = "#6366f1" }) {
|
|
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",
|
|
1280
|
+
{
|
|
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
|
+
}
|
|
1298
|
+
),
|
|
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
|
+
] });
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
// src/components/HourglassLoader.tsx
|
|
1324
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1325
|
+
var HourglassLoader = ({
|
|
1326
|
+
size = 16,
|
|
1327
|
+
primaryColor = "#10b981",
|
|
1328
|
+
glow = false
|
|
1329
|
+
}) => {
|
|
1330
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1331
|
+
"svg",
|
|
1332
|
+
{
|
|
1333
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1334
|
+
viewBox: "0 0 100 100",
|
|
1335
|
+
preserveAspectRatio: "xMidYMid",
|
|
1336
|
+
style: {
|
|
1337
|
+
width: size,
|
|
1338
|
+
height: size,
|
|
1339
|
+
background: "transparent",
|
|
1340
|
+
filter: glow ? `drop-shadow(0 0 4px ${primaryColor})` : "none"
|
|
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
|
+
}
|
|
1399
|
+
);
|
|
1400
|
+
};
|
|
1401
|
+
var HourglassLoader_default = HourglassLoader;
|
|
1402
|
+
|
|
1403
|
+
// src/utils/synonyms.ts
|
|
1404
|
+
var FIELD_SYNONYMS = {
|
|
1405
|
+
name: ["product", "item", "title", "label", "heading", "subject", "product name", "item name"],
|
|
1406
|
+
price: ["cost", "amount", "msrp", "price", "rate", "value", "price_usd"],
|
|
1407
|
+
brand: ["manufacturer", "vendor", "make", "company", "brand_name", "supplier"],
|
|
1408
|
+
image: [
|
|
1409
|
+
"imageUrl",
|
|
1410
|
+
"thumbnail",
|
|
1411
|
+
"img",
|
|
1412
|
+
"url",
|
|
1413
|
+
"photo",
|
|
1414
|
+
"picture",
|
|
1415
|
+
"media",
|
|
1416
|
+
"image_url",
|
|
1417
|
+
"main_image",
|
|
1418
|
+
"product_image",
|
|
1419
|
+
"thumb"
|
|
1420
|
+
],
|
|
1421
|
+
stock: [
|
|
1422
|
+
"inventory",
|
|
1423
|
+
"quantity",
|
|
1424
|
+
"count",
|
|
1425
|
+
"availability",
|
|
1426
|
+
"stock_level",
|
|
1427
|
+
"inStock",
|
|
1428
|
+
"is_available",
|
|
1429
|
+
"in stock",
|
|
1430
|
+
"status"
|
|
1431
|
+
],
|
|
1432
|
+
description: ["summary", "content", "body", "text", "info", "details"],
|
|
1433
|
+
link: ["url", "href", "product_url", "page_url", "link"]
|
|
1434
|
+
};
|
|
1435
|
+
function addSynonyms(customSynonyms) {
|
|
1436
|
+
for (const [key, aliases] of Object.entries(customSynonyms)) {
|
|
1437
|
+
if (!FIELD_SYNONYMS[key]) {
|
|
1438
|
+
FIELD_SYNONYMS[key] = [];
|
|
1439
|
+
}
|
|
1440
|
+
const existing = new Set(FIELD_SYNONYMS[key].map((s) => s.toLowerCase()));
|
|
1441
|
+
for (const alias of aliases) {
|
|
1442
|
+
if (!existing.has(alias.toLowerCase())) {
|
|
1443
|
+
FIELD_SYNONYMS[key].push(alias);
|
|
1444
|
+
existing.add(alias.toLowerCase());
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
function resolveMetadataValue(meta, uiKey) {
|
|
1450
|
+
var _a;
|
|
1451
|
+
const synonyms = (_a = FIELD_SYNONYMS[uiKey]) != null ? _a : [];
|
|
1452
|
+
const keys = Object.keys(meta);
|
|
1453
|
+
const systemKeys = ["namespace", "filename", "filesize", "filetype", "docid", "uploadedat", "dimension", "chunkindex"];
|
|
1454
|
+
let match = keys.find((k) => k.toLowerCase() === uiKey.toLowerCase());
|
|
1455
|
+
if (match !== void 0) return meta[match];
|
|
1456
|
+
match = keys.find((k) => synonyms.map((s) => s.toLowerCase()).includes(k.toLowerCase()));
|
|
1457
|
+
if (match !== void 0) return meta[match];
|
|
1458
|
+
const isBlacklisted = (kl) => {
|
|
1459
|
+
return systemKeys.includes(kl) || kl.startsWith("option1") || kl.startsWith("option2") || kl.startsWith("option3");
|
|
1460
|
+
};
|
|
1461
|
+
match = keys.find((k) => {
|
|
1462
|
+
const kl = k.toLowerCase();
|
|
1463
|
+
if (isBlacklisted(kl)) return false;
|
|
1464
|
+
return kl.includes(uiKey.toLowerCase());
|
|
1465
|
+
});
|
|
1466
|
+
if (match !== void 0) return meta[match];
|
|
1467
|
+
match = keys.find((k) => {
|
|
1468
|
+
const kl = k.toLowerCase();
|
|
1469
|
+
if (isBlacklisted(kl)) return false;
|
|
1470
|
+
return synonyms.some((sk) => kl.includes(sk.toLowerCase()) || sk.toLowerCase().includes(kl));
|
|
1471
|
+
});
|
|
1472
|
+
return match !== void 0 ? meta[match] : void 0;
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
// src/utils/ProductExtractor.ts
|
|
602
1476
|
function sanitizeJson(raw) {
|
|
603
1477
|
let s = raw.trim();
|
|
604
1478
|
s = s.replace(
|
|
@@ -615,36 +1489,34 @@ function sanitizeJson(raw) {
|
|
|
615
1489
|
s = s.replace(/'([^'\\]*(?:\\.[^'\\]*)*)'/g, '"$1"');
|
|
616
1490
|
s = s.replace(/,\s*([}\]])/g, "$1");
|
|
617
1491
|
s = s.replace(/([{,])\s*""\s*(?=[,}])/g, "$1");
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
continue;
|
|
630
|
-
}
|
|
631
|
-
if (ch === '"') {
|
|
632
|
-
inString = !inString;
|
|
633
|
-
continue;
|
|
634
|
-
}
|
|
635
|
-
if (inString) continue;
|
|
636
|
-
if (ch === "{" || ch === "[") {
|
|
637
|
-
stack.push(ch);
|
|
638
|
-
} else if (ch === "}") {
|
|
639
|
-
if (stack[stack.length - 1] === "{") stack.pop();
|
|
640
|
-
} else if (ch === "]") {
|
|
641
|
-
if (stack[stack.length - 1] === "[") stack.pop();
|
|
642
|
-
}
|
|
1492
|
+
const stack = [];
|
|
1493
|
+
let inString = false;
|
|
1494
|
+
let escape = false;
|
|
1495
|
+
for (const ch of s) {
|
|
1496
|
+
if (escape) {
|
|
1497
|
+
escape = false;
|
|
1498
|
+
continue;
|
|
1499
|
+
}
|
|
1500
|
+
if (ch === "\\" && inString) {
|
|
1501
|
+
escape = true;
|
|
1502
|
+
continue;
|
|
643
1503
|
}
|
|
644
|
-
if (
|
|
645
|
-
|
|
646
|
-
|
|
1504
|
+
if (ch === '"') {
|
|
1505
|
+
inString = !inString;
|
|
1506
|
+
continue;
|
|
647
1507
|
}
|
|
1508
|
+
if (inString) continue;
|
|
1509
|
+
if (ch === "{" || ch === "[") {
|
|
1510
|
+
stack.push(ch);
|
|
1511
|
+
} else if (ch === "}") {
|
|
1512
|
+
if (stack[stack.length - 1] === "{") stack.pop();
|
|
1513
|
+
} else if (ch === "]") {
|
|
1514
|
+
if (stack[stack.length - 1] === "[") stack.pop();
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
if (inString) s += '"';
|
|
1518
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
1519
|
+
s += stack[i] === "{" ? "}" : "]";
|
|
648
1520
|
}
|
|
649
1521
|
const lastClose = Math.max(s.lastIndexOf("}"), s.lastIndexOf("]"));
|
|
650
1522
|
if (lastClose !== -1 && lastClose < s.length - 1 && /\S/.test(s.slice(lastClose + 1))) {
|
|
@@ -745,10 +1617,6 @@ function extractStructuredPayload(raw) {
|
|
|
745
1617
|
text: stripStructuredUiLabels(raw).replace(/\n{3,}/g, "\n\n").trim()
|
|
746
1618
|
};
|
|
747
1619
|
}
|
|
748
|
-
function isLikelyUiOnlyMessage(text) {
|
|
749
|
-
const trimmed = text.trim();
|
|
750
|
-
return trimmed.length === 0 || trimmed.length < 30 || /^(chart data|table data|visualization|visual representation|product catalog|product recommendations|catalog summary|availability|inventory status|details)\s*:?\s*$/i.test(trimmed);
|
|
751
|
-
}
|
|
752
1620
|
function resolveImage(data) {
|
|
753
1621
|
const isPlaceholder = (val) => typeof val === "string" && (val === "..." || val === "" || val.toLowerCase() === "null" || val.toLowerCase() === "undefined");
|
|
754
1622
|
for (const key of ["image", "img", "thumbnail", "images", "product_image", "Image", "Thumbnail"]) {
|
|
@@ -758,92 +1626,140 @@ function resolveImage(data) {
|
|
|
758
1626
|
}
|
|
759
1627
|
return void 0;
|
|
760
1628
|
}
|
|
761
|
-
function
|
|
762
|
-
const
|
|
763
|
-
|
|
764
|
-
const foundKey = metaKeys.find((k) => searchKeys.includes(k.toLowerCase()));
|
|
765
|
-
if (foundKey) return meta[foundKey];
|
|
766
|
-
const partialKey = metaKeys.find((k) => {
|
|
767
|
-
const kLow = k.toLowerCase();
|
|
768
|
-
return searchKeys.some((sk) => kLow.includes(sk) || sk.includes(kLow));
|
|
769
|
-
});
|
|
770
|
-
return partialKey ? meta[partialKey] : void 0;
|
|
771
|
-
}
|
|
772
|
-
function normaliseChild(children) {
|
|
773
|
-
if (typeof children === "object" && children !== null && !Array.isArray(children) && !import_react6.default.isValidElement(children)) {
|
|
774
|
-
return JSON.stringify(children);
|
|
775
|
-
}
|
|
776
|
-
return children;
|
|
777
|
-
}
|
|
778
|
-
function normaliseFieldName(value) {
|
|
779
|
-
return value.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
780
|
-
}
|
|
781
|
-
function formatColumnLabel(value) {
|
|
782
|
-
return value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim().replace(/\b\w/g, (char) => char.toUpperCase());
|
|
1629
|
+
function isLikelyUiOnlyMessage(text) {
|
|
1630
|
+
const trimmed = text.trim();
|
|
1631
|
+
return trimmed.length === 0 || trimmed.length < 30 || /^(chart data|table data|visualization|visual representation|product catalog|product recommendations|catalog summary|availability|inventory status|details)\s*:?\s*$/i.test(trimmed);
|
|
783
1632
|
}
|
|
784
|
-
function
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
const
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
)
|
|
1633
|
+
function extractProductsFromSources(sources, isUser) {
|
|
1634
|
+
if (isUser || !sources) return [];
|
|
1635
|
+
return sources.filter((s) => {
|
|
1636
|
+
var _a;
|
|
1637
|
+
const m = (_a = s.metadata) != null ? _a : {};
|
|
1638
|
+
const keys = Object.keys(m).map((k) => k.toLowerCase());
|
|
1639
|
+
const hasProductKey = keys.some(
|
|
1640
|
+
(k) => ["price", "image", "img", "thumbnail", "images", "brand", "product", "sku", "category", "model", "cost"].includes(k)
|
|
792
1641
|
);
|
|
793
|
-
const
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
1642
|
+
const hasPricePattern = /\$\s*\d+/.test(s.content);
|
|
1643
|
+
return hasProductKey || hasPricePattern || m.type === "product";
|
|
1644
|
+
}).map((s) => {
|
|
1645
|
+
var _a, _b;
|
|
1646
|
+
const m = (_a = s.metadata) != null ? _a : {};
|
|
1647
|
+
const name = resolveMetadataValue(m, "name");
|
|
1648
|
+
const brand = resolveMetadataValue(m, "brand");
|
|
1649
|
+
const price = resolveMetadataValue(m, "price");
|
|
1650
|
+
const description = resolveMetadataValue(m, "description");
|
|
1651
|
+
return {
|
|
1652
|
+
id: s.id,
|
|
1653
|
+
name: (_b = name != null ? name : s.content.split("\n")[0]) != null ? _b : "Unknown Product",
|
|
1654
|
+
brand,
|
|
1655
|
+
price,
|
|
1656
|
+
image: resolveImage(m),
|
|
1657
|
+
link: resolveMetadataValue(m, "link"),
|
|
1658
|
+
description: description ? description : ""
|
|
1659
|
+
//description ?? s.content,
|
|
800
1660
|
};
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
1661
|
+
});
|
|
1662
|
+
}
|
|
1663
|
+
function extractProductsFromContent(content, payloadText, payloadCandidates, productsFromSources, isStreaming = false) {
|
|
1664
|
+
var _a, _b;
|
|
1665
|
+
const jsonRegex = /```(?:json|ui)?\s*([\s\S]*?)\s*```/g;
|
|
1666
|
+
const products = [];
|
|
1667
|
+
let cleanContent = payloadText;
|
|
1668
|
+
for (const candidate of payloadCandidates) {
|
|
1669
|
+
try {
|
|
1670
|
+
const data = JSON.parse(sanitizeJson(candidate));
|
|
1671
|
+
const itemSet = Array.isArray(data.data) ? data.data : Array.isArray(data.items) ? data.items : Array.isArray(data.products) ? data.products : null;
|
|
1672
|
+
if ((data.type === "products" || data.view === "carousel" || data.view === "table" || Array.isArray(data.products)) && itemSet) {
|
|
1673
|
+
products.push(
|
|
1674
|
+
...itemSet.map((item) => {
|
|
1675
|
+
var _a2;
|
|
1676
|
+
return __spreadProps(__spreadValues({}, item), {
|
|
1677
|
+
image: (_a2 = item.image) != null ? _a2 : resolveImage(item)
|
|
1678
|
+
});
|
|
1679
|
+
})
|
|
1680
|
+
);
|
|
1681
|
+
}
|
|
1682
|
+
} catch (e) {
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
if (cleanContent.includes('"type": "products"') || cleanContent.includes('"type":"products"')) {
|
|
1686
|
+
for (const match of Array.from(cleanContent.matchAll(jsonRegex))) {
|
|
1687
|
+
try {
|
|
1688
|
+
const data = JSON.parse(sanitizeJson(match[1]));
|
|
1689
|
+
if (data.type === "products" && Array.isArray(data.items)) {
|
|
1690
|
+
products.push(
|
|
1691
|
+
...data.items.map((item) => {
|
|
1692
|
+
var _a2;
|
|
1693
|
+
return __spreadProps(__spreadValues({}, item), {
|
|
1694
|
+
image: (_a2 = item.image) != null ? _a2 : resolveImage(item)
|
|
1695
|
+
});
|
|
1696
|
+
})
|
|
1697
|
+
);
|
|
1698
|
+
cleanContent = cleanContent.replace(match[0], "");
|
|
1699
|
+
}
|
|
1700
|
+
} catch (e) {
|
|
1701
|
+
}
|
|
806
1702
|
}
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1703
|
+
}
|
|
1704
|
+
const bulletRegex = /^[ \t]*(?:[•*-]|\d+\.)\s+(?:\*\*)?([^\n\-\$–—\(]+?)(?:\*\*)?(?:\s*\(?Price\s*[:\-–—]?\s*)?(?:\s*[:\-–—]\s*|\s+)\$?([\d,.]+)(?:\s*USD)?/gim;
|
|
1705
|
+
const matches = Array.from(cleanContent.matchAll(bulletRegex));
|
|
1706
|
+
if (!isStreaming && matches.length >= 2) {
|
|
1707
|
+
const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1708
|
+
for (const match of matches) {
|
|
1709
|
+
let name = ((_a = match[1]) == null ? void 0 : _a.trim()) || "";
|
|
1710
|
+
name = name.replace(/\s*\(?Price\s*$/i, "").replace(/[:\-–—]\s*$/g, "").trim();
|
|
1711
|
+
name = name.replace(/^\*\*|\*\*$/g, "").replace(/^\*|\*$/g, "").trim();
|
|
1712
|
+
let price = ((_b = match[2]) == null ? void 0 : _b.trim()) || "";
|
|
1713
|
+
price = price.replace(/[,\s]+$/, "").trim();
|
|
1714
|
+
if (name && price) {
|
|
1715
|
+
const newProduct = {
|
|
1716
|
+
id: `text-prod-${name}-${price}`,
|
|
1717
|
+
name,
|
|
1718
|
+
price: `$${price}`
|
|
1719
|
+
};
|
|
1720
|
+
const normName = normalize(name);
|
|
1721
|
+
const sourceMatch = productsFromSources.find((s) => {
|
|
1722
|
+
const sn = normalize(s.name);
|
|
1723
|
+
return sn.includes(normName) || normName.includes(sn);
|
|
1724
|
+
});
|
|
1725
|
+
if (sourceMatch) {
|
|
1726
|
+
newProduct.image = sourceMatch.image;
|
|
1727
|
+
newProduct.brand = sourceMatch.brand;
|
|
1728
|
+
newProduct.link = sourceMatch.link;
|
|
1729
|
+
newProduct.description = sourceMatch.description;
|
|
1730
|
+
}
|
|
1731
|
+
products.push(newProduct);
|
|
1732
|
+
cleanContent = cleanContent.replace(match[0], `
|
|
1733
|
+
**${name}** \u2014 $${price}`);
|
|
1734
|
+
}
|
|
813
1735
|
}
|
|
814
|
-
|
|
815
|
-
}, [config]);
|
|
816
|
-
if (!config.data.length || !columns.length) {
|
|
817
|
-
return /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-xs text-slate-400 italic my-2" }, "No data to display.");
|
|
1736
|
+
cleanContent = cleanContent.replace(/\n{3,}/g, "\n\n").trim();
|
|
818
1737
|
}
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
},
|
|
837
|
-
columns.map((column) => /* @__PURE__ */ import_react6.default.createElement(
|
|
838
|
-
"td",
|
|
839
|
-
{
|
|
840
|
-
key: column.label,
|
|
841
|
-
className: `${isCompact ? "px-2.5 py-2" : "px-4 py-3"} text-slate-600 dark:text-white/70 ${column.accessor.toLowerCase().includes("description") ? "whitespace-normal break-words" : "whitespace-nowrap"}`
|
|
842
|
-
},
|
|
843
|
-
formatCell(row[column.accessor])
|
|
844
|
-
))
|
|
845
|
-
))))), /* @__PURE__ */ import_react6.default.createElement("div", { className: "px-4 py-2 bg-slate-50 dark:bg-white/5 border-t border-slate-100 dark:border-white/5" }, /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-[11px] text-slate-400 dark:text-white/30" }, config.data.length, " row", config.data.length !== 1 ? "s" : "")));
|
|
1738
|
+
return { productsFromContent: products, cleanContent: cleanContent.trim() };
|
|
1739
|
+
}
|
|
1740
|
+
function deduplicateProducts(productsFromSources, productsFromContent, messageContent) {
|
|
1741
|
+
if (productsFromContent.length > 0) return productsFromContent;
|
|
1742
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1743
|
+
const contentLower = messageContent.toLowerCase();
|
|
1744
|
+
return productsFromSources.filter((p) => {
|
|
1745
|
+
var _a;
|
|
1746
|
+
const id = String((_a = p.id) != null ? _a : p.name);
|
|
1747
|
+
if (seen.has(id)) return false;
|
|
1748
|
+
const mentioned = contentLower.includes(p.name.toLowerCase()) || (p.brand ? contentLower.includes(p.brand.toLowerCase()) : false);
|
|
1749
|
+
if (mentioned) {
|
|
1750
|
+
seen.add(id);
|
|
1751
|
+
return true;
|
|
1752
|
+
}
|
|
1753
|
+
return false;
|
|
1754
|
+
});
|
|
846
1755
|
}
|
|
1756
|
+
|
|
1757
|
+
// src/components/MarkdownComponents.tsx
|
|
1758
|
+
var import_react8 = __toESM(require("react"));
|
|
1759
|
+
|
|
1760
|
+
// src/components/UIDispatcher.tsx
|
|
1761
|
+
var import_react7 = __toESM(require("react"));
|
|
1762
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
847
1763
|
function normalizeTabularRows(rows, columns) {
|
|
848
1764
|
if (!Array.isArray(rows)) return [];
|
|
849
1765
|
const SYNONYMS = {
|
|
@@ -911,8 +1827,7 @@ function resolveStructuredRows(config) {
|
|
|
911
1827
|
}
|
|
912
1828
|
function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAddToCart, viewportSize = "large" }) {
|
|
913
1829
|
var _a;
|
|
914
|
-
const result =
|
|
915
|
-
if (isStreaming) return { loading: true };
|
|
1830
|
+
const result = import_react7.default.useMemo(() => {
|
|
916
1831
|
try {
|
|
917
1832
|
const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
|
|
918
1833
|
const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
|
|
@@ -941,10 +1856,10 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
941
1856
|
} else if (viewStr.includes("chart") || viewStr.includes("pie") || viewStr.includes("bar") || viewStr.includes("line") || hasAggregationLikeData || typeof config2.type === "string" && ["pie", "bar", "line"].includes(config2.type) || typeof config2.chartType === "string" && ["pie", "bar", "line"].includes(config2.chartType)) {
|
|
942
1857
|
config2.view = "chart";
|
|
943
1858
|
config2.chartType = config2.chartType || viewStr.replace("_chart", "") || config2.type || "bar";
|
|
944
|
-
} else if (viewStr.includes("table")) {
|
|
1859
|
+
} else if (viewStr.includes("table") || config2.type === "table") {
|
|
945
1860
|
config2.view = "table";
|
|
946
1861
|
} else {
|
|
947
|
-
config2.view = "
|
|
1862
|
+
config2.view = "none";
|
|
948
1863
|
}
|
|
949
1864
|
}
|
|
950
1865
|
const normalizedConfig = __spreadProps(__spreadValues({}, config2), {
|
|
@@ -952,14 +1867,18 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
952
1867
|
});
|
|
953
1868
|
return { config: normalizedConfig };
|
|
954
1869
|
} catch (err) {
|
|
1870
|
+
if (isStreaming) return { loading: true };
|
|
955
1871
|
return { error: String(err) };
|
|
956
1872
|
}
|
|
957
1873
|
}, [rawContent, isStreaming]);
|
|
958
1874
|
if ("loading" in result) {
|
|
959
|
-
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
|
+
] });
|
|
960
1879
|
}
|
|
961
1880
|
if ("error" in result) {
|
|
962
|
-
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 }) });
|
|
963
1882
|
}
|
|
964
1883
|
const { config } = result;
|
|
965
1884
|
const isCompact = viewportSize === "compact";
|
|
@@ -967,49 +1886,199 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
967
1886
|
const hasDescription = typeof config.description === "string" && config.description.trim().length > 0;
|
|
968
1887
|
switch (config.view) {
|
|
969
1888
|
case "chart":
|
|
970
|
-
return /* @__PURE__ */
|
|
971
|
-
|
|
972
|
-
{
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
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)
|
|
979
1913
|
},
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
}
|
|
984
|
-
), hasInsights && /* @__PURE__ */ import_react6.default.createElement("div", { className: "mt-4 flex flex-wrap gap-2 px-2" }, (_a = config.insights) == null ? void 0 : _a.map((insight, i) => /* @__PURE__ */ import_react6.default.createElement(
|
|
985
|
-
"span",
|
|
986
|
-
{
|
|
987
|
-
key: `insight-${i}`,
|
|
988
|
-
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`
|
|
989
|
-
},
|
|
990
|
-
String(insight)
|
|
991
|
-
))));
|
|
1914
|
+
`insight-${i}`
|
|
1915
|
+
)) })
|
|
1916
|
+
] });
|
|
992
1917
|
case "carousel":
|
|
993
|
-
return /* @__PURE__ */
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
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
|
+
] });
|
|
999
1928
|
case "table":
|
|
1000
|
-
return /* @__PURE__ */
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
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
|
+
{
|
|
1935
|
+
data: {
|
|
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
|
+
] });
|
|
1009
1949
|
default:
|
|
1010
1950
|
return null;
|
|
1011
1951
|
}
|
|
1012
1952
|
}
|
|
1953
|
+
|
|
1954
|
+
// src/components/MarkdownComponents.tsx
|
|
1955
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1956
|
+
function createMarkdownComponents({
|
|
1957
|
+
primaryColor,
|
|
1958
|
+
accentColor,
|
|
1959
|
+
isStreaming,
|
|
1960
|
+
onAddToCart,
|
|
1961
|
+
viewportSize
|
|
1962
|
+
}) {
|
|
1963
|
+
return {
|
|
1964
|
+
p: (_a) => {
|
|
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, []);
|
|
1970
|
+
if (isStreaming) {
|
|
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
|
+
] });
|
|
1975
|
+
}
|
|
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)(
|
|
1977
|
+
"table",
|
|
1978
|
+
__spreadValues({
|
|
1979
|
+
className: "!table w-full text-left border-collapse min-w-[400px] text-sm"
|
|
1980
|
+
}, props)
|
|
1981
|
+
) }) });
|
|
1982
|
+
},
|
|
1983
|
+
thead: (_c) => {
|
|
1984
|
+
var props = __objRest(_c, []);
|
|
1985
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1986
|
+
"thead",
|
|
1987
|
+
__spreadValues({
|
|
1988
|
+
className: "!table-header-group bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10"
|
|
1989
|
+
}, props)
|
|
1990
|
+
);
|
|
1991
|
+
},
|
|
1992
|
+
tbody: (_d) => {
|
|
1993
|
+
var props = __objRest(_d, []);
|
|
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)(
|
|
1999
|
+
"tr",
|
|
2000
|
+
__spreadValues({
|
|
2001
|
+
className: "!table-row hover:bg-slate-50/70 dark:hover:bg-white/5 transition-colors"
|
|
2002
|
+
}, props)
|
|
2003
|
+
);
|
|
2004
|
+
},
|
|
2005
|
+
th: (_f) => {
|
|
2006
|
+
var _g = _f, { children } = _g, props = __objRest(_g, ["children"]);
|
|
2007
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2008
|
+
"th",
|
|
2009
|
+
__spreadProps(__spreadValues({
|
|
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"
|
|
2011
|
+
}, props), {
|
|
2012
|
+
children: normaliseChild(children)
|
|
2013
|
+
})
|
|
2014
|
+
);
|
|
2015
|
+
},
|
|
2016
|
+
td: (_h) => {
|
|
2017
|
+
var _i = _h, { children } = _i, props = __objRest(_i, ["children"]);
|
|
2018
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2019
|
+
"td",
|
|
2020
|
+
__spreadProps(__spreadValues({
|
|
2021
|
+
className: "!table-cell px-4 py-3 text-slate-600 dark:text-white/70 whitespace-nowrap text-sm"
|
|
2022
|
+
}, props), {
|
|
2023
|
+
children: normaliseChild(children)
|
|
2024
|
+
})
|
|
2025
|
+
);
|
|
2026
|
+
},
|
|
2027
|
+
code(_j) {
|
|
2028
|
+
var _k = _j, {
|
|
2029
|
+
inline,
|
|
2030
|
+
className,
|
|
2031
|
+
children
|
|
2032
|
+
} = _k, props = __objRest(_k, [
|
|
2033
|
+
"inline",
|
|
2034
|
+
"className",
|
|
2035
|
+
"children"
|
|
2036
|
+
]);
|
|
2037
|
+
var _a;
|
|
2038
|
+
const lang = (_a = /language-(\w+)/.exec(className != null ? className : "")) == null ? void 0 : _a[1];
|
|
2039
|
+
if (!inline && (lang === "ui" || lang === "chart" || lang === "json")) {
|
|
2040
|
+
const content = String(children != null ? children : "").trim();
|
|
2041
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2042
|
+
UIDispatcher,
|
|
2043
|
+
{
|
|
2044
|
+
rawContent: content,
|
|
2045
|
+
primaryColor,
|
|
2046
|
+
accentColor,
|
|
2047
|
+
isStreaming,
|
|
2048
|
+
onAddToCart,
|
|
2049
|
+
viewportSize
|
|
2050
|
+
}
|
|
2051
|
+
);
|
|
2052
|
+
}
|
|
2053
|
+
if (!inline) {
|
|
2054
|
+
const content = String(children != null ? children : "").trim();
|
|
2055
|
+
if (content.startsWith("{") && content.endsWith("}")) {
|
|
2056
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2057
|
+
UIDispatcher,
|
|
2058
|
+
{
|
|
2059
|
+
rawContent: content,
|
|
2060
|
+
primaryColor,
|
|
2061
|
+
accentColor,
|
|
2062
|
+
isStreaming,
|
|
2063
|
+
onAddToCart,
|
|
2064
|
+
viewportSize
|
|
2065
|
+
}
|
|
2066
|
+
);
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", __spreadProps(__spreadValues({ className }, props), { children: typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children) }));
|
|
2070
|
+
}
|
|
2071
|
+
};
|
|
2072
|
+
}
|
|
2073
|
+
function normaliseChild(children) {
|
|
2074
|
+
if (typeof children === "object" && children !== null && !Array.isArray(children) && !import_react8.default.isValidElement(children)) {
|
|
2075
|
+
return JSON.stringify(children);
|
|
2076
|
+
}
|
|
2077
|
+
return children;
|
|
2078
|
+
}
|
|
2079
|
+
|
|
2080
|
+
// src/components/MessageBubble.tsx
|
|
2081
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1013
2082
|
function MessageBubble({
|
|
1014
2083
|
message,
|
|
1015
2084
|
sources,
|
|
@@ -1022,12 +2091,13 @@ function MessageBubble({
|
|
|
1022
2091
|
const isUser = message.role === "user";
|
|
1023
2092
|
const isCompact = viewportSize === "compact";
|
|
1024
2093
|
const isMedium = viewportSize === "medium";
|
|
1025
|
-
const [showSources, setShowSources] =
|
|
1026
|
-
const
|
|
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(
|
|
1027
2097
|
() => isUser ? { payload: null, text: message.content } : extractStructuredPayload(message.content),
|
|
1028
2098
|
[isUser, message.content]
|
|
1029
2099
|
);
|
|
1030
|
-
const hasRichUI =
|
|
2100
|
+
const hasRichUI = import_react9.default.useMemo(() => {
|
|
1031
2101
|
if (message.uiTransformation) {
|
|
1032
2102
|
const type = message.uiTransformation.type;
|
|
1033
2103
|
if (type && !["text", "table"].includes(type)) return true;
|
|
@@ -1038,421 +2108,168 @@ function MessageBubble({
|
|
|
1038
2108
|
return false;
|
|
1039
2109
|
}, [message.uiTransformation, structuredContent.payload]);
|
|
1040
2110
|
const shouldRenderStructuredOnly = !isUser && hasRichUI && isLikelyUiOnlyMessage(structuredContent.text);
|
|
1041
|
-
const productsFromSources =
|
|
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
|
-
const jsonRegex = /```(?:json|ui)?\s*([\s\S]*?)\s*```/g;
|
|
1075
|
-
const products = [];
|
|
1076
|
-
let content = structuredContent.text;
|
|
1077
|
-
const payloadCandidates = [structuredContent.payload, ...Array.from(content.matchAll(jsonRegex)).map((match) => match[1])].filter(Boolean);
|
|
1078
|
-
for (const candidate of payloadCandidates) {
|
|
1079
|
-
try {
|
|
1080
|
-
const data = JSON.parse(sanitizeJson(candidate));
|
|
1081
|
-
const itemSet = Array.isArray(data.data) ? data.data : Array.isArray(data.items) ? data.items : Array.isArray(data.products) ? data.products : null;
|
|
1082
|
-
if ((data.type === "products" || data.view === "carousel" || data.view === "table" || Array.isArray(data.products)) && itemSet) {
|
|
1083
|
-
products.push(
|
|
1084
|
-
...itemSet.map((item) => {
|
|
1085
|
-
var _a2;
|
|
1086
|
-
return __spreadProps(__spreadValues({}, item), {
|
|
1087
|
-
image: (_a2 = item.image) != null ? _a2 : resolveImage(item)
|
|
1088
|
-
});
|
|
1089
|
-
})
|
|
1090
|
-
);
|
|
1091
|
-
}
|
|
1092
|
-
} catch (e) {
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
if (content.includes('"type": "products"') || content.includes('"type":"products"')) {
|
|
1096
|
-
for (const match of Array.from(content.matchAll(jsonRegex))) {
|
|
1097
|
-
try {
|
|
1098
|
-
const data = JSON.parse(sanitizeJson(match[1]));
|
|
1099
|
-
if (data.type === "products" && Array.isArray(data.items)) {
|
|
1100
|
-
products.push(
|
|
1101
|
-
...data.items.map((item) => {
|
|
1102
|
-
var _a2;
|
|
1103
|
-
return __spreadProps(__spreadValues({}, item), {
|
|
1104
|
-
image: (_a2 = item.image) != null ? _a2 : resolveImage(item)
|
|
1105
|
-
});
|
|
1106
|
-
})
|
|
1107
|
-
);
|
|
1108
|
-
content = content.replace(match[0], "");
|
|
1109
|
-
}
|
|
1110
|
-
} catch (e) {
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
}
|
|
1114
|
-
const bulletRegex = /(?:[•*-]\s*)?([^•\n\-\$*–—\(]+?)(?:\s*\(?Price\s*[:\-–—]?\s*)?(?:\s*[:\-–—]\s*|\s+)\$?([\d,.]+)(?:\s*USD)?/gi;
|
|
1115
|
-
const matches = Array.from(content.matchAll(bulletRegex));
|
|
1116
|
-
if (matches.length >= 2) {
|
|
1117
|
-
const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1118
|
-
for (const match of matches) {
|
|
1119
|
-
let name = ((_a = match[1]) == null ? void 0 : _a.trim()) || "";
|
|
1120
|
-
name = name.replace(/\s*\(?Price\s*$/i, "").replace(/[:\-–—]\s*$/g, "").trim();
|
|
1121
|
-
let price = ((_b = match[2]) == null ? void 0 : _b.trim()) || "";
|
|
1122
|
-
price = price.replace(/[,\s]+$/, "").trim();
|
|
1123
|
-
if (name && price) {
|
|
1124
|
-
const newProduct = {
|
|
1125
|
-
id: `text-prod-${name}-${price}`,
|
|
1126
|
-
name,
|
|
1127
|
-
price: `$${price}`
|
|
1128
|
-
};
|
|
1129
|
-
const normName = normalize(name);
|
|
1130
|
-
const sourceMatch = productsFromSources.find((s) => {
|
|
1131
|
-
const sn = normalize(s.name);
|
|
1132
|
-
return sn.includes(normName) || normName.includes(sn);
|
|
1133
|
-
});
|
|
1134
|
-
if (sourceMatch) {
|
|
1135
|
-
newProduct.image = sourceMatch.image;
|
|
1136
|
-
newProduct.brand = sourceMatch.brand;
|
|
1137
|
-
newProduct.link = sourceMatch.link;
|
|
1138
|
-
newProduct.description = sourceMatch.description;
|
|
1139
|
-
}
|
|
1140
|
-
products.push(newProduct);
|
|
1141
|
-
content = content.replace(match[0], `
|
|
1142
|
-
**${name}** \u2014 $${price}`);
|
|
1143
|
-
}
|
|
1144
|
-
}
|
|
1145
|
-
content = content.replace(/\n{3,}/g, "\n\n").trim();
|
|
1146
|
-
}
|
|
1147
|
-
return { productsFromContent: products, cleanContent: content.trim() };
|
|
1148
|
-
}, [message.content, isUser, structuredContent, productsFromSources]);
|
|
1149
|
-
const allProducts = import_react6.default.useMemo(() => {
|
|
1150
|
-
if (productsFromContent.length > 0) return productsFromContent;
|
|
1151
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1152
|
-
const contentLower = message.content.toLowerCase();
|
|
1153
|
-
return productsFromSources.filter((p) => {
|
|
1154
|
-
var _a;
|
|
1155
|
-
const id = String((_a = p.id) != null ? _a : p.name);
|
|
1156
|
-
if (seen.has(id)) return false;
|
|
1157
|
-
const mentioned = contentLower.includes(p.name.toLowerCase()) || (p.brand ? contentLower.includes(p.brand.toLowerCase()) : false);
|
|
1158
|
-
if (mentioned) {
|
|
1159
|
-
seen.add(id);
|
|
1160
|
-
return true;
|
|
1161
|
-
}
|
|
1162
|
-
return false;
|
|
1163
|
-
});
|
|
1164
|
-
}, [productsFromSources, productsFromContent, message.content]);
|
|
1165
|
-
const processedMarkdown = import_react6.default.useMemo(() => {
|
|
1166
|
-
let raw = structuredContent.payload ? structuredContent.text : cleanContent || message.content;
|
|
1167
|
-
const hasStructuredUiBlock = Boolean(structuredContent.payload) || /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|chartType|type|data|items|rows|products|results)"\s*:/i.test(raw);
|
|
1168
|
-
raw = raw.replace(/([^\n])\n\|/g, "$1\n\n|").replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, "$1\n");
|
|
1169
|
-
if (!isStreaming) {
|
|
1170
|
-
raw = raw.replace(/(?:^|\n)\s*\{[\s\S]*\}\s*(?:\n|$)/g, (match) => {
|
|
1171
|
-
if (match.includes("```")) return match;
|
|
1172
|
-
if (!looksLikeStructuredPayload(match)) return match;
|
|
1173
|
-
const type = match.includes('"view"') || match.includes('"chartType"') || match.includes('"type": "pie"') || match.includes('"type":"pie"') || match.includes('"type": "bar"') || match.includes('"type":"bar"') || match.includes('"type": "line"') || match.includes('"type":"line"') ? "ui" : "json";
|
|
1174
|
-
return `
|
|
1175
|
-
|
|
1176
|
-
\`\`\`${type}
|
|
1177
|
-
${match.trim()}
|
|
1178
|
-
\`\`\`
|
|
1179
|
-
|
|
1180
|
-
`;
|
|
1181
|
-
});
|
|
1182
|
-
}
|
|
1183
|
-
if (hasStructuredUiBlock) {
|
|
1184
|
-
raw = stripStructuredUiLabels(stripMarkdownTables(raw)).replace(/\n{3,}/g, "\n\n").trim();
|
|
1185
|
-
}
|
|
1186
|
-
if (isStreaming) {
|
|
1187
|
-
raw = raw.replace(/((?:^|\n)\|.*)+/g, (match) => {
|
|
1188
|
-
return `
|
|
1189
|
-
|
|
1190
|
-
\`\`\`table-loading
|
|
1191
|
-
${match.trim()}
|
|
1192
|
-
\`\`\`
|
|
1193
|
-
|
|
1194
|
-
`;
|
|
1195
|
-
});
|
|
1196
|
-
}
|
|
1197
|
-
return raw;
|
|
1198
|
-
}, [cleanContent, message.content, isStreaming, structuredContent]);
|
|
1199
|
-
const markdownComponents = import_react6.default.useMemo(
|
|
1200
|
-
() => ({
|
|
1201
|
-
// Wrap in not-prose so Tailwind Typography resets don't clobber our styles.
|
|
1202
|
-
// prose applies display:block and padding:0 to table/th/td — not-prose opts out.
|
|
1203
|
-
table: (_a) => {
|
|
1204
|
-
var props = __objRest(_a, []);
|
|
1205
|
-
if (isStreaming) {
|
|
1206
|
-
return /* @__PURE__ */ import_react6.default.createElement("div", { className: "my-5 p-6 bg-slate-50 dark:bg-white/5 rounded-xl border border-dashed border-slate-300 dark:border-white/10 flex items-center justify-center gap-3 select-none" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-4 h-4 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-xs text-slate-500 font-medium italic animate-pulse" }, "Generating data table..."));
|
|
1207
|
-
}
|
|
1208
|
-
return /* @__PURE__ */ import_react6.default.createElement("div", { className: "not-prose overflow-hidden my-5 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm bg-white dark:bg-slate-900/50" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ import_react6.default.createElement(
|
|
1209
|
-
"table",
|
|
1210
|
-
__spreadValues({
|
|
1211
|
-
className: "!table w-full text-left border-collapse min-w-[400px] text-sm"
|
|
1212
|
-
}, props)
|
|
1213
|
-
)));
|
|
1214
|
-
},
|
|
1215
|
-
thead: (_b) => {
|
|
1216
|
-
var props = __objRest(_b, []);
|
|
1217
|
-
return /* @__PURE__ */ import_react6.default.createElement(
|
|
1218
|
-
"thead",
|
|
1219
|
-
__spreadValues({
|
|
1220
|
-
className: "!table-header-group bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10"
|
|
1221
|
-
}, props)
|
|
1222
|
-
);
|
|
1223
|
-
},
|
|
1224
|
-
tbody: (_c) => {
|
|
1225
|
-
var props = __objRest(_c, []);
|
|
1226
|
-
return /* @__PURE__ */ import_react6.default.createElement("tbody", __spreadValues({ className: "!table-row-group divide-y divide-slate-100 dark:divide-white/5" }, props));
|
|
1227
|
-
},
|
|
1228
|
-
tr: (_d) => {
|
|
1229
|
-
var props = __objRest(_d, []);
|
|
1230
|
-
return /* @__PURE__ */ import_react6.default.createElement(
|
|
1231
|
-
"tr",
|
|
1232
|
-
__spreadValues({
|
|
1233
|
-
className: "!table-row hover:bg-slate-50/70 dark:hover:bg-white/5 transition-colors"
|
|
1234
|
-
}, props)
|
|
1235
|
-
);
|
|
1236
|
-
},
|
|
1237
|
-
th: (_e) => {
|
|
1238
|
-
var _f = _e, { children } = _f, props = __objRest(_f, ["children"]);
|
|
1239
|
-
return /* @__PURE__ */ import_react6.default.createElement(
|
|
1240
|
-
"th",
|
|
1241
|
-
__spreadValues({
|
|
1242
|
-
className: "!table-cell px-4 py-3 font-bold text-slate-700 dark:text-white/90 whitespace-nowrap text-[11px] uppercase tracking-wider text-left"
|
|
1243
|
-
}, props),
|
|
1244
|
-
normaliseChild(children)
|
|
1245
|
-
);
|
|
1246
|
-
},
|
|
1247
|
-
td: (_g) => {
|
|
1248
|
-
var _h = _g, { children } = _h, props = __objRest(_h, ["children"]);
|
|
1249
|
-
return /* @__PURE__ */ import_react6.default.createElement(
|
|
1250
|
-
"td",
|
|
1251
|
-
__spreadValues({
|
|
1252
|
-
className: "!table-cell px-4 py-3 text-slate-600 dark:text-white/70 whitespace-nowrap text-sm"
|
|
1253
|
-
}, props),
|
|
1254
|
-
normaliseChild(children)
|
|
1255
|
-
);
|
|
1256
|
-
},
|
|
1257
|
-
code(_i) {
|
|
1258
|
-
var _j = _i, {
|
|
1259
|
-
inline,
|
|
1260
|
-
className,
|
|
1261
|
-
children
|
|
1262
|
-
} = _j, props = __objRest(_j, [
|
|
1263
|
-
"inline",
|
|
1264
|
-
"className",
|
|
1265
|
-
"children"
|
|
1266
|
-
]);
|
|
1267
|
-
var _a;
|
|
1268
|
-
const lang = (_a = /language-(\w+)/.exec(className != null ? className : "")) == null ? void 0 : _a[1];
|
|
1269
|
-
if (!inline && (lang === "ui" || lang === "chart")) {
|
|
1270
|
-
return /* @__PURE__ */ import_react6.default.createElement(
|
|
1271
|
-
UIDispatcher,
|
|
1272
|
-
{
|
|
1273
|
-
rawContent: String(children != null ? children : "").trim(),
|
|
1274
|
-
primaryColor,
|
|
1275
|
-
accentColor,
|
|
1276
|
-
isStreaming,
|
|
1277
|
-
onAddToCart,
|
|
1278
|
-
viewportSize
|
|
1279
|
-
}
|
|
1280
|
-
);
|
|
1281
|
-
}
|
|
1282
|
-
if (!inline && lang === "json") {
|
|
1283
|
-
const content = String(children != null ? children : "").trim();
|
|
1284
|
-
if (looksLikeStructuredPayload(content)) {
|
|
1285
|
-
return /* @__PURE__ */ import_react6.default.createElement(
|
|
1286
|
-
UIDispatcher,
|
|
1287
|
-
{
|
|
1288
|
-
rawContent: content,
|
|
1289
|
-
primaryColor,
|
|
1290
|
-
accentColor,
|
|
1291
|
-
isStreaming,
|
|
1292
|
-
onAddToCart,
|
|
1293
|
-
viewportSize
|
|
1294
|
-
}
|
|
1295
|
-
);
|
|
1296
|
-
}
|
|
1297
|
-
}
|
|
1298
|
-
if (!inline) {
|
|
1299
|
-
const content = String(children != null ? children : "").trim();
|
|
1300
|
-
if (looksLikeStructuredPayload(content)) {
|
|
1301
|
-
return /* @__PURE__ */ import_react6.default.createElement(
|
|
1302
|
-
UIDispatcher,
|
|
1303
|
-
{
|
|
1304
|
-
rawContent: content,
|
|
1305
|
-
primaryColor,
|
|
1306
|
-
accentColor,
|
|
1307
|
-
isStreaming,
|
|
1308
|
-
onAddToCart,
|
|
1309
|
-
viewportSize
|
|
1310
|
-
}
|
|
1311
|
-
);
|
|
1312
|
-
}
|
|
1313
|
-
}
|
|
1314
|
-
if (!inline && lang === "table-loading") {
|
|
1315
|
-
return /* @__PURE__ */ import_react6.default.createElement("div", { className: "my-5 p-6 bg-slate-50 dark:bg-white/5 rounded-xl border border-dashed border-slate-300 dark:border-white/10 flex items-center justify-center gap-3 select-none" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-4 h-4 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-xs text-slate-500 font-medium italic animate-pulse" }, "Generating data table..."));
|
|
1316
|
-
}
|
|
1317
|
-
return /* @__PURE__ */ import_react6.default.createElement("code", __spreadValues({ className }, props), typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children));
|
|
1318
|
-
}
|
|
1319
|
-
}),
|
|
1320
|
-
[primaryColor, accentColor, isStreaming, onAddToCart, viewportSize]
|
|
1321
|
-
);
|
|
1322
|
-
return /* @__PURE__ */ import_react6.default.createElement("div", { className: `flex ${isCompact ? "gap-2" : "gap-3"} ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ import_react6.default.createElement(
|
|
1323
|
-
"div",
|
|
1324
|
-
{
|
|
1325
|
-
className: `flex-shrink-0 ${isCompact ? "w-7 h-7" : "w-8 h-8"} rounded-full flex items-center justify-center shadow-lg ${isUser ? "text-white" : "bg-slate-100 dark:bg-white/10 text-slate-700 dark:text-white/80"}`,
|
|
1326
|
-
style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
|
|
1327
|
-
},
|
|
1328
|
-
isUser ? /* @__PURE__ */ import_react6.default.createElement(import_lucide_react4.User, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"} text-white` }) : /* @__PURE__ */ import_react6.default.createElement(import_lucide_react4.Bot, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"}` })
|
|
1329
|
-
), /* @__PURE__ */ import_react6.default.createElement("div", { className: `flex flex-col gap-1 ${isCompact ? "max-w-[94%]" : isMedium ? "max-w-[92%]" : "max-w-[90%]"} ${isUser ? "items-end" : "items-start"}` }, /* @__PURE__ */ import_react6.default.createElement(
|
|
1330
|
-
"div",
|
|
1331
|
-
{
|
|
1332
|
-
className: `relative ${isCompact ? "px-3 py-2.5 text-[13px]" : "px-4 py-3 text-sm"} rounded-2xl leading-relaxed shadow-sm dark:shadow-lg ${isUser ? "text-white rounded-tr-sm" : "bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 text-slate-800 dark:text-white/90 rounded-tl-sm"}`,
|
|
1333
|
-
style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
|
|
1334
|
-
},
|
|
1335
|
-
isStreaming && !message.content ? /* @__PURE__ */ import_react6.default.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }), /* @__PURE__ */ import_react6.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }), /* @__PURE__ */ import_react6.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })) : /* @__PURE__ */ import_react6.default.createElement("div", { className: `prose ${isCompact ? "prose-xs" : "prose-sm"} max-w-none break-words ${isUser ? "prose-invert" : "dark:prose-invert"}` }, !isUser && structuredContent.payload && /* @__PURE__ */ import_react6.default.createElement(
|
|
1336
|
-
UIDispatcher,
|
|
1337
|
-
{
|
|
1338
|
-
rawContent: structuredContent.payload,
|
|
1339
|
-
primaryColor,
|
|
1340
|
-
accentColor,
|
|
1341
|
-
isStreaming,
|
|
1342
|
-
onAddToCart,
|
|
1343
|
-
viewportSize
|
|
1344
|
-
}
|
|
1345
|
-
), !shouldRenderStructuredOnly && /* @__PURE__ */ import_react6.default.createElement(import_react_markdown.default, { components: markdownComponents }, processedMarkdown), isStreaming && message.content && /* @__PURE__ */ import_react6.default.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
|
|
1346
|
-
), (() => {
|
|
1347
|
-
var _a, _b;
|
|
1348
|
-
if (isUser || structuredContent.payload || !message.uiTransformation) return null;
|
|
1349
|
-
const ui = message.uiTransformation;
|
|
1350
|
-
const textContent = (_b = (_a = ui.data) == null ? void 0 : _a.content) != null ? _b : "";
|
|
1351
|
-
const shouldShow = ui.type === "table" && allProducts.length === 0 || !["text", "table"].includes(ui.type) || ui.type === "text" && !hasRichUI && allProducts.length === 0 && textContent && !processedMarkdown.toLowerCase().includes(textContent.trim().toLowerCase());
|
|
1352
|
-
if (!shouldShow) return null;
|
|
1353
|
-
return /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-full mt-3" }, /* @__PURE__ */ import_react6.default.createElement(
|
|
1354
|
-
VisualizationRenderer,
|
|
1355
|
-
{
|
|
1356
|
-
data: ui,
|
|
1357
|
-
primaryColor,
|
|
1358
|
-
onAddToCart,
|
|
1359
|
-
className: "rounded-3xl border border-slate-200/60 dark:border-white/10 bg-white/90 dark:bg-slate-900/80 p-4"
|
|
1360
|
-
}
|
|
1361
|
-
));
|
|
1362
|
-
})(), !isUser && !hasRichUI && allProducts.length > 0 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ import_react6.default.createElement(
|
|
1363
|
-
ProductCarousel,
|
|
1364
|
-
{
|
|
1365
|
-
products: allProducts,
|
|
1366
|
-
primaryColor,
|
|
1367
|
-
onAddToCart
|
|
1368
|
-
}
|
|
1369
|
-
)), !isUser && sources && sources.length > 0 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-full" }, /* @__PURE__ */ import_react6.default.createElement(
|
|
1370
|
-
"button",
|
|
1371
|
-
{
|
|
1372
|
-
onClick: () => setShowSources((s) => !s),
|
|
1373
|
-
className: "text-[11px] text-indigo-400 hover:text-indigo-300 transition-colors flex items-center gap-1 mt-1"
|
|
1374
|
-
},
|
|
1375
|
-
showSources ? /* @__PURE__ */ import_react6.default.createElement(import_lucide_react4.ChevronDown, { className: "w-3 h-3" }) : /* @__PURE__ */ import_react6.default.createElement(import_lucide_react4.ChevronRight, { className: "w-3 h-3" }),
|
|
1376
|
-
sources.length,
|
|
1377
|
-
" source",
|
|
1378
|
-
sources.length !== 1 ? "s" : "",
|
|
1379
|
-
" used"
|
|
1380
|
-
), showSources && /* @__PURE__ */ import_react6.default.createElement("div", { className: "mt-2 flex flex-col gap-2" }, sources.map((src, i) => /* @__PURE__ */ import_react6.default.createElement(SourceCard, { key: src.id, source: src, index: i }))))));
|
|
1381
|
-
}
|
|
1382
|
-
|
|
1383
|
-
// src/components/ConfigProvider.tsx
|
|
1384
|
-
var import_react7 = __toESM(require("react"));
|
|
1385
|
-
|
|
1386
|
-
// src/utils/templateUtils.ts
|
|
1387
|
-
function mergeDefined(base, override) {
|
|
1388
|
-
const merged = __spreadValues({}, base || {});
|
|
1389
|
-
if (!override) {
|
|
1390
|
-
return merged;
|
|
1391
|
-
}
|
|
1392
|
-
for (const [key, value] of Object.entries(override)) {
|
|
1393
|
-
if (value !== void 0 && value !== null && value !== "") {
|
|
1394
|
-
merged[key] = value;
|
|
1395
|
-
}
|
|
1396
|
-
}
|
|
1397
|
-
return merged;
|
|
1398
|
-
}
|
|
1399
|
-
|
|
1400
|
-
// src/config/uiConstants.ts
|
|
1401
|
-
var DEFAULT_CONFIG = {
|
|
1402
|
-
projectId: "default",
|
|
1403
|
-
ui: {
|
|
1404
|
-
title: "AI Assistant",
|
|
1405
|
-
subtitle: "Powered by RAG",
|
|
1406
|
-
primaryColor: "#6366f1",
|
|
1407
|
-
accentColor: "#8b5cf6",
|
|
1408
|
-
logoUrl: "",
|
|
1409
|
-
placeholder: "Ask me anything\u2026",
|
|
1410
|
-
showSources: true,
|
|
1411
|
-
welcomeMessage: "Hello! I'm your AI assistant. Ask me anything about your documents.",
|
|
1412
|
-
showWidget: true,
|
|
1413
|
-
poweredBy: "RAG",
|
|
1414
|
-
visualStyle: "glass",
|
|
1415
|
-
borderRadius: "xl",
|
|
1416
|
-
allowUpload: true,
|
|
1417
|
-
allowResize: true,
|
|
1418
|
-
enableVoiceInput: true
|
|
1419
|
-
}
|
|
1420
|
-
};
|
|
1421
|
-
var BORDER_RADIUS_MAP = {
|
|
1422
|
-
none: "rounded-none",
|
|
1423
|
-
sm: "rounded-sm",
|
|
1424
|
-
md: "rounded-md",
|
|
1425
|
-
lg: "rounded-lg",
|
|
1426
|
-
xl: "rounded-xl",
|
|
1427
|
-
full: "rounded-3xl"
|
|
1428
|
-
};
|
|
1429
|
-
var CHAT_SUGGESTIONS = [
|
|
1430
|
-
"What can you help me with?",
|
|
1431
|
-
"Summarise the key topics",
|
|
1432
|
-
"Show me an example"
|
|
1433
|
-
];
|
|
2111
|
+
const productsFromSources = import_react9.default.useMemo(() => {
|
|
2112
|
+
return extractProductsFromSources(sources, isUser);
|
|
2113
|
+
}, [sources, isUser]);
|
|
2114
|
+
const { productsFromContent, cleanContent } = import_react9.default.useMemo(() => {
|
|
2115
|
+
if (isUser) {
|
|
2116
|
+
return { productsFromContent: [], cleanContent: message.content };
|
|
2117
|
+
}
|
|
2118
|
+
const payloadCandidates = [
|
|
2119
|
+
structuredContent.payload,
|
|
2120
|
+
...Array.from(structuredContent.text.matchAll(/```(?:json|ui)?\s*([\s\S]*?)\s*```/g)).map((m) => m[1])
|
|
2121
|
+
].filter(Boolean);
|
|
2122
|
+
return extractProductsFromContent(
|
|
2123
|
+
message.content,
|
|
2124
|
+
structuredContent.text,
|
|
2125
|
+
payloadCandidates,
|
|
2126
|
+
productsFromSources,
|
|
2127
|
+
isStreaming
|
|
2128
|
+
);
|
|
2129
|
+
}, [message.content, isUser, structuredContent, productsFromSources, isStreaming]);
|
|
2130
|
+
const allProducts = import_react9.default.useMemo(() => {
|
|
2131
|
+
return deduplicateProducts(productsFromSources, productsFromContent, message.content);
|
|
2132
|
+
}, [productsFromSources, productsFromContent, message.content]);
|
|
2133
|
+
const processedMarkdown = import_react9.default.useMemo(() => {
|
|
2134
|
+
let raw = structuredContent.payload ? structuredContent.text : cleanContent || message.content;
|
|
2135
|
+
const hasStructuredUiBlock = Boolean(structuredContent.payload) || /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|chartType|type|data|items|rows|products|results)"\s*:/i.test(raw);
|
|
2136
|
+
raw = raw.replace(/([^\n])\n\|/g, "$1\n\n|").replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, "$1\n");
|
|
2137
|
+
if (!isStreaming) {
|
|
2138
|
+
raw = raw.replace(/(?:^|\n)\s*\{[\s\S]*\}\s*(?:\n|$)/g, (match) => {
|
|
2139
|
+
if (match.includes("```")) return match;
|
|
2140
|
+
if (!looksLikeStructuredPayload(match)) return match;
|
|
2141
|
+
const type = match.includes('"view"') || match.includes('"chartType"') || match.includes('"type": "pie"') || match.includes('"type":"pie"') || match.includes('"type": "bar"') || match.includes('"type":"bar"') || match.includes('"type": "line"') || match.includes('"type":"line"') ? "ui" : "json";
|
|
2142
|
+
return `
|
|
1434
2143
|
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
})
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
}
|
|
1447
|
-
|
|
1448
|
-
|
|
2144
|
+
\`\`\`${type}
|
|
2145
|
+
${match.trim()}
|
|
2146
|
+
\`\`\`
|
|
2147
|
+
|
|
2148
|
+
`;
|
|
2149
|
+
});
|
|
2150
|
+
}
|
|
2151
|
+
if (hasStructuredUiBlock) {
|
|
2152
|
+
raw = stripStructuredUiLabels(stripMarkdownTables(raw)).replace(/\n{3,}/g, "\n\n").trim();
|
|
2153
|
+
}
|
|
2154
|
+
return raw;
|
|
2155
|
+
}, [cleanContent, message.content, isStreaming, structuredContent]);
|
|
2156
|
+
const markdownComponents = import_react9.default.useMemo(
|
|
2157
|
+
() => createMarkdownComponents({ primaryColor, accentColor, isStreaming, onAddToCart, viewportSize }),
|
|
2158
|
+
[primaryColor, accentColor, isStreaming, onAddToCart, viewportSize]
|
|
2159
|
+
);
|
|
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",
|
|
2163
|
+
{
|
|
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"}` })
|
|
2167
|
+
}
|
|
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
|
+
] });
|
|
1449
2266
|
}
|
|
1450
2267
|
|
|
1451
2268
|
// src/hooks/useRagChat.ts
|
|
1452
|
-
var
|
|
2269
|
+
var import_react10 = require("react");
|
|
1453
2270
|
|
|
1454
2271
|
// src/hooks/useStoredMessages.ts
|
|
1455
|
-
var
|
|
2272
|
+
var React10 = __toESM(require("react"));
|
|
1456
2273
|
function readStoredMessages(storageKey) {
|
|
1457
2274
|
if (typeof window === "undefined") {
|
|
1458
2275
|
return [];
|
|
@@ -1469,8 +2286,8 @@ function readStoredMessages(storageKey) {
|
|
|
1469
2286
|
}
|
|
1470
2287
|
}
|
|
1471
2288
|
function useStoredMessages(storageKey, persist) {
|
|
1472
|
-
const [messages, setMessages] =
|
|
1473
|
-
|
|
2289
|
+
const [messages, setMessages] = React10.useState(() => persist ? readStoredMessages(storageKey) : []);
|
|
2290
|
+
React10.useEffect(() => {
|
|
1474
2291
|
if (!persist || typeof window === "undefined") {
|
|
1475
2292
|
return;
|
|
1476
2293
|
}
|
|
@@ -1510,14 +2327,14 @@ function useRagChat(projectId, options = {}) {
|
|
|
1510
2327
|
} = options;
|
|
1511
2328
|
const storageKey = `rag_chat_${projectId}`;
|
|
1512
2329
|
const [messages, setMessages] = useStoredMessages(storageKey, persist);
|
|
1513
|
-
const [isLoading, setIsLoading] = (0,
|
|
1514
|
-
const [error, setError] = (0,
|
|
1515
|
-
const lastInputRef = (0,
|
|
1516
|
-
const messagesRef = (0,
|
|
1517
|
-
(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)(() => {
|
|
1518
2335
|
messagesRef.current = messages;
|
|
1519
2336
|
}, [messages]);
|
|
1520
|
-
const sendMessage = (0,
|
|
2337
|
+
const sendMessage = (0, import_react10.useCallback)(
|
|
1521
2338
|
async (text, opts) => {
|
|
1522
2339
|
var _a, _b;
|
|
1523
2340
|
const trimmed = text.trim();
|
|
@@ -1557,6 +2374,7 @@ function useRagChat(projectId, options = {}) {
|
|
|
1557
2374
|
let assistantContent = "";
|
|
1558
2375
|
let sources = [];
|
|
1559
2376
|
let uiTransformation = null;
|
|
2377
|
+
let trace;
|
|
1560
2378
|
let buffer = "";
|
|
1561
2379
|
const assistantMessageId = `assistant_${Date.now()}`;
|
|
1562
2380
|
setMessages((prev) => [
|
|
@@ -1583,6 +2401,8 @@ function useRagChat(projectId, options = {}) {
|
|
|
1583
2401
|
sources = (_a = frame.sources) != null ? _a : [];
|
|
1584
2402
|
} else if (frame.type === "ui_transformation") {
|
|
1585
2403
|
uiTransformation = frame.data;
|
|
2404
|
+
} else if (frame.type === "observability") {
|
|
2405
|
+
trace = frame.data;
|
|
1586
2406
|
} else if (frame.type === "error") {
|
|
1587
2407
|
setError(frame.error || "Stream error");
|
|
1588
2408
|
}
|
|
@@ -1601,17 +2421,22 @@ function useRagChat(projectId, options = {}) {
|
|
|
1601
2421
|
for (const frame of parseSseChunk(buffer)) {
|
|
1602
2422
|
if (frame.type === "text" && frame.text) assistantContent += frame.text;
|
|
1603
2423
|
else if (frame.type === "metadata") sources = (_b = frame.sources) != null ? _b : [];
|
|
2424
|
+
else if (frame.type === "observability") trace = frame.data;
|
|
1604
2425
|
}
|
|
1605
2426
|
}
|
|
1606
|
-
const
|
|
2427
|
+
const finalMsg = {
|
|
1607
2428
|
id: assistantMessageId,
|
|
1608
2429
|
role: "assistant",
|
|
1609
2430
|
content: assistantContent,
|
|
1610
2431
|
sources: sources.length > 0 ? sources : void 0,
|
|
1611
|
-
uiTransformation: uiTransformation
|
|
2432
|
+
uiTransformation: uiTransformation != null ? uiTransformation : void 0,
|
|
2433
|
+
trace,
|
|
1612
2434
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1613
2435
|
};
|
|
1614
|
-
|
|
2436
|
+
setMessages(
|
|
2437
|
+
(prev) => prev.map((msg) => msg.id === assistantMessageId ? finalMsg : msg)
|
|
2438
|
+
);
|
|
2439
|
+
onReply == null ? void 0 : onReply(finalMsg);
|
|
1615
2440
|
} catch (err) {
|
|
1616
2441
|
const msg = err instanceof Error ? err.message : "Something went wrong. Please try again.";
|
|
1617
2442
|
setError(msg);
|
|
@@ -1622,12 +2447,12 @@ function useRagChat(projectId, options = {}) {
|
|
|
1622
2447
|
},
|
|
1623
2448
|
[apiUrl, isLoading, namespace, onError, onReply, projectId, setMessages]
|
|
1624
2449
|
);
|
|
1625
|
-
const clear = (0,
|
|
2450
|
+
const clear = (0, import_react10.useCallback)(() => {
|
|
1626
2451
|
setMessages([]);
|
|
1627
2452
|
setError(null);
|
|
1628
2453
|
if (persist) localStorage.removeItem(storageKey);
|
|
1629
2454
|
}, [persist, setMessages, storageKey]);
|
|
1630
|
-
const retry = (0,
|
|
2455
|
+
const retry = (0, import_react10.useCallback)(async () => {
|
|
1631
2456
|
if (lastInputRef.current) {
|
|
1632
2457
|
const latestMessage = messagesRef.current[messagesRef.current.length - 1];
|
|
1633
2458
|
await sendMessage(lastInputRef.current, {
|
|
@@ -1647,6 +2472,7 @@ function useRagChat(projectId, options = {}) {
|
|
|
1647
2472
|
}
|
|
1648
2473
|
|
|
1649
2474
|
// src/components/ChatWindow.tsx
|
|
2475
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1650
2476
|
function ChatWindow({
|
|
1651
2477
|
className = "",
|
|
1652
2478
|
style,
|
|
@@ -1661,20 +2487,21 @@ function ChatWindow({
|
|
|
1661
2487
|
}) {
|
|
1662
2488
|
var _a;
|
|
1663
2489
|
const { ui, projectId } = useConfig();
|
|
1664
|
-
const [input, setInput] = (0,
|
|
1665
|
-
const [mounted, setMounted] = (0,
|
|
1666
|
-
const [viewportSize, setViewportSize] = (0,
|
|
1667
|
-
const windowRef = (0,
|
|
1668
|
-
const bottomRef = (0,
|
|
1669
|
-
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);
|
|
1670
2496
|
const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
|
|
1671
2497
|
namespace: projectId
|
|
1672
2498
|
});
|
|
1673
|
-
const [suggestions, setSuggestions] = (0,
|
|
1674
|
-
const [isSuggesting, setIsSuggesting] = (0,
|
|
1675
|
-
const [isListening, setIsListening] = (0,
|
|
1676
|
-
const
|
|
1677
|
-
(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)(() => {
|
|
1678
2505
|
if (typeof window !== "undefined") {
|
|
1679
2506
|
const win = window;
|
|
1680
2507
|
const SpeechRecognition = win.SpeechRecognition || win.webkitSpeechRecognition;
|
|
@@ -1720,10 +2547,10 @@ function ChatWindow({
|
|
|
1720
2547
|
}
|
|
1721
2548
|
}
|
|
1722
2549
|
};
|
|
1723
|
-
(0,
|
|
2550
|
+
(0, import_react11.useEffect)(() => {
|
|
1724
2551
|
setMounted(true);
|
|
1725
2552
|
}, []);
|
|
1726
|
-
(0,
|
|
2553
|
+
(0, import_react11.useEffect)(() => {
|
|
1727
2554
|
const element = windowRef.current;
|
|
1728
2555
|
if (!element || typeof ResizeObserver === "undefined") return;
|
|
1729
2556
|
const resolveViewportSize = (width) => {
|
|
@@ -1739,13 +2566,13 @@ function ChatWindow({
|
|
|
1739
2566
|
observer.observe(element);
|
|
1740
2567
|
return () => observer.disconnect();
|
|
1741
2568
|
}, []);
|
|
1742
|
-
(0,
|
|
2569
|
+
(0, import_react11.useEffect)(() => {
|
|
1743
2570
|
var _a2;
|
|
1744
2571
|
if (messages.length > 0 || isLoading) {
|
|
1745
2572
|
(_a2 = bottomRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth" });
|
|
1746
2573
|
}
|
|
1747
2574
|
}, [messages, isLoading]);
|
|
1748
|
-
const sendMessage = (0,
|
|
2575
|
+
const sendMessage = (0, import_react11.useCallback)(async () => {
|
|
1749
2576
|
var _a2;
|
|
1750
2577
|
const text = input.trim();
|
|
1751
2578
|
if (!text || isLoading) return;
|
|
@@ -1775,7 +2602,7 @@ function ChatWindow({
|
|
|
1775
2602
|
const isEmpty = messages.length === 0;
|
|
1776
2603
|
const currentRadius = BORDER_RADIUS_MAP[ui.borderRadius || "xl"];
|
|
1777
2604
|
const isGlass = ui.visualStyle !== "solid";
|
|
1778
|
-
(0,
|
|
2605
|
+
(0, import_react11.useEffect)(() => {
|
|
1779
2606
|
if (input.trim().length < 3) {
|
|
1780
2607
|
return;
|
|
1781
2608
|
}
|
|
@@ -1799,194 +2626,273 @@ function ChatWindow({
|
|
|
1799
2626
|
}, 800);
|
|
1800
2627
|
return () => clearTimeout(timer);
|
|
1801
2628
|
}, [input, projectId]);
|
|
1802
|
-
return /* @__PURE__ */
|
|
2629
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1803
2630
|
"div",
|
|
1804
2631
|
{
|
|
1805
2632
|
ref: windowRef,
|
|
1806
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}`,
|
|
1807
|
-
style: __spreadValues({ "--primary": ui.primaryColor, "--accent": ui.accentColor }, style)
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
{
|
|
1812
|
-
onMouseDown: onResizeStart,
|
|
1813
|
-
className: "absolute top-0 left-0 w-6 h-6 cursor-nw-resize z-[100] group flex items-start justify-start p-1",
|
|
1814
|
-
title: "Drag to resize"
|
|
1815
|
-
},
|
|
1816
|
-
/* @__PURE__ */ import_react9.default.createElement("div", { className: "w-2.5 h-2.5 border-t-2 border-l-2 border-slate-300 dark:border-white/20 group-hover:border-slate-500 dark:group-hover:border-white/50 transition-colors rounded-tl-[2px]" })
|
|
1817
|
-
),
|
|
1818
|
-
/* @__PURE__ */ import_react9.default.createElement(
|
|
1819
|
-
"div",
|
|
1820
|
-
{
|
|
1821
|
-
className: "flex items-center justify-between px-5 py-4 border-b border-slate-200 dark:border-white/10",
|
|
1822
|
-
style: { background: `linear-gradient(135deg, ${ui.primaryColor}15, ${ui.accentColor}10)` }
|
|
1823
|
-
},
|
|
1824
|
-
/* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center gap-3" }, ui.logoUrl ? (
|
|
1825
|
-
// eslint-disable-next-line @next/next/no-img-element
|
|
1826
|
-
/* @__PURE__ */ import_react9.default.createElement("img", { src: ui.logoUrl, alt: "logo", className: "w-8 h-8 rounded-lg object-cover" })
|
|
1827
|
-
) : /* @__PURE__ */ import_react9.default.createElement(
|
|
1828
|
-
"div",
|
|
1829
|
-
{
|
|
1830
|
-
className: `w-9 h-9 flex items-center justify-center shadow-md ${ui.borderRadius === "full" ? "rounded-full" : "rounded-xl"}`,
|
|
1831
|
-
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` }
|
|
1832
|
-
},
|
|
1833
|
-
/* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Bot, { className: "w-5 h-5 text-white" })
|
|
1834
|
-
), /* @__PURE__ */ import_react9.default.createElement("div", null, /* @__PURE__ */ import_react9.default.createElement("h2", { className: "text-slate-900 dark:text-white font-semibold text-sm leading-tight" }, ui.title), ui.poweredBy && /* @__PURE__ */ import_react9.default.createElement("p", { className: "text-slate-500 dark:text-white/40 text-[11px] leading-tight" }, `Powered by ${ui.poweredBy}`))),
|
|
1835
|
-
/* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ import_react9.default.createElement("span", { className: "flex items-center gap-1 text-[10px] text-emerald-500 dark:text-emerald-400 mr-2" }, /* @__PURE__ */ import_react9.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500 dark:bg-emerald-400 animate-pulse" }), "Online"), /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center bg-slate-100/50 dark:bg-white/5 rounded-lg p-0.5 border border-slate-200/50 dark:border-white/5" }, mounted && messages.length > 0 && /* @__PURE__ */ import_react9.default.createElement(
|
|
1836
|
-
"button",
|
|
1837
|
-
{
|
|
1838
|
-
onClick: clearHistory,
|
|
1839
|
-
title: "Clear conversation",
|
|
1840
|
-
className: "w-7 h-7 rounded-md flex items-center justify-center text-slate-400 hover:text-rose-500 dark:text-white/40 dark:hover:text-rose-400 hover:bg-white dark:hover:bg-white/10 transition-all cursor-pointer"
|
|
1841
|
-
},
|
|
1842
|
-
/* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Trash2, { className: "w-3.5 h-3.5" })
|
|
1843
|
-
), isResized && onResetResize && /* @__PURE__ */ import_react9.default.createElement(
|
|
1844
|
-
"button",
|
|
1845
|
-
{
|
|
1846
|
-
onClick: onResetResize,
|
|
1847
|
-
title: "Reset to default size",
|
|
1848
|
-
className: "w-7 h-7 rounded-md flex items-center justify-center text-slate-400 hover:text-blue-500 dark:text-white/40 dark:hover:text-blue-400 hover:bg-white dark:hover:bg-white/10 transition-all cursor-pointer"
|
|
1849
|
-
},
|
|
1850
|
-
/* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.RotateCcw, { className: "w-3.5 h-3.5" })
|
|
1851
|
-
), onMaximize && /* @__PURE__ */ import_react9.default.createElement(
|
|
1852
|
-
"button",
|
|
1853
|
-
{
|
|
1854
|
-
onClick: onMaximize,
|
|
1855
|
-
title: isMaximized ? "Minimize" : "Maximize",
|
|
1856
|
-
className: "w-7 h-7 rounded-md flex items-center justify-center text-slate-400 hover:text-blue-500 dark:text-white/40 dark:hover:text-blue-400 hover:bg-white dark:hover:bg-white/10 transition-all cursor-pointer"
|
|
1857
|
-
},
|
|
1858
|
-
isMaximized ? /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Minimize2, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Maximize2, { className: "w-3.5 h-3.5" })
|
|
1859
|
-
), showClose && onClose && /* @__PURE__ */ import_react9.default.createElement(
|
|
1860
|
-
"button",
|
|
1861
|
-
{
|
|
1862
|
-
onClick: onClose,
|
|
1863
|
-
title: "Close chat",
|
|
1864
|
-
className: "w-7 h-7 rounded-md flex items-center justify-center text-slate-400 hover:text-slate-600 dark:text-white/40 dark:hover:text-white/70 hover:bg-white dark:hover:bg-white/10 transition-all cursor-pointer"
|
|
1865
|
-
},
|
|
1866
|
-
/* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.X, { className: "w-4 h-4" })
|
|
1867
|
-
)))
|
|
1868
|
-
),
|
|
1869
|
-
/* @__PURE__ */ import_react9.default.createElement("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5 scrollbar-thin scrollbar-thumb-slate-200 dark:scrollbar-thumb-white/10 scrollbar-track-transparent min-h-0 bg-slate-50 dark:bg-transparent" }, !mounted || isEmpty ? (
|
|
1870
|
-
/* Welcome state */
|
|
1871
|
-
/* @__PURE__ */ import_react9.default.createElement("div", { className: "h-full flex flex-col items-center justify-center text-center gap-4 px-6 py-12" }, /* @__PURE__ */ import_react9.default.createElement(
|
|
1872
|
-
"div",
|
|
1873
|
-
{
|
|
1874
|
-
className: `w-16 h-16 flex items-center justify-center shadow-lg ${ui.borderRadius === "full" ? "rounded-full" : "rounded-2xl"}`,
|
|
1875
|
-
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` }
|
|
1876
|
-
},
|
|
1877
|
-
/* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Sparkles, { className: "w-8 h-8 text-white" })
|
|
1878
|
-
), /* @__PURE__ */ import_react9.default.createElement("div", null, /* @__PURE__ */ import_react9.default.createElement("p", { className: "text-slate-800 dark:text-white/80 font-medium leading-relaxed" }, ui.welcomeMessage), /* @__PURE__ */ import_react9.default.createElement("p", { className: "text-slate-500 dark:text-white/30 text-sm mt-2" }, "Ask a question to get started")), /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex flex-wrap gap-2 justify-center mt-2" }, CHAT_SUGGESTIONS.map(
|
|
1879
|
-
(suggestion) => /* @__PURE__ */ import_react9.default.createElement(
|
|
1880
|
-
"button",
|
|
2634
|
+
style: __spreadValues({ "--primary": ui.primaryColor, "--accent": ui.accentColor }, style),
|
|
2635
|
+
children: [
|
|
2636
|
+
onResizeStart && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2637
|
+
"div",
|
|
1881
2638
|
{
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
(_a2 = inputRef.current) == null ? void 0 : _a2.focus();
|
|
1887
|
-
},
|
|
1888
|
-
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"
|
|
1889
|
-
},
|
|
1890
|
-
suggestion
|
|
1891
|
-
)
|
|
1892
|
-
)))
|
|
1893
|
-
) : messages.map((msg, index) => /* @__PURE__ */ import_react9.default.createElement(
|
|
1894
|
-
MessageBubble,
|
|
1895
|
-
{
|
|
1896
|
-
key: msg.id,
|
|
1897
|
-
message: msg,
|
|
1898
|
-
sources: msg.sources,
|
|
1899
|
-
isStreaming: isLoading && index === messages.length - 1 && msg.role === "assistant",
|
|
1900
|
-
primaryColor: ui.primaryColor,
|
|
1901
|
-
accentColor: ui.accentColor,
|
|
1902
|
-
onAddToCart,
|
|
1903
|
-
viewportSize
|
|
1904
|
-
}
|
|
1905
|
-
)), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */ import_react9.default.createElement(
|
|
1906
|
-
MessageBubble,
|
|
1907
|
-
{
|
|
1908
|
-
message: { id: "loading", role: "assistant", content: "", createdAt: (/* @__PURE__ */ new Date()).toISOString() },
|
|
1909
|
-
isStreaming: true,
|
|
1910
|
-
primaryColor: ui.primaryColor,
|
|
1911
|
-
accentColor: ui.accentColor,
|
|
1912
|
-
onAddToCart,
|
|
1913
|
-
viewportSize
|
|
1914
|
-
}
|
|
1915
|
-
), error && /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center gap-2 text-rose-500 dark:text-rose-400 text-sm bg-rose-50 dark:bg-rose-400/10 border border-rose-200 dark:border-rose-400/20 rounded-xl px-4 py-3" }, /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.TriangleAlert, { className: "w-4 h-4 flex-shrink-0" }), /* @__PURE__ */ import_react9.default.createElement("span", null, error)), /* @__PURE__ */ import_react9.default.createElement("div", { ref: bottomRef })),
|
|
1916
|
-
/* @__PURE__ */ import_react9.default.createElement("div", { className: `px-4 pb-4 pt-2 border-t border-slate-200 dark:border-white/10 ${isGlass ? "bg-transparent" : "bg-white dark:bg-[#0f0f1a]"}` }, (suggestions.length > 0 || isSuggesting) && !isLoading && /* @__PURE__ */ import_react9.default.createElement("div", { className: "mb-3 flex flex-wrap gap-2 animate-in fade-in slide-in-from-bottom-2 duration-300" }, suggestions.map((suggestion) => /* @__PURE__ */ import_react9.default.createElement(
|
|
1917
|
-
"button",
|
|
1918
|
-
{
|
|
1919
|
-
key: suggestion,
|
|
1920
|
-
onClick: () => {
|
|
1921
|
-
var _a2;
|
|
1922
|
-
setInput(suggestion);
|
|
1923
|
-
setSuggestions([]);
|
|
1924
|
-
(_a2 = inputRef.current) == null ? void 0 : _a2.focus();
|
|
1925
|
-
},
|
|
1926
|
-
className: "flex items-center gap-1.5 px-3 py-1.5 rounded-xl text-[11px] font-medium bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 text-slate-600 dark:text-white/60 hover:text-slate-900 dark:hover:text-white/90 hover:border-slate-300 dark:hover:border-white/20 transition-all shadow-sm cursor-pointer group"
|
|
1927
|
-
},
|
|
1928
|
-
/* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Sparkles, { className: "w-3 h-3 text-amber-400" }),
|
|
1929
|
-
suggestion
|
|
1930
|
-
)), isSuggesting && suggestions.length === 0 && /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center gap-1.5 px-3 py-1.5 rounded-xl text-[11px] font-medium text-slate-400 dark:text-white/30 animate-pulse" }, /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Sparkles, { className: "w-3 h-3" }), "Thinking...")), /* @__PURE__ */ import_react9.default.createElement("div", { className: `flex items-end gap-2 bg-slate-50 dark:bg-white/5 border border-slate-200 dark:border-white/10 p-2 focus-within:border-slate-300 dark:focus-within:border-white/20 transition-all ${ui.borderRadius === "full" ? "rounded-3xl" : "rounded-2xl"}` }, /* @__PURE__ */ import_react9.default.createElement(
|
|
1931
|
-
"textarea",
|
|
1932
|
-
{
|
|
1933
|
-
ref: inputRef,
|
|
1934
|
-
value: input,
|
|
1935
|
-
onChange: (e) => {
|
|
1936
|
-
const val = e.target.value;
|
|
1937
|
-
setInput(val);
|
|
1938
|
-
if (val.trim().length < 3) {
|
|
1939
|
-
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]" })
|
|
1940
2643
|
}
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
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
|
+
}
|
|
1972
2878
|
);
|
|
1973
2879
|
}
|
|
1974
2880
|
|
|
1975
2881
|
// src/components/ChatWidget.tsx
|
|
2882
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1976
2883
|
var DEFAULT_DIMENSIONS = { width: 380, height: 600 };
|
|
1977
2884
|
function ChatWidget({ position = "bottom-right", onAddToCart }) {
|
|
1978
2885
|
const { ui } = useConfig();
|
|
1979
|
-
const [isOpen, setIsOpen] = (0,
|
|
1980
|
-
const [hasUnread, setHasUnread] = (0,
|
|
1981
|
-
const [dimensions, setDimensions] = (0,
|
|
1982
|
-
const [isResizing, setIsResizing] = (0,
|
|
1983
|
-
const [isMaximized, setIsMaximized] = (0,
|
|
1984
|
-
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);
|
|
1985
2892
|
if (ui.showWidget === false) return null;
|
|
1986
2893
|
const positionClass = position === "bottom-left" ? "bottom-6 left-6" : "bottom-6 right-6";
|
|
1987
2894
|
const windowPositionClass = position === "bottom-left" ? "bottom-20 left-6" : "bottom-20 right-6";
|
|
1988
2895
|
const handleOpen = () => {
|
|
1989
|
-
console.log("ChatWidget: Opening...");
|
|
1990
2896
|
setIsOpen(true);
|
|
1991
2897
|
setHasUnread(false);
|
|
1992
2898
|
};
|
|
@@ -2031,186 +2937,67 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
|
|
|
2031
2937
|
}
|
|
2032
2938
|
};
|
|
2033
2939
|
const isResized = dimensions.width !== DEFAULT_DIMENSIONS.width || dimensions.height !== DEFAULT_DIMENSIONS.height;
|
|
2034
|
-
return /* @__PURE__ */
|
|
2035
|
-
|
|
2036
|
-
{
|
|
2037
|
-
className: `fixed z-[9998] max-w-[calc(100vw-3rem)] ease-in-out ${windowPositionClass} ${isOpen ? "opacity-100 translate-y-0 pointer-events-auto" : "opacity-0 translate-y-4 pointer-events-none"} ${isResizing ? "" : "transition-all duration-300"}`,
|
|
2038
|
-
style: {
|
|
2039
|
-
width: `${dimensions.width}px`,
|
|
2040
|
-
height: `${dimensions.height}px`,
|
|
2041
|
-
maxHeight: "calc(100vh - 6rem)"
|
|
2042
|
-
}
|
|
2043
|
-
},
|
|
2044
|
-
/* @__PURE__ */ import_react10.default.createElement(
|
|
2045
|
-
ChatWindow,
|
|
2046
|
-
{
|
|
2047
|
-
className: "h-full relative z-10",
|
|
2048
|
-
showClose: true,
|
|
2049
|
-
onClose: () => setIsOpen(false),
|
|
2050
|
-
onResizeStart: ui.allowResize !== false ? handleResizeStart : void 0,
|
|
2051
|
-
onResetResize: ui.allowResize !== false ? handleResetResize : void 0,
|
|
2052
|
-
isResized,
|
|
2053
|
-
onMaximize: ui.allowResize !== false ? handleMaximize : void 0,
|
|
2054
|
-
isMaximized,
|
|
2055
|
-
onAddToCart
|
|
2056
|
-
}
|
|
2057
|
-
),
|
|
2058
|
-
/* @__PURE__ */ import_react10.default.createElement(
|
|
2940
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
2941
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
2059
2942
|
"div",
|
|
2060
2943
|
{
|
|
2061
|
-
className: `
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
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
|
+
]
|
|
2077
2972
|
}
|
|
2078
2973
|
),
|
|
2079
|
-
/* @__PURE__ */
|
|
2080
|
-
"span",
|
|
2081
|
-
{
|
|
2082
|
-
className: `transition-transform duration-300 ${isOpen ? "rotate-90 scale-90" : "rotate-0 scale-100"}`
|
|
2083
|
-
},
|
|
2084
|
-
isOpen ? /* @__PURE__ */ import_react10.default.createElement(import_lucide_react6.X, { className: "w-6 h-6 text-white" }) : /* @__PURE__ */ import_react10.default.createElement(import_lucide_react6.MessageSquare, { className: "w-6 h-6 text-white" })
|
|
2085
|
-
),
|
|
2086
|
-
hasUnread && !isOpen && /* @__PURE__ */ import_react10.default.createElement("span", { className: "absolute top-0 right-0 w-4 h-4 bg-rose-500 rounded-full border-2 border-white flex items-center justify-center text-[9px] font-bold text-white" }, "1")
|
|
2087
|
-
));
|
|
2088
|
-
}
|
|
2089
|
-
|
|
2090
|
-
// src/components/DocumentUpload.tsx
|
|
2091
|
-
var import_react11 = __toESM(require("react"));
|
|
2092
|
-
var import_lucide_react7 = require("lucide-react");
|
|
2093
|
-
function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
|
|
2094
|
-
const { ui } = useConfig();
|
|
2095
|
-
const [fileStates, setFileStates] = (0, import_react11.useState)([]);
|
|
2096
|
-
const [isDragging, setIsDragging] = (0, import_react11.useState)(false);
|
|
2097
|
-
const fileInputRef = (0, import_react11.useRef)(null);
|
|
2098
|
-
const addFiles = (files) => {
|
|
2099
|
-
const newStates = files.map((file) => ({ file, status: "idle" }));
|
|
2100
|
-
setFileStates((prev) => [...prev, ...newStates]);
|
|
2101
|
-
};
|
|
2102
|
-
const removeFile = (index) => {
|
|
2103
|
-
setFileStates((prev) => prev.filter((_, i) => i !== index));
|
|
2104
|
-
};
|
|
2105
|
-
const onDragOver = (e) => {
|
|
2106
|
-
e.preventDefault();
|
|
2107
|
-
setIsDragging(true);
|
|
2108
|
-
};
|
|
2109
|
-
const onDragLeave = () => {
|
|
2110
|
-
setIsDragging(false);
|
|
2111
|
-
};
|
|
2112
|
-
const onDrop = (e) => {
|
|
2113
|
-
e.preventDefault();
|
|
2114
|
-
setIsDragging(false);
|
|
2115
|
-
if (e.dataTransfer.files) {
|
|
2116
|
-
addFiles(Array.from(e.dataTransfer.files));
|
|
2117
|
-
}
|
|
2118
|
-
};
|
|
2119
|
-
const onFileSelect = (e) => {
|
|
2120
|
-
if (e.target.files) {
|
|
2121
|
-
addFiles(Array.from(e.target.files));
|
|
2122
|
-
}
|
|
2123
|
-
};
|
|
2124
|
-
const uploadFiles = async () => {
|
|
2125
|
-
const idleFiles = fileStates.filter((s) => s.status === "idle");
|
|
2126
|
-
if (idleFiles.length === 0) return;
|
|
2127
|
-
setFileStates((prev) => prev.map((s) => s.status === "idle" ? __spreadProps(__spreadValues({}, s), { status: "uploading" }) : s));
|
|
2128
|
-
const formData = new FormData();
|
|
2129
|
-
idleFiles.forEach((s) => formData.append("files", s.file));
|
|
2130
|
-
if (namespace) formData.append("namespace", namespace);
|
|
2131
|
-
try {
|
|
2132
|
-
const response = await fetch("/api/upload", {
|
|
2133
|
-
method: "POST",
|
|
2134
|
-
body: formData
|
|
2135
|
-
});
|
|
2136
|
-
const result = await response.json();
|
|
2137
|
-
if (!response.ok) throw new Error(result.error || "Upload failed");
|
|
2138
|
-
setFileStates((prev) => prev.map((s) => s.status === "uploading" ? __spreadProps(__spreadValues({}, s), { status: "success" }) : s));
|
|
2139
|
-
if (onUploadComplete) onUploadComplete(result);
|
|
2140
|
-
} catch (err) {
|
|
2141
|
-
const message = err instanceof Error ? err.message : "Upload failed";
|
|
2142
|
-
setFileStates((prev) => prev.map((s) => s.status === "uploading" ? __spreadProps(__spreadValues({}, s), { status: "error", error: message }) : s));
|
|
2143
|
-
}
|
|
2144
|
-
};
|
|
2145
|
-
const isUploading = fileStates.some((s) => s.status === "uploading");
|
|
2146
|
-
const hasIdle = fileStates.some((s) => s.status === "idle");
|
|
2147
|
-
return /* @__PURE__ */ import_react11.default.createElement(
|
|
2148
|
-
"div",
|
|
2149
|
-
{
|
|
2150
|
-
className: `p-6 border-2 border-dashed transition-all duration-300 rounded-2xl ${isDragging ? "border-emerald-500 bg-emerald-50/50 dark:bg-emerald-500/5" : "border-slate-200 dark:border-white/10 bg-white dark:bg-white/5"} ${className}`,
|
|
2151
|
-
onDragOver,
|
|
2152
|
-
onDragLeave,
|
|
2153
|
-
onDrop
|
|
2154
|
-
},
|
|
2155
|
-
/* @__PURE__ */ import_react11.default.createElement("div", { className: "flex flex-col items-center justify-center text-center" }, /* @__PURE__ */ import_react11.default.createElement(
|
|
2156
|
-
"div",
|
|
2157
|
-
{
|
|
2158
|
-
className: "w-12 h-12 rounded-full flex items-center justify-center mb-4 shadow-sm",
|
|
2159
|
-
style: { background: `linear-gradient(135deg, ${ui.primaryColor}20, ${ui.accentColor}20)` }
|
|
2160
|
-
},
|
|
2161
|
-
/* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.Upload, { className: "w-6 h-6", style: { color: ui.primaryColor } })
|
|
2162
|
-
), /* @__PURE__ */ import_react11.default.createElement("h3", { className: "text-slate-900 dark:text-white font-semibold mb-1" }, "Upload Documents"), /* @__PURE__ */ import_react11.default.createElement("p", { className: "text-slate-500 dark:text-white/40 text-sm mb-6 max-w-xs" }, "Drag and drop PDF, DOCX, TXT, or JSON files to train your AI on your own data."), /* @__PURE__ */ import_react11.default.createElement(
|
|
2974
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
2163
2975
|
"button",
|
|
2164
2976
|
{
|
|
2165
|
-
onClick: () =>
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
accept: ".pdf,.docx,.txt,.md,.json,.csv"
|
|
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
|
+
]
|
|
2187
2998
|
}
|
|
2188
|
-
)
|
|
2189
|
-
|
|
2190
|
-
"div",
|
|
2191
|
-
{
|
|
2192
|
-
key: i,
|
|
2193
|
-
className: "flex items-center justify-between p-3 rounded-xl bg-slate-50 dark:bg-white/5 border border-slate-100 dark:border-white/10"
|
|
2194
|
-
},
|
|
2195
|
-
/* @__PURE__ */ import_react11.default.createElement("div", { className: "flex items-center gap-3 overflow-hidden" }, /* @__PURE__ */ import_react11.default.createElement("div", { className: "w-8 h-8 rounded-lg bg-white dark:bg-white/10 flex items-center justify-center shadow-sm" }, /* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.File, { className: "w-4 h-4 text-slate-400" })), /* @__PURE__ */ import_react11.default.createElement("div", { className: "truncate" }, /* @__PURE__ */ import_react11.default.createElement("p", { className: "text-xs font-medium text-slate-700 dark:text-white/80 truncate" }, state.file.name), /* @__PURE__ */ import_react11.default.createElement("p", { className: "text-[10px] text-slate-400" }, (state.file.size / 1024).toFixed(1), " KB"))),
|
|
2196
|
-
/* @__PURE__ */ import_react11.default.createElement("div", { className: "flex items-center gap-2" }, state.status === "uploading" && /* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.Loader2, { className: "w-4 h-4 text-slate-400 animate-spin" }), state.status === "success" && /* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.CheckCircle, { className: "w-4 h-4 text-emerald-500" }), state.status === "error" && /* @__PURE__ */ import_react11.default.createElement("div", { title: state.error }, /* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.AlertCircle, { className: "w-4 h-4 text-rose-500" })), state.status !== "uploading" && /* @__PURE__ */ import_react11.default.createElement(
|
|
2197
|
-
"button",
|
|
2198
|
-
{
|
|
2199
|
-
onClick: () => removeFile(i),
|
|
2200
|
-
className: "p-1 rounded-md hover:bg-slate-200 dark:hover:bg-white/10 transition-colors"
|
|
2201
|
-
},
|
|
2202
|
-
/* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.X, { className: "w-3.5 h-3.5 text-slate-400" })
|
|
2203
|
-
))
|
|
2204
|
-
)), hasIdle && !isUploading && /* @__PURE__ */ import_react11.default.createElement(
|
|
2205
|
-
"button",
|
|
2206
|
-
{
|
|
2207
|
-
onClick: uploadFiles,
|
|
2208
|
-
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]",
|
|
2209
|
-
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` }
|
|
2210
|
-
},
|
|
2211
|
-
"Start Upload"
|
|
2212
|
-
))
|
|
2213
|
-
);
|
|
2999
|
+
)
|
|
3000
|
+
] });
|
|
2214
3001
|
}
|
|
2215
3002
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2216
3003
|
0 && (module.exports = {
|
|
@@ -2219,7 +3006,9 @@ function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
|
|
|
2219
3006
|
ConfigProvider,
|
|
2220
3007
|
DocumentUpload,
|
|
2221
3008
|
MessageBubble,
|
|
3009
|
+
ObservabilityPanel,
|
|
2222
3010
|
SourceCard,
|
|
3011
|
+
addSynonyms,
|
|
2223
3012
|
useConfig,
|
|
2224
3013
|
useRagChat
|
|
2225
3014
|
});
|