@retrivora-ai/rag-engine 1.8.1 → 1.8.2
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/{MultiTablePostgresProvider-YY7LPNJK.mjs → MultiTablePostgresProvider-ZLGSKTJR.mjs} +1 -1
- package/dist/chunk-ICKRMZQK.mjs +76 -0
- package/dist/{chunk-BFYLQYQU.mjs → chunk-LZVVLSDN.mjs} +192 -100
- package/dist/{chunk-R3RGUMHE.mjs → chunk-OZFBG4BA.mjs} +121 -48
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +368 -147
- package/dist/handlers/index.mjs +4 -1
- package/dist/{index-BV0z5mb6.d.mts → index-BwpcaziY.d.ts} +4 -2
- package/dist/{index-1Z4GuYBi.d.ts → index-D3V9Et2M.d.mts} +4 -2
- package/dist/index.d.mts +23 -3
- package/dist/index.d.ts +23 -3
- package/dist/index.js +1143 -790
- package/dist/index.mjs +1065 -770
- package/dist/server.d.mts +15 -25
- package/dist/server.d.ts +15 -25
- package/dist/server.js +366 -147
- package/dist/server.mjs +3 -2
- package/package.json +4 -2
- package/src/app/api/upload/route.ts +4 -0
- package/src/app/constants.tsx +2 -2
- 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/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 +140 -0
- package/src/components/MessageBubble.tsx +88 -1010
- 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 +344 -0
- package/src/components/VisualizationRenderer.tsx +48 -26
- package/src/core/Pipeline.ts +186 -76
- 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/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/index.js
CHANGED
|
@@ -64,58 +64,282 @@ __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_react15 = __toESM(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_react14 = __toESM(require("react"));
|
|
81
|
+
var import_lucide_react7 = require("lucide-react");
|
|
82
|
+
|
|
83
|
+
// src/components/DocumentUpload.tsx
|
|
84
|
+
var import_react2 = __toESM(require("react"));
|
|
85
|
+
var import_lucide_react = require("lucide-react");
|
|
86
|
+
|
|
87
|
+
// src/components/ConfigProvider.tsx
|
|
88
|
+
var import_react = __toESM(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 ConfigContext = (0, import_react.createContext)(DEFAULT_CONFIG);
|
|
141
|
+
function ConfigProvider({
|
|
142
|
+
config,
|
|
143
|
+
children
|
|
144
|
+
}) {
|
|
145
|
+
const merged = {
|
|
146
|
+
projectId: (config == null ? void 0 : config.projectId) || DEFAULT_CONFIG.projectId,
|
|
147
|
+
ui: mergeDefined(DEFAULT_CONFIG.ui, config == null ? void 0 : config.ui),
|
|
148
|
+
embedding: config == null ? void 0 : config.embedding
|
|
149
|
+
};
|
|
150
|
+
return /* @__PURE__ */ import_react.default.createElement(ConfigContext.Provider, { value: merged }, children);
|
|
151
|
+
}
|
|
152
|
+
function useConfig() {
|
|
153
|
+
return (0, import_react.useContext)(ConfigContext);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// src/components/DocumentUpload.tsx
|
|
157
|
+
function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
|
|
158
|
+
var _a;
|
|
159
|
+
const { ui, embedding } = useConfig();
|
|
160
|
+
const [fileStates, setFileStates] = (0, import_react2.useState)([]);
|
|
161
|
+
const [isDragging, setIsDragging] = (0, import_react2.useState)(false);
|
|
162
|
+
const fileInputRef = (0, import_react2.useRef)(null);
|
|
163
|
+
const MULTI_DIMENSION_MODELS = {
|
|
164
|
+
"text-embedding-3-small": [512, 1536],
|
|
165
|
+
"text-embedding-3-large": [256, 1024, 3072],
|
|
166
|
+
"nomic-embed-text": [64, 128, 256, 512, 768]
|
|
167
|
+
};
|
|
168
|
+
const COMMON_DIMENSIONS = [64, 128, 256, 384, 512, 768, 1024, 1536, 3072];
|
|
169
|
+
const currentModel = (embedding == null ? void 0 : embedding.model) || "unknown";
|
|
170
|
+
const defaultDimension = (embedding == null ? void 0 : embedding.dimensions) || 1536;
|
|
171
|
+
let availableDimensions = (_a = Object.entries(MULTI_DIMENSION_MODELS).find(([k]) => currentModel.includes(k))) == null ? void 0 : _a[1];
|
|
172
|
+
if (!availableDimensions) {
|
|
173
|
+
availableDimensions = COMMON_DIMENSIONS.includes(defaultDimension) ? COMMON_DIMENSIONS : [...COMMON_DIMENSIONS, defaultDimension].sort((a, b) => a - b);
|
|
174
|
+
}
|
|
175
|
+
const isChangeable = true;
|
|
176
|
+
const [dimension, setDimension] = (0, import_react2.useState)(defaultDimension);
|
|
177
|
+
const addFiles = (files) => {
|
|
178
|
+
const newStates = files.map((file) => ({ file, status: "idle" }));
|
|
179
|
+
setFileStates((prev) => [...prev, ...newStates]);
|
|
180
|
+
};
|
|
181
|
+
const removeFile = (index) => {
|
|
182
|
+
setFileStates((prev) => prev.filter((_, i) => i !== index));
|
|
183
|
+
};
|
|
184
|
+
const onDragOver = (e) => {
|
|
185
|
+
e.preventDefault();
|
|
186
|
+
setIsDragging(true);
|
|
187
|
+
};
|
|
188
|
+
const onDragLeave = () => {
|
|
189
|
+
setIsDragging(false);
|
|
190
|
+
};
|
|
191
|
+
const onDrop = (e) => {
|
|
192
|
+
e.preventDefault();
|
|
193
|
+
setIsDragging(false);
|
|
194
|
+
if (e.dataTransfer.files) {
|
|
195
|
+
addFiles(Array.from(e.dataTransfer.files));
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
const onFileSelect = (e) => {
|
|
199
|
+
if (e.target.files) {
|
|
200
|
+
addFiles(Array.from(e.target.files));
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
const uploadFiles = async () => {
|
|
204
|
+
const idleFiles = fileStates.filter((s) => s.status === "idle");
|
|
205
|
+
if (idleFiles.length === 0) return;
|
|
206
|
+
setFileStates((prev) => prev.map((s) => s.status === "idle" ? __spreadProps(__spreadValues({}, s), { status: "uploading" }) : s));
|
|
207
|
+
const formData = new FormData();
|
|
208
|
+
idleFiles.forEach((s) => formData.append("files", s.file));
|
|
209
|
+
if (namespace) formData.append("namespace", namespace);
|
|
210
|
+
formData.append("dimension", dimension.toString());
|
|
211
|
+
try {
|
|
212
|
+
const response = await fetch("/api/upload", {
|
|
213
|
+
method: "POST",
|
|
214
|
+
body: formData
|
|
215
|
+
});
|
|
216
|
+
const result = await response.json();
|
|
217
|
+
if (!response.ok) throw new Error(result.error || "Upload failed");
|
|
218
|
+
setFileStates((prev) => prev.map((s) => s.status === "uploading" ? __spreadProps(__spreadValues({}, s), { status: "success" }) : s));
|
|
219
|
+
if (onUploadComplete) onUploadComplete(result);
|
|
220
|
+
} catch (err) {
|
|
221
|
+
const message = err instanceof Error ? err.message : "Upload failed";
|
|
222
|
+
setFileStates((prev) => prev.map((s) => s.status === "uploading" ? __spreadProps(__spreadValues({}, s), { status: "error", error: message }) : s));
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
const isUploading = fileStates.some((s) => s.status === "uploading");
|
|
226
|
+
const hasIdle = fileStates.some((s) => s.status === "idle");
|
|
227
|
+
return /* @__PURE__ */ import_react2.default.createElement(
|
|
228
|
+
"div",
|
|
229
|
+
{
|
|
230
|
+
className: `p-6 border-2 border-dashed transition-all duration-300 rounded-2xl ${isDragging ? "border-emerald-500 bg-emerald-50/50 dark:bg-emerald-500/5" : "border-slate-200 dark:border-white/10 bg-white dark:bg-white/5"} ${className}`,
|
|
231
|
+
onDragOver,
|
|
232
|
+
onDragLeave,
|
|
233
|
+
onDrop
|
|
234
|
+
},
|
|
235
|
+
/* @__PURE__ */ import_react2.default.createElement("div", { className: "flex flex-col items-center justify-center text-center" }, /* @__PURE__ */ import_react2.default.createElement(
|
|
236
|
+
"div",
|
|
237
|
+
{
|
|
238
|
+
className: "w-12 h-12 rounded-full flex items-center justify-center mb-4 shadow-sm",
|
|
239
|
+
style: { background: `linear-gradient(135deg, ${ui.primaryColor}20, ${ui.accentColor}20)` }
|
|
240
|
+
},
|
|
241
|
+
/* @__PURE__ */ import_react2.default.createElement(import_lucide_react.Upload, { className: "w-6 h-6", style: { color: ui.primaryColor } })
|
|
242
|
+
), /* @__PURE__ */ import_react2.default.createElement("h3", { className: "text-slate-900 dark:text-white font-semibold mb-1" }, "Upload Documents"), /* @__PURE__ */ import_react2.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_react2.default.createElement(
|
|
243
|
+
"button",
|
|
244
|
+
{
|
|
245
|
+
onClick: () => {
|
|
246
|
+
var _a2;
|
|
247
|
+
return (_a2 = fileInputRef.current) == null ? void 0 : _a2.click();
|
|
248
|
+
},
|
|
249
|
+
disabled: isUploading,
|
|
250
|
+
className: "px-4 py-2 rounded-lg text-sm font-medium transition-all hover:scale-105 active:scale-95 disabled:opacity-50",
|
|
251
|
+
style: {
|
|
252
|
+
backgroundColor: `${ui.primaryColor}15`,
|
|
253
|
+
color: ui.primaryColor,
|
|
254
|
+
border: `1px solid ${ui.primaryColor}30`
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
"Select Files"
|
|
258
|
+
), /* @__PURE__ */ import_react2.default.createElement(
|
|
259
|
+
"input",
|
|
260
|
+
{
|
|
261
|
+
ref: fileInputRef,
|
|
262
|
+
type: "file",
|
|
263
|
+
multiple: true,
|
|
264
|
+
onChange: onFileSelect,
|
|
265
|
+
className: "hidden",
|
|
266
|
+
accept: ".pdf,.docx,.txt,.md,.json,.csv"
|
|
267
|
+
}
|
|
268
|
+
), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mt-6 flex flex-col items-center gap-2 text-sm" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "text-slate-600 dark:text-white/60 font-medium" }, "Embedding Dimension"), isChangeable ? /* @__PURE__ */ import_react2.default.createElement(
|
|
269
|
+
"select",
|
|
270
|
+
{
|
|
271
|
+
value: dimension,
|
|
272
|
+
onChange: (e) => setDimension(Number(e.target.value)),
|
|
273
|
+
disabled: isUploading,
|
|
274
|
+
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"
|
|
275
|
+
},
|
|
276
|
+
availableDimensions.map((dim) => /* @__PURE__ */ import_react2.default.createElement("option", { key: dim, value: dim, className: "bg-white dark:bg-slate-900" }, dim))
|
|
277
|
+
) : /* @__PURE__ */ import_react2.default.createElement("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" }, dimension, " (Fixed for ", currentModel, ")"))),
|
|
278
|
+
fileStates.length > 0 && /* @__PURE__ */ import_react2.default.createElement("div", { className: "mt-8 space-y-3" }, fileStates.map((state, i) => /* @__PURE__ */ import_react2.default.createElement(
|
|
279
|
+
"div",
|
|
280
|
+
{
|
|
281
|
+
key: i,
|
|
282
|
+
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"
|
|
283
|
+
},
|
|
284
|
+
/* @__PURE__ */ import_react2.default.createElement("div", { className: "flex items-center gap-3 overflow-hidden" }, /* @__PURE__ */ import_react2.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_react2.default.createElement(import_lucide_react.File, { className: "w-4 h-4 text-slate-400" })), /* @__PURE__ */ import_react2.default.createElement("div", { className: "truncate" }, /* @__PURE__ */ import_react2.default.createElement("p", { className: "text-xs font-medium text-slate-700 dark:text-white/80 truncate" }, state.file.name), /* @__PURE__ */ import_react2.default.createElement("p", { className: "text-[10px] text-slate-400" }, (state.file.size / 1024).toFixed(1), " KB"))),
|
|
285
|
+
/* @__PURE__ */ import_react2.default.createElement("div", { className: "flex items-center gap-2" }, state.status === "uploading" && /* @__PURE__ */ import_react2.default.createElement(import_lucide_react.Loader2, { className: "w-4 h-4 text-slate-400 animate-spin" }), state.status === "success" && /* @__PURE__ */ import_react2.default.createElement(import_lucide_react.CheckCircle, { className: "w-4 h-4 text-emerald-500" }), state.status === "error" && /* @__PURE__ */ import_react2.default.createElement("div", { title: state.error }, /* @__PURE__ */ import_react2.default.createElement(import_lucide_react.AlertCircle, { className: "w-4 h-4 text-rose-500" })), state.status !== "uploading" && /* @__PURE__ */ import_react2.default.createElement(
|
|
286
|
+
"button",
|
|
287
|
+
{
|
|
288
|
+
onClick: () => removeFile(i),
|
|
289
|
+
className: "p-1 rounded-md hover:bg-slate-200 dark:hover:bg-white/10 transition-colors"
|
|
290
|
+
},
|
|
291
|
+
/* @__PURE__ */ import_react2.default.createElement(import_lucide_react.X, { className: "w-3.5 h-3.5 text-slate-400" })
|
|
292
|
+
))
|
|
293
|
+
)), hasIdle && !isUploading && /* @__PURE__ */ import_react2.default.createElement(
|
|
294
|
+
"button",
|
|
295
|
+
{
|
|
296
|
+
onClick: uploadFiles,
|
|
297
|
+
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]",
|
|
298
|
+
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` }
|
|
299
|
+
},
|
|
300
|
+
"Start Upload"
|
|
301
|
+
))
|
|
302
|
+
);
|
|
303
|
+
}
|
|
80
304
|
|
|
81
305
|
// src/components/MessageBubble.tsx
|
|
82
|
-
var
|
|
83
|
-
var
|
|
306
|
+
var import_react12 = __toESM(require("react"));
|
|
307
|
+
var import_lucide_react6 = require("lucide-react");
|
|
84
308
|
var import_react_markdown = __toESM(require("react-markdown"));
|
|
85
309
|
|
|
86
310
|
// src/components/SourceCard.tsx
|
|
87
|
-
var
|
|
88
|
-
var
|
|
311
|
+
var import_react3 = __toESM(require("react"));
|
|
312
|
+
var import_lucide_react2 = require("lucide-react");
|
|
89
313
|
function SourceCard({ source, index }) {
|
|
90
314
|
var _a, _b;
|
|
91
|
-
const [expanded, setExpanded] =
|
|
315
|
+
const [expanded, setExpanded] = import_react3.default.useState(false);
|
|
92
316
|
const scorePercent = Math.round(source.score * 100);
|
|
93
317
|
const scoreColor = source.score >= 0.8 ? "text-emerald-400" : source.score >= 0.6 ? "text-amber-400" : "text-rose-400";
|
|
94
318
|
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
319
|
const preview = source.content.slice(0, 120);
|
|
96
320
|
const hasMore = source.content.length > 120;
|
|
97
|
-
return /* @__PURE__ */
|
|
321
|
+
return /* @__PURE__ */ import_react3.default.createElement(
|
|
98
322
|
"div",
|
|
99
323
|
{
|
|
100
324
|
className: `rounded-xl border backdrop-blur-sm p-3 transition-all duration-200 hover:scale-[1.01] cursor-pointer ${scoreBg}`,
|
|
101
325
|
onClick: () => setExpanded((e) => !e)
|
|
102
326
|
},
|
|
103
|
-
/* @__PURE__ */
|
|
104
|
-
/* @__PURE__ */
|
|
105
|
-
hasMore && /* @__PURE__ */
|
|
327
|
+
/* @__PURE__ */ import_react3.default.createElement("div", { className: "flex items-start justify-between gap-2" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ import_react3.default.createElement("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" }, index + 1), /* @__PURE__ */ import_react3.default.createElement("span", { className: "text-xs text-slate-500 dark:text-white/50 truncate font-mono" }, (_b = (_a = source.metadata) == null ? void 0 : _a.docId) != null ? _b : source.id)), /* @__PURE__ */ import_react3.default.createElement("span", { className: `flex-shrink-0 text-xs font-semibold ${scoreColor} tabular-nums` }, scorePercent, "%")),
|
|
328
|
+
/* @__PURE__ */ import_react3.default.createElement("p", { className: "mt-2 text-xs text-slate-600 dark:text-white/70 leading-relaxed" }, expanded ? source.content : `${preview}${hasMore && !expanded ? "\u2026" : ""}`),
|
|
329
|
+
hasMore && /* @__PURE__ */ import_react3.default.createElement("button", { className: "mt-1 text-[10px] text-indigo-400 hover:text-indigo-300 transition-colors flex items-center gap-0.5" }, expanded ? /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement(import_lucide_react2.ChevronUp, { className: "w-3 h-3" }), " Show less") : /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement(import_lucide_react2.ChevronDown, { className: "w-3 h-3" }), " Show more"))
|
|
106
330
|
);
|
|
107
331
|
}
|
|
108
332
|
|
|
109
333
|
// src/components/ProductCarousel.tsx
|
|
110
|
-
var
|
|
111
|
-
var
|
|
334
|
+
var import_react5 = __toESM(require("react"));
|
|
335
|
+
var import_lucide_react4 = require("lucide-react");
|
|
112
336
|
|
|
113
337
|
// src/components/ProductCard.tsx
|
|
114
|
-
var
|
|
338
|
+
var import_react4 = __toESM(require("react"));
|
|
115
339
|
var import_image = __toESM(require("next/image"));
|
|
116
|
-
var
|
|
340
|
+
var import_lucide_react3 = require("lucide-react");
|
|
117
341
|
function ProductCard({ product, primaryColor = "#6366f1", onAddToCart }) {
|
|
118
|
-
return /* @__PURE__ */
|
|
342
|
+
return /* @__PURE__ */ import_react4.default.createElement("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" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "relative h-40 w-full bg-slate-100 dark:bg-white/5 flex items-center justify-center overflow-hidden" }, product.image ? /* @__PURE__ */ import_react4.default.createElement(
|
|
119
343
|
import_image.default,
|
|
120
344
|
{
|
|
121
345
|
src: product.image,
|
|
@@ -124,16 +348,16 @@ function ProductCard({ product, primaryColor = "#6366f1", onAddToCart }) {
|
|
|
124
348
|
unoptimized: true,
|
|
125
349
|
className: "object-cover group-hover:scale-105 transition-transform duration-500"
|
|
126
350
|
}
|
|
127
|
-
) : /* @__PURE__ */
|
|
351
|
+
) : /* @__PURE__ */ import_react4.default.createElement("div", { className: "text-slate-400 dark:text-white/20" }, /* @__PURE__ */ import_react4.default.createElement(import_lucide_react3.ShoppingCart, { className: "w-12 h-12" })), product.brand && /* @__PURE__ */ import_react4.default.createElement("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" }, product.brand)), /* @__PURE__ */ import_react4.default.createElement("div", { className: "p-4 flex flex-col gap-2" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "flex justify-between items-start gap-2" }, /* @__PURE__ */ import_react4.default.createElement("h3", { className: "text-sm font-semibold text-slate-800 dark:text-white/90 line-clamp-1" }, product.name), product.price && /* @__PURE__ */ import_react4.default.createElement("span", { className: "text-sm font-bold", style: { color: primaryColor } }, typeof product.price === "number" ? `$${product.price}` : String(product.price).match(/^[\d.]/) ? `$${product.price}` : product.price)), product.description && /* @__PURE__ */ import_react4.default.createElement("p", { className: "text-[11px] text-slate-500 dark:text-white/50 line-clamp-2 leading-relaxed" }, product.description), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mt-2 flex gap-2" }, /* @__PURE__ */ import_react4.default.createElement(
|
|
128
352
|
"button",
|
|
129
353
|
{
|
|
130
354
|
onClick: () => onAddToCart == null ? void 0 : onAddToCart(product),
|
|
131
355
|
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",
|
|
132
356
|
style: { background: primaryColor }
|
|
133
357
|
},
|
|
134
|
-
/* @__PURE__ */
|
|
358
|
+
/* @__PURE__ */ import_react4.default.createElement(import_lucide_react3.ShoppingCart, { className: "w-3 h-3" }),
|
|
135
359
|
"Add to Cart"
|
|
136
|
-
), product.link && /* @__PURE__ */
|
|
360
|
+
), product.link && /* @__PURE__ */ import_react4.default.createElement(
|
|
137
361
|
"a",
|
|
138
362
|
{
|
|
139
363
|
href: product.link,
|
|
@@ -141,15 +365,15 @@ function ProductCard({ product, primaryColor = "#6366f1", onAddToCart }) {
|
|
|
141
365
|
rel: "noopener noreferrer",
|
|
142
366
|
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"
|
|
143
367
|
},
|
|
144
|
-
/* @__PURE__ */
|
|
368
|
+
/* @__PURE__ */ import_react4.default.createElement(import_lucide_react3.ExternalLink, { className: "w-3.5 h-3.5" })
|
|
145
369
|
))));
|
|
146
370
|
}
|
|
147
371
|
|
|
148
372
|
// src/components/ProductCarousel.tsx
|
|
149
373
|
function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
|
|
150
|
-
const scrollRef = (0,
|
|
151
|
-
const [canScroll, setCanScroll] = (0,
|
|
152
|
-
(0,
|
|
374
|
+
const scrollRef = (0, import_react5.useRef)(null);
|
|
375
|
+
const [canScroll, setCanScroll] = (0, import_react5.useState)(false);
|
|
376
|
+
(0, import_react5.useEffect)(() => {
|
|
153
377
|
const checkScroll = () => {
|
|
154
378
|
if (scrollRef.current) {
|
|
155
379
|
const hasOverflow = scrollRef.current.scrollWidth > scrollRef.current.clientWidth;
|
|
@@ -173,9 +397,9 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
|
|
|
173
397
|
};
|
|
174
398
|
if (!products || products.length === 0) return null;
|
|
175
399
|
if (products.length === 1) {
|
|
176
|
-
return /* @__PURE__ */
|
|
400
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-4 w-[min(88%,18rem)] min-w-0 max-w-full animate-fade-in-up" }, /* @__PURE__ */ import_react5.default.createElement(ProductCard, { product: products[0], primaryColor, onAddToCart }));
|
|
177
401
|
}
|
|
178
|
-
return /* @__PURE__ */
|
|
402
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "relative w-full my-4 group/carousel animate-fade-in-up" }, canScroll && /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("div", { className: "absolute -left-4 top-1/2 -translate-y-1/2 z-20 opacity-100 md:opacity-0 md:group-hover/carousel:opacity-100 transition-opacity" }, /* @__PURE__ */ import_react5.default.createElement(
|
|
179
403
|
"button",
|
|
180
404
|
{
|
|
181
405
|
onClick: (e) => {
|
|
@@ -185,8 +409,8 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
|
|
|
185
409
|
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",
|
|
186
410
|
"aria-label": "Scroll left"
|
|
187
411
|
},
|
|
188
|
-
/* @__PURE__ */
|
|
189
|
-
)), /* @__PURE__ */
|
|
412
|
+
/* @__PURE__ */ import_react5.default.createElement(import_lucide_react4.ChevronLeft, { className: "w-5 h-5" })
|
|
413
|
+
)), /* @__PURE__ */ import_react5.default.createElement("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" }, /* @__PURE__ */ import_react5.default.createElement(
|
|
190
414
|
"button",
|
|
191
415
|
{
|
|
192
416
|
onClick: (e) => {
|
|
@@ -196,40 +420,45 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
|
|
|
196
420
|
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",
|
|
197
421
|
"aria-label": "Scroll right"
|
|
198
422
|
},
|
|
199
|
-
/* @__PURE__ */
|
|
200
|
-
))), /* @__PURE__ */
|
|
423
|
+
/* @__PURE__ */ import_react5.default.createElement(import_lucide_react4.ChevronRight, { className: "w-5 h-5" })
|
|
424
|
+
))), /* @__PURE__ */ import_react5.default.createElement(
|
|
201
425
|
"div",
|
|
202
426
|
{
|
|
203
427
|
ref: scrollRef,
|
|
204
428
|
className: "flex gap-4 overflow-x-auto pb-4 px-1 scrollbar-hide snap-x snap-mandatory",
|
|
205
429
|
style: { scrollbarWidth: "none", msOverflowStyle: "none" }
|
|
206
430
|
},
|
|
207
|
-
products.map((product) => /* @__PURE__ */
|
|
431
|
+
products.map((product) => /* @__PURE__ */ import_react5.default.createElement(
|
|
208
432
|
"div",
|
|
209
433
|
{
|
|
210
434
|
key: product.id,
|
|
211
435
|
className: "snap-start flex-shrink-0 w-[min(88%,18rem)] min-w-[11rem] max-w-full"
|
|
212
436
|
},
|
|
213
|
-
/* @__PURE__ */
|
|
437
|
+
/* @__PURE__ */ import_react5.default.createElement(ProductCard, { product, primaryColor, onAddToCart })
|
|
214
438
|
))
|
|
215
439
|
));
|
|
216
440
|
}
|
|
217
441
|
|
|
442
|
+
// src/components/VisualizationRenderer.tsx
|
|
443
|
+
var import_react7 = __toESM(require("react"));
|
|
444
|
+
var import_recharts2 = require("recharts");
|
|
445
|
+
|
|
218
446
|
// src/components/DynamicChart.tsx
|
|
219
|
-
var
|
|
447
|
+
var import_react6 = __toESM(require("react"));
|
|
220
448
|
var import_recharts = require("recharts");
|
|
221
|
-
var
|
|
449
|
+
var CHART_COLORS = ["#6366f1", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#ec4899"];
|
|
222
450
|
function DynamicChart({
|
|
223
451
|
config,
|
|
224
452
|
primaryColor = "#6366f1",
|
|
225
453
|
accentColor = "#8b5cf6",
|
|
226
|
-
viewportSize = "large"
|
|
454
|
+
viewportSize = "large",
|
|
455
|
+
isStreaming = false
|
|
227
456
|
}) {
|
|
228
457
|
const { type, data } = config;
|
|
229
|
-
const colors = config.colors || [primaryColor, accentColor, ...
|
|
230
|
-
const containerRef =
|
|
231
|
-
const [containerWidth, setContainerWidth] =
|
|
232
|
-
|
|
458
|
+
const colors = config.colors || [primaryColor, accentColor, ...CHART_COLORS];
|
|
459
|
+
const containerRef = import_react6.default.useRef(null);
|
|
460
|
+
const [containerWidth, setContainerWidth] = import_react6.default.useState(0);
|
|
461
|
+
import_react6.default.useEffect(() => {
|
|
233
462
|
const element = containerRef.current;
|
|
234
463
|
if (!element || typeof ResizeObserver === "undefined") return;
|
|
235
464
|
const updateWidth = (width) => {
|
|
@@ -255,7 +484,7 @@ function DynamicChart({
|
|
|
255
484
|
return text.length > maxLength ? `${text.slice(0, maxLength)}\u2026` : text;
|
|
256
485
|
};
|
|
257
486
|
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 =
|
|
487
|
+
const sanitizedData = import_react6.default.useMemo(() => {
|
|
259
488
|
if (!data) return [];
|
|
260
489
|
return data.map((item) => {
|
|
261
490
|
const newItem = {};
|
|
@@ -287,8 +516,19 @@ function DynamicChart({
|
|
|
287
516
|
return newItem;
|
|
288
517
|
});
|
|
289
518
|
}, [data]);
|
|
519
|
+
if (isStreaming) {
|
|
520
|
+
const bars = type === "pie" ? 6 : 5;
|
|
521
|
+
return /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-full mt-4 mb-2 animate-pulse" }, type === "pie" ? /* @__PURE__ */ import_react6.default.createElement("div", { className: "mx-auto w-40 h-40 rounded-full bg-slate-100 dark:bg-white/10" }) : /* @__PURE__ */ import_react6.default.createElement("div", { className: "flex items-end gap-2 h-32 px-2" }, Array.from({ length: bars }).map((_, i) => /* @__PURE__ */ import_react6.default.createElement(
|
|
522
|
+
"div",
|
|
523
|
+
{
|
|
524
|
+
key: i,
|
|
525
|
+
className: "flex-1 rounded-t-md bg-slate-100 dark:bg-white/10",
|
|
526
|
+
style: { height: `${40 + i % 3 * 25}%` }
|
|
527
|
+
}
|
|
528
|
+
))));
|
|
529
|
+
}
|
|
290
530
|
if (!data || data.length === 0) {
|
|
291
|
-
return /* @__PURE__ */
|
|
531
|
+
return /* @__PURE__ */ import_react6.default.createElement("div", { className: "p-4 text-sm text-slate-500" }, "No data available for chart.");
|
|
292
532
|
}
|
|
293
533
|
const firstItem = sanitizedData[0];
|
|
294
534
|
const allKeys = Object.keys(firstItem);
|
|
@@ -313,13 +553,13 @@ function DynamicChart({
|
|
|
313
553
|
const renderTooltip = (row, label) => {
|
|
314
554
|
var _a, _b;
|
|
315
555
|
if (!row) return null;
|
|
316
|
-
return /* @__PURE__ */
|
|
556
|
+
return /* @__PURE__ */ import_react6.default.createElement("div", { className: "rounded-xl border border-slate-200 bg-white px-3 py-2 text-xs shadow-xl dark:border-white/10 dark:bg-slate-950" }, /* @__PURE__ */ import_react6.default.createElement("p", { className: "mb-2 font-semibold text-slate-800 dark:text-white/90" }, String((_b = (_a = row[finalXKey]) != null ? _a : label) != null ? _b : "Details")), Object.entries(row).map(([key, value]) => {
|
|
317
557
|
var _a2;
|
|
318
558
|
if (value === null || value === void 0 || key === finalXKey) return null;
|
|
319
559
|
if (typeof value === "object") return null;
|
|
320
560
|
const forbiddenKeys = ["fill", "color", "payload", "percent", "stroke", "inStock"];
|
|
321
561
|
if (forbiddenKeys.includes(key)) return null;
|
|
322
|
-
return /* @__PURE__ */
|
|
562
|
+
return /* @__PURE__ */ import_react6.default.createElement("div", { key, className: "flex items-center justify-between gap-3 text-slate-600 dark:text-white/70" }, /* @__PURE__ */ import_react6.default.createElement("span", null, (_a2 = tooltipLabelMap[key]) != null ? _a2 : key), /* @__PURE__ */ import_react6.default.createElement("span", { className: "font-medium text-slate-900 dark:text-white/90" }, String(value)));
|
|
323
563
|
}));
|
|
324
564
|
};
|
|
325
565
|
const getTooltipRow = (payload) => {
|
|
@@ -331,7 +571,7 @@ function DynamicChart({
|
|
|
331
571
|
return row;
|
|
332
572
|
};
|
|
333
573
|
if (type === "pie") {
|
|
334
|
-
return /* @__PURE__ */
|
|
574
|
+
return /* @__PURE__ */ import_react6.default.createElement("div", { ref: containerRef, className: "w-full min-w-0 mt-4 mb-2 select-none overflow-hidden" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "mx-auto w-full max-w-full aspect-square" }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.PieChart, null, /* @__PURE__ */ import_react6.default.createElement(
|
|
335
575
|
import_recharts.Pie,
|
|
336
576
|
{
|
|
337
577
|
data: sanitizedData,
|
|
@@ -343,10 +583,10 @@ function DynamicChart({
|
|
|
343
583
|
label: false,
|
|
344
584
|
labelLine: false
|
|
345
585
|
},
|
|
346
|
-
sanitizedData.map((_entry, index) => /* @__PURE__ */
|
|
347
|
-
), /* @__PURE__ */
|
|
586
|
+
sanitizedData.map((_entry, index) => /* @__PURE__ */ import_react6.default.createElement(import_recharts.Cell, { key: `cell-${index}`, fill: colors[index % colors.length] }))
|
|
587
|
+
), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }), showLegend && !isCompact && /* @__PURE__ */ import_react6.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: 12 }, verticalAlign: "bottom" })))));
|
|
348
588
|
}
|
|
349
|
-
return /* @__PURE__ */
|
|
589
|
+
return /* @__PURE__ */ import_react6.default.createElement("div", { ref: containerRef, className: "w-full min-w-0 mt-4 mb-2 select-none overflow-hidden" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-full aspect-[4/3]" }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, type === "bar" ? /* @__PURE__ */ import_react6.default.createElement(import_recharts.BarChart, { data: sanitizedData, margin: chartMargin }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.XAxis, { dataKey: finalXKey, tick: axisTick, tickFormatter: truncateAxisLabel, tickLine: false, axisLine: { stroke: "#cbd5e1" }, interval: 0, minTickGap: isTiny ? 2 : isCompact ? 6 : 12 }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.YAxis, { tick: axisTick, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0), cursor: { fill: "#f1f5f9" } }), showLegend && /* @__PURE__ */ import_react6.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ import_react6.default.createElement(
|
|
350
590
|
import_recharts.Bar,
|
|
351
591
|
{
|
|
352
592
|
key,
|
|
@@ -355,7 +595,7 @@ function DynamicChart({
|
|
|
355
595
|
radius: [4, 4, 0, 0],
|
|
356
596
|
barSize: isTiny ? Math.max(10, 28 / data.length) : isCompact ? Math.max(14, 42 / data.length) : Math.max(20, 60 / data.length)
|
|
357
597
|
}
|
|
358
|
-
))) : /* @__PURE__ */
|
|
598
|
+
))) : /* @__PURE__ */ import_react6.default.createElement(import_recharts.LineChart, { data: sanitizedData, margin: chartMargin }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.XAxis, { dataKey: finalXKey, tick: axisTick, tickFormatter: truncateAxisLabel, tickLine: false, axisLine: { stroke: "#cbd5e1" }, interval: 0, minTickGap: isTiny ? 2 : isCompact ? 6 : 12 }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.YAxis, { tick: axisTick, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }), showLegend && /* @__PURE__ */ import_react6.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ import_react6.default.createElement(
|
|
359
599
|
import_recharts.Line,
|
|
360
600
|
{
|
|
361
601
|
key,
|
|
@@ -370,26 +610,6 @@ function DynamicChart({
|
|
|
370
610
|
}
|
|
371
611
|
|
|
372
612
|
// src/components/VisualizationRenderer.tsx
|
|
373
|
-
var import_react5 = __toESM(require("react"));
|
|
374
|
-
var import_recharts2 = require("recharts");
|
|
375
|
-
var CHART_COLORS = [
|
|
376
|
-
"#6366f1",
|
|
377
|
-
// indigo
|
|
378
|
-
"#10b981",
|
|
379
|
-
// emerald
|
|
380
|
-
"#f59e0b",
|
|
381
|
-
// amber
|
|
382
|
-
"#ef4444",
|
|
383
|
-
// red
|
|
384
|
-
"#8b5cf6",
|
|
385
|
-
// purple
|
|
386
|
-
"#ec4899",
|
|
387
|
-
// pink
|
|
388
|
-
"#06b6d4",
|
|
389
|
-
// cyan
|
|
390
|
-
"#f97316"
|
|
391
|
-
// orange
|
|
392
|
-
];
|
|
393
613
|
function getColor(index) {
|
|
394
614
|
return CHART_COLORS[index % CHART_COLORS.length];
|
|
395
615
|
}
|
|
@@ -399,60 +619,71 @@ function CustomTooltip({
|
|
|
399
619
|
label
|
|
400
620
|
}) {
|
|
401
621
|
if (!active || !payload || payload.length === 0) return null;
|
|
402
|
-
return /* @__PURE__ */
|
|
622
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "rounded-xl border border-slate-200 bg-white px-3 py-2 text-xs shadow-xl dark:border-white/10 dark:bg-slate-950" }, label && /* @__PURE__ */ import_react7.default.createElement("p", { className: "mb-2 font-semibold text-slate-800 dark:text-white/90" }, label), payload.map((entry, i) => /* @__PURE__ */ import_react7.default.createElement("div", { key: i, className: "flex items-center justify-between gap-3 text-slate-600 dark:text-white/70" }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "flex items-center gap-1.5" }, entry.color && /* @__PURE__ */ import_react7.default.createElement(
|
|
403
623
|
"span",
|
|
404
624
|
{
|
|
405
625
|
className: "inline-block w-2 h-2 rounded-full flex-shrink-0",
|
|
406
626
|
style: { background: entry.color }
|
|
407
627
|
}
|
|
408
|
-
), entry.name), /* @__PURE__ */
|
|
628
|
+
), entry.name), /* @__PURE__ */ import_react7.default.createElement("span", { className: "font-medium text-slate-900 dark:text-white/90" }, entry.value))));
|
|
409
629
|
}
|
|
410
630
|
function VisualizationRenderer({
|
|
411
631
|
data,
|
|
412
632
|
className = "",
|
|
413
633
|
primaryColor,
|
|
414
|
-
onAddToCart
|
|
634
|
+
onAddToCart,
|
|
635
|
+
isStreaming
|
|
415
636
|
}) {
|
|
416
637
|
var _a;
|
|
417
638
|
if (!data) {
|
|
418
|
-
return /* @__PURE__ */
|
|
639
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: `p-4 text-gray-500 ${className}` }, "No data available for visualization");
|
|
419
640
|
}
|
|
420
|
-
return /* @__PURE__ */
|
|
641
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: `space-y-4 ${className}` }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react7.default.createElement("h3", { className: "text-sm font-semibold text-slate-900 dark:text-white" }, data.title), data.description && data.description !== ((_a = data.data) == null ? void 0 : _a.content) && /* @__PURE__ */ import_react7.default.createElement("p", { className: "text-xs text-slate-500 dark:text-slate-400" }, data.description)), renderVisualization(data.type, data.data, onAddToCart, primaryColor, isStreaming));
|
|
421
642
|
}
|
|
422
|
-
function renderVisualization(type, data, onAddToCart, primaryColor) {
|
|
643
|
+
function renderVisualization(type, data, onAddToCart, primaryColor, isStreaming) {
|
|
423
644
|
try {
|
|
424
645
|
switch (type) {
|
|
425
646
|
case "pie_chart":
|
|
426
|
-
return /* @__PURE__ */
|
|
647
|
+
return /* @__PURE__ */ import_react7.default.createElement(PieChartView, { data, isStreaming });
|
|
427
648
|
case "bar_chart":
|
|
428
|
-
return /* @__PURE__ */
|
|
649
|
+
return /* @__PURE__ */ import_react7.default.createElement(BarChartView, { data, primaryColor, isStreaming });
|
|
429
650
|
case "line_chart":
|
|
430
|
-
return /* @__PURE__ */
|
|
651
|
+
return /* @__PURE__ */ import_react7.default.createElement(LineChartView, { data, primaryColor, isStreaming });
|
|
431
652
|
case "radar_chart":
|
|
432
|
-
return /* @__PURE__ */
|
|
653
|
+
return /* @__PURE__ */ import_react7.default.createElement(RadarChartView, { data, isStreaming });
|
|
433
654
|
case "table":
|
|
434
|
-
return /* @__PURE__ */
|
|
655
|
+
return /* @__PURE__ */ import_react7.default.createElement(TableView, { data, isStreaming });
|
|
435
656
|
case "product_carousel":
|
|
436
657
|
case "carousel":
|
|
437
|
-
return /* @__PURE__ */
|
|
658
|
+
return /* @__PURE__ */ import_react7.default.createElement(CarouselView, { data, onAddToCart, primaryColor });
|
|
438
659
|
case "text":
|
|
439
660
|
default:
|
|
440
|
-
return /* @__PURE__ */
|
|
661
|
+
return /* @__PURE__ */ import_react7.default.createElement(TextView, { data });
|
|
441
662
|
}
|
|
442
663
|
} catch (error) {
|
|
443
664
|
console.warn("[VisualizationRenderer] Rendering failed, falling back to text:", error);
|
|
444
|
-
return /* @__PURE__ */
|
|
665
|
+
return /* @__PURE__ */ import_react7.default.createElement(TextView, { data: { content: "Unable to render the requested visualization." } });
|
|
445
666
|
}
|
|
446
667
|
}
|
|
447
|
-
function
|
|
668
|
+
function ChartSkeleton({ type }) {
|
|
669
|
+
if (type === "pie") {
|
|
670
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "w-full mt-4 mb-2 animate-pulse" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "mx-auto w-40 h-40 rounded-full bg-slate-100 dark:bg-white/10" }));
|
|
671
|
+
}
|
|
672
|
+
if (type === "table") {
|
|
673
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "w-full mt-4 mb-2 animate-pulse space-y-2" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "h-8 bg-slate-100 dark:bg-white/10 rounded" }), /* @__PURE__ */ import_react7.default.createElement("div", { className: "h-8 bg-slate-100 dark:bg-white/10 rounded" }), /* @__PURE__ */ import_react7.default.createElement("div", { className: "h-8 bg-slate-100 dark:bg-white/10 rounded" }));
|
|
674
|
+
}
|
|
675
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "w-full mt-4 mb-2 animate-pulse flex items-end gap-2 h-32 px-2" }, Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ import_react7.default.createElement("div", { key: i, className: "flex-1 rounded-t-md bg-slate-100 dark:bg-white/10", style: { height: `${40 + i % 3 * 25}%` } })));
|
|
676
|
+
}
|
|
677
|
+
function PieChartView({ data, isStreaming }) {
|
|
678
|
+
if (isStreaming) return /* @__PURE__ */ import_react7.default.createElement(ChartSkeleton, { type: "pie" });
|
|
448
679
|
if (!Array.isArray(data) || data.length === 0) {
|
|
449
|
-
return /* @__PURE__ */
|
|
680
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid pie chart data");
|
|
450
681
|
}
|
|
451
682
|
const chartData = data.map((item) => ({
|
|
452
683
|
name: item.label,
|
|
453
684
|
value: item.value
|
|
454
685
|
}));
|
|
455
|
-
return /* @__PURE__ */
|
|
686
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm" }, /* @__PURE__ */ import_react7.default.createElement(import_recharts2.ResponsiveContainer, { width: "100%", height: 280 }, /* @__PURE__ */ import_react7.default.createElement(import_recharts2.PieChart, null, /* @__PURE__ */ import_react7.default.createElement(
|
|
456
687
|
import_recharts2.Pie,
|
|
457
688
|
{
|
|
458
689
|
data: chartData,
|
|
@@ -464,12 +695,13 @@ function PieChartView({ data }) {
|
|
|
464
695
|
label: false,
|
|
465
696
|
labelLine: false
|
|
466
697
|
},
|
|
467
|
-
chartData.map((_entry, index) => /* @__PURE__ */
|
|
468
|
-
), /* @__PURE__ */
|
|
698
|
+
chartData.map((_entry, index) => /* @__PURE__ */ import_react7.default.createElement(import_recharts2.Cell, { key: `cell-${index}`, fill: getColor(index) }))
|
|
699
|
+
), /* @__PURE__ */ import_react7.default.createElement(import_recharts2.Tooltip, { content: /* @__PURE__ */ import_react7.default.createElement(CustomTooltip, null) }), /* @__PURE__ */ import_react7.default.createElement(import_recharts2.Legend, { wrapperStyle: { fontSize: 12 }, verticalAlign: "bottom" }))));
|
|
469
700
|
}
|
|
470
|
-
function BarChartView({ data, primaryColor }) {
|
|
701
|
+
function BarChartView({ data, primaryColor, isStreaming }) {
|
|
702
|
+
if (isStreaming) return /* @__PURE__ */ import_react7.default.createElement(ChartSkeleton, { type: "bar" });
|
|
471
703
|
if (!Array.isArray(data) || data.length === 0) {
|
|
472
|
-
return /* @__PURE__ */
|
|
704
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid bar chart data");
|
|
473
705
|
}
|
|
474
706
|
const chartData = data.map((item) => __spreadValues(__spreadValues({
|
|
475
707
|
category: item.category,
|
|
@@ -477,7 +709,7 @@ function BarChartView({ data, primaryColor }) {
|
|
|
477
709
|
}, item.inStockCount !== void 0 && { inStockCount: item.inStockCount }), item.outOfStockCount !== void 0 && { outOfStockCount: item.outOfStockCount }));
|
|
478
710
|
const barColor = primaryColor != null ? primaryColor : getColor(0);
|
|
479
711
|
const hasStock = chartData.some((d) => "inStockCount" in d);
|
|
480
|
-
return /* @__PURE__ */
|
|
712
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm overflow-x-auto" }, /* @__PURE__ */ import_react7.default.createElement(import_recharts2.ResponsiveContainer, { width: "100%", height: 260 }, /* @__PURE__ */ import_react7.default.createElement(import_recharts2.BarChart, { data: chartData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react7.default.createElement(import_recharts2.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react7.default.createElement(
|
|
481
713
|
import_recharts2.XAxis,
|
|
482
714
|
{
|
|
483
715
|
dataKey: "category",
|
|
@@ -485,11 +717,12 @@ function BarChartView({ data, primaryColor }) {
|
|
|
485
717
|
tickLine: false,
|
|
486
718
|
axisLine: { stroke: "#cbd5e1" }
|
|
487
719
|
}
|
|
488
|
-
), /* @__PURE__ */
|
|
720
|
+
), /* @__PURE__ */ import_react7.default.createElement(import_recharts2.YAxis, { tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react7.default.createElement(import_recharts2.Tooltip, { content: /* @__PURE__ */ import_react7.default.createElement(CustomTooltip, null), cursor: { fill: "#f1f5f9" } }), /* @__PURE__ */ import_react7.default.createElement(import_recharts2.Legend, { wrapperStyle: { fontSize: 12 } }), hasStock ? /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, /* @__PURE__ */ import_react7.default.createElement(import_recharts2.Bar, { dataKey: "inStockCount", name: "In Stock", fill: getColor(1), radius: [4, 4, 0, 0] }), /* @__PURE__ */ import_react7.default.createElement(import_recharts2.Bar, { dataKey: "outOfStockCount", name: "Out of Stock", fill: getColor(3), radius: [4, 4, 0, 0] })) : /* @__PURE__ */ import_react7.default.createElement(import_recharts2.Bar, { dataKey: "value", name: "Value", fill: barColor, radius: [4, 4, 0, 0] }))));
|
|
489
721
|
}
|
|
490
|
-
function LineChartView({ data, primaryColor }) {
|
|
722
|
+
function LineChartView({ data, primaryColor, isStreaming }) {
|
|
723
|
+
if (isStreaming) return /* @__PURE__ */ import_react7.default.createElement(ChartSkeleton, { type: "bar" });
|
|
491
724
|
if (!Array.isArray(data) || data.length === 0) {
|
|
492
|
-
return /* @__PURE__ */
|
|
725
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid line chart data");
|
|
493
726
|
}
|
|
494
727
|
const chartData = data.map((point) => {
|
|
495
728
|
var _a;
|
|
@@ -499,7 +732,7 @@ function LineChartView({ data, primaryColor }) {
|
|
|
499
732
|
};
|
|
500
733
|
});
|
|
501
734
|
const lineColor = primaryColor != null ? primaryColor : getColor(0);
|
|
502
|
-
return /* @__PURE__ */
|
|
735
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm overflow-x-auto" }, /* @__PURE__ */ import_react7.default.createElement(import_recharts2.ResponsiveContainer, { width: "100%", height: 260 }, /* @__PURE__ */ import_react7.default.createElement(import_recharts2.LineChart, { data: chartData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react7.default.createElement(import_recharts2.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react7.default.createElement(
|
|
503
736
|
import_recharts2.XAxis,
|
|
504
737
|
{
|
|
505
738
|
dataKey: "label",
|
|
@@ -507,7 +740,7 @@ function LineChartView({ data, primaryColor }) {
|
|
|
507
740
|
tickLine: false,
|
|
508
741
|
axisLine: { stroke: "#cbd5e1" }
|
|
509
742
|
}
|
|
510
|
-
), /* @__PURE__ */
|
|
743
|
+
), /* @__PURE__ */ import_react7.default.createElement(import_recharts2.YAxis, { tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react7.default.createElement(import_recharts2.Tooltip, { content: /* @__PURE__ */ import_react7.default.createElement(CustomTooltip, null) }), /* @__PURE__ */ import_react7.default.createElement(
|
|
511
744
|
import_recharts2.Line,
|
|
512
745
|
{
|
|
513
746
|
type: "monotone",
|
|
@@ -520,14 +753,15 @@ function LineChartView({ data, primaryColor }) {
|
|
|
520
753
|
}
|
|
521
754
|
))));
|
|
522
755
|
}
|
|
523
|
-
function RadarChartView({ data }) {
|
|
756
|
+
function RadarChartView({ data, isStreaming }) {
|
|
757
|
+
if (isStreaming) return /* @__PURE__ */ import_react7.default.createElement(ChartSkeleton, { type: "pie" });
|
|
524
758
|
if (!Array.isArray(data) || data.length === 0) {
|
|
525
|
-
return /* @__PURE__ */
|
|
759
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid radar chart data");
|
|
526
760
|
}
|
|
527
761
|
const productNames = Array.from(
|
|
528
762
|
new Set(data.flatMap((item) => Object.keys(item).filter((key) => key !== "attribute")))
|
|
529
763
|
);
|
|
530
|
-
return /* @__PURE__ */
|
|
764
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm" }, /* @__PURE__ */ import_react7.default.createElement(import_recharts2.ResponsiveContainer, { width: "100%", height: 300 }, /* @__PURE__ */ import_react7.default.createElement(import_recharts2.RadarChart, { cx: "50%", cy: "50%", outerRadius: "80%", data }, /* @__PURE__ */ import_react7.default.createElement(import_recharts2.PolarGrid, { stroke: "#e2e8f0" }), /* @__PURE__ */ import_react7.default.createElement(import_recharts2.PolarAngleAxis, { dataKey: "attribute", tick: { fontSize: 11, fill: "#64748b" } }), /* @__PURE__ */ import_react7.default.createElement(import_recharts2.PolarRadiusAxis, { tick: { fontSize: 10, fill: "#64748b" } }), productNames.map((productName, index) => /* @__PURE__ */ import_react7.default.createElement(
|
|
531
765
|
import_recharts2.Radar,
|
|
532
766
|
{
|
|
533
767
|
key: productName,
|
|
@@ -537,26 +771,27 @@ function RadarChartView({ data }) {
|
|
|
537
771
|
fill: getColor(index),
|
|
538
772
|
fillOpacity: 0.4
|
|
539
773
|
}
|
|
540
|
-
)), /* @__PURE__ */
|
|
774
|
+
)), /* @__PURE__ */ import_react7.default.createElement(import_recharts2.Tooltip, { content: /* @__PURE__ */ import_react7.default.createElement(CustomTooltip, null) }), /* @__PURE__ */ import_react7.default.createElement(import_recharts2.Legend, { wrapperStyle: { fontSize: 12 } }))));
|
|
541
775
|
}
|
|
542
|
-
function TableView({ data }) {
|
|
776
|
+
function TableView({ data, isStreaming }) {
|
|
777
|
+
if (isStreaming) return /* @__PURE__ */ import_react7.default.createElement(ChartSkeleton, { type: "table" });
|
|
543
778
|
if (!(data == null ? void 0 : data.columns) || !(data == null ? void 0 : data.rows)) {
|
|
544
|
-
return /* @__PURE__ */
|
|
779
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid table data");
|
|
545
780
|
}
|
|
546
|
-
return /* @__PURE__ */
|
|
781
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ import_react7.default.createElement("table", { className: "w-full text-sm border-collapse" }, /* @__PURE__ */ import_react7.default.createElement("thead", { className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ import_react7.default.createElement("tr", null, data.columns.map((col, idx) => /* @__PURE__ */ import_react7.default.createElement(
|
|
547
782
|
"th",
|
|
548
783
|
{
|
|
549
784
|
key: idx,
|
|
550
785
|
className: "px-4 py-3 text-left text-xs font-semibold text-slate-700 dark:text-white/90 whitespace-nowrap uppercase tracking-wider"
|
|
551
786
|
},
|
|
552
787
|
col
|
|
553
|
-
)))), /* @__PURE__ */
|
|
788
|
+
)))), /* @__PURE__ */ import_react7.default.createElement("tbody", { className: "divide-y divide-slate-100 dark:divide-white/5" }, data.rows.map((row, rowIdx) => /* @__PURE__ */ import_react7.default.createElement(
|
|
554
789
|
"tr",
|
|
555
790
|
{
|
|
556
791
|
key: rowIdx,
|
|
557
792
|
className: "hover:bg-slate-50/60 dark:hover:bg-white/5 transition-colors"
|
|
558
793
|
},
|
|
559
|
-
row.map((cell, cellIdx) => /* @__PURE__ */
|
|
794
|
+
row.map((cell, cellIdx) => /* @__PURE__ */ import_react7.default.createElement(
|
|
560
795
|
"td",
|
|
561
796
|
{
|
|
562
797
|
key: cellIdx,
|
|
@@ -564,7 +799,7 @@ function TableView({ data }) {
|
|
|
564
799
|
},
|
|
565
800
|
String(cell)
|
|
566
801
|
))
|
|
567
|
-
))))), /* @__PURE__ */
|
|
802
|
+
))))), /* @__PURE__ */ import_react7.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_react7.default.createElement("p", { className: "text-[11px] text-slate-400 dark:text-white/30" }, data.rows.length, " row", data.rows.length !== 1 ? "s" : "")));
|
|
568
803
|
}
|
|
569
804
|
function CarouselView({
|
|
570
805
|
data,
|
|
@@ -572,7 +807,7 @@ function CarouselView({
|
|
|
572
807
|
primaryColor
|
|
573
808
|
}) {
|
|
574
809
|
if (!Array.isArray(data)) {
|
|
575
|
-
return /* @__PURE__ */
|
|
810
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid carousel data");
|
|
576
811
|
}
|
|
577
812
|
const products = data.map((product) => ({
|
|
578
813
|
id: product.id,
|
|
@@ -584,7 +819,7 @@ function CarouselView({
|
|
|
584
819
|
description: product.description,
|
|
585
820
|
inStock: product.inStock
|
|
586
821
|
}));
|
|
587
|
-
return /* @__PURE__ */
|
|
822
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "w-full" }, /* @__PURE__ */ import_react7.default.createElement(
|
|
588
823
|
ProductCarousel,
|
|
589
824
|
{
|
|
590
825
|
products,
|
|
@@ -595,10 +830,333 @@ function CarouselView({
|
|
|
595
830
|
}
|
|
596
831
|
function TextView({ data }) {
|
|
597
832
|
const content = (data == null ? void 0 : data.content) || String(data != null ? data : "");
|
|
598
|
-
return /* @__PURE__ */
|
|
833
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm" }, /* @__PURE__ */ import_react7.default.createElement("p", { className: "text-sm text-slate-700 dark:text-slate-300 whitespace-pre-wrap leading-relaxed" }, content));
|
|
599
834
|
}
|
|
600
835
|
|
|
601
|
-
// src/components/
|
|
836
|
+
// src/components/ObservabilityPanel.tsx
|
|
837
|
+
var import_react8 = __toESM(require("react"));
|
|
838
|
+
var import_lucide_react5 = require("lucide-react");
|
|
839
|
+
function fmtMs(ms) {
|
|
840
|
+
return ms >= 1e3 ? `${(ms / 1e3).toFixed(2)}s` : `${Math.round(ms)}ms`;
|
|
841
|
+
}
|
|
842
|
+
function fmtTokens(n) {
|
|
843
|
+
return n >= 1e3 ? `${(n / 1e3).toFixed(1)}k` : String(n);
|
|
844
|
+
}
|
|
845
|
+
function ScoreBadge({ score }) {
|
|
846
|
+
const pct = Math.round(score * 100);
|
|
847
|
+
const color = pct <= 20 ? "text-emerald-600 bg-emerald-50 border-emerald-200 dark:text-emerald-400 dark:bg-emerald-500/10 dark:border-emerald-500/20" : pct <= 50 ? "text-amber-600 bg-amber-50 border-amber-200 dark:text-amber-400 dark:bg-amber-500/10 dark:border-amber-500/20" : "text-red-600 bg-red-50 border-red-200 dark:text-red-400 dark:bg-red-500/10 dark:border-red-500/20";
|
|
848
|
+
return /* @__PURE__ */ import_react8.default.createElement("span", { className: `inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[11px] font-semibold border ${color}` }, pct <= 20 ? /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.CheckCircle, { className: "w-3 h-3" }) : /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.AlertCircle, { className: "w-3 h-3" }), pct, "% hallucination risk");
|
|
849
|
+
}
|
|
850
|
+
function RetrievalTab({ trace }) {
|
|
851
|
+
return /* @__PURE__ */ import_react8.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-[11px] text-slate-500 dark:text-white/40" }, trace.chunks.length, " chunk", trace.chunks.length !== 1 ? "s" : "", " retrieved", trace.rewrittenQuery && /* @__PURE__ */ import_react8.default.createElement("span", { className: "ml-2 italic" }, "(query rewritten: ", /* @__PURE__ */ import_react8.default.createElement("em", { className: "text-indigo-500" }, trace.rewrittenQuery), ")")), /* @__PURE__ */ import_react8.default.createElement("div", { className: "space-y-1.5 max-h-56 overflow-y-auto pr-1 custom-scrollbar" }, trace.chunks.map((chunk, i) => /* @__PURE__ */ import_react8.default.createElement(
|
|
852
|
+
"div",
|
|
853
|
+
{
|
|
854
|
+
key: String(chunk.id),
|
|
855
|
+
className: "rounded-lg border border-slate-100 dark:border-white/8 bg-slate-50 dark:bg-white/3 p-2.5"
|
|
856
|
+
},
|
|
857
|
+
/* @__PURE__ */ import_react8.default.createElement("div", { className: "flex items-center justify-between mb-1" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[10px] font-mono text-slate-400 dark:text-white/30" }, "[", i + 1, "] ", String(chunk.id).slice(0, 20)), /* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[10px] font-semibold text-indigo-600 dark:text-indigo-400" }, "score: ", chunk.score.toFixed(3))),
|
|
858
|
+
/* @__PURE__ */ import_react8.default.createElement("div", { className: "h-1 rounded-full bg-slate-200 dark:bg-white/10 mb-2 overflow-hidden" }, /* @__PURE__ */ import_react8.default.createElement(
|
|
859
|
+
"div",
|
|
860
|
+
{
|
|
861
|
+
className: "h-full rounded-full bg-indigo-500 dark:bg-indigo-400 transition-all",
|
|
862
|
+
style: { width: `${Math.min(100, chunk.score * 100)}%` }
|
|
863
|
+
}
|
|
864
|
+
)),
|
|
865
|
+
/* @__PURE__ */ import_react8.default.createElement("p", { className: "text-[11px] text-slate-600 dark:text-white/60 line-clamp-2 leading-relaxed" }, chunk.content)
|
|
866
|
+
))));
|
|
867
|
+
}
|
|
868
|
+
function LatencyTab({ trace }) {
|
|
869
|
+
const { latency } = trace;
|
|
870
|
+
const bars = [
|
|
871
|
+
{ label: "Embed", ms: latency.embedMs, color: "#6366f1" },
|
|
872
|
+
{ label: "Retrieve", ms: latency.retrieveMs, color: "#10b981" },
|
|
873
|
+
...latency.rerankMs != null ? [{ label: "Rerank", ms: latency.rerankMs, color: "#f59e0b" }] : [],
|
|
874
|
+
{ label: "Generate", ms: latency.generateMs, color: "#8b5cf6" }
|
|
875
|
+
];
|
|
876
|
+
const maxMs = Math.max(...bars.map((b) => b.ms), 1);
|
|
877
|
+
return /* @__PURE__ */ import_react8.default.createElement("div", { className: "space-y-3" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[11px] text-slate-500 dark:text-white/40" }, "Pipeline stages"), /* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[11px] font-semibold text-slate-700 dark:text-white/70" }, "Total: ", fmtMs(latency.totalMs))), /* @__PURE__ */ import_react8.default.createElement("div", { className: "space-y-2" }, bars.map((bar) => /* @__PURE__ */ import_react8.default.createElement("div", { key: bar.label, className: "space-y-0.5" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[11px] text-slate-600 dark:text-white/60" }, bar.label), /* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[11px] font-mono text-slate-500 dark:text-white/40" }, fmtMs(bar.ms))), /* @__PURE__ */ import_react8.default.createElement("div", { className: "h-2 rounded-full bg-slate-100 dark:bg-white/8 overflow-hidden" }, /* @__PURE__ */ import_react8.default.createElement(
|
|
878
|
+
"div",
|
|
879
|
+
{
|
|
880
|
+
className: "h-full rounded-full transition-all duration-700",
|
|
881
|
+
style: {
|
|
882
|
+
width: `${bar.ms / maxMs * 100}%`,
|
|
883
|
+
background: bar.color,
|
|
884
|
+
opacity: 0.85
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
))))));
|
|
888
|
+
}
|
|
889
|
+
function TokensTab({ trace }) {
|
|
890
|
+
const { tokens } = trace;
|
|
891
|
+
if (!tokens) {
|
|
892
|
+
return /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-[11px] text-slate-400 dark:text-white/30 italic" }, "Token data not available.");
|
|
893
|
+
}
|
|
894
|
+
const stats = [
|
|
895
|
+
{ label: "Prompt Tokens", value: fmtTokens(tokens.promptTokens), color: "text-indigo-600 dark:text-indigo-400" },
|
|
896
|
+
{ label: "Completion Tokens", value: fmtTokens(tokens.completionTokens), color: "text-emerald-600 dark:text-emerald-400" },
|
|
897
|
+
{ label: "Total Tokens", value: fmtTokens(tokens.totalTokens), color: "text-slate-700 dark:text-white/80" }
|
|
898
|
+
];
|
|
899
|
+
return /* @__PURE__ */ import_react8.default.createElement("div", { className: "space-y-3" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "grid grid-cols-3 gap-2" }, stats.map((s) => /* @__PURE__ */ import_react8.default.createElement("div", { key: s.label, className: "rounded-lg border border-slate-100 dark:border-white/8 bg-slate-50 dark:bg-white/3 p-2.5 text-center" }, /* @__PURE__ */ import_react8.default.createElement("p", { className: `text-lg font-bold ${s.color}` }, s.value), /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-[10px] text-slate-400 dark:text-white/30 mt-0.5" }, s.label)))), tokens.estimatedCostUsd != null && /* @__PURE__ */ import_react8.default.createElement("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" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[11px] text-emerald-700 dark:text-emerald-400 font-medium" }, "Estimated Cost"), /* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[11px] font-bold text-emerald-700 dark:text-emerald-400" }, "$", tokens.estimatedCostUsd < 1e-4 ? tokens.estimatedCostUsd.toExponential(2) : tokens.estimatedCostUsd.toFixed(5), " USD")), /* @__PURE__ */ import_react8.default.createElement("div", { className: "h-2 rounded-full overflow-hidden flex" }, /* @__PURE__ */ import_react8.default.createElement(
|
|
900
|
+
"div",
|
|
901
|
+
{
|
|
902
|
+
className: "h-full bg-indigo-500 dark:bg-indigo-400",
|
|
903
|
+
style: { width: `${tokens.promptTokens / tokens.totalTokens * 100}%` },
|
|
904
|
+
title: "Prompt tokens"
|
|
905
|
+
}
|
|
906
|
+
), /* @__PURE__ */ import_react8.default.createElement(
|
|
907
|
+
"div",
|
|
908
|
+
{
|
|
909
|
+
className: "h-full bg-emerald-500 dark:bg-emerald-400",
|
|
910
|
+
style: { width: `${tokens.completionTokens / tokens.totalTokens * 100}%` },
|
|
911
|
+
title: "Completion tokens"
|
|
912
|
+
}
|
|
913
|
+
)), /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex gap-3 text-[10px] text-slate-400 dark:text-white/30" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "inline-block w-2 h-2 rounded-full bg-indigo-500" }), " Prompt"), /* @__PURE__ */ import_react8.default.createElement("span", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "inline-block w-2 h-2 rounded-full bg-emerald-500" }), " Completion")));
|
|
914
|
+
}
|
|
915
|
+
function HallucinationTab({ trace }) {
|
|
916
|
+
if (trace.hallucinationScore == null) {
|
|
917
|
+
return /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-[11px] text-slate-400 dark:text-white/30 italic" }, "Hallucination scoring not available for this response.");
|
|
918
|
+
}
|
|
919
|
+
const score = trace.hallucinationScore;
|
|
920
|
+
const pct = Math.round(score * 100);
|
|
921
|
+
const barColor = pct <= 20 ? "#10b981" : pct <= 50 ? "#f59e0b" : "#ef4444";
|
|
922
|
+
return /* @__PURE__ */ import_react8.default.createElement("div", { className: "space-y-3" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react8.default.createElement(ScoreBadge, { score }), /* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[11px] font-mono text-slate-500 dark:text-white/40" }, pct, "/100")), /* @__PURE__ */ import_react8.default.createElement("div", { className: "h-3 rounded-full bg-slate-100 dark:bg-white/8 overflow-hidden" }, /* @__PURE__ */ import_react8.default.createElement(
|
|
923
|
+
"div",
|
|
924
|
+
{
|
|
925
|
+
className: "h-full rounded-full transition-all duration-700",
|
|
926
|
+
style: { width: `${pct}%`, background: barColor }
|
|
927
|
+
}
|
|
928
|
+
)), trace.hallucinationReason && /* @__PURE__ */ import_react8.default.createElement("div", { className: "rounded-lg border border-slate-100 dark:border-white/8 bg-slate-50 dark:bg-white/3 p-2.5" }, /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-[11px] text-slate-500 dark:text-white/40 font-medium mb-0.5" }, "AI self-assessment"), /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-[11px] text-slate-700 dark:text-white/70 leading-relaxed" }, trace.hallucinationReason)), /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex gap-2 text-[10px] text-slate-400 dark:text-white/30" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "inline-block w-2 h-2 rounded-full bg-emerald-500" }), " 0\u201320%: Grounded"), /* @__PURE__ */ import_react8.default.createElement("span", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "inline-block w-2 h-2 rounded-full bg-amber-500" }), " 21\u201350%: Uncertain"), /* @__PURE__ */ import_react8.default.createElement("span", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "inline-block w-2 h-2 rounded-full bg-red-500" }), " 51\u2013100%: Risk")));
|
|
929
|
+
}
|
|
930
|
+
function PromptTab({ trace }) {
|
|
931
|
+
const [showSystem, setShowSystem] = import_react8.default.useState(false);
|
|
932
|
+
return /* @__PURE__ */ import_react8.default.createElement("div", { className: "space-y-3" }, /* @__PURE__ */ import_react8.default.createElement("div", null, /* @__PURE__ */ import_react8.default.createElement(
|
|
933
|
+
"button",
|
|
934
|
+
{
|
|
935
|
+
onClick: () => setShowSystem((s) => !s),
|
|
936
|
+
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"
|
|
937
|
+
},
|
|
938
|
+
showSystem ? /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.ChevronDown, { className: "w-3 h-3" }) : /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.ChevronRight, { className: "w-3 h-3" }),
|
|
939
|
+
"System Prompt"
|
|
940
|
+
), showSystem && /* @__PURE__ */ import_react8.default.createElement("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" }, trace.systemPrompt || "(empty)")), /* @__PURE__ */ import_react8.default.createElement("div", null, /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-[11px] font-semibold text-slate-600 dark:text-white/60 mb-1.5" }, "User Prompt"), /* @__PURE__ */ import_react8.default.createElement("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" }, trace.userPrompt)));
|
|
941
|
+
}
|
|
942
|
+
function ChunksTab({ trace }) {
|
|
943
|
+
const [expanded, setExpanded] = import_react8.default.useState(/* @__PURE__ */ new Set());
|
|
944
|
+
const toggle = (i) => setExpanded((prev) => {
|
|
945
|
+
const next = new Set(prev);
|
|
946
|
+
if (next.has(i)) {
|
|
947
|
+
next.delete(i);
|
|
948
|
+
} else {
|
|
949
|
+
next.add(i);
|
|
950
|
+
}
|
|
951
|
+
return next;
|
|
952
|
+
});
|
|
953
|
+
return /* @__PURE__ */ import_react8.default.createElement("div", { className: "space-y-1.5 max-h-64 overflow-y-auto pr-1 custom-scrollbar" }, trace.chunks.map((chunk, i) => {
|
|
954
|
+
const isOpen = expanded.has(i);
|
|
955
|
+
return /* @__PURE__ */ import_react8.default.createElement(
|
|
956
|
+
"div",
|
|
957
|
+
{
|
|
958
|
+
key: String(chunk.id),
|
|
959
|
+
className: "rounded-lg border border-slate-100 dark:border-white/8 bg-slate-50 dark:bg-white/3 overflow-hidden"
|
|
960
|
+
},
|
|
961
|
+
/* @__PURE__ */ import_react8.default.createElement(
|
|
962
|
+
"button",
|
|
963
|
+
{
|
|
964
|
+
onClick: () => toggle(i),
|
|
965
|
+
className: "w-full flex items-center justify-between px-3 py-2 text-left hover:bg-slate-100 dark:hover:bg-white/5 transition-colors"
|
|
966
|
+
},
|
|
967
|
+
/* @__PURE__ */ import_react8.default.createElement("div", { className: "flex items-center gap-2" }, isOpen ? /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.ChevronDown, { className: "w-3 h-3 text-slate-400" }) : /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.ChevronRight, { className: "w-3 h-3 text-slate-400" }), /* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[11px] font-medium text-slate-700 dark:text-white/70" }, "Chunk ", i + 1), /* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[10px] font-mono text-slate-400 dark:text-white/30" }, String(chunk.id).slice(0, 16))),
|
|
968
|
+
/* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[10px] font-semibold text-indigo-600 dark:text-indigo-400" }, chunk.score.toFixed(3))
|
|
969
|
+
),
|
|
970
|
+
isOpen && /* @__PURE__ */ import_react8.default.createElement("div", { className: "px-3 pb-3 space-y-2 border-t border-slate-100 dark:border-white/5 pt-2" }, /* @__PURE__ */ import_react8.default.createElement("div", null, /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-[10px] text-slate-400 dark:text-white/30 font-semibold uppercase tracking-wider mb-1" }, "Content"), /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-[11px] text-slate-600 dark:text-white/60 leading-relaxed whitespace-pre-wrap" }, chunk.content)), Object.keys(chunk.metadata).length > 0 && /* @__PURE__ */ import_react8.default.createElement("div", null, /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-[10px] text-slate-400 dark:text-white/30 font-semibold uppercase tracking-wider mb-1" }, "Metadata"), /* @__PURE__ */ import_react8.default.createElement("pre", { className: "text-[10px] font-mono text-slate-500 dark:text-white/40 bg-slate-900 dark:bg-black/30 rounded-md p-2 overflow-auto max-h-24" }, JSON.stringify(chunk.metadata, null, 2))))
|
|
971
|
+
);
|
|
972
|
+
}));
|
|
973
|
+
}
|
|
974
|
+
var TABS = [
|
|
975
|
+
{ id: "retrieval", label: "Retrieval", icon: /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Layers, { className: "w-3 h-3" }) },
|
|
976
|
+
{ id: "latency", label: "Latency", icon: /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Clock, { className: "w-3 h-3" }) },
|
|
977
|
+
{ id: "tokens", label: "Tokens", icon: /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Cpu, { className: "w-3 h-3" }) },
|
|
978
|
+
{ id: "hallucination", label: "Grounding", icon: /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.AlertTriangle, { className: "w-3 h-3" }) },
|
|
979
|
+
{ id: "prompt", label: "Prompt", icon: /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.FileText, { className: "w-3 h-3" }) },
|
|
980
|
+
{ id: "chunks", label: "Chunks", icon: /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Zap, { className: "w-3 h-3" }) }
|
|
981
|
+
];
|
|
982
|
+
function ObservabilityPanel({ trace, primaryColor = "#6366f1" }) {
|
|
983
|
+
const [activeTab, setActiveTab] = import_react8.default.useState("retrieval");
|
|
984
|
+
return /* @__PURE__ */ import_react8.default.createElement("div", { className: "mt-2 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]" }, /* @__PURE__ */ import_react8.default.createElement(
|
|
985
|
+
"div",
|
|
986
|
+
{
|
|
987
|
+
className: "flex items-center gap-2 px-3 py-2 border-b border-slate-100 dark:border-white/8",
|
|
988
|
+
style: { background: `${primaryColor}08` }
|
|
989
|
+
},
|
|
990
|
+
/* @__PURE__ */ import_react8.default.createElement(
|
|
991
|
+
"span",
|
|
992
|
+
{
|
|
993
|
+
className: "inline-flex items-center gap-1 text-[10px] font-bold uppercase tracking-wider",
|
|
994
|
+
style: { color: primaryColor }
|
|
995
|
+
},
|
|
996
|
+
/* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Zap, { className: "w-3 h-3" }),
|
|
997
|
+
"Observability Trace"
|
|
998
|
+
),
|
|
999
|
+
/* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[10px] text-slate-400 dark:text-white/30 ml-auto font-mono" }, trace.requestId)
|
|
1000
|
+
), /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex border-b border-slate-100 dark:border-white/8 overflow-x-auto" }, TABS.map((tab) => /* @__PURE__ */ import_react8.default.createElement(
|
|
1001
|
+
"button",
|
|
1002
|
+
{
|
|
1003
|
+
key: tab.id,
|
|
1004
|
+
onClick: () => setActiveTab(tab.id),
|
|
1005
|
+
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"}`,
|
|
1006
|
+
style: activeTab === tab.id ? { borderBottomColor: primaryColor, color: primaryColor } : {}
|
|
1007
|
+
},
|
|
1008
|
+
tab.icon,
|
|
1009
|
+
tab.label
|
|
1010
|
+
))), /* @__PURE__ */ import_react8.default.createElement("div", { className: "p-3" }, activeTab === "retrieval" && /* @__PURE__ */ import_react8.default.createElement(RetrievalTab, { trace }), activeTab === "latency" && /* @__PURE__ */ import_react8.default.createElement(LatencyTab, { trace }), activeTab === "tokens" && /* @__PURE__ */ import_react8.default.createElement(TokensTab, { trace }), activeTab === "hallucination" && /* @__PURE__ */ import_react8.default.createElement(HallucinationTab, { trace }), activeTab === "prompt" && /* @__PURE__ */ import_react8.default.createElement(PromptTab, { trace }), activeTab === "chunks" && /* @__PURE__ */ import_react8.default.createElement(ChunksTab, { trace })));
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
// src/components/HourglassLoader.tsx
|
|
1014
|
+
var import_react9 = __toESM(require("react"));
|
|
1015
|
+
var HourglassLoader = ({
|
|
1016
|
+
size = 16,
|
|
1017
|
+
primaryColor = "#10b981",
|
|
1018
|
+
glow = false
|
|
1019
|
+
}) => {
|
|
1020
|
+
return /* @__PURE__ */ import_react9.default.createElement(
|
|
1021
|
+
"svg",
|
|
1022
|
+
{
|
|
1023
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1024
|
+
viewBox: "0 0 100 100",
|
|
1025
|
+
preserveAspectRatio: "xMidYMid",
|
|
1026
|
+
style: {
|
|
1027
|
+
width: size,
|
|
1028
|
+
height: size,
|
|
1029
|
+
background: "transparent",
|
|
1030
|
+
filter: glow ? `drop-shadow(0 0 4px ${primaryColor})` : "none"
|
|
1031
|
+
}
|
|
1032
|
+
},
|
|
1033
|
+
/* @__PURE__ */ import_react9.default.createElement("g", null, /* @__PURE__ */ import_react9.default.createElement(
|
|
1034
|
+
"animateTransform",
|
|
1035
|
+
{
|
|
1036
|
+
attributeName: "transform",
|
|
1037
|
+
type: "rotate",
|
|
1038
|
+
calcMode: "spline",
|
|
1039
|
+
values: "0 50 50; 0 50 50; 180 50 50",
|
|
1040
|
+
keyTimes: "0; 0.8; 1",
|
|
1041
|
+
keySplines: "0 0 1 1; 0.4 0 0.2 1",
|
|
1042
|
+
dur: "2s",
|
|
1043
|
+
repeatCount: "indefinite"
|
|
1044
|
+
}
|
|
1045
|
+
), /* @__PURE__ */ import_react9.default.createElement(
|
|
1046
|
+
"path",
|
|
1047
|
+
{
|
|
1048
|
+
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",
|
|
1049
|
+
fill: "none",
|
|
1050
|
+
stroke: primaryColor,
|
|
1051
|
+
strokeWidth: "5",
|
|
1052
|
+
strokeLinejoin: "round",
|
|
1053
|
+
strokeLinecap: "round"
|
|
1054
|
+
}
|
|
1055
|
+
), /* @__PURE__ */ import_react9.default.createElement("path", { fill: primaryColor }, /* @__PURE__ */ import_react9.default.createElement(
|
|
1056
|
+
"animate",
|
|
1057
|
+
{
|
|
1058
|
+
attributeName: "d",
|
|
1059
|
+
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",
|
|
1060
|
+
keyTimes: "0; 0.8; 1",
|
|
1061
|
+
dur: "2s",
|
|
1062
|
+
repeatCount: "indefinite"
|
|
1063
|
+
}
|
|
1064
|
+
)), /* @__PURE__ */ import_react9.default.createElement("path", { fill: primaryColor }, /* @__PURE__ */ import_react9.default.createElement(
|
|
1065
|
+
"animate",
|
|
1066
|
+
{
|
|
1067
|
+
attributeName: "d",
|
|
1068
|
+
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",
|
|
1069
|
+
keyTimes: "0; 0.8; 1",
|
|
1070
|
+
dur: "2s",
|
|
1071
|
+
repeatCount: "indefinite"
|
|
1072
|
+
}
|
|
1073
|
+
)), /* @__PURE__ */ import_react9.default.createElement("line", { x1: "50", y1: "50", x2: "50", y2: "80", stroke: primaryColor, strokeWidth: "3" }, /* @__PURE__ */ import_react9.default.createElement(
|
|
1074
|
+
"animate",
|
|
1075
|
+
{
|
|
1076
|
+
attributeName: "opacity",
|
|
1077
|
+
values: "0; 1; 1; 0; 0",
|
|
1078
|
+
keyTimes: "0; 0.1; 0.7; 0.8; 1",
|
|
1079
|
+
dur: "2s",
|
|
1080
|
+
repeatCount: "indefinite"
|
|
1081
|
+
}
|
|
1082
|
+
)))
|
|
1083
|
+
);
|
|
1084
|
+
};
|
|
1085
|
+
var HourglassLoader_default = HourglassLoader;
|
|
1086
|
+
|
|
1087
|
+
// src/utils/synonyms.ts
|
|
1088
|
+
var FIELD_SYNONYMS = {
|
|
1089
|
+
name: ["product", "item", "title", "label", "heading", "subject", "product name", "item name"],
|
|
1090
|
+
price: ["cost", "amount", "msrp", "price", "rate", "value", "price_usd"],
|
|
1091
|
+
brand: ["manufacturer", "vendor", "make", "company", "brand_name", "supplier"],
|
|
1092
|
+
image: [
|
|
1093
|
+
"imageUrl",
|
|
1094
|
+
"thumbnail",
|
|
1095
|
+
"img",
|
|
1096
|
+
"url",
|
|
1097
|
+
"photo",
|
|
1098
|
+
"picture",
|
|
1099
|
+
"media",
|
|
1100
|
+
"image_url",
|
|
1101
|
+
"main_image",
|
|
1102
|
+
"product_image",
|
|
1103
|
+
"thumb"
|
|
1104
|
+
],
|
|
1105
|
+
stock: [
|
|
1106
|
+
"inventory",
|
|
1107
|
+
"quantity",
|
|
1108
|
+
"count",
|
|
1109
|
+
"availability",
|
|
1110
|
+
"stock_level",
|
|
1111
|
+
"inStock",
|
|
1112
|
+
"is_available",
|
|
1113
|
+
"in stock",
|
|
1114
|
+
"status"
|
|
1115
|
+
],
|
|
1116
|
+
description: ["summary", "content", "body", "text", "info", "details"],
|
|
1117
|
+
link: ["url", "href", "product_url", "page_url", "link"]
|
|
1118
|
+
};
|
|
1119
|
+
function addSynonyms(customSynonyms) {
|
|
1120
|
+
for (const [key, aliases] of Object.entries(customSynonyms)) {
|
|
1121
|
+
if (!FIELD_SYNONYMS[key]) {
|
|
1122
|
+
FIELD_SYNONYMS[key] = [];
|
|
1123
|
+
}
|
|
1124
|
+
const existing = new Set(FIELD_SYNONYMS[key].map((s) => s.toLowerCase()));
|
|
1125
|
+
for (const alias of aliases) {
|
|
1126
|
+
if (!existing.has(alias.toLowerCase())) {
|
|
1127
|
+
FIELD_SYNONYMS[key].push(alias);
|
|
1128
|
+
existing.add(alias.toLowerCase());
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
function resolveMetadataValue(meta, uiKey) {
|
|
1134
|
+
var _a;
|
|
1135
|
+
const synonyms = (_a = FIELD_SYNONYMS[uiKey]) != null ? _a : [];
|
|
1136
|
+
const keys = Object.keys(meta);
|
|
1137
|
+
const systemKeys = ["namespace", "filename", "filesize", "filetype", "docid", "uploadedat", "dimension", "chunkindex"];
|
|
1138
|
+
let match = keys.find((k) => k.toLowerCase() === uiKey.toLowerCase());
|
|
1139
|
+
if (match !== void 0) return meta[match];
|
|
1140
|
+
match = keys.find((k) => synonyms.map((s) => s.toLowerCase()).includes(k.toLowerCase()));
|
|
1141
|
+
if (match !== void 0) return meta[match];
|
|
1142
|
+
const isBlacklisted = (kl) => {
|
|
1143
|
+
return systemKeys.includes(kl) || kl.startsWith("option1") || kl.startsWith("option2") || kl.startsWith("option3");
|
|
1144
|
+
};
|
|
1145
|
+
match = keys.find((k) => {
|
|
1146
|
+
const kl = k.toLowerCase();
|
|
1147
|
+
if (isBlacklisted(kl)) return false;
|
|
1148
|
+
return kl.includes(uiKey.toLowerCase());
|
|
1149
|
+
});
|
|
1150
|
+
if (match !== void 0) return meta[match];
|
|
1151
|
+
match = keys.find((k) => {
|
|
1152
|
+
const kl = k.toLowerCase();
|
|
1153
|
+
if (isBlacklisted(kl)) return false;
|
|
1154
|
+
return synonyms.some((sk) => kl.includes(sk.toLowerCase()) || sk.toLowerCase().includes(kl));
|
|
1155
|
+
});
|
|
1156
|
+
return match !== void 0 ? meta[match] : void 0;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
// src/utils/ProductExtractor.ts
|
|
602
1160
|
function sanitizeJson(raw) {
|
|
603
1161
|
let s = raw.trim();
|
|
604
1162
|
s = s.replace(
|
|
@@ -615,37 +1173,35 @@ function sanitizeJson(raw) {
|
|
|
615
1173
|
s = s.replace(/'([^'\\]*(?:\\.[^'\\]*)*)'/g, '"$1"');
|
|
616
1174
|
s = s.replace(/,\s*([}\]])/g, "$1");
|
|
617
1175
|
s = s.replace(/([{,])\s*""\s*(?=[,}])/g, "$1");
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
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
|
-
}
|
|
1176
|
+
const stack = [];
|
|
1177
|
+
let inString = false;
|
|
1178
|
+
let escape = false;
|
|
1179
|
+
for (const ch of s) {
|
|
1180
|
+
if (escape) {
|
|
1181
|
+
escape = false;
|
|
1182
|
+
continue;
|
|
1183
|
+
}
|
|
1184
|
+
if (ch === "\\" && inString) {
|
|
1185
|
+
escape = true;
|
|
1186
|
+
continue;
|
|
1187
|
+
}
|
|
1188
|
+
if (ch === '"') {
|
|
1189
|
+
inString = !inString;
|
|
1190
|
+
continue;
|
|
643
1191
|
}
|
|
644
|
-
if (inString)
|
|
645
|
-
|
|
646
|
-
|
|
1192
|
+
if (inString) continue;
|
|
1193
|
+
if (ch === "{" || ch === "[") {
|
|
1194
|
+
stack.push(ch);
|
|
1195
|
+
} else if (ch === "}") {
|
|
1196
|
+
if (stack[stack.length - 1] === "{") stack.pop();
|
|
1197
|
+
} else if (ch === "]") {
|
|
1198
|
+
if (stack[stack.length - 1] === "[") stack.pop();
|
|
647
1199
|
}
|
|
648
1200
|
}
|
|
1201
|
+
if (inString) s += '"';
|
|
1202
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
1203
|
+
s += stack[i] === "{" ? "}" : "]";
|
|
1204
|
+
}
|
|
649
1205
|
const lastClose = Math.max(s.lastIndexOf("}"), s.lastIndexOf("]"));
|
|
650
1206
|
if (lastClose !== -1 && lastClose < s.length - 1 && /\S/.test(s.slice(lastClose + 1))) {
|
|
651
1207
|
s = s.substring(0, lastClose + 1);
|
|
@@ -745,10 +1301,6 @@ function extractStructuredPayload(raw) {
|
|
|
745
1301
|
text: stripStructuredUiLabels(raw).replace(/\n{3,}/g, "\n\n").trim()
|
|
746
1302
|
};
|
|
747
1303
|
}
|
|
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
1304
|
function resolveImage(data) {
|
|
753
1305
|
const isPlaceholder = (val) => typeof val === "string" && (val === "..." || val === "" || val.toLowerCase() === "null" || val.toLowerCase() === "undefined");
|
|
754
1306
|
for (const key of ["image", "img", "thumbnail", "images", "product_image", "Image", "Thumbnail"]) {
|
|
@@ -758,92 +1310,140 @@ function resolveImage(data) {
|
|
|
758
1310
|
}
|
|
759
1311
|
return void 0;
|
|
760
1312
|
}
|
|
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());
|
|
1313
|
+
function isLikelyUiOnlyMessage(text) {
|
|
1314
|
+
const trimmed = text.trim();
|
|
1315
|
+
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
1316
|
}
|
|
784
|
-
function
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
const
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
)
|
|
1317
|
+
function extractProductsFromSources(sources, isUser) {
|
|
1318
|
+
if (isUser || !sources) return [];
|
|
1319
|
+
return sources.filter((s) => {
|
|
1320
|
+
var _a;
|
|
1321
|
+
const m = (_a = s.metadata) != null ? _a : {};
|
|
1322
|
+
const keys = Object.keys(m).map((k) => k.toLowerCase());
|
|
1323
|
+
const hasProductKey = keys.some(
|
|
1324
|
+
(k) => ["price", "image", "img", "thumbnail", "images", "brand", "product", "sku", "category", "model", "cost"].includes(k)
|
|
792
1325
|
);
|
|
793
|
-
const
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
1326
|
+
const hasPricePattern = /\$\s*\d+/.test(s.content);
|
|
1327
|
+
return hasProductKey || hasPricePattern || m.type === "product";
|
|
1328
|
+
}).map((s) => {
|
|
1329
|
+
var _a, _b;
|
|
1330
|
+
const m = (_a = s.metadata) != null ? _a : {};
|
|
1331
|
+
const name = resolveMetadataValue(m, "name");
|
|
1332
|
+
const brand = resolveMetadataValue(m, "brand");
|
|
1333
|
+
const price = resolveMetadataValue(m, "price");
|
|
1334
|
+
const description = resolveMetadataValue(m, "description");
|
|
1335
|
+
console.log("\u{1F680} ~ extractProductsFromSources ~ description:", s);
|
|
1336
|
+
return {
|
|
1337
|
+
id: s.id,
|
|
1338
|
+
name: (_b = name != null ? name : s.content.split("\n")[0]) != null ? _b : "Unknown Product",
|
|
1339
|
+
brand,
|
|
1340
|
+
price,
|
|
1341
|
+
image: resolveImage(m),
|
|
1342
|
+
link: resolveMetadataValue(m, "link"),
|
|
1343
|
+
description: description ? description : ""
|
|
1344
|
+
//description ?? s.content,
|
|
800
1345
|
};
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1348
|
+
function extractProductsFromContent(content, payloadText, payloadCandidates, productsFromSources) {
|
|
1349
|
+
var _a, _b;
|
|
1350
|
+
const jsonRegex = /```(?:json|ui)?\s*([\s\S]*?)\s*```/g;
|
|
1351
|
+
const products = [];
|
|
1352
|
+
let cleanContent = payloadText;
|
|
1353
|
+
for (const candidate of payloadCandidates) {
|
|
1354
|
+
try {
|
|
1355
|
+
const data = JSON.parse(sanitizeJson(candidate));
|
|
1356
|
+
const itemSet = Array.isArray(data.data) ? data.data : Array.isArray(data.items) ? data.items : Array.isArray(data.products) ? data.products : null;
|
|
1357
|
+
if ((data.type === "products" || data.view === "carousel" || data.view === "table" || Array.isArray(data.products)) && itemSet) {
|
|
1358
|
+
products.push(
|
|
1359
|
+
...itemSet.map((item) => {
|
|
1360
|
+
var _a2;
|
|
1361
|
+
return __spreadProps(__spreadValues({}, item), {
|
|
1362
|
+
image: (_a2 = item.image) != null ? _a2 : resolveImage(item)
|
|
1363
|
+
});
|
|
1364
|
+
})
|
|
1365
|
+
);
|
|
1366
|
+
}
|
|
1367
|
+
} catch (e) {
|
|
806
1368
|
}
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1369
|
+
}
|
|
1370
|
+
if (cleanContent.includes('"type": "products"') || cleanContent.includes('"type":"products"')) {
|
|
1371
|
+
for (const match of Array.from(cleanContent.matchAll(jsonRegex))) {
|
|
1372
|
+
try {
|
|
1373
|
+
const data = JSON.parse(sanitizeJson(match[1]));
|
|
1374
|
+
if (data.type === "products" && Array.isArray(data.items)) {
|
|
1375
|
+
products.push(
|
|
1376
|
+
...data.items.map((item) => {
|
|
1377
|
+
var _a2;
|
|
1378
|
+
return __spreadProps(__spreadValues({}, item), {
|
|
1379
|
+
image: (_a2 = item.image) != null ? _a2 : resolveImage(item)
|
|
1380
|
+
});
|
|
1381
|
+
})
|
|
1382
|
+
);
|
|
1383
|
+
cleanContent = cleanContent.replace(match[0], "");
|
|
1384
|
+
}
|
|
1385
|
+
} catch (e) {
|
|
1386
|
+
}
|
|
813
1387
|
}
|
|
814
|
-
return rowKeys.map((key) => ({ label: formatColumnLabel(key), accessor: key }));
|
|
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.");
|
|
818
1388
|
}
|
|
819
|
-
const
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
1389
|
+
const bulletRegex = /^[ \t]*(?:[•*-]|\d+\.)\s+(?:\*\*)?([^\n\-\$–—\(]+?)(?:\*\*)?(?:\s*\(?Price\s*[:\-–—]?\s*)?(?:\s*[:\-–—]\s*|\s+)\$?([\d,.]+)(?:\s*USD)?/gim;
|
|
1390
|
+
const matches = Array.from(cleanContent.matchAll(bulletRegex));
|
|
1391
|
+
if (matches.length >= 2) {
|
|
1392
|
+
const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1393
|
+
for (const match of matches) {
|
|
1394
|
+
let name = ((_a = match[1]) == null ? void 0 : _a.trim()) || "";
|
|
1395
|
+
name = name.replace(/\s*\(?Price\s*$/i, "").replace(/[:\-–—]\s*$/g, "").trim();
|
|
1396
|
+
name = name.replace(/^\*\*|\*\*$/g, "").replace(/^\*|\*$/g, "").trim();
|
|
1397
|
+
let price = ((_b = match[2]) == null ? void 0 : _b.trim()) || "";
|
|
1398
|
+
price = price.replace(/[,\s]+$/, "").trim();
|
|
1399
|
+
if (name && price) {
|
|
1400
|
+
const newProduct = {
|
|
1401
|
+
id: `text-prod-${name}-${price}`,
|
|
1402
|
+
name,
|
|
1403
|
+
price: `$${price}`
|
|
1404
|
+
};
|
|
1405
|
+
const normName = normalize(name);
|
|
1406
|
+
const sourceMatch = productsFromSources.find((s) => {
|
|
1407
|
+
const sn = normalize(s.name);
|
|
1408
|
+
return sn.includes(normName) || normName.includes(sn);
|
|
1409
|
+
});
|
|
1410
|
+
if (sourceMatch) {
|
|
1411
|
+
newProduct.image = sourceMatch.image;
|
|
1412
|
+
newProduct.brand = sourceMatch.brand;
|
|
1413
|
+
newProduct.link = sourceMatch.link;
|
|
1414
|
+
newProduct.description = sourceMatch.description;
|
|
1415
|
+
}
|
|
1416
|
+
products.push(newProduct);
|
|
1417
|
+
cleanContent = cleanContent.replace(match[0], `
|
|
1418
|
+
**${name}** \u2014 $${price}`);
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
cleanContent = cleanContent.replace(/\n{3,}/g, "\n\n").trim();
|
|
1422
|
+
}
|
|
1423
|
+
return { productsFromContent: products, cleanContent: cleanContent.trim() };
|
|
1424
|
+
}
|
|
1425
|
+
function deduplicateProducts(productsFromSources, productsFromContent, messageContent) {
|
|
1426
|
+
if (productsFromContent.length > 0) return productsFromContent;
|
|
1427
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1428
|
+
const contentLower = messageContent.toLowerCase();
|
|
1429
|
+
return productsFromSources.filter((p) => {
|
|
1430
|
+
var _a;
|
|
1431
|
+
const id = String((_a = p.id) != null ? _a : p.name);
|
|
1432
|
+
if (seen.has(id)) return false;
|
|
1433
|
+
const mentioned = contentLower.includes(p.name.toLowerCase()) || (p.brand ? contentLower.includes(p.brand.toLowerCase()) : false);
|
|
1434
|
+
if (mentioned) {
|
|
1435
|
+
seen.add(id);
|
|
1436
|
+
return true;
|
|
1437
|
+
}
|
|
1438
|
+
return false;
|
|
1439
|
+
});
|
|
846
1440
|
}
|
|
1441
|
+
|
|
1442
|
+
// src/components/MarkdownComponents.tsx
|
|
1443
|
+
var import_react11 = __toESM(require("react"));
|
|
1444
|
+
|
|
1445
|
+
// src/components/UIDispatcher.tsx
|
|
1446
|
+
var import_react10 = __toESM(require("react"));
|
|
847
1447
|
function normalizeTabularRows(rows, columns) {
|
|
848
1448
|
if (!Array.isArray(rows)) return [];
|
|
849
1449
|
const SYNONYMS = {
|
|
@@ -911,8 +1511,7 @@ function resolveStructuredRows(config) {
|
|
|
911
1511
|
}
|
|
912
1512
|
function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAddToCart, viewportSize = "large" }) {
|
|
913
1513
|
var _a;
|
|
914
|
-
const result =
|
|
915
|
-
if (isStreaming) return { loading: true };
|
|
1514
|
+
const result = import_react10.default.useMemo(() => {
|
|
916
1515
|
try {
|
|
917
1516
|
const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
|
|
918
1517
|
const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
|
|
@@ -941,10 +1540,10 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
941
1540
|
} 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
1541
|
config2.view = "chart";
|
|
943
1542
|
config2.chartType = config2.chartType || viewStr.replace("_chart", "") || config2.type || "bar";
|
|
944
|
-
} else if (viewStr.includes("table")) {
|
|
1543
|
+
} else if (viewStr.includes("table") || config2.type === "table") {
|
|
945
1544
|
config2.view = "table";
|
|
946
1545
|
} else {
|
|
947
|
-
config2.view = "
|
|
1546
|
+
config2.view = "none";
|
|
948
1547
|
}
|
|
949
1548
|
}
|
|
950
1549
|
const normalizedConfig = __spreadProps(__spreadValues({}, config2), {
|
|
@@ -952,22 +1551,25 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
952
1551
|
});
|
|
953
1552
|
return { config: normalizedConfig };
|
|
954
1553
|
} catch (err) {
|
|
1554
|
+
if (isStreaming) return { loading: true };
|
|
955
1555
|
return { error: String(err) };
|
|
956
1556
|
}
|
|
957
1557
|
}, [rawContent, isStreaming]);
|
|
958
1558
|
if ("loading" in result) {
|
|
959
|
-
return /* @__PURE__ */
|
|
1559
|
+
return /* @__PURE__ */ import_react10.default.createElement("div", { className: "my-4 p-8 bg-slate-50 dark:bg-white/5 rounded-xl border border-dashed border-slate-300 dark:border-white/10 flex flex-col items-center justify-center gap-3 animate-pulse" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "w-5 h-5 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ import_react10.default.createElement("p", { className: "text-xs text-slate-500 font-medium italic" }, "Preparing view..."));
|
|
960
1560
|
}
|
|
961
1561
|
if ("error" in result) {
|
|
962
|
-
return /* @__PURE__ */
|
|
1562
|
+
return /* @__PURE__ */ import_react10.default.createElement("pre", { className: "p-4 my-2 bg-slate-900 text-slate-100 rounded-lg text-[10px] overflow-auto max-h-40" }, /* @__PURE__ */ import_react10.default.createElement("code", null, rawContent));
|
|
963
1563
|
}
|
|
964
1564
|
const { config } = result;
|
|
965
1565
|
const isCompact = viewportSize === "compact";
|
|
966
1566
|
const hasInsights = Array.isArray(config.insights) && config.insights.length > 0;
|
|
967
1567
|
const hasDescription = typeof config.description === "string" && config.description.trim().length > 0;
|
|
1568
|
+
console.log("\u{1F680} ~ UIDispatcher ~ description:", config.description);
|
|
1569
|
+
console.log("\u{1F680} ~ UIDispatcher ~ hasDescription:", hasDescription);
|
|
968
1570
|
switch (config.view) {
|
|
969
1571
|
case "chart":
|
|
970
|
-
return /* @__PURE__ */
|
|
1572
|
+
return /* @__PURE__ */ import_react10.default.createElement("div", { className: `${isCompact ? "my-4 p-3" : "my-6 p-4"} bg-white dark:bg-slate-900 rounded-2xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden` }, config.title && /* @__PURE__ */ import_react10.default.createElement("h4", { className: `${isCompact ? "text-[11px] mb-3" : "text-xs mb-4"} font-semibold text-slate-500 px-2` }, config.title), hasDescription && /* @__PURE__ */ import_react10.default.createElement("p", { className: `px-2 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react10.default.createElement(
|
|
971
1573
|
DynamicChart,
|
|
972
1574
|
{
|
|
973
1575
|
config: {
|
|
@@ -979,9 +1581,10 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
979
1581
|
},
|
|
980
1582
|
primaryColor,
|
|
981
1583
|
accentColor,
|
|
982
|
-
viewportSize
|
|
1584
|
+
viewportSize,
|
|
1585
|
+
isStreaming
|
|
983
1586
|
}
|
|
984
|
-
), hasInsights && /* @__PURE__ */
|
|
1587
|
+
), hasInsights && /* @__PURE__ */ import_react10.default.createElement("div", { className: "mt-4 flex flex-wrap gap-2 px-2" }, (_a = config.insights) == null ? void 0 : _a.map((insight, i) => /* @__PURE__ */ import_react10.default.createElement(
|
|
985
1588
|
"span",
|
|
986
1589
|
{
|
|
987
1590
|
key: `insight-${i}`,
|
|
@@ -990,26 +1593,151 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
990
1593
|
String(insight)
|
|
991
1594
|
))));
|
|
992
1595
|
case "carousel":
|
|
993
|
-
return /* @__PURE__ */
|
|
1596
|
+
return /* @__PURE__ */ import_react10.default.createElement("div", { className: "my-4" }, config.title && /* @__PURE__ */ import_react10.default.createElement("h4", { className: `${isCompact ? "mb-1.5 text-[11px]" : "mb-2 text-xs"} font-semibold text-slate-500` }, config.title), hasDescription && /* @__PURE__ */ import_react10.default.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react10.default.createElement(ProductCarousel, { products: config.data.map((item) => {
|
|
994
1597
|
var _a2;
|
|
995
1598
|
return __spreadProps(__spreadValues({}, item), {
|
|
996
1599
|
image: (_a2 = item.image) != null ? _a2 : typeof resolveImage === "function" ? resolveImage(item) : void 0
|
|
997
1600
|
});
|
|
998
1601
|
}), primaryColor, onAddToCart }));
|
|
999
1602
|
case "table":
|
|
1000
|
-
return /* @__PURE__ */
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1603
|
+
return /* @__PURE__ */ import_react10.default.createElement("div", { className: `${isCompact ? "my-3 p-3 max-h-[320px]" : "my-4 p-4 max-h-[400px]"} bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-auto` }, config.title && /* @__PURE__ */ import_react10.default.createElement("h4", { className: `${isCompact ? "text-[11px]" : "text-xs"} font-semibold text-slate-500 mb-2` }, config.title), hasDescription && /* @__PURE__ */ import_react10.default.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react10.default.createElement(
|
|
1604
|
+
VisualizationRenderer,
|
|
1605
|
+
{
|
|
1606
|
+
data: {
|
|
1607
|
+
type: "table",
|
|
1608
|
+
title: config.title || "",
|
|
1609
|
+
description: config.description,
|
|
1610
|
+
data: {
|
|
1611
|
+
columns: config.columns || Object.keys(config.data[0] || {}),
|
|
1612
|
+
rows: config.data.map((row) => Object.values(row))
|
|
1613
|
+
}
|
|
1614
|
+
},
|
|
1615
|
+
primaryColor,
|
|
1616
|
+
isStreaming
|
|
1617
|
+
}
|
|
1618
|
+
));
|
|
1009
1619
|
default:
|
|
1010
1620
|
return null;
|
|
1011
1621
|
}
|
|
1012
1622
|
}
|
|
1623
|
+
|
|
1624
|
+
// src/components/MarkdownComponents.tsx
|
|
1625
|
+
function createMarkdownComponents({
|
|
1626
|
+
primaryColor,
|
|
1627
|
+
accentColor,
|
|
1628
|
+
isStreaming,
|
|
1629
|
+
onAddToCart,
|
|
1630
|
+
viewportSize
|
|
1631
|
+
}) {
|
|
1632
|
+
return {
|
|
1633
|
+
table: (_a) => {
|
|
1634
|
+
var props = __objRest(_a, []);
|
|
1635
|
+
if (isStreaming) {
|
|
1636
|
+
return /* @__PURE__ */ import_react11.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_react11.default.createElement("div", { className: "w-4 h-4 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ import_react11.default.createElement("p", { className: "text-xs text-slate-500 font-medium italic animate-pulse" }, "Generating data table..."));
|
|
1637
|
+
}
|
|
1638
|
+
return /* @__PURE__ */ import_react11.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_react11.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ import_react11.default.createElement(
|
|
1639
|
+
"table",
|
|
1640
|
+
__spreadValues({
|
|
1641
|
+
className: "!table w-full text-left border-collapse min-w-[400px] text-sm"
|
|
1642
|
+
}, props)
|
|
1643
|
+
)));
|
|
1644
|
+
},
|
|
1645
|
+
thead: (_b) => {
|
|
1646
|
+
var props = __objRest(_b, []);
|
|
1647
|
+
return /* @__PURE__ */ import_react11.default.createElement(
|
|
1648
|
+
"thead",
|
|
1649
|
+
__spreadValues({
|
|
1650
|
+
className: "!table-header-group bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10"
|
|
1651
|
+
}, props)
|
|
1652
|
+
);
|
|
1653
|
+
},
|
|
1654
|
+
tbody: (_c) => {
|
|
1655
|
+
var props = __objRest(_c, []);
|
|
1656
|
+
return /* @__PURE__ */ import_react11.default.createElement("tbody", __spreadValues({ className: "!table-row-group divide-y divide-slate-100 dark:divide-white/5" }, props));
|
|
1657
|
+
},
|
|
1658
|
+
tr: (_d) => {
|
|
1659
|
+
var props = __objRest(_d, []);
|
|
1660
|
+
return /* @__PURE__ */ import_react11.default.createElement(
|
|
1661
|
+
"tr",
|
|
1662
|
+
__spreadValues({
|
|
1663
|
+
className: "!table-row hover:bg-slate-50/70 dark:hover:bg-white/5 transition-colors"
|
|
1664
|
+
}, props)
|
|
1665
|
+
);
|
|
1666
|
+
},
|
|
1667
|
+
th: (_e) => {
|
|
1668
|
+
var _f = _e, { children } = _f, props = __objRest(_f, ["children"]);
|
|
1669
|
+
return /* @__PURE__ */ import_react11.default.createElement(
|
|
1670
|
+
"th",
|
|
1671
|
+
__spreadValues({
|
|
1672
|
+
className: "!table-cell px-4 py-3 font-bold text-slate-700 dark:text-white/90 whitespace-nowrap text-[11px] uppercase tracking-wider text-left"
|
|
1673
|
+
}, props),
|
|
1674
|
+
normaliseChild(children)
|
|
1675
|
+
);
|
|
1676
|
+
},
|
|
1677
|
+
td: (_g) => {
|
|
1678
|
+
var _h = _g, { children } = _h, props = __objRest(_h, ["children"]);
|
|
1679
|
+
return /* @__PURE__ */ import_react11.default.createElement(
|
|
1680
|
+
"td",
|
|
1681
|
+
__spreadValues({
|
|
1682
|
+
className: "!table-cell px-4 py-3 text-slate-600 dark:text-white/70 whitespace-nowrap text-sm"
|
|
1683
|
+
}, props),
|
|
1684
|
+
normaliseChild(children)
|
|
1685
|
+
);
|
|
1686
|
+
},
|
|
1687
|
+
code(_i) {
|
|
1688
|
+
var _j = _i, {
|
|
1689
|
+
inline,
|
|
1690
|
+
className,
|
|
1691
|
+
children
|
|
1692
|
+
} = _j, props = __objRest(_j, [
|
|
1693
|
+
"inline",
|
|
1694
|
+
"className",
|
|
1695
|
+
"children"
|
|
1696
|
+
]);
|
|
1697
|
+
var _a;
|
|
1698
|
+
const lang = (_a = /language-(\w+)/.exec(className != null ? className : "")) == null ? void 0 : _a[1];
|
|
1699
|
+
if (!inline && (lang === "ui" || lang === "chart" || lang === "json")) {
|
|
1700
|
+
const content = String(children != null ? children : "").trim();
|
|
1701
|
+
return /* @__PURE__ */ import_react11.default.createElement(
|
|
1702
|
+
UIDispatcher,
|
|
1703
|
+
{
|
|
1704
|
+
rawContent: content,
|
|
1705
|
+
primaryColor,
|
|
1706
|
+
accentColor,
|
|
1707
|
+
isStreaming,
|
|
1708
|
+
onAddToCart,
|
|
1709
|
+
viewportSize
|
|
1710
|
+
}
|
|
1711
|
+
);
|
|
1712
|
+
}
|
|
1713
|
+
if (!inline) {
|
|
1714
|
+
const content = String(children != null ? children : "").trim();
|
|
1715
|
+
if (content.startsWith("{") && content.endsWith("}")) {
|
|
1716
|
+
return /* @__PURE__ */ import_react11.default.createElement(
|
|
1717
|
+
UIDispatcher,
|
|
1718
|
+
{
|
|
1719
|
+
rawContent: content,
|
|
1720
|
+
primaryColor,
|
|
1721
|
+
accentColor,
|
|
1722
|
+
isStreaming,
|
|
1723
|
+
onAddToCart,
|
|
1724
|
+
viewportSize
|
|
1725
|
+
}
|
|
1726
|
+
);
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
return /* @__PURE__ */ import_react11.default.createElement("code", __spreadValues({ className }, props), typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children));
|
|
1730
|
+
}
|
|
1731
|
+
};
|
|
1732
|
+
}
|
|
1733
|
+
function normaliseChild(children) {
|
|
1734
|
+
if (typeof children === "object" && children !== null && !Array.isArray(children) && !import_react11.default.isValidElement(children)) {
|
|
1735
|
+
return JSON.stringify(children);
|
|
1736
|
+
}
|
|
1737
|
+
return children;
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
// src/components/MessageBubble.tsx
|
|
1013
1741
|
function MessageBubble({
|
|
1014
1742
|
message,
|
|
1015
1743
|
sources,
|
|
@@ -1022,147 +1750,45 @@ function MessageBubble({
|
|
|
1022
1750
|
const isUser = message.role === "user";
|
|
1023
1751
|
const isCompact = viewportSize === "compact";
|
|
1024
1752
|
const isMedium = viewportSize === "medium";
|
|
1025
|
-
const [showSources, setShowSources] =
|
|
1026
|
-
const
|
|
1753
|
+
const [showSources, setShowSources] = import_react12.default.useState(false);
|
|
1754
|
+
const [showTrace, setShowTrace] = import_react12.default.useState(false);
|
|
1755
|
+
const structuredContent = import_react12.default.useMemo(
|
|
1027
1756
|
() => isUser ? { payload: null, text: message.content } : extractStructuredPayload(message.content),
|
|
1028
1757
|
[isUser, message.content]
|
|
1029
|
-
);
|
|
1030
|
-
const hasRichUI =
|
|
1031
|
-
if (message.uiTransformation) {
|
|
1032
|
-
const type = message.uiTransformation.type;
|
|
1033
|
-
if (type && !["text", "table"].includes(type)) return true;
|
|
1034
|
-
}
|
|
1035
|
-
if (structuredContent.payload) {
|
|
1036
|
-
return /"?(?:view|type|chartType)"?\s*:\s*"?(?:chart|carousel|pie|bar|line|product_carousel)"?/i.test(structuredContent.payload);
|
|
1037
|
-
}
|
|
1038
|
-
return false;
|
|
1039
|
-
}, [message.uiTransformation, structuredContent.payload]);
|
|
1040
|
-
const shouldRenderStructuredOnly = !isUser && hasRichUI && isLikelyUiOnlyMessage(structuredContent.text);
|
|
1041
|
-
const productsFromSources = import_react6.default.useMemo(() => {
|
|
1042
|
-
if (isUser || !sources) return [];
|
|
1043
|
-
return sources.filter((s) => {
|
|
1044
|
-
var _a;
|
|
1045
|
-
const m = (_a = s.metadata) != null ? _a : {};
|
|
1046
|
-
const keys = Object.keys(m).map((k) => k.toLowerCase());
|
|
1047
|
-
const hasProductKey = keys.some(
|
|
1048
|
-
(k) => ["price", "image", "img", "thumbnail", "images", "brand", "product", "sku", "category", "model", "cost"].includes(k)
|
|
1049
|
-
);
|
|
1050
|
-
const hasPricePattern = /\$\s*\d+/.test(s.content);
|
|
1051
|
-
return hasProductKey || hasPricePattern || m.type === "product";
|
|
1052
|
-
}).map((s) => {
|
|
1053
|
-
var _a, _b;
|
|
1054
|
-
const m = (_a = s.metadata) != null ? _a : {};
|
|
1055
|
-
const name = getMetadataValue(m, ["name", "product", "title", "label", "item"]);
|
|
1056
|
-
const brand = getMetadataValue(m, ["brand", "manufacturer", "vendor", "make"]);
|
|
1057
|
-
const price = getMetadataValue(m, ["price", "cost", "amount", "msrp", "rate"]);
|
|
1058
|
-
return {
|
|
1059
|
-
id: s.id,
|
|
1060
|
-
name: (_b = name != null ? name : s.content.split("\n")[0]) != null ? _b : "Unknown Product",
|
|
1061
|
-
brand,
|
|
1062
|
-
price,
|
|
1063
|
-
image: resolveImage(m),
|
|
1064
|
-
link: getMetadataValue(m, ["link", "url", "product_url"]),
|
|
1065
|
-
description: s.content
|
|
1066
|
-
};
|
|
1067
|
-
});
|
|
1068
|
-
}, [sources, isUser]);
|
|
1069
|
-
const { productsFromContent, cleanContent } = import_react6.default.useMemo(() => {
|
|
1070
|
-
var _a, _b;
|
|
1071
|
-
if (isUser) {
|
|
1072
|
-
return { productsFromContent: [], cleanContent: message.content };
|
|
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
|
-
}
|
|
1758
|
+
);
|
|
1759
|
+
const hasRichUI = import_react12.default.useMemo(() => {
|
|
1760
|
+
if (message.uiTransformation) {
|
|
1761
|
+
const type = message.uiTransformation.type;
|
|
1762
|
+
if (type && !["text", "table"].includes(type)) return true;
|
|
1094
1763
|
}
|
|
1095
|
-
if (
|
|
1096
|
-
|
|
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
|
-
}
|
|
1764
|
+
if (structuredContent.payload) {
|
|
1765
|
+
return /"?(?:view|type|chartType)"?\s*:\s*"?(?:chart|carousel|pie|bar|line|product_carousel)"?/i.test(structuredContent.payload);
|
|
1113
1766
|
}
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
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();
|
|
1767
|
+
return false;
|
|
1768
|
+
}, [message.uiTransformation, structuredContent.payload]);
|
|
1769
|
+
const shouldRenderStructuredOnly = !isUser && hasRichUI && isLikelyUiOnlyMessage(structuredContent.text);
|
|
1770
|
+
const productsFromSources = import_react12.default.useMemo(() => {
|
|
1771
|
+
return extractProductsFromSources(sources, isUser);
|
|
1772
|
+
}, [sources, isUser]);
|
|
1773
|
+
const { productsFromContent, cleanContent } = import_react12.default.useMemo(() => {
|
|
1774
|
+
if (isUser) {
|
|
1775
|
+
return { productsFromContent: [], cleanContent: message.content };
|
|
1146
1776
|
}
|
|
1147
|
-
|
|
1777
|
+
const payloadCandidates = [
|
|
1778
|
+
structuredContent.payload,
|
|
1779
|
+
...Array.from(structuredContent.text.matchAll(/```(?:json|ui)?\s*([\s\S]*?)\s*```/g)).map((m) => m[1])
|
|
1780
|
+
].filter(Boolean);
|
|
1781
|
+
return extractProductsFromContent(
|
|
1782
|
+
message.content,
|
|
1783
|
+
structuredContent.text,
|
|
1784
|
+
payloadCandidates,
|
|
1785
|
+
productsFromSources
|
|
1786
|
+
);
|
|
1148
1787
|
}, [message.content, isUser, structuredContent, productsFromSources]);
|
|
1149
|
-
const allProducts =
|
|
1150
|
-
|
|
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
|
-
});
|
|
1788
|
+
const allProducts = import_react12.default.useMemo(() => {
|
|
1789
|
+
return deduplicateProducts(productsFromSources, productsFromContent, message.content);
|
|
1164
1790
|
}, [productsFromSources, productsFromContent, message.content]);
|
|
1165
|
-
const processedMarkdown =
|
|
1791
|
+
const processedMarkdown = import_react12.default.useMemo(() => {
|
|
1166
1792
|
let raw = structuredContent.payload ? structuredContent.text : cleanContent || message.content;
|
|
1167
1793
|
const hasStructuredUiBlock = Boolean(structuredContent.payload) || /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|chartType|type|data|items|rows|products|results)"\s*:/i.test(raw);
|
|
1168
1794
|
raw = raw.replace(/([^\n])\n\|/g, "$1\n\n|").replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, "$1\n");
|
|
@@ -1183,156 +1809,26 @@ ${match.trim()}
|
|
|
1183
1809
|
if (hasStructuredUiBlock) {
|
|
1184
1810
|
raw = stripStructuredUiLabels(stripMarkdownTables(raw)).replace(/\n{3,}/g, "\n\n").trim();
|
|
1185
1811
|
}
|
|
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
1812
|
return raw;
|
|
1198
1813
|
}, [cleanContent, message.content, isStreaming, structuredContent]);
|
|
1199
|
-
const markdownComponents =
|
|
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
|
-
}),
|
|
1814
|
+
const markdownComponents = import_react12.default.useMemo(
|
|
1815
|
+
() => createMarkdownComponents({ primaryColor, accentColor, isStreaming, onAddToCart, viewportSize }),
|
|
1320
1816
|
[primaryColor, accentColor, isStreaming, onAddToCart, viewportSize]
|
|
1321
1817
|
);
|
|
1322
|
-
return /* @__PURE__ */
|
|
1818
|
+
return /* @__PURE__ */ import_react12.default.createElement("div", { className: `flex ${isCompact ? "gap-2" : "gap-3"} ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ import_react12.default.createElement(
|
|
1323
1819
|
"div",
|
|
1324
1820
|
{
|
|
1325
1821
|
className: `flex-shrink-0 ${isCompact ? "w-7 h-7" : "w-8 h-8"} rounded-full flex items-center justify-center shadow-lg ${isUser ? "text-white" : "bg-slate-100 dark:bg-white/10 text-slate-700 dark:text-white/80"}`,
|
|
1326
1822
|
style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
|
|
1327
1823
|
},
|
|
1328
|
-
isUser ? /* @__PURE__ */
|
|
1329
|
-
), /* @__PURE__ */
|
|
1824
|
+
isUser ? /* @__PURE__ */ import_react12.default.createElement(import_lucide_react6.User, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"} text-white` }) : /* @__PURE__ */ import_react12.default.createElement(import_lucide_react6.Bot, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"}` })
|
|
1825
|
+
), /* @__PURE__ */ import_react12.default.createElement("div", { className: `flex flex-col gap-1 min-w-0 ${isCompact ? "max-w-[94%]" : isMedium ? "max-w-[92%]" : "max-w-[90%]"} ${isUser ? "items-end" : "items-start"}` }, /* @__PURE__ */ import_react12.default.createElement(
|
|
1330
1826
|
"div",
|
|
1331
1827
|
{
|
|
1332
1828
|
className: `relative ${isCompact ? "px-3 py-2.5 text-[13px]" : "px-4 py-3 text-sm"} rounded-2xl leading-relaxed shadow-sm dark:shadow-lg ${isUser ? "text-white rounded-tr-sm" : "bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 text-slate-800 dark:text-white/90 rounded-tl-sm"}`,
|
|
1333
1829
|
style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
|
|
1334
1830
|
},
|
|
1335
|
-
isStreaming && !message.content ? /* @__PURE__ */
|
|
1831
|
+
isStreaming && !message.content ? /* @__PURE__ */ import_react12.default.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ import_react12.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }), /* @__PURE__ */ import_react12.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }), /* @__PURE__ */ import_react12.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })) : /* @__PURE__ */ import_react12.default.createElement("div", { className: `prose ${isCompact ? "prose-xs" : "prose-sm"} max-w-none break-words ${isUser ? "prose-invert" : "dark:prose-invert"}` }, !isUser && structuredContent.payload && /* @__PURE__ */ import_react12.default.createElement(
|
|
1336
1832
|
UIDispatcher,
|
|
1337
1833
|
{
|
|
1338
1834
|
rawContent: structuredContent.payload,
|
|
@@ -1342,7 +1838,15 @@ ${match.trim()}
|
|
|
1342
1838
|
onAddToCart,
|
|
1343
1839
|
viewportSize
|
|
1344
1840
|
}
|
|
1345
|
-
), !shouldRenderStructuredOnly && /* @__PURE__ */
|
|
1841
|
+
), !shouldRenderStructuredOnly && /* @__PURE__ */ import_react12.default.createElement(import_react_markdown.default, { components: markdownComponents }, processedMarkdown), isStreaming && /* @__PURE__ */ import_react12.default.createElement("span", { className: "inline-flex items-center gap-1.5 ml-2 text-emerald-500 animate-pulse align-middle text-xs font-medium" }, /* @__PURE__ */ import_react12.default.createElement(
|
|
1842
|
+
HourglassLoader_default,
|
|
1843
|
+
{
|
|
1844
|
+
size: 18,
|
|
1845
|
+
primaryColor,
|
|
1846
|
+
accentColor,
|
|
1847
|
+
glow: false
|
|
1848
|
+
}
|
|
1849
|
+
), "Thinking..."))
|
|
1346
1850
|
), (() => {
|
|
1347
1851
|
var _a, _b;
|
|
1348
1852
|
if (isUser || structuredContent.payload || !message.uiTransformation) return null;
|
|
@@ -1350,109 +1854,50 @@ ${match.trim()}
|
|
|
1350
1854
|
const textContent = (_b = (_a = ui.data) == null ? void 0 : _a.content) != null ? _b : "";
|
|
1351
1855
|
const shouldShow = ui.type === "table" && allProducts.length === 0 || !["text", "table"].includes(ui.type) || ui.type === "text" && !hasRichUI && allProducts.length === 0 && textContent && !processedMarkdown.toLowerCase().includes(textContent.trim().toLowerCase());
|
|
1352
1856
|
if (!shouldShow) return null;
|
|
1353
|
-
return /* @__PURE__ */
|
|
1857
|
+
return /* @__PURE__ */ import_react12.default.createElement("div", { className: "w-full mt-3" }, /* @__PURE__ */ import_react12.default.createElement(
|
|
1354
1858
|
VisualizationRenderer,
|
|
1355
1859
|
{
|
|
1356
1860
|
data: ui,
|
|
1357
1861
|
primaryColor,
|
|
1358
1862
|
onAddToCart,
|
|
1359
|
-
className: "rounded-3xl border border-slate-200/60 dark:border-white/10 bg-white/90 dark:bg-slate-900/80 p-4"
|
|
1863
|
+
className: "rounded-3xl border border-slate-200/60 dark:border-white/10 bg-white/90 dark:bg-slate-900/80 p-4",
|
|
1864
|
+
isStreaming
|
|
1360
1865
|
}
|
|
1361
1866
|
));
|
|
1362
|
-
})(), !isUser && !hasRichUI && allProducts.length > 0 && /* @__PURE__ */
|
|
1867
|
+
})(), !isUser && !hasRichUI && allProducts.length > 0 && /* @__PURE__ */ import_react12.default.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ import_react12.default.createElement(
|
|
1363
1868
|
ProductCarousel,
|
|
1364
1869
|
{
|
|
1365
1870
|
products: allProducts,
|
|
1366
1871
|
primaryColor,
|
|
1367
1872
|
onAddToCart
|
|
1368
1873
|
}
|
|
1369
|
-
)), !isUser &&
|
|
1874
|
+
)), !isUser && /* @__PURE__ */ import_react12.default.createElement("div", { className: "flex items-center gap-4 mt-1 w-full flex-wrap" }, sources && sources.length > 0 && /* @__PURE__ */ import_react12.default.createElement(
|
|
1370
1875
|
"button",
|
|
1371
1876
|
{
|
|
1372
1877
|
onClick: () => setShowSources((s) => !s),
|
|
1373
|
-
className: "text-[11px] text-indigo-400 hover:text-indigo-300 transition-colors flex items-center gap-1
|
|
1878
|
+
className: "text-[11px] text-indigo-400 hover:text-indigo-300 transition-colors flex items-center gap-1"
|
|
1374
1879
|
},
|
|
1375
|
-
showSources ? /* @__PURE__ */
|
|
1880
|
+
showSources ? /* @__PURE__ */ import_react12.default.createElement(import_lucide_react6.ChevronDown, { className: "w-3 h-3" }) : /* @__PURE__ */ import_react12.default.createElement(import_lucide_react6.ChevronRight, { className: "w-3 h-3" }),
|
|
1376
1881
|
sources.length,
|
|
1377
1882
|
" source",
|
|
1378
1883
|
sources.length !== 1 ? "s" : "",
|
|
1379
1884
|
" used"
|
|
1380
|
-
),
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
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
|
-
];
|
|
1434
|
-
|
|
1435
|
-
// src/components/ConfigProvider.tsx
|
|
1436
|
-
var ConfigContext = (0, import_react7.createContext)(DEFAULT_CONFIG);
|
|
1437
|
-
function ConfigProvider({
|
|
1438
|
-
config,
|
|
1439
|
-
children
|
|
1440
|
-
}) {
|
|
1441
|
-
const merged = {
|
|
1442
|
-
projectId: (config == null ? void 0 : config.projectId) || DEFAULT_CONFIG.projectId,
|
|
1443
|
-
ui: mergeDefined(DEFAULT_CONFIG.ui, config == null ? void 0 : config.ui)
|
|
1444
|
-
};
|
|
1445
|
-
return /* @__PURE__ */ import_react7.default.createElement(ConfigContext.Provider, { value: merged }, children);
|
|
1446
|
-
}
|
|
1447
|
-
function useConfig() {
|
|
1448
|
-
return (0, import_react7.useContext)(ConfigContext);
|
|
1885
|
+
), message.trace && /* @__PURE__ */ import_react12.default.createElement(
|
|
1886
|
+
"button",
|
|
1887
|
+
{
|
|
1888
|
+
onClick: () => setShowTrace((t) => !t),
|
|
1889
|
+
className: "text-[11px] text-emerald-500 hover:text-emerald-400 transition-colors flex items-center gap-1"
|
|
1890
|
+
},
|
|
1891
|
+
/* @__PURE__ */ import_react12.default.createElement(import_lucide_react6.Activity, { className: "w-3 h-3" }),
|
|
1892
|
+
showTrace ? "Hide Trace" : "Trace"
|
|
1893
|
+
)), /* @__PURE__ */ import_react12.default.createElement("div", { className: "w-full flex flex-col gap-2 min-w-0" }, showSources && sources && sources.length > 0 && /* @__PURE__ */ import_react12.default.createElement("div", { className: "mt-1 flex flex-col gap-2" }, sources.map((src, i) => /* @__PURE__ */ import_react12.default.createElement(SourceCard, { key: src.id, source: src, index: i }))), showTrace && message.trace && /* @__PURE__ */ import_react12.default.createElement(ObservabilityPanel, { trace: message.trace, primaryColor }))));
|
|
1449
1894
|
}
|
|
1450
1895
|
|
|
1451
1896
|
// src/hooks/useRagChat.ts
|
|
1452
|
-
var
|
|
1897
|
+
var import_react13 = require("react");
|
|
1453
1898
|
|
|
1454
1899
|
// src/hooks/useStoredMessages.ts
|
|
1455
|
-
var
|
|
1900
|
+
var React13 = __toESM(require("react"));
|
|
1456
1901
|
function readStoredMessages(storageKey) {
|
|
1457
1902
|
if (typeof window === "undefined") {
|
|
1458
1903
|
return [];
|
|
@@ -1469,8 +1914,8 @@ function readStoredMessages(storageKey) {
|
|
|
1469
1914
|
}
|
|
1470
1915
|
}
|
|
1471
1916
|
function useStoredMessages(storageKey, persist) {
|
|
1472
|
-
const [messages, setMessages] =
|
|
1473
|
-
|
|
1917
|
+
const [messages, setMessages] = React13.useState(() => persist ? readStoredMessages(storageKey) : []);
|
|
1918
|
+
React13.useEffect(() => {
|
|
1474
1919
|
if (!persist || typeof window === "undefined") {
|
|
1475
1920
|
return;
|
|
1476
1921
|
}
|
|
@@ -1510,14 +1955,14 @@ function useRagChat(projectId, options = {}) {
|
|
|
1510
1955
|
} = options;
|
|
1511
1956
|
const storageKey = `rag_chat_${projectId}`;
|
|
1512
1957
|
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,
|
|
1958
|
+
const [isLoading, setIsLoading] = (0, import_react13.useState)(false);
|
|
1959
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
1960
|
+
const lastInputRef = (0, import_react13.useRef)("");
|
|
1961
|
+
const messagesRef = (0, import_react13.useRef)(messages);
|
|
1962
|
+
(0, import_react13.useEffect)(() => {
|
|
1518
1963
|
messagesRef.current = messages;
|
|
1519
1964
|
}, [messages]);
|
|
1520
|
-
const sendMessage = (0,
|
|
1965
|
+
const sendMessage = (0, import_react13.useCallback)(
|
|
1521
1966
|
async (text, opts) => {
|
|
1522
1967
|
var _a, _b;
|
|
1523
1968
|
const trimmed = text.trim();
|
|
@@ -1557,6 +2002,7 @@ function useRagChat(projectId, options = {}) {
|
|
|
1557
2002
|
let assistantContent = "";
|
|
1558
2003
|
let sources = [];
|
|
1559
2004
|
let uiTransformation = null;
|
|
2005
|
+
let trace;
|
|
1560
2006
|
let buffer = "";
|
|
1561
2007
|
const assistantMessageId = `assistant_${Date.now()}`;
|
|
1562
2008
|
setMessages((prev) => [
|
|
@@ -1583,6 +2029,8 @@ function useRagChat(projectId, options = {}) {
|
|
|
1583
2029
|
sources = (_a = frame.sources) != null ? _a : [];
|
|
1584
2030
|
} else if (frame.type === "ui_transformation") {
|
|
1585
2031
|
uiTransformation = frame.data;
|
|
2032
|
+
} else if (frame.type === "observability") {
|
|
2033
|
+
trace = frame.data;
|
|
1586
2034
|
} else if (frame.type === "error") {
|
|
1587
2035
|
setError(frame.error || "Stream error");
|
|
1588
2036
|
}
|
|
@@ -1601,17 +2049,22 @@ function useRagChat(projectId, options = {}) {
|
|
|
1601
2049
|
for (const frame of parseSseChunk(buffer)) {
|
|
1602
2050
|
if (frame.type === "text" && frame.text) assistantContent += frame.text;
|
|
1603
2051
|
else if (frame.type === "metadata") sources = (_b = frame.sources) != null ? _b : [];
|
|
2052
|
+
else if (frame.type === "observability") trace = frame.data;
|
|
1604
2053
|
}
|
|
1605
2054
|
}
|
|
1606
|
-
const
|
|
2055
|
+
const finalMsg = {
|
|
1607
2056
|
id: assistantMessageId,
|
|
1608
2057
|
role: "assistant",
|
|
1609
2058
|
content: assistantContent,
|
|
1610
2059
|
sources: sources.length > 0 ? sources : void 0,
|
|
1611
|
-
uiTransformation: uiTransformation
|
|
2060
|
+
uiTransformation: uiTransformation != null ? uiTransformation : void 0,
|
|
2061
|
+
trace,
|
|
1612
2062
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1613
2063
|
};
|
|
1614
|
-
|
|
2064
|
+
setMessages(
|
|
2065
|
+
(prev) => prev.map((msg) => msg.id === assistantMessageId ? finalMsg : msg)
|
|
2066
|
+
);
|
|
2067
|
+
onReply == null ? void 0 : onReply(finalMsg);
|
|
1615
2068
|
} catch (err) {
|
|
1616
2069
|
const msg = err instanceof Error ? err.message : "Something went wrong. Please try again.";
|
|
1617
2070
|
setError(msg);
|
|
@@ -1622,12 +2075,12 @@ function useRagChat(projectId, options = {}) {
|
|
|
1622
2075
|
},
|
|
1623
2076
|
[apiUrl, isLoading, namespace, onError, onReply, projectId, setMessages]
|
|
1624
2077
|
);
|
|
1625
|
-
const clear = (0,
|
|
2078
|
+
const clear = (0, import_react13.useCallback)(() => {
|
|
1626
2079
|
setMessages([]);
|
|
1627
2080
|
setError(null);
|
|
1628
2081
|
if (persist) localStorage.removeItem(storageKey);
|
|
1629
2082
|
}, [persist, setMessages, storageKey]);
|
|
1630
|
-
const retry = (0,
|
|
2083
|
+
const retry = (0, import_react13.useCallback)(async () => {
|
|
1631
2084
|
if (lastInputRef.current) {
|
|
1632
2085
|
const latestMessage = messagesRef.current[messagesRef.current.length - 1];
|
|
1633
2086
|
await sendMessage(lastInputRef.current, {
|
|
@@ -1661,20 +2114,21 @@ function ChatWindow({
|
|
|
1661
2114
|
}) {
|
|
1662
2115
|
var _a;
|
|
1663
2116
|
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,
|
|
2117
|
+
const [input, setInput] = (0, import_react14.useState)("");
|
|
2118
|
+
const [mounted, setMounted] = (0, import_react14.useState)(false);
|
|
2119
|
+
const [viewportSize, setViewportSize] = (0, import_react14.useState)("large");
|
|
2120
|
+
const windowRef = (0, import_react14.useRef)(null);
|
|
2121
|
+
const bottomRef = (0, import_react14.useRef)(null);
|
|
2122
|
+
const inputRef = (0, import_react14.useRef)(null);
|
|
1670
2123
|
const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
|
|
1671
2124
|
namespace: projectId
|
|
1672
2125
|
});
|
|
1673
|
-
const [suggestions, setSuggestions] = (0,
|
|
1674
|
-
const [isSuggesting, setIsSuggesting] = (0,
|
|
1675
|
-
const [isListening, setIsListening] = (0,
|
|
1676
|
-
const
|
|
1677
|
-
(0,
|
|
2126
|
+
const [suggestions, setSuggestions] = (0, import_react14.useState)([]);
|
|
2127
|
+
const [isSuggesting, setIsSuggesting] = (0, import_react14.useState)(false);
|
|
2128
|
+
const [isListening, setIsListening] = (0, import_react14.useState)(false);
|
|
2129
|
+
const [isUploadModalOpen, setIsUploadModalOpen] = (0, import_react14.useState)(false);
|
|
2130
|
+
const recognitionRef = (0, import_react14.useRef)(null);
|
|
2131
|
+
(0, import_react14.useEffect)(() => {
|
|
1678
2132
|
if (typeof window !== "undefined") {
|
|
1679
2133
|
const win = window;
|
|
1680
2134
|
const SpeechRecognition = win.SpeechRecognition || win.webkitSpeechRecognition;
|
|
@@ -1720,10 +2174,10 @@ function ChatWindow({
|
|
|
1720
2174
|
}
|
|
1721
2175
|
}
|
|
1722
2176
|
};
|
|
1723
|
-
(0,
|
|
2177
|
+
(0, import_react14.useEffect)(() => {
|
|
1724
2178
|
setMounted(true);
|
|
1725
2179
|
}, []);
|
|
1726
|
-
(0,
|
|
2180
|
+
(0, import_react14.useEffect)(() => {
|
|
1727
2181
|
const element = windowRef.current;
|
|
1728
2182
|
if (!element || typeof ResizeObserver === "undefined") return;
|
|
1729
2183
|
const resolveViewportSize = (width) => {
|
|
@@ -1739,13 +2193,13 @@ function ChatWindow({
|
|
|
1739
2193
|
observer.observe(element);
|
|
1740
2194
|
return () => observer.disconnect();
|
|
1741
2195
|
}, []);
|
|
1742
|
-
(0,
|
|
2196
|
+
(0, import_react14.useEffect)(() => {
|
|
1743
2197
|
var _a2;
|
|
1744
2198
|
if (messages.length > 0 || isLoading) {
|
|
1745
2199
|
(_a2 = bottomRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth" });
|
|
1746
2200
|
}
|
|
1747
2201
|
}, [messages, isLoading]);
|
|
1748
|
-
const sendMessage = (0,
|
|
2202
|
+
const sendMessage = (0, import_react14.useCallback)(async () => {
|
|
1749
2203
|
var _a2;
|
|
1750
2204
|
const text = input.trim();
|
|
1751
2205
|
if (!text || isLoading) return;
|
|
@@ -1775,7 +2229,7 @@ function ChatWindow({
|
|
|
1775
2229
|
const isEmpty = messages.length === 0;
|
|
1776
2230
|
const currentRadius = BORDER_RADIUS_MAP[ui.borderRadius || "xl"];
|
|
1777
2231
|
const isGlass = ui.visualStyle !== "solid";
|
|
1778
|
-
(0,
|
|
2232
|
+
(0, import_react14.useEffect)(() => {
|
|
1779
2233
|
if (input.trim().length < 3) {
|
|
1780
2234
|
return;
|
|
1781
2235
|
}
|
|
@@ -1799,84 +2253,84 @@ function ChatWindow({
|
|
|
1799
2253
|
}, 800);
|
|
1800
2254
|
return () => clearTimeout(timer);
|
|
1801
2255
|
}, [input, projectId]);
|
|
1802
|
-
return /* @__PURE__ */
|
|
2256
|
+
return /* @__PURE__ */ import_react14.default.createElement(
|
|
1803
2257
|
"div",
|
|
1804
2258
|
{
|
|
1805
2259
|
ref: windowRef,
|
|
1806
2260
|
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
2261
|
style: __spreadValues({ "--primary": ui.primaryColor, "--accent": ui.accentColor }, style)
|
|
1808
2262
|
},
|
|
1809
|
-
onResizeStart && /* @__PURE__ */
|
|
2263
|
+
onResizeStart && /* @__PURE__ */ import_react14.default.createElement(
|
|
1810
2264
|
"div",
|
|
1811
2265
|
{
|
|
1812
2266
|
onMouseDown: onResizeStart,
|
|
1813
2267
|
className: "absolute top-0 left-0 w-6 h-6 cursor-nw-resize z-[100] group flex items-start justify-start p-1",
|
|
1814
2268
|
title: "Drag to resize"
|
|
1815
2269
|
},
|
|
1816
|
-
/* @__PURE__ */
|
|
2270
|
+
/* @__PURE__ */ import_react14.default.createElement("div", { className: "w-2.5 h-2.5 border-t-2 border-l-2 border-slate-300 dark:border-white/20 group-hover:border-slate-500 dark:group-hover:border-white/50 transition-colors rounded-tl-[2px]" })
|
|
1817
2271
|
),
|
|
1818
|
-
/* @__PURE__ */
|
|
2272
|
+
/* @__PURE__ */ import_react14.default.createElement(
|
|
1819
2273
|
"div",
|
|
1820
2274
|
{
|
|
1821
2275
|
className: "flex items-center justify-between px-5 py-4 border-b border-slate-200 dark:border-white/10",
|
|
1822
2276
|
style: { background: `linear-gradient(135deg, ${ui.primaryColor}15, ${ui.accentColor}10)` }
|
|
1823
2277
|
},
|
|
1824
|
-
/* @__PURE__ */
|
|
2278
|
+
/* @__PURE__ */ import_react14.default.createElement("div", { className: "flex items-center gap-3" }, ui.logoUrl ? (
|
|
1825
2279
|
// eslint-disable-next-line @next/next/no-img-element
|
|
1826
|
-
/* @__PURE__ */
|
|
1827
|
-
) : /* @__PURE__ */
|
|
2280
|
+
/* @__PURE__ */ import_react14.default.createElement("img", { src: ui.logoUrl, alt: "logo", className: "w-8 h-8 rounded-lg object-cover" })
|
|
2281
|
+
) : /* @__PURE__ */ import_react14.default.createElement(
|
|
1828
2282
|
"div",
|
|
1829
2283
|
{
|
|
1830
2284
|
className: `w-9 h-9 flex items-center justify-center shadow-md ${ui.borderRadius === "full" ? "rounded-full" : "rounded-xl"}`,
|
|
1831
2285
|
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` }
|
|
1832
2286
|
},
|
|
1833
|
-
/* @__PURE__ */
|
|
1834
|
-
), /* @__PURE__ */
|
|
1835
|
-
/* @__PURE__ */
|
|
2287
|
+
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Bot, { className: "w-5 h-5 text-white" })
|
|
2288
|
+
), /* @__PURE__ */ import_react14.default.createElement("div", null, /* @__PURE__ */ import_react14.default.createElement("h2", { className: "text-slate-900 dark:text-white font-semibold text-sm leading-tight" }, ui.title), ui.poweredBy && /* @__PURE__ */ import_react14.default.createElement("p", { className: "text-slate-500 dark:text-white/40 text-[11px] leading-tight" }, `Powered by ${ui.poweredBy}`))),
|
|
2289
|
+
/* @__PURE__ */ import_react14.default.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ import_react14.default.createElement("span", { className: "flex items-center gap-1 text-[10px] text-emerald-500 dark:text-emerald-400 mr-2" }, /* @__PURE__ */ import_react14.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500 dark:bg-emerald-400 animate-pulse" }), "Online"), /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex items-center bg-slate-100/50 dark:bg-white/5 rounded-lg p-0.5 border border-slate-200/50 dark:border-white/5" }, mounted && messages.length > 0 && /* @__PURE__ */ import_react14.default.createElement(
|
|
1836
2290
|
"button",
|
|
1837
2291
|
{
|
|
1838
2292
|
onClick: clearHistory,
|
|
1839
2293
|
title: "Clear conversation",
|
|
1840
2294
|
className: "w-7 h-7 rounded-md flex items-center justify-center text-slate-400 hover:text-rose-500 dark:text-white/40 dark:hover:text-rose-400 hover:bg-white dark:hover:bg-white/10 transition-all cursor-pointer"
|
|
1841
2295
|
},
|
|
1842
|
-
/* @__PURE__ */
|
|
1843
|
-
), isResized && onResetResize && /* @__PURE__ */
|
|
2296
|
+
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Trash2, { className: "w-3.5 h-3.5" })
|
|
2297
|
+
), isResized && onResetResize && /* @__PURE__ */ import_react14.default.createElement(
|
|
1844
2298
|
"button",
|
|
1845
2299
|
{
|
|
1846
2300
|
onClick: onResetResize,
|
|
1847
2301
|
title: "Reset to default size",
|
|
1848
2302
|
className: "w-7 h-7 rounded-md flex items-center justify-center text-slate-400 hover:text-blue-500 dark:text-white/40 dark:hover:text-blue-400 hover:bg-white dark:hover:bg-white/10 transition-all cursor-pointer"
|
|
1849
2303
|
},
|
|
1850
|
-
/* @__PURE__ */
|
|
1851
|
-
), onMaximize && /* @__PURE__ */
|
|
2304
|
+
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.RotateCcw, { className: "w-3.5 h-3.5" })
|
|
2305
|
+
), onMaximize && /* @__PURE__ */ import_react14.default.createElement(
|
|
1852
2306
|
"button",
|
|
1853
2307
|
{
|
|
1854
2308
|
onClick: onMaximize,
|
|
1855
2309
|
title: isMaximized ? "Minimize" : "Maximize",
|
|
1856
2310
|
className: "w-7 h-7 rounded-md flex items-center justify-center text-slate-400 hover:text-blue-500 dark:text-white/40 dark:hover:text-blue-400 hover:bg-white dark:hover:bg-white/10 transition-all cursor-pointer"
|
|
1857
2311
|
},
|
|
1858
|
-
isMaximized ? /* @__PURE__ */
|
|
1859
|
-
), showClose && onClose && /* @__PURE__ */
|
|
2312
|
+
isMaximized ? /* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Minimize2, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Maximize2, { className: "w-3.5 h-3.5" })
|
|
2313
|
+
), showClose && onClose && /* @__PURE__ */ import_react14.default.createElement(
|
|
1860
2314
|
"button",
|
|
1861
2315
|
{
|
|
1862
2316
|
onClick: onClose,
|
|
1863
2317
|
title: "Close chat",
|
|
1864
2318
|
className: "w-7 h-7 rounded-md flex items-center justify-center text-slate-400 hover:text-slate-600 dark:text-white/40 dark:hover:text-white/70 hover:bg-white dark:hover:bg-white/10 transition-all cursor-pointer"
|
|
1865
2319
|
},
|
|
1866
|
-
/* @__PURE__ */
|
|
2320
|
+
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.X, { className: "w-4 h-4" })
|
|
1867
2321
|
)))
|
|
1868
2322
|
),
|
|
1869
|
-
/* @__PURE__ */
|
|
2323
|
+
/* @__PURE__ */ import_react14.default.createElement("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5 scrollbar-thin scrollbar-thumb-slate-200 dark:scrollbar-thumb-white/10 scrollbar-track-transparent min-h-0 bg-slate-50 dark:bg-transparent" }, !mounted || isEmpty ? (
|
|
1870
2324
|
/* Welcome state */
|
|
1871
|
-
/* @__PURE__ */
|
|
2325
|
+
/* @__PURE__ */ import_react14.default.createElement("div", { className: "h-full flex flex-col items-center justify-center text-center gap-4 px-6 py-12" }, /* @__PURE__ */ import_react14.default.createElement(
|
|
1872
2326
|
"div",
|
|
1873
2327
|
{
|
|
1874
2328
|
className: `w-16 h-16 flex items-center justify-center shadow-lg ${ui.borderRadius === "full" ? "rounded-full" : "rounded-2xl"}`,
|
|
1875
2329
|
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` }
|
|
1876
2330
|
},
|
|
1877
|
-
/* @__PURE__ */
|
|
1878
|
-
), /* @__PURE__ */
|
|
1879
|
-
(suggestion) => /* @__PURE__ */
|
|
2331
|
+
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Sparkles, { className: "w-8 h-8 text-white" })
|
|
2332
|
+
), /* @__PURE__ */ import_react14.default.createElement("div", null, /* @__PURE__ */ import_react14.default.createElement("p", { className: "text-slate-800 dark:text-white/80 font-medium leading-relaxed" }, ui.welcomeMessage), /* @__PURE__ */ import_react14.default.createElement("p", { className: "text-slate-500 dark:text-white/30 text-sm mt-2" }, "Ask a question to get started")), /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex flex-wrap gap-2 justify-center mt-2" }, CHAT_SUGGESTIONS.map(
|
|
2333
|
+
(suggestion) => /* @__PURE__ */ import_react14.default.createElement(
|
|
1880
2334
|
"button",
|
|
1881
2335
|
{
|
|
1882
2336
|
key: suggestion,
|
|
@@ -1890,7 +2344,7 @@ function ChatWindow({
|
|
|
1890
2344
|
suggestion
|
|
1891
2345
|
)
|
|
1892
2346
|
)))
|
|
1893
|
-
) : messages.map((msg, index) => /* @__PURE__ */
|
|
2347
|
+
) : messages.map((msg, index) => /* @__PURE__ */ import_react14.default.createElement(
|
|
1894
2348
|
MessageBubble,
|
|
1895
2349
|
{
|
|
1896
2350
|
key: msg.id,
|
|
@@ -1902,7 +2356,7 @@ function ChatWindow({
|
|
|
1902
2356
|
onAddToCart,
|
|
1903
2357
|
viewportSize
|
|
1904
2358
|
}
|
|
1905
|
-
)), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */
|
|
2359
|
+
)), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */ import_react14.default.createElement(
|
|
1906
2360
|
MessageBubble,
|
|
1907
2361
|
{
|
|
1908
2362
|
message: { id: "loading", role: "assistant", content: "", createdAt: (/* @__PURE__ */ new Date()).toISOString() },
|
|
@@ -1912,8 +2366,22 @@ function ChatWindow({
|
|
|
1912
2366
|
onAddToCart,
|
|
1913
2367
|
viewportSize
|
|
1914
2368
|
}
|
|
1915
|
-
), error && /* @__PURE__ */
|
|
1916
|
-
/* @__PURE__ */
|
|
2369
|
+
), error && /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex items-center gap-2 text-rose-500 dark:text-rose-400 text-sm bg-rose-50 dark:bg-rose-400/10 border border-rose-200 dark:border-rose-400/20 rounded-xl px-4 py-3" }, /* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.TriangleAlert, { className: "w-4 h-4 flex-shrink-0" }), /* @__PURE__ */ import_react14.default.createElement("span", null, error)), /* @__PURE__ */ import_react14.default.createElement("div", { ref: bottomRef })),
|
|
2370
|
+
isUploadModalOpen && /* @__PURE__ */ import_react14.default.createElement("div", { className: "absolute inset-0 z-50 flex items-center justify-center p-4 bg-slate-900/50 backdrop-blur-sm rounded-inherit" }, /* @__PURE__ */ import_react14.default.createElement("div", { className: "relative w-full max-w-md bg-white dark:bg-[#0f0f1a] rounded-2xl shadow-2xl overflow-hidden animate-in zoom-in-95 duration-200" }, /* @__PURE__ */ import_react14.default.createElement(
|
|
2371
|
+
"button",
|
|
2372
|
+
{
|
|
2373
|
+
onClick: () => setIsUploadModalOpen(false),
|
|
2374
|
+
className: "absolute top-4 right-4 p-1.5 rounded-lg text-slate-400 hover:text-slate-600 hover:bg-slate-100 dark:hover:text-white/80 dark:hover:bg-white/10 transition-colors z-10"
|
|
2375
|
+
},
|
|
2376
|
+
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.X, { className: "w-5 h-5" })
|
|
2377
|
+
), /* @__PURE__ */ import_react14.default.createElement(
|
|
2378
|
+
DocumentUpload,
|
|
2379
|
+
{
|
|
2380
|
+
namespace: projectId,
|
|
2381
|
+
onUploadComplete: () => setIsUploadModalOpen(false)
|
|
2382
|
+
}
|
|
2383
|
+
))),
|
|
2384
|
+
/* @__PURE__ */ import_react14.default.createElement("div", { className: `px-4 pb-4 pt-2 border-t border-slate-200 dark:border-white/10 ${isGlass ? "bg-transparent" : "bg-white dark:bg-[#0f0f1a]"}` }, (suggestions.length > 0 || isSuggesting) && !isLoading && /* @__PURE__ */ import_react14.default.createElement("div", { className: "mb-3 flex flex-wrap gap-2 animate-in fade-in slide-in-from-bottom-2 duration-300" }, suggestions.map((suggestion) => /* @__PURE__ */ import_react14.default.createElement(
|
|
1917
2385
|
"button",
|
|
1918
2386
|
{
|
|
1919
2387
|
key: suggestion,
|
|
@@ -1925,9 +2393,9 @@ function ChatWindow({
|
|
|
1925
2393
|
},
|
|
1926
2394
|
className: "flex items-center gap-1.5 px-3 py-1.5 rounded-xl text-[11px] font-medium bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 text-slate-600 dark:text-white/60 hover:text-slate-900 dark:hover:text-white/90 hover:border-slate-300 dark:hover:border-white/20 transition-all shadow-sm cursor-pointer group"
|
|
1927
2395
|
},
|
|
1928
|
-
/* @__PURE__ */
|
|
2396
|
+
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Sparkles, { className: "w-3 h-3 text-amber-400" }),
|
|
1929
2397
|
suggestion
|
|
1930
|
-
)), isSuggesting && suggestions.length === 0 && /* @__PURE__ */
|
|
2398
|
+
)), isSuggesting && suggestions.length === 0 && /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex items-center gap-1.5 px-3 py-1.5 rounded-xl text-[11px] font-medium text-slate-400 dark:text-white/30 animate-pulse" }, /* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Sparkles, { className: "w-3 h-3" }), "Thinking...")), /* @__PURE__ */ import_react14.default.createElement("div", { className: `flex items-end gap-2 bg-slate-50 dark:bg-white/5 border border-slate-200 dark:border-white/10 p-2 focus-within:border-slate-300 dark:focus-within:border-white/20 transition-all ${ui.borderRadius === "full" ? "rounded-3xl" : "rounded-2xl"}` }, /* @__PURE__ */ import_react14.default.createElement(
|
|
1931
2399
|
"textarea",
|
|
1932
2400
|
{
|
|
1933
2401
|
ref: inputRef,
|
|
@@ -1946,7 +2414,7 @@ function ChatWindow({
|
|
|
1946
2414
|
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",
|
|
1947
2415
|
style: { scrollbarWidth: "none" }
|
|
1948
2416
|
}
|
|
1949
|
-
), ui.enableVoiceInput !== false && /* @__PURE__ */
|
|
2417
|
+
), ui.enableVoiceInput !== false && /* @__PURE__ */ import_react14.default.createElement(
|
|
1950
2418
|
"button",
|
|
1951
2419
|
{
|
|
1952
2420
|
type: "button",
|
|
@@ -1955,8 +2423,17 @@ function ChatWindow({
|
|
|
1955
2423
|
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"}`,
|
|
1956
2424
|
title: isListening ? "Stop listening" : "Start voice input"
|
|
1957
2425
|
},
|
|
1958
|
-
isListening ? /* @__PURE__ */
|
|
1959
|
-
), /* @__PURE__ */
|
|
2426
|
+
isListening ? /* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.MicOff, { className: "w-4 h-4" }) : /* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Mic, { className: "w-4 h-4" })
|
|
2427
|
+
), ui.allowUpload !== false && /* @__PURE__ */ import_react14.default.createElement(
|
|
2428
|
+
"button",
|
|
2429
|
+
{
|
|
2430
|
+
type: "button",
|
|
2431
|
+
onClick: () => setIsUploadModalOpen(true),
|
|
2432
|
+
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",
|
|
2433
|
+
title: "Upload Document"
|
|
2434
|
+
},
|
|
2435
|
+
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.Paperclip, { className: "w-4 h-4" })
|
|
2436
|
+
), /* @__PURE__ */ import_react14.default.createElement(
|
|
1960
2437
|
"button",
|
|
1961
2438
|
{
|
|
1962
2439
|
onClick: sendMessage,
|
|
@@ -1967,8 +2444,8 @@ function ChatWindow({
|
|
|
1967
2444
|
// slate-400/20 for light mode disabled
|
|
1968
2445
|
}
|
|
1969
2446
|
},
|
|
1970
|
-
/* @__PURE__ */
|
|
1971
|
-
)), /* @__PURE__ */
|
|
2447
|
+
/* @__PURE__ */ import_react14.default.createElement(import_lucide_react7.ArrowUp, { className: "w-4 h-4 text-white" })
|
|
2448
|
+
)), /* @__PURE__ */ import_react14.default.createElement("p", { className: "text-center text-[10px] text-slate-400 dark:text-white/20 mt-2" }, "Press Enter to send \xB7 Shift+Enter for new line"))
|
|
1972
2449
|
);
|
|
1973
2450
|
}
|
|
1974
2451
|
|
|
@@ -1976,12 +2453,12 @@ function ChatWindow({
|
|
|
1976
2453
|
var DEFAULT_DIMENSIONS = { width: 380, height: 600 };
|
|
1977
2454
|
function ChatWidget({ position = "bottom-right", onAddToCart }) {
|
|
1978
2455
|
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,
|
|
2456
|
+
const [isOpen, setIsOpen] = (0, import_react15.useState)(false);
|
|
2457
|
+
const [hasUnread, setHasUnread] = (0, import_react15.useState)(false);
|
|
2458
|
+
const [dimensions, setDimensions] = (0, import_react15.useState)(DEFAULT_DIMENSIONS);
|
|
2459
|
+
const [isResizing, setIsResizing] = (0, import_react15.useState)(false);
|
|
2460
|
+
const [isMaximized, setIsMaximized] = (0, import_react15.useState)(false);
|
|
2461
|
+
const [prevDimensions, setPrevDimensions] = (0, import_react15.useState)(DEFAULT_DIMENSIONS);
|
|
1985
2462
|
if (ui.showWidget === false) return null;
|
|
1986
2463
|
const positionClass = position === "bottom-left" ? "bottom-6 left-6" : "bottom-6 right-6";
|
|
1987
2464
|
const windowPositionClass = position === "bottom-left" ? "bottom-20 left-6" : "bottom-20 right-6";
|
|
@@ -2031,7 +2508,7 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
|
|
|
2031
2508
|
}
|
|
2032
2509
|
};
|
|
2033
2510
|
const isResized = dimensions.width !== DEFAULT_DIMENSIONS.width || dimensions.height !== DEFAULT_DIMENSIONS.height;
|
|
2034
|
-
return /* @__PURE__ */
|
|
2511
|
+
return /* @__PURE__ */ import_react15.default.createElement(import_react15.default.Fragment, null, /* @__PURE__ */ import_react15.default.createElement(
|
|
2035
2512
|
"div",
|
|
2036
2513
|
{
|
|
2037
2514
|
className: `fixed z-[9998] max-w-[calc(100vw-3rem)] ease-in-out ${windowPositionClass} ${isOpen ? "opacity-100 translate-y-0 pointer-events-auto" : "opacity-0 translate-y-4 pointer-events-none"} ${isResizing ? "" : "transition-all duration-300"}`,
|
|
@@ -2041,7 +2518,7 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
|
|
|
2041
2518
|
maxHeight: "calc(100vh - 6rem)"
|
|
2042
2519
|
}
|
|
2043
2520
|
},
|
|
2044
|
-
/* @__PURE__ */
|
|
2521
|
+
/* @__PURE__ */ import_react15.default.createElement(
|
|
2045
2522
|
ChatWindow,
|
|
2046
2523
|
{
|
|
2047
2524
|
className: "h-full relative z-10",
|
|
@@ -2055,13 +2532,13 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
|
|
|
2055
2532
|
onAddToCart
|
|
2056
2533
|
}
|
|
2057
2534
|
),
|
|
2058
|
-
/* @__PURE__ */
|
|
2535
|
+
/* @__PURE__ */ import_react15.default.createElement(
|
|
2059
2536
|
"div",
|
|
2060
2537
|
{
|
|
2061
2538
|
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"}`
|
|
2062
2539
|
}
|
|
2063
2540
|
)
|
|
2064
|
-
), /* @__PURE__ */
|
|
2541
|
+
), /* @__PURE__ */ import_react15.default.createElement(
|
|
2065
2542
|
"button",
|
|
2066
2543
|
{
|
|
2067
2544
|
onClick: isOpen ? () => setIsOpen(false) : handleOpen,
|
|
@@ -2069,149 +2546,23 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
|
|
|
2069
2546
|
style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` },
|
|
2070
2547
|
"aria-label": "Open chat"
|
|
2071
2548
|
},
|
|
2072
|
-
/* @__PURE__ */
|
|
2549
|
+
/* @__PURE__ */ import_react15.default.createElement(
|
|
2073
2550
|
"span",
|
|
2074
2551
|
{
|
|
2075
2552
|
className: "absolute inset-0 rounded-full animate-ping opacity-20",
|
|
2076
2553
|
style: { background: ui.primaryColor }
|
|
2077
2554
|
}
|
|
2078
2555
|
),
|
|
2079
|
-
/* @__PURE__ */
|
|
2556
|
+
/* @__PURE__ */ import_react15.default.createElement(
|
|
2080
2557
|
"span",
|
|
2081
2558
|
{
|
|
2082
2559
|
className: `transition-transform duration-300 ${isOpen ? "rotate-90 scale-90" : "rotate-0 scale-100"}`
|
|
2083
2560
|
},
|
|
2084
|
-
isOpen ? /* @__PURE__ */
|
|
2561
|
+
isOpen ? /* @__PURE__ */ import_react15.default.createElement(import_lucide_react8.X, { className: "w-6 h-6 text-white" }) : /* @__PURE__ */ import_react15.default.createElement(import_lucide_react8.MessageSquare, { className: "w-6 h-6 text-white" })
|
|
2085
2562
|
),
|
|
2086
|
-
hasUnread && !isOpen && /* @__PURE__ */
|
|
2563
|
+
hasUnread && !isOpen && /* @__PURE__ */ import_react15.default.createElement("span", { className: "absolute top-0 right-0 w-4 h-4 bg-rose-500 rounded-full border-2 border-white flex items-center justify-center text-[9px] font-bold text-white" }, "1")
|
|
2087
2564
|
));
|
|
2088
2565
|
}
|
|
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(
|
|
2163
|
-
"button",
|
|
2164
|
-
{
|
|
2165
|
-
onClick: () => {
|
|
2166
|
-
var _a;
|
|
2167
|
-
return (_a = fileInputRef.current) == null ? void 0 : _a.click();
|
|
2168
|
-
},
|
|
2169
|
-
disabled: isUploading,
|
|
2170
|
-
className: "px-4 py-2 rounded-lg text-sm font-medium transition-all hover:scale-105 active:scale-95 disabled:opacity-50",
|
|
2171
|
-
style: {
|
|
2172
|
-
backgroundColor: `${ui.primaryColor}15`,
|
|
2173
|
-
color: ui.primaryColor,
|
|
2174
|
-
border: `1px solid ${ui.primaryColor}30`
|
|
2175
|
-
}
|
|
2176
|
-
},
|
|
2177
|
-
"Select Files"
|
|
2178
|
-
), /* @__PURE__ */ import_react11.default.createElement(
|
|
2179
|
-
"input",
|
|
2180
|
-
{
|
|
2181
|
-
ref: fileInputRef,
|
|
2182
|
-
type: "file",
|
|
2183
|
-
multiple: true,
|
|
2184
|
-
onChange: onFileSelect,
|
|
2185
|
-
className: "hidden",
|
|
2186
|
-
accept: ".pdf,.docx,.txt,.md,.json,.csv"
|
|
2187
|
-
}
|
|
2188
|
-
)),
|
|
2189
|
-
fileStates.length > 0 && /* @__PURE__ */ import_react11.default.createElement("div", { className: "mt-8 space-y-3" }, fileStates.map((state, i) => /* @__PURE__ */ import_react11.default.createElement(
|
|
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
|
-
);
|
|
2214
|
-
}
|
|
2215
2566
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2216
2567
|
0 && (module.exports = {
|
|
2217
2568
|
ChatWidget,
|
|
@@ -2219,7 +2570,9 @@ function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
|
|
|
2219
2570
|
ConfigProvider,
|
|
2220
2571
|
DocumentUpload,
|
|
2221
2572
|
MessageBubble,
|
|
2573
|
+
ObservabilityPanel,
|
|
2222
2574
|
SourceCard,
|
|
2575
|
+
addSynonyms,
|
|
2223
2576
|
useConfig,
|
|
2224
2577
|
useRagChat
|
|
2225
2578
|
});
|