@retrivora-ai/rag-engine 1.2.1 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/DocumentChunker-BXOUMKoP.d.ts +93 -0
  2. package/dist/DocumentChunker-D1dg5iCi.d.mts +93 -0
  3. package/dist/{chunk-GCPPRD2G.mjs → chunk-WGPNEAK3.mjs} +37 -3
  4. package/dist/handlers/index.d.mts +2 -2
  5. package/dist/handlers/index.d.ts +2 -2
  6. package/dist/handlers/index.js +37 -3
  7. package/dist/handlers/index.mjs +1 -1
  8. package/dist/{index-DbtE8wLM.d.ts → index-B67KQ9NN.d.ts} +1 -1
  9. package/dist/{RagConfig-BOLOz0_O.d.mts → index-Cti1u0y1.d.mts} +86 -94
  10. package/dist/{RagConfig-BOLOz0_O.d.ts → index-Cti1u0y1.d.ts} +86 -94
  11. package/dist/{index-64BDupW3.d.mts → index-kUXnRvuI.d.mts} +1 -1
  12. package/dist/index.d.mts +52 -78
  13. package/dist/index.d.ts +52 -78
  14. package/dist/index.js +313 -124
  15. package/dist/index.mjs +293 -97
  16. package/dist/server.d.mts +5 -4
  17. package/dist/server.d.ts +5 -4
  18. package/dist/server.js +37 -3
  19. package/dist/server.mjs +1 -1
  20. package/package.json +2 -1
  21. package/src/components/ChatWidget.tsx +1 -8
  22. package/src/components/ChatWindow.tsx +120 -29
  23. package/src/components/ConfigProvider.tsx +7 -33
  24. package/src/components/DocumentUpload.tsx +1 -8
  25. package/src/components/DynamicChart.tsx +113 -0
  26. package/src/components/MessageBubble.tsx +51 -13
  27. package/src/components/ProductCard.tsx +1 -7
  28. package/src/components/ProductCarousel.tsx +1 -7
  29. package/src/components/SourceCard.tsx +1 -6
  30. package/src/config/RagConfig.ts +2 -0
  31. package/src/config/uiConstants.ts +23 -0
  32. package/src/core/LangChainAgent.ts +20 -2
  33. package/src/core/Pipeline.ts +19 -1
  34. package/src/core/VectorPlugin.ts +1 -1
  35. package/src/handlers/index.ts +1 -1
  36. package/src/hooks/useRagChat.ts +1 -45
  37. package/src/hooks/useStoredMessages.ts +1 -1
  38. package/src/index.ts +20 -5
  39. package/src/llm/ILLMProvider.ts +1 -13
  40. package/src/llm/providers/AnthropicProvider.ts +2 -1
  41. package/src/llm/providers/GeminiProvider.ts +2 -1
  42. package/src/llm/providers/OllamaProvider.ts +2 -1
  43. package/src/llm/providers/OpenAIProvider.ts +2 -1
  44. package/src/llm/providers/UniversalLLMAdapter.ts +2 -1
  45. package/src/server.ts +2 -2
  46. package/src/types/chat.ts +53 -0
  47. package/src/types/index.ts +3 -0
  48. package/src/types/props.ts +79 -0
  49. package/dist/DocumentChunker-Dh9TvmGG.d.mts +0 -45
  50. package/dist/DocumentChunker-Dh9TvmGG.d.ts +0 -45
package/dist/index.js CHANGED
@@ -22,6 +22,18 @@ var __spreadValues = (a, b) => {
22
22
  return a;
23
23
  };
24
24
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
25
+ var __objRest = (source, exclude) => {
26
+ var target = {};
27
+ for (var prop in source)
28
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
29
+ target[prop] = source[prop];
30
+ if (source != null && __getOwnPropSymbols)
31
+ for (var prop of __getOwnPropSymbols(source)) {
32
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
33
+ target[prop] = source[prop];
34
+ }
35
+ return target;
36
+ };
25
37
  var __export = (target, all) => {
26
38
  for (var name in all)
27
39
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -59,15 +71,15 @@ __export(index_exports, {
59
71
  module.exports = __toCommonJS(index_exports);
60
72
 
61
73
  // src/components/ChatWidget.tsx
62
- var import_react8 = __toESM(require("react"));
74
+ var import_react9 = __toESM(require("react"));
63
75
  var import_lucide_react6 = require("lucide-react");
64
76
 
65
77
  // src/components/ChatWindow.tsx
66
- var import_react7 = __toESM(require("react"));
78
+ var import_react8 = __toESM(require("react"));
67
79
  var import_lucide_react5 = require("lucide-react");
68
80
 
69
81
  // src/components/MessageBubble.tsx
70
- var import_react4 = __toESM(require("react"));
82
+ var import_react5 = __toESM(require("react"));
71
83
  var import_lucide_react4 = require("lucide-react");
72
84
  var import_react_markdown = __toESM(require("react-markdown"));
73
85
  var import_remark_gfm = __toESM(require("remark-gfm"));
@@ -204,6 +216,71 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
204
216
  ));
205
217
  }
206
218
 
219
+ // src/components/DynamicChart.tsx
220
+ var import_react4 = __toESM(require("react"));
221
+ var import_recharts = require("recharts");
222
+ var DEFAULT_COLORS = ["#6366f1", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#ec4899"];
223
+ function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6" }) {
224
+ const { type, data, xAxisKey = "name", dataKeys = [] } = config;
225
+ const colors = config.colors || [primaryColor, accentColor, ...DEFAULT_COLORS];
226
+ if (!data || data.length === 0) {
227
+ return /* @__PURE__ */ import_react4.default.createElement("div", { className: "p-4 text-sm text-slate-500" }, "No data available for chart.");
228
+ }
229
+ if (type === "pie") {
230
+ const pieDataKey = dataKeys[0] || Object.keys(data[0]).find((k) => k !== xAxisKey) || "value";
231
+ return /* @__PURE__ */ import_react4.default.createElement("div", { className: "w-full h-64 mt-4 mb-2 select-none" }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.PieChart, null, /* @__PURE__ */ import_react4.default.createElement(
232
+ import_recharts.Pie,
233
+ {
234
+ data,
235
+ dataKey: pieDataKey,
236
+ nameKey: xAxisKey,
237
+ cx: "50%",
238
+ cy: "50%",
239
+ outerRadius: 80,
240
+ label: ({ name, percent }) => `${name} ${((percent != null ? percent : 0) * 100).toFixed(0)}%`
241
+ },
242
+ data.map((entry, index) => /* @__PURE__ */ import_react4.default.createElement(import_recharts.Cell, { key: `cell-${index}`, fill: colors[index % colors.length] }))
243
+ ), /* @__PURE__ */ import_react4.default.createElement(
244
+ import_recharts.Tooltip,
245
+ {
246
+ contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" }
247
+ }
248
+ ), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, null))));
249
+ }
250
+ return /* @__PURE__ */ import_react4.default.createElement("div", { className: "w-full h-64 mt-4 mb-2 select-none" }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, type === "bar" ? /* @__PURE__ */ import_react4.default.createElement(import_recharts.BarChart, { data, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.XAxis, { dataKey: xAxisKey, tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.YAxis, { tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react4.default.createElement(
251
+ import_recharts.Tooltip,
252
+ {
253
+ contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" },
254
+ cursor: { fill: "#f1f5f9" }
255
+ }
256
+ ), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: 12 } }), dataKeys.map((key, index) => /* @__PURE__ */ import_react4.default.createElement(
257
+ import_recharts.Bar,
258
+ {
259
+ key,
260
+ dataKey: key,
261
+ fill: colors[index % colors.length],
262
+ radius: [4, 4, 0, 0],
263
+ barSize: Math.max(20, 60 / data.length)
264
+ }
265
+ ))) : /* @__PURE__ */ import_react4.default.createElement(import_recharts.LineChart, { data, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.XAxis, { dataKey: xAxisKey, tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.YAxis, { tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react4.default.createElement(
266
+ import_recharts.Tooltip,
267
+ {
268
+ contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" }
269
+ }
270
+ ), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: 12 } }), dataKeys.map((key, index) => /* @__PURE__ */ import_react4.default.createElement(
271
+ import_recharts.Line,
272
+ {
273
+ key,
274
+ type: "monotone",
275
+ dataKey: key,
276
+ stroke: colors[index % colors.length],
277
+ strokeWidth: 3,
278
+ dot: { r: 4, strokeWidth: 2 },
279
+ activeDot: { r: 6 }
280
+ }
281
+ )))));
282
+ }
283
+
207
284
  // src/components/MessageBubble.tsx
208
285
  function MessageBubble({
209
286
  message,
@@ -214,7 +291,7 @@ function MessageBubble({
214
291
  onAddToCart
215
292
  }) {
216
293
  const isUser = message.role === "user";
217
- const [showSources, setShowSources] = import_react4.default.useState(false);
294
+ const [showSources, setShowSources] = import_react5.default.useState(false);
218
295
  const resolveImage = (data) => {
219
296
  if (!data) return void 0;
220
297
  const singleFields = ["image", "img", "thumbnail"];
@@ -227,7 +304,7 @@ function MessageBubble({
227
304
  }
228
305
  return void 0;
229
306
  };
230
- const productsFromSources = import_react4.default.useMemo(() => {
307
+ const productsFromSources = import_react5.default.useMemo(() => {
231
308
  if (isUser || !sources) return [];
232
309
  return sources.filter((s) => {
233
310
  const m = s.metadata || {};
@@ -245,7 +322,7 @@ function MessageBubble({
245
322
  };
246
323
  });
247
324
  }, [sources, isUser]);
248
- const { productsFromContent, cleanContent } = import_react4.default.useMemo(() => {
325
+ const { productsFromContent, cleanContent } = import_react5.default.useMemo(() => {
249
326
  if (isUser) return { productsFromContent: [], cleanContent: message.content };
250
327
  const jsonRegex = /```json\s*([\s\S]*?)\s*```/g;
251
328
  const products = [];
@@ -268,7 +345,7 @@ function MessageBubble({
268
345
  }
269
346
  return { productsFromContent: products, cleanContent: content.trim() };
270
347
  }, [message.content, isUser]);
271
- const allProducts = import_react4.default.useMemo(() => {
348
+ const allProducts = import_react5.default.useMemo(() => {
272
349
  if (productsFromContent.length > 0) return productsFromContent;
273
350
  const uniqueProducts = [];
274
351
  const seenIds = /* @__PURE__ */ new Set();
@@ -286,43 +363,88 @@ function MessageBubble({
286
363
  return uniqueProducts;
287
364
  }, [productsFromSources, productsFromContent, message.content]);
288
365
  const hasProducts = allProducts.length > 0;
289
- return /* @__PURE__ */ import_react4.default.createElement("div", { className: `flex gap-3 ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ import_react4.default.createElement(
366
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: `flex gap-3 ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ import_react5.default.createElement(
290
367
  "div",
291
368
  {
292
369
  className: `flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center shadow-lg ${isUser ? "text-white" : "bg-slate-100 dark:bg-white/10 text-slate-700 dark:text-white/80"}`,
293
370
  style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
294
371
  },
295
- isUser ? /* @__PURE__ */ import_react4.default.createElement(import_lucide_react4.User, { className: "w-4 h-4 text-white" }) : /* @__PURE__ */ import_react4.default.createElement(import_lucide_react4.Bot, { className: "w-4 h-4" })
296
- ), /* @__PURE__ */ import_react4.default.createElement("div", { className: `flex flex-col gap-1 max-w-[90%] ${isUser ? "items-end" : "items-start"}` }, /* @__PURE__ */ import_react4.default.createElement(
372
+ isUser ? /* @__PURE__ */ import_react5.default.createElement(import_lucide_react4.User, { className: "w-4 h-4 text-white" }) : /* @__PURE__ */ import_react5.default.createElement(import_lucide_react4.Bot, { className: "w-4 h-4" })
373
+ ), /* @__PURE__ */ import_react5.default.createElement("div", { className: `flex flex-col gap-1 max-w-[90%] ${isUser ? "items-end" : "items-start"}` }, /* @__PURE__ */ import_react5.default.createElement(
297
374
  "div",
298
375
  {
299
376
  className: `relative px-4 py-3 rounded-2xl text-sm 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"}`,
300
377
  style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
301
378
  },
302
- isStreaming && !message.content ? /* @__PURE__ */ import_react4.default.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ import_react4.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_react4.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_react4.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_react4.default.createElement("div", { className: `prose prose-sm max-w-none ${isUser ? "prose-invert" : "dark:prose-invert"}` }, /* @__PURE__ */ import_react4.default.createElement(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default] }, cleanContent || message.content), isStreaming && message.content && /* @__PURE__ */ import_react4.default.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
303
- ), !isUser && hasProducts && /* @__PURE__ */ import_react4.default.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ import_react4.default.createElement(
379
+ isStreaming && !message.content ? /* @__PURE__ */ import_react5.default.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }), /* @__PURE__ */ import_react5.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }), /* @__PURE__ */ import_react5.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })) : /* @__PURE__ */ import_react5.default.createElement("div", { className: `prose prose-sm max-w-none ${isUser ? "prose-invert" : "dark:prose-invert"}` }, /* @__PURE__ */ import_react5.default.createElement(
380
+ import_react_markdown.default,
381
+ {
382
+ remarkPlugins: [import_remark_gfm.default],
383
+ components: {
384
+ table: (_a) => {
385
+ var props = __objRest(_a, []);
386
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "overflow-x-auto my-4 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm" }, /* @__PURE__ */ import_react5.default.createElement("table", __spreadValues({ className: "w-full text-left border-collapse min-w-[400px]" }, props)));
387
+ },
388
+ thead: (_b) => {
389
+ var props = __objRest(_b, []);
390
+ return /* @__PURE__ */ import_react5.default.createElement("thead", __spreadValues({ className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, props));
391
+ },
392
+ th: (_c) => {
393
+ var props = __objRest(_c, []);
394
+ return /* @__PURE__ */ import_react5.default.createElement("th", __spreadValues({ className: "p-3 font-semibold text-slate-700 dark:text-white/90 first:rounded-tl-xl last:rounded-tr-xl" }, props));
395
+ },
396
+ td: (_d) => {
397
+ var props = __objRest(_d, []);
398
+ return /* @__PURE__ */ import_react5.default.createElement("td", __spreadValues({ className: "p-3 border-b border-slate-100 dark:border-white/5 last:border-0 text-slate-600 dark:text-white/70" }, props));
399
+ },
400
+ code(_e) {
401
+ var _f = _e, { inline, className, children } = _f, props = __objRest(_f, ["inline", "className", "children"]);
402
+ const match = /language-(\w+)/.exec(className || "");
403
+ const isChart = match && match[1] === "chart";
404
+ if (!inline && isChart) {
405
+ try {
406
+ const config = JSON.parse(String(children).replace(/\n$/, ""));
407
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-4 p-4 bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm" }, /* @__PURE__ */ import_react5.default.createElement(
408
+ DynamicChart,
409
+ {
410
+ config,
411
+ primaryColor,
412
+ accentColor
413
+ }
414
+ ));
415
+ } catch (e) {
416
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "p-4 bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 rounded-lg text-sm" }, "Failed to render chart: Invalid configuration.");
417
+ }
418
+ }
419
+ return /* @__PURE__ */ import_react5.default.createElement("code", __spreadValues({ className }, props), children);
420
+ }
421
+ }
422
+ },
423
+ cleanContent || message.content
424
+ ), isStreaming && message.content && /* @__PURE__ */ import_react5.default.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
425
+ ), !isUser && hasProducts && /* @__PURE__ */ import_react5.default.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ import_react5.default.createElement(
304
426
  ProductCarousel,
305
427
  {
306
428
  products: allProducts,
307
429
  primaryColor,
308
430
  onAddToCart
309
431
  }
310
- )), !isUser && sources && sources.length > 0 && /* @__PURE__ */ import_react4.default.createElement("div", { className: "w-full" }, /* @__PURE__ */ import_react4.default.createElement(
432
+ )), !isUser && sources && sources.length > 0 && /* @__PURE__ */ import_react5.default.createElement("div", { className: "w-full" }, /* @__PURE__ */ import_react5.default.createElement(
311
433
  "button",
312
434
  {
313
435
  onClick: () => setShowSources((s) => !s),
314
436
  className: "text-[11px] text-indigo-400 hover:text-indigo-300 transition-colors flex items-center gap-1 mt-1"
315
437
  },
316
- showSources ? /* @__PURE__ */ import_react4.default.createElement(import_lucide_react4.ChevronDown, { className: "w-3 h-3" }) : /* @__PURE__ */ import_react4.default.createElement(import_lucide_react4.ChevronRight, { className: "w-3 h-3" }),
438
+ showSources ? /* @__PURE__ */ import_react5.default.createElement(import_lucide_react4.ChevronDown, { className: "w-3 h-3" }) : /* @__PURE__ */ import_react5.default.createElement(import_lucide_react4.ChevronRight, { className: "w-3 h-3" }),
317
439
  sources.length,
318
440
  " source",
319
441
  sources.length !== 1 ? "s" : "",
320
442
  " used"
321
- ), showSources && /* @__PURE__ */ import_react4.default.createElement("div", { className: "mt-2 flex flex-col gap-2" }, sources.map((src, i) => /* @__PURE__ */ import_react4.default.createElement(SourceCard, { key: src.id, source: src, index: i }))))));
443
+ ), showSources && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mt-2 flex flex-col gap-2" }, sources.map((src, i) => /* @__PURE__ */ import_react5.default.createElement(SourceCard, { key: src.id, source: src, index: i }))))));
322
444
  }
323
445
 
324
446
  // src/components/ConfigProvider.tsx
325
- var import_react5 = __toESM(require("react"));
447
+ var import_react6 = __toESM(require("react"));
326
448
 
327
449
  // src/utils/templateUtils.ts
328
450
  function mergeDefined(base, override) {
@@ -338,8 +460,8 @@ function mergeDefined(base, override) {
338
460
  return merged;
339
461
  }
340
462
 
341
- // src/components/ConfigProvider.tsx
342
- var defaultConfig = {
463
+ // src/config/uiConstants.ts
464
+ var DEFAULT_CONFIG = {
343
465
  projectId: "default",
344
466
  ui: {
345
467
  title: "AI Assistant",
@@ -355,29 +477,45 @@ var defaultConfig = {
355
477
  visualStyle: "glass",
356
478
  borderRadius: "xl",
357
479
  allowUpload: true,
358
- allowResize: true
480
+ allowResize: true,
481
+ enableVoiceInput: true
359
482
  }
360
483
  };
361
- var ConfigContext = (0, import_react5.createContext)(defaultConfig);
484
+ var BORDER_RADIUS_MAP = {
485
+ none: "rounded-none",
486
+ sm: "rounded-sm",
487
+ md: "rounded-md",
488
+ lg: "rounded-lg",
489
+ xl: "rounded-xl",
490
+ full: "rounded-3xl"
491
+ };
492
+ var CHAT_SUGGESTIONS = [
493
+ "What can you help me with?",
494
+ "Summarise the key topics",
495
+ "Show me an example"
496
+ ];
497
+
498
+ // src/components/ConfigProvider.tsx
499
+ var ConfigContext = (0, import_react6.createContext)(DEFAULT_CONFIG);
362
500
  function ConfigProvider({
363
501
  config,
364
502
  children
365
503
  }) {
366
504
  const merged = {
367
- projectId: (config == null ? void 0 : config.projectId) || defaultConfig.projectId,
368
- ui: mergeDefined(defaultConfig.ui, config == null ? void 0 : config.ui)
505
+ projectId: (config == null ? void 0 : config.projectId) || DEFAULT_CONFIG.projectId,
506
+ ui: mergeDefined(DEFAULT_CONFIG.ui, config == null ? void 0 : config.ui)
369
507
  };
370
- return /* @__PURE__ */ import_react5.default.createElement(ConfigContext.Provider, { value: merged }, children);
508
+ return /* @__PURE__ */ import_react6.default.createElement(ConfigContext.Provider, { value: merged }, children);
371
509
  }
372
510
  function useConfig() {
373
- return (0, import_react5.useContext)(ConfigContext);
511
+ return (0, import_react6.useContext)(ConfigContext);
374
512
  }
375
513
 
376
514
  // src/hooks/useRagChat.ts
377
- var import_react6 = require("react");
515
+ var import_react7 = require("react");
378
516
 
379
517
  // src/hooks/useStoredMessages.ts
380
- var React6 = __toESM(require("react"));
518
+ var React7 = __toESM(require("react"));
381
519
  function readStoredMessages(storageKey) {
382
520
  if (typeof window === "undefined") {
383
521
  return [];
@@ -394,8 +532,8 @@ function readStoredMessages(storageKey) {
394
532
  }
395
533
  }
396
534
  function useStoredMessages(storageKey, persist) {
397
- const [messages, setMessages] = React6.useState(() => persist ? readStoredMessages(storageKey) : []);
398
- React6.useEffect(() => {
535
+ const [messages, setMessages] = React7.useState(() => persist ? readStoredMessages(storageKey) : []);
536
+ React7.useEffect(() => {
399
537
  if (!persist || typeof window === "undefined") {
400
538
  return;
401
539
  }
@@ -435,14 +573,14 @@ function useRagChat(projectId, options = {}) {
435
573
  } = options;
436
574
  const storageKey = `rag_chat_${projectId}`;
437
575
  const [messages, setMessages] = useStoredMessages(storageKey, persist);
438
- const [isLoading, setIsLoading] = (0, import_react6.useState)(false);
439
- const [error, setError] = (0, import_react6.useState)(null);
440
- const lastInputRef = (0, import_react6.useRef)("");
441
- const messagesRef = (0, import_react6.useRef)(messages);
442
- (0, import_react6.useEffect)(() => {
576
+ const [isLoading, setIsLoading] = (0, import_react7.useState)(false);
577
+ const [error, setError] = (0, import_react7.useState)(null);
578
+ const lastInputRef = (0, import_react7.useRef)("");
579
+ const messagesRef = (0, import_react7.useRef)(messages);
580
+ (0, import_react7.useEffect)(() => {
443
581
  messagesRef.current = messages;
444
582
  }, [messages]);
445
- const sendMessage = (0, import_react6.useCallback)(
583
+ const sendMessage = (0, import_react7.useCallback)(
446
584
  async (text, opts) => {
447
585
  var _a, _b;
448
586
  const trimmed = text.trim();
@@ -539,12 +677,12 @@ function useRagChat(projectId, options = {}) {
539
677
  },
540
678
  [apiUrl, isLoading, namespace, onError, onReply, projectId, setMessages]
541
679
  );
542
- const clear = (0, import_react6.useCallback)(() => {
680
+ const clear = (0, import_react7.useCallback)(() => {
543
681
  setMessages([]);
544
682
  setError(null);
545
683
  if (persist) localStorage.removeItem(storageKey);
546
684
  }, [persist, setMessages, storageKey]);
547
- const retry = (0, import_react6.useCallback)(async () => {
685
+ const retry = (0, import_react7.useCallback)(async () => {
548
686
  if (lastInputRef.current) {
549
687
  const latestMessage = messagesRef.current[messagesRef.current.length - 1];
550
688
  await sendMessage(lastInputRef.current, {
@@ -563,21 +701,6 @@ function useRagChat(projectId, options = {}) {
563
701
  };
564
702
  }
565
703
 
566
- // src/config/uiConstants.ts
567
- var BORDER_RADIUS_MAP = {
568
- none: "rounded-none",
569
- sm: "rounded-sm",
570
- md: "rounded-md",
571
- lg: "rounded-lg",
572
- xl: "rounded-xl",
573
- full: "rounded-3xl"
574
- };
575
- var CHAT_SUGGESTIONS = [
576
- "What can you help me with?",
577
- "Summarise the key topics",
578
- "Show me an example"
579
- ];
580
-
581
704
  // src/components/ChatWindow.tsx
582
705
  function ChatWindow({
583
706
  className = "",
@@ -593,32 +716,88 @@ function ChatWindow({
593
716
  }) {
594
717
  var _a;
595
718
  const { ui, projectId } = useConfig();
596
- const [input, setInput] = (0, import_react7.useState)("");
597
- const [mounted, setMounted] = (0, import_react7.useState)(false);
598
- const bottomRef = (0, import_react7.useRef)(null);
599
- const inputRef = (0, import_react7.useRef)(null);
719
+ const [input, setInput] = (0, import_react8.useState)("");
720
+ const [mounted, setMounted] = (0, import_react8.useState)(false);
721
+ const bottomRef = (0, import_react8.useRef)(null);
722
+ const inputRef = (0, import_react8.useRef)(null);
600
723
  const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
601
724
  namespace: projectId
602
725
  });
603
- (0, import_react7.useEffect)(() => {
726
+ const [suggestions, setSuggestions] = (0, import_react8.useState)([]);
727
+ const [isSuggesting, setIsSuggesting] = (0, import_react8.useState)(false);
728
+ const [isListening, setIsListening] = (0, import_react8.useState)(false);
729
+ const recognitionRef = (0, import_react8.useRef)(null);
730
+ (0, import_react8.useEffect)(() => {
731
+ if (typeof window !== "undefined") {
732
+ const win = window;
733
+ const SpeechRecognition = win.SpeechRecognition || win.webkitSpeechRecognition;
734
+ if (SpeechRecognition) {
735
+ const recognition = new SpeechRecognition();
736
+ recognition.continuous = true;
737
+ recognition.interimResults = true;
738
+ recognition.onresult = (event) => {
739
+ let finalTranscript = "";
740
+ for (let i = event.resultIndex; i < event.results.length; ++i) {
741
+ if (event.results[i].isFinal) {
742
+ finalTranscript += event.results[i][0].transcript;
743
+ }
744
+ }
745
+ if (finalTranscript) {
746
+ setInput((prev) => (prev ? prev + " " : "") + finalTranscript.trim());
747
+ }
748
+ };
749
+ recognition.onerror = (event) => {
750
+ console.error("Speech recognition error:", event.error);
751
+ setIsListening(false);
752
+ };
753
+ recognition.onend = () => {
754
+ setIsListening(false);
755
+ };
756
+ recognitionRef.current = recognition;
757
+ }
758
+ }
759
+ }, []);
760
+ const toggleListening = () => {
761
+ if (!recognitionRef.current) {
762
+ alert("Speech recognition is not supported in your browser.");
763
+ return;
764
+ }
765
+ if (isListening) {
766
+ recognitionRef.current.stop();
767
+ } else {
768
+ try {
769
+ recognitionRef.current.start();
770
+ setIsListening(true);
771
+ } catch (err) {
772
+ console.error("Failed to start recognition:", err);
773
+ }
774
+ }
775
+ };
776
+ (0, import_react8.useEffect)(() => {
604
777
  setMounted(true);
605
778
  }, []);
606
- (0, import_react7.useEffect)(() => {
779
+ (0, import_react8.useEffect)(() => {
607
780
  var _a2;
608
781
  if (messages.length > 0 || isLoading) {
609
782
  (_a2 = bottomRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth" });
610
783
  }
611
784
  }, [messages, isLoading]);
612
- const sendMessage = (0, import_react7.useCallback)(async () => {
785
+ const sendMessage = (0, import_react8.useCallback)(async () => {
786
+ var _a2;
613
787
  const text = input.trim();
614
788
  if (!text || isLoading) return;
789
+ if (isListening) {
790
+ (_a2 = recognitionRef.current) == null ? void 0 : _a2.stop();
791
+ }
615
792
  setInput("");
793
+ setSuggestions([]);
794
+ setIsSuggesting(false);
616
795
  await send(text);
617
796
  window.setTimeout(() => {
618
- var _a2;
619
- return (_a2 = inputRef.current) == null ? void 0 : _a2.focus();
797
+ var _a3;
798
+ return (_a3 = inputRef.current) == null ? void 0 : _a3.focus();
620
799
  }, 50);
621
- }, [input, isLoading, send]);
800
+ }, [input, isLoading, send, isListening]);
622
801
  const handleKeyDown = (e) => {
623
802
  if (e.key === "Enter" && !e.shiftKey) {
624
803
  e.preventDefault();
@@ -627,13 +806,13 @@ function ChatWindow({
627
806
  };
628
807
  const clearHistory = () => {
629
808
  clear();
809
+ setSuggestions([]);
810
+ setIsSuggesting(false);
630
811
  };
631
812
  const isEmpty = messages.length === 0;
632
813
  const currentRadius = BORDER_RADIUS_MAP[ui.borderRadius || "xl"];
633
814
  const isGlass = ui.visualStyle !== "solid";
634
- const [suggestions, setSuggestions] = (0, import_react7.useState)([]);
635
- const [isSuggesting, setIsSuggesting] = (0, import_react7.useState)(false);
636
- (0, import_react7.useEffect)(() => {
815
+ (0, import_react8.useEffect)(() => {
637
816
  if (input.trim().length < 3) {
638
817
  return;
639
818
  }
@@ -657,83 +836,83 @@ function ChatWindow({
657
836
  }, 800);
658
837
  return () => clearTimeout(timer);
659
838
  }, [input, projectId]);
660
- return /* @__PURE__ */ import_react7.default.createElement(
839
+ return /* @__PURE__ */ import_react8.default.createElement(
661
840
  "div",
662
841
  {
663
842
  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}`,
664
843
  style: __spreadValues({ "--primary": ui.primaryColor, "--accent": ui.accentColor }, style)
665
844
  },
666
- onResizeStart && /* @__PURE__ */ import_react7.default.createElement(
845
+ onResizeStart && /* @__PURE__ */ import_react8.default.createElement(
667
846
  "div",
668
847
  {
669
848
  onMouseDown: onResizeStart,
670
849
  className: "absolute top-0 left-0 w-6 h-6 cursor-nw-resize z-[100] group flex items-start justify-start p-1",
671
850
  title: "Drag to resize"
672
851
  },
673
- /* @__PURE__ */ import_react7.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]" })
852
+ /* @__PURE__ */ import_react8.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]" })
674
853
  ),
675
- /* @__PURE__ */ import_react7.default.createElement(
854
+ /* @__PURE__ */ import_react8.default.createElement(
676
855
  "div",
677
856
  {
678
857
  className: "flex items-center justify-between px-5 py-4 border-b border-slate-200 dark:border-white/10",
679
858
  style: { background: `linear-gradient(135deg, ${ui.primaryColor}15, ${ui.accentColor}10)` }
680
859
  },
681
- /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center gap-3" }, ui.logoUrl ? (
860
+ /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex items-center gap-3" }, ui.logoUrl ? (
682
861
  // eslint-disable-next-line @next/next/no-img-element
683
- /* @__PURE__ */ import_react7.default.createElement("img", { src: ui.logoUrl, alt: "logo", className: "w-8 h-8 rounded-lg object-cover" })
684
- ) : /* @__PURE__ */ import_react7.default.createElement(
862
+ /* @__PURE__ */ import_react8.default.createElement("img", { src: ui.logoUrl, alt: "logo", className: "w-8 h-8 rounded-lg object-cover" })
863
+ ) : /* @__PURE__ */ import_react8.default.createElement(
685
864
  "div",
686
865
  {
687
866
  className: `w-9 h-9 flex items-center justify-center shadow-md ${ui.borderRadius === "full" ? "rounded-full" : "rounded-xl"}`,
688
867
  style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` }
689
868
  },
690
- /* @__PURE__ */ import_react7.default.createElement(import_lucide_react5.Bot, { className: "w-5 h-5 text-white" })
691
- ), /* @__PURE__ */ import_react7.default.createElement("div", null, /* @__PURE__ */ import_react7.default.createElement("h2", { className: "text-slate-900 dark:text-white font-semibold text-sm leading-tight" }, ui.title), ui.poweredBy && /* @__PURE__ */ import_react7.default.createElement("p", { className: "text-slate-500 dark:text-white/40 text-[11px] leading-tight" }, `Powered by ${ui.poweredBy}`))),
692
- /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "flex items-center gap-1 text-[10px] text-emerald-500 dark:text-emerald-400 mr-2" }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500 dark:bg-emerald-400 animate-pulse" }), "Online"), /* @__PURE__ */ import_react7.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_react7.default.createElement(
869
+ /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Bot, { className: "w-5 h-5 text-white" })
870
+ ), /* @__PURE__ */ import_react8.default.createElement("div", null, /* @__PURE__ */ import_react8.default.createElement("h2", { className: "text-slate-900 dark:text-white font-semibold text-sm leading-tight" }, ui.title), ui.poweredBy && /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-slate-500 dark:text-white/40 text-[11px] leading-tight" }, `Powered by ${ui.poweredBy}`))),
871
+ /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "flex items-center gap-1 text-[10px] text-emerald-500 dark:text-emerald-400 mr-2" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500 dark:bg-emerald-400 animate-pulse" }), "Online"), /* @__PURE__ */ import_react8.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_react8.default.createElement(
693
872
  "button",
694
873
  {
695
874
  onClick: clearHistory,
696
875
  title: "Clear conversation",
697
876
  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"
698
877
  },
699
- /* @__PURE__ */ import_react7.default.createElement(import_lucide_react5.Trash2, { className: "w-3.5 h-3.5" })
700
- ), isResized && onResetResize && /* @__PURE__ */ import_react7.default.createElement(
878
+ /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Trash2, { className: "w-3.5 h-3.5" })
879
+ ), isResized && onResetResize && /* @__PURE__ */ import_react8.default.createElement(
701
880
  "button",
702
881
  {
703
882
  onClick: onResetResize,
704
883
  title: "Reset to default size",
705
884
  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"
706
885
  },
707
- /* @__PURE__ */ import_react7.default.createElement(import_lucide_react5.RotateCcw, { className: "w-3.5 h-3.5" })
708
- ), onMaximize && /* @__PURE__ */ import_react7.default.createElement(
886
+ /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.RotateCcw, { className: "w-3.5 h-3.5" })
887
+ ), onMaximize && /* @__PURE__ */ import_react8.default.createElement(
709
888
  "button",
710
889
  {
711
890
  onClick: onMaximize,
712
891
  title: isMaximized ? "Minimize" : "Maximize",
713
892
  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"
714
893
  },
715
- isMaximized ? /* @__PURE__ */ import_react7.default.createElement(import_lucide_react5.Minimize2, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ import_react7.default.createElement(import_lucide_react5.Maximize2, { className: "w-3.5 h-3.5" })
716
- ), showClose && onClose && /* @__PURE__ */ import_react7.default.createElement(
894
+ isMaximized ? /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Minimize2, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Maximize2, { className: "w-3.5 h-3.5" })
895
+ ), showClose && onClose && /* @__PURE__ */ import_react8.default.createElement(
717
896
  "button",
718
897
  {
719
898
  onClick: onClose,
720
899
  title: "Close chat",
721
900
  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"
722
901
  },
723
- /* @__PURE__ */ import_react7.default.createElement(import_lucide_react5.X, { className: "w-4 h-4" })
902
+ /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.X, { className: "w-4 h-4" })
724
903
  )))
725
904
  ),
726
- /* @__PURE__ */ import_react7.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 ? (
905
+ /* @__PURE__ */ import_react8.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 ? (
727
906
  /* Welcome state */
728
- /* @__PURE__ */ import_react7.default.createElement("div", { className: "h-full flex flex-col items-center justify-center text-center gap-4 px-6 py-12" }, /* @__PURE__ */ import_react7.default.createElement(
907
+ /* @__PURE__ */ import_react8.default.createElement("div", { className: "h-full flex flex-col items-center justify-center text-center gap-4 px-6 py-12" }, /* @__PURE__ */ import_react8.default.createElement(
729
908
  "div",
730
909
  {
731
910
  className: `w-16 h-16 flex items-center justify-center shadow-lg ${ui.borderRadius === "full" ? "rounded-full" : "rounded-2xl"}`,
732
911
  style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` }
733
912
  },
734
- /* @__PURE__ */ import_react7.default.createElement(import_lucide_react5.Sparkles, { className: "w-8 h-8 text-white" })
735
- ), /* @__PURE__ */ import_react7.default.createElement("div", null, /* @__PURE__ */ import_react7.default.createElement("p", { className: "text-slate-800 dark:text-white/80 font-medium leading-relaxed" }, ui.welcomeMessage), /* @__PURE__ */ import_react7.default.createElement("p", { className: "text-slate-500 dark:text-white/30 text-sm mt-2" }, "Ask a question to get started")), /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex flex-wrap gap-2 justify-center mt-2" }, CHAT_SUGGESTIONS.map(
736
- (suggestion) => /* @__PURE__ */ import_react7.default.createElement(
913
+ /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Sparkles, { className: "w-8 h-8 text-white" })
914
+ ), /* @__PURE__ */ import_react8.default.createElement("div", null, /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-slate-800 dark:text-white/80 font-medium leading-relaxed" }, ui.welcomeMessage), /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-slate-500 dark:text-white/30 text-sm mt-2" }, "Ask a question to get started")), /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex flex-wrap gap-2 justify-center mt-2" }, CHAT_SUGGESTIONS.map(
915
+ (suggestion) => /* @__PURE__ */ import_react8.default.createElement(
737
916
  "button",
738
917
  {
739
918
  key: suggestion,
@@ -747,7 +926,7 @@ function ChatWindow({
747
926
  suggestion
748
927
  )
749
928
  )))
750
- ) : messages.map((msg, index) => /* @__PURE__ */ import_react7.default.createElement(
929
+ ) : messages.map((msg, index) => /* @__PURE__ */ import_react8.default.createElement(
751
930
  MessageBubble,
752
931
  {
753
932
  key: msg.id,
@@ -758,17 +937,17 @@ function ChatWindow({
758
937
  accentColor: ui.accentColor,
759
938
  onAddToCart
760
939
  }
761
- )), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */ import_react7.default.createElement(
940
+ )), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */ import_react8.default.createElement(
762
941
  MessageBubble,
763
942
  {
764
- message: { role: "assistant", content: "" },
943
+ message: { id: "loading", role: "assistant", content: "", createdAt: (/* @__PURE__ */ new Date()).toISOString() },
765
944
  isStreaming: true,
766
945
  primaryColor: ui.primaryColor,
767
946
  accentColor: ui.accentColor,
768
947
  onAddToCart
769
948
  }
770
- ), error && /* @__PURE__ */ import_react7.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_react7.default.createElement(import_lucide_react5.TriangleAlert, { className: "w-4 h-4 flex-shrink-0" }), /* @__PURE__ */ import_react7.default.createElement("span", null, error)), /* @__PURE__ */ import_react7.default.createElement("div", { ref: bottomRef })),
771
- /* @__PURE__ */ import_react7.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_react7.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_react7.default.createElement(
949
+ ), error && /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex items-center gap-2 text-rose-500 dark:text-rose-400 text-sm bg-rose-50 dark:bg-rose-400/10 border border-rose-200 dark:border-rose-400/20 rounded-xl px-4 py-3" }, /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.TriangleAlert, { className: "w-4 h-4 flex-shrink-0" }), /* @__PURE__ */ import_react8.default.createElement("span", null, error)), /* @__PURE__ */ import_react8.default.createElement("div", { ref: bottomRef })),
950
+ /* @__PURE__ */ import_react8.default.createElement("div", { className: `px-4 pb-4 pt-2 border-t border-slate-200 dark:border-white/10 ${isGlass ? "bg-transparent" : "bg-white dark:bg-[#0f0f1a]"}` }, (suggestions.length > 0 || isSuggesting) && !isLoading && /* @__PURE__ */ import_react8.default.createElement("div", { className: "mb-3 flex flex-wrap gap-2 animate-in fade-in slide-in-from-bottom-2 duration-300" }, suggestions.map((suggestion) => /* @__PURE__ */ import_react8.default.createElement(
772
951
  "button",
773
952
  {
774
953
  key: suggestion,
@@ -780,9 +959,9 @@ function ChatWindow({
780
959
  },
781
960
  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"
782
961
  },
783
- /* @__PURE__ */ import_react7.default.createElement(import_lucide_react5.Sparkles, { className: "w-3 h-3 text-amber-400" }),
962
+ /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Sparkles, { className: "w-3 h-3 text-amber-400" }),
784
963
  suggestion
785
- )), isSuggesting && suggestions.length === 0 && /* @__PURE__ */ import_react7.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_react7.default.createElement(import_lucide_react5.Sparkles, { className: "w-3 h-3" }), "Thinking...")), /* @__PURE__ */ import_react7.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_react7.default.createElement(
964
+ )), isSuggesting && suggestions.length === 0 && /* @__PURE__ */ import_react8.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_react8.default.createElement(import_lucide_react5.Sparkles, { className: "w-3 h-3" }), "Thinking...")), /* @__PURE__ */ import_react8.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_react8.default.createElement(
786
965
  "textarea",
787
966
  {
788
967
  ref: inputRef,
@@ -801,7 +980,17 @@ function ChatWindow({
801
980
  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",
802
981
  style: { scrollbarWidth: "none" }
803
982
  }
804
- ), /* @__PURE__ */ import_react7.default.createElement(
983
+ ), ui.enableVoiceInput !== false && /* @__PURE__ */ import_react8.default.createElement(
984
+ "button",
985
+ {
986
+ type: "button",
987
+ onClick: toggleListening,
988
+ disabled: isLoading,
989
+ 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"}`,
990
+ title: isListening ? "Stop listening" : "Start voice input"
991
+ },
992
+ isListening ? /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.MicOff, { className: "w-4 h-4" }) : /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Mic, { className: "w-4 h-4" })
993
+ ), /* @__PURE__ */ import_react8.default.createElement(
805
994
  "button",
806
995
  {
807
996
  onClick: sendMessage,
@@ -812,8 +1001,8 @@ function ChatWindow({
812
1001
  // slate-400/20 for light mode disabled
813
1002
  }
814
1003
  },
815
- /* @__PURE__ */ import_react7.default.createElement(import_lucide_react5.ArrowUp, { className: "w-4 h-4 text-white" })
816
- )), /* @__PURE__ */ import_react7.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"))
1004
+ /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.ArrowUp, { className: "w-4 h-4 text-white" })
1005
+ )), /* @__PURE__ */ import_react8.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"))
817
1006
  );
818
1007
  }
819
1008
 
@@ -821,12 +1010,12 @@ function ChatWindow({
821
1010
  var DEFAULT_DIMENSIONS = { width: 380, height: 600 };
822
1011
  function ChatWidget({ position = "bottom-right", onAddToCart }) {
823
1012
  const { ui } = useConfig();
824
- const [isOpen, setIsOpen] = (0, import_react8.useState)(false);
825
- const [hasUnread, setHasUnread] = (0, import_react8.useState)(false);
826
- const [dimensions, setDimensions] = (0, import_react8.useState)(DEFAULT_DIMENSIONS);
827
- const [isResizing, setIsResizing] = (0, import_react8.useState)(false);
828
- const [isMaximized, setIsMaximized] = (0, import_react8.useState)(false);
829
- const [prevDimensions, setPrevDimensions] = (0, import_react8.useState)(DEFAULT_DIMENSIONS);
1013
+ const [isOpen, setIsOpen] = (0, import_react9.useState)(false);
1014
+ const [hasUnread, setHasUnread] = (0, import_react9.useState)(false);
1015
+ const [dimensions, setDimensions] = (0, import_react9.useState)(DEFAULT_DIMENSIONS);
1016
+ const [isResizing, setIsResizing] = (0, import_react9.useState)(false);
1017
+ const [isMaximized, setIsMaximized] = (0, import_react9.useState)(false);
1018
+ const [prevDimensions, setPrevDimensions] = (0, import_react9.useState)(DEFAULT_DIMENSIONS);
830
1019
  if (ui.showWidget === false) return null;
831
1020
  const positionClass = position === "bottom-left" ? "bottom-6 left-6" : "bottom-6 right-6";
832
1021
  const windowPositionClass = position === "bottom-left" ? "bottom-20 left-6" : "bottom-20 right-6";
@@ -876,7 +1065,7 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
876
1065
  }
877
1066
  };
878
1067
  const isResized = dimensions.width !== DEFAULT_DIMENSIONS.width || dimensions.height !== DEFAULT_DIMENSIONS.height;
879
- return /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, null, /* @__PURE__ */ import_react8.default.createElement(
1068
+ return /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement(
880
1069
  "div",
881
1070
  {
882
1071
  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"}`,
@@ -886,7 +1075,7 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
886
1075
  maxHeight: "calc(100vh - 6rem)"
887
1076
  }
888
1077
  },
889
- /* @__PURE__ */ import_react8.default.createElement(
1078
+ /* @__PURE__ */ import_react9.default.createElement(
890
1079
  ChatWindow,
891
1080
  {
892
1081
  className: "h-full relative z-10",
@@ -900,13 +1089,13 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
900
1089
  onAddToCart
901
1090
  }
902
1091
  ),
903
- /* @__PURE__ */ import_react8.default.createElement(
1092
+ /* @__PURE__ */ import_react9.default.createElement(
904
1093
  "div",
905
1094
  {
906
1095
  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"}`
907
1096
  }
908
1097
  )
909
- ), /* @__PURE__ */ import_react8.default.createElement(
1098
+ ), /* @__PURE__ */ import_react9.default.createElement(
910
1099
  "button",
911
1100
  {
912
1101
  onClick: isOpen ? () => setIsOpen(false) : handleOpen,
@@ -914,32 +1103,32 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
914
1103
  style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` },
915
1104
  "aria-label": "Open chat"
916
1105
  },
917
- /* @__PURE__ */ import_react8.default.createElement(
1106
+ /* @__PURE__ */ import_react9.default.createElement(
918
1107
  "span",
919
1108
  {
920
1109
  className: "absolute inset-0 rounded-full animate-ping opacity-20",
921
1110
  style: { background: ui.primaryColor }
922
1111
  }
923
1112
  ),
924
- /* @__PURE__ */ import_react8.default.createElement(
1113
+ /* @__PURE__ */ import_react9.default.createElement(
925
1114
  "span",
926
1115
  {
927
1116
  className: `transition-transform duration-300 ${isOpen ? "rotate-90 scale-90" : "rotate-0 scale-100"}`
928
1117
  },
929
- isOpen ? /* @__PURE__ */ import_react8.default.createElement(import_lucide_react6.X, { className: "w-6 h-6 text-white" }) : /* @__PURE__ */ import_react8.default.createElement(import_lucide_react6.MessageSquare, { className: "w-6 h-6 text-white" })
1118
+ isOpen ? /* @__PURE__ */ import_react9.default.createElement(import_lucide_react6.X, { className: "w-6 h-6 text-white" }) : /* @__PURE__ */ import_react9.default.createElement(import_lucide_react6.MessageSquare, { className: "w-6 h-6 text-white" })
930
1119
  ),
931
- hasUnread && !isOpen && /* @__PURE__ */ import_react8.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")
1120
+ hasUnread && !isOpen && /* @__PURE__ */ import_react9.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")
932
1121
  ));
933
1122
  }
934
1123
 
935
1124
  // src/components/DocumentUpload.tsx
936
- var import_react9 = __toESM(require("react"));
1125
+ var import_react10 = __toESM(require("react"));
937
1126
  var import_lucide_react7 = require("lucide-react");
938
1127
  function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
939
1128
  const { ui } = useConfig();
940
- const [fileStates, setFileStates] = (0, import_react9.useState)([]);
941
- const [isDragging, setIsDragging] = (0, import_react9.useState)(false);
942
- const fileInputRef = (0, import_react9.useRef)(null);
1129
+ const [fileStates, setFileStates] = (0, import_react10.useState)([]);
1130
+ const [isDragging, setIsDragging] = (0, import_react10.useState)(false);
1131
+ const fileInputRef = (0, import_react10.useRef)(null);
943
1132
  const addFiles = (files) => {
944
1133
  const newStates = files.map((file) => ({ file, status: "idle" }));
945
1134
  setFileStates((prev) => [...prev, ...newStates]);
@@ -989,7 +1178,7 @@ function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
989
1178
  };
990
1179
  const isUploading = fileStates.some((s) => s.status === "uploading");
991
1180
  const hasIdle = fileStates.some((s) => s.status === "idle");
992
- return /* @__PURE__ */ import_react9.default.createElement(
1181
+ return /* @__PURE__ */ import_react10.default.createElement(
993
1182
  "div",
994
1183
  {
995
1184
  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}`,
@@ -997,14 +1186,14 @@ function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
997
1186
  onDragLeave,
998
1187
  onDrop
999
1188
  },
1000
- /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex flex-col items-center justify-center text-center" }, /* @__PURE__ */ import_react9.default.createElement(
1189
+ /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex flex-col items-center justify-center text-center" }, /* @__PURE__ */ import_react10.default.createElement(
1001
1190
  "div",
1002
1191
  {
1003
1192
  className: "w-12 h-12 rounded-full flex items-center justify-center mb-4 shadow-sm",
1004
1193
  style: { background: `linear-gradient(135deg, ${ui.primaryColor}20, ${ui.accentColor}20)` }
1005
1194
  },
1006
- /* @__PURE__ */ import_react9.default.createElement(import_lucide_react7.Upload, { className: "w-6 h-6", style: { color: ui.primaryColor } })
1007
- ), /* @__PURE__ */ import_react9.default.createElement("h3", { className: "text-slate-900 dark:text-white font-semibold mb-1" }, "Upload Documents"), /* @__PURE__ */ import_react9.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_react9.default.createElement(
1195
+ /* @__PURE__ */ import_react10.default.createElement(import_lucide_react7.Upload, { className: "w-6 h-6", style: { color: ui.primaryColor } })
1196
+ ), /* @__PURE__ */ import_react10.default.createElement("h3", { className: "text-slate-900 dark:text-white font-semibold mb-1" }, "Upload Documents"), /* @__PURE__ */ import_react10.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_react10.default.createElement(
1008
1197
  "button",
1009
1198
  {
1010
1199
  onClick: () => {
@@ -1020,7 +1209,7 @@ function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
1020
1209
  }
1021
1210
  },
1022
1211
  "Select Files"
1023
- ), /* @__PURE__ */ import_react9.default.createElement(
1212
+ ), /* @__PURE__ */ import_react10.default.createElement(
1024
1213
  "input",
1025
1214
  {
1026
1215
  ref: fileInputRef,
@@ -1031,22 +1220,22 @@ function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
1031
1220
  accept: ".pdf,.docx,.txt,.md,.json,.csv"
1032
1221
  }
1033
1222
  )),
1034
- fileStates.length > 0 && /* @__PURE__ */ import_react9.default.createElement("div", { className: "mt-8 space-y-3" }, fileStates.map((state, i) => /* @__PURE__ */ import_react9.default.createElement(
1223
+ fileStates.length > 0 && /* @__PURE__ */ import_react10.default.createElement("div", { className: "mt-8 space-y-3" }, fileStates.map((state, i) => /* @__PURE__ */ import_react10.default.createElement(
1035
1224
  "div",
1036
1225
  {
1037
1226
  key: i,
1038
1227
  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"
1039
1228
  },
1040
- /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center gap-3 overflow-hidden" }, /* @__PURE__ */ import_react9.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_react9.default.createElement(import_lucide_react7.File, { className: "w-4 h-4 text-slate-400" })), /* @__PURE__ */ import_react9.default.createElement("div", { className: "truncate" }, /* @__PURE__ */ import_react9.default.createElement("p", { className: "text-xs font-medium text-slate-700 dark:text-white/80 truncate" }, state.file.name), /* @__PURE__ */ import_react9.default.createElement("p", { className: "text-[10px] text-slate-400" }, (state.file.size / 1024).toFixed(1), " KB"))),
1041
- /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center gap-2" }, state.status === "uploading" && /* @__PURE__ */ import_react9.default.createElement(import_lucide_react7.Loader2, { className: "w-4 h-4 text-slate-400 animate-spin" }), state.status === "success" && /* @__PURE__ */ import_react9.default.createElement(import_lucide_react7.CheckCircle, { className: "w-4 h-4 text-emerald-500" }), state.status === "error" && /* @__PURE__ */ import_react9.default.createElement("div", { title: state.error }, /* @__PURE__ */ import_react9.default.createElement(import_lucide_react7.AlertCircle, { className: "w-4 h-4 text-rose-500" })), state.status !== "uploading" && /* @__PURE__ */ import_react9.default.createElement(
1229
+ /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center gap-3 overflow-hidden" }, /* @__PURE__ */ import_react10.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_react10.default.createElement(import_lucide_react7.File, { className: "w-4 h-4 text-slate-400" })), /* @__PURE__ */ import_react10.default.createElement("div", { className: "truncate" }, /* @__PURE__ */ import_react10.default.createElement("p", { className: "text-xs font-medium text-slate-700 dark:text-white/80 truncate" }, state.file.name), /* @__PURE__ */ import_react10.default.createElement("p", { className: "text-[10px] text-slate-400" }, (state.file.size / 1024).toFixed(1), " KB"))),
1230
+ /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center gap-2" }, state.status === "uploading" && /* @__PURE__ */ import_react10.default.createElement(import_lucide_react7.Loader2, { className: "w-4 h-4 text-slate-400 animate-spin" }), state.status === "success" && /* @__PURE__ */ import_react10.default.createElement(import_lucide_react7.CheckCircle, { className: "w-4 h-4 text-emerald-500" }), state.status === "error" && /* @__PURE__ */ import_react10.default.createElement("div", { title: state.error }, /* @__PURE__ */ import_react10.default.createElement(import_lucide_react7.AlertCircle, { className: "w-4 h-4 text-rose-500" })), state.status !== "uploading" && /* @__PURE__ */ import_react10.default.createElement(
1042
1231
  "button",
1043
1232
  {
1044
1233
  onClick: () => removeFile(i),
1045
1234
  className: "p-1 rounded-md hover:bg-slate-200 dark:hover:bg-white/10 transition-colors"
1046
1235
  },
1047
- /* @__PURE__ */ import_react9.default.createElement(import_lucide_react7.X, { className: "w-3.5 h-3.5 text-slate-400" })
1236
+ /* @__PURE__ */ import_react10.default.createElement(import_lucide_react7.X, { className: "w-3.5 h-3.5 text-slate-400" })
1048
1237
  ))
1049
- )), hasIdle && !isUploading && /* @__PURE__ */ import_react9.default.createElement(
1238
+ )), hasIdle && !isUploading && /* @__PURE__ */ import_react10.default.createElement(
1050
1239
  "button",
1051
1240
  {
1052
1241
  onClick: uploadFiles,