@retrivora-ai/rag-engine 1.2.0 → 1.2.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/DocumentChunker-BXOUMKoP.d.ts +93 -0
- package/dist/DocumentChunker-D1dg5iCi.d.mts +93 -0
- package/dist/{chunk-OCDCJUNE.mjs → chunk-GCPPRD2G.mjs} +70 -1
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +70 -0
- package/dist/handlers/index.mjs +3 -1
- package/dist/{index-CYgr00ot.d.ts → index-B67KQ9NN.d.ts} +14 -2
- package/dist/{RagConfig-FyMB_UG6.d.mts → index-Cti1u0y1.d.mts} +87 -86
- package/dist/{RagConfig-FyMB_UG6.d.ts → index-Cti1u0y1.d.ts} +87 -86
- package/dist/{index-D-lfcqlL.d.mts → index-kUXnRvuI.d.mts} +14 -2
- package/dist/index.d.mts +53 -89
- package/dist/index.d.ts +53 -89
- package/dist/index.js +139 -27
- package/dist/index.mjs +143 -27
- package/dist/server.d.mts +9 -4
- package/dist/server.d.ts +9 -4
- package/dist/server.js +51 -0
- package/dist/server.mjs +1 -1
- package/package.json +1 -1
- package/src/app/api/suggestions/route.ts +4 -0
- package/src/components/ChatWidget.tsx +1 -7
- package/src/components/ChatWindow.tsx +180 -25
- package/src/components/ConfigProvider.tsx +7 -33
- package/src/components/DocumentUpload.tsx +1 -8
- package/src/components/MessageBubble.tsx +1 -12
- package/src/components/ProductCard.tsx +1 -15
- package/src/components/ProductCarousel.tsx +2 -7
- package/src/components/SourceCard.tsx +1 -6
- package/src/config/RagConfig.ts +2 -0
- package/src/config/uiConstants.ts +23 -0
- package/src/core/Pipeline.ts +57 -1
- package/src/core/VectorPlugin.ts +8 -1
- package/src/handlers/index.ts +31 -1
- package/src/hooks/useRagChat.ts +1 -45
- package/src/hooks/useStoredMessages.ts +1 -1
- package/src/index.ts +20 -5
- package/src/llm/ILLMProvider.ts +1 -13
- package/src/llm/providers/AnthropicProvider.ts +2 -1
- package/src/llm/providers/GeminiProvider.ts +2 -1
- package/src/llm/providers/OllamaProvider.ts +2 -1
- package/src/llm/providers/OpenAIProvider.ts +2 -1
- package/src/llm/providers/UniversalLLMAdapter.ts +2 -1
- package/src/server.ts +2 -2
- package/src/types/chat.ts +53 -0
- package/src/types/index.ts +17 -0
- package/src/types/props.ts +79 -0
- package/dist/DocumentChunker-Dh9TvmGG.d.mts +0 -45
- package/dist/DocumentChunker-Dh9TvmGG.d.ts +0 -45
package/dist/index.js
CHANGED
|
@@ -338,8 +338,8 @@ function mergeDefined(base, override) {
|
|
|
338
338
|
return merged;
|
|
339
339
|
}
|
|
340
340
|
|
|
341
|
-
// src/
|
|
342
|
-
var
|
|
341
|
+
// src/config/uiConstants.ts
|
|
342
|
+
var DEFAULT_CONFIG = {
|
|
343
343
|
projectId: "default",
|
|
344
344
|
ui: {
|
|
345
345
|
title: "AI Assistant",
|
|
@@ -355,17 +355,33 @@ var defaultConfig = {
|
|
|
355
355
|
visualStyle: "glass",
|
|
356
356
|
borderRadius: "xl",
|
|
357
357
|
allowUpload: true,
|
|
358
|
-
allowResize: true
|
|
358
|
+
allowResize: true,
|
|
359
|
+
enableVoiceInput: true
|
|
359
360
|
}
|
|
360
361
|
};
|
|
361
|
-
var
|
|
362
|
+
var BORDER_RADIUS_MAP = {
|
|
363
|
+
none: "rounded-none",
|
|
364
|
+
sm: "rounded-sm",
|
|
365
|
+
md: "rounded-md",
|
|
366
|
+
lg: "rounded-lg",
|
|
367
|
+
xl: "rounded-xl",
|
|
368
|
+
full: "rounded-3xl"
|
|
369
|
+
};
|
|
370
|
+
var CHAT_SUGGESTIONS = [
|
|
371
|
+
"What can you help me with?",
|
|
372
|
+
"Summarise the key topics",
|
|
373
|
+
"Show me an example"
|
|
374
|
+
];
|
|
375
|
+
|
|
376
|
+
// src/components/ConfigProvider.tsx
|
|
377
|
+
var ConfigContext = (0, import_react5.createContext)(DEFAULT_CONFIG);
|
|
362
378
|
function ConfigProvider({
|
|
363
379
|
config,
|
|
364
380
|
children
|
|
365
381
|
}) {
|
|
366
382
|
const merged = {
|
|
367
|
-
projectId: (config == null ? void 0 : config.projectId) ||
|
|
368
|
-
ui: mergeDefined(
|
|
383
|
+
projectId: (config == null ? void 0 : config.projectId) || DEFAULT_CONFIG.projectId,
|
|
384
|
+
ui: mergeDefined(DEFAULT_CONFIG.ui, config == null ? void 0 : config.ui)
|
|
369
385
|
};
|
|
370
386
|
return /* @__PURE__ */ import_react5.default.createElement(ConfigContext.Provider, { value: merged }, children);
|
|
371
387
|
}
|
|
@@ -563,21 +579,6 @@ function useRagChat(projectId, options = {}) {
|
|
|
563
579
|
};
|
|
564
580
|
}
|
|
565
581
|
|
|
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
582
|
// src/components/ChatWindow.tsx
|
|
582
583
|
function ChatWindow({
|
|
583
584
|
className = "",
|
|
@@ -600,6 +601,56 @@ function ChatWindow({
|
|
|
600
601
|
const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
|
|
601
602
|
namespace: projectId
|
|
602
603
|
});
|
|
604
|
+
const [suggestions, setSuggestions] = (0, import_react7.useState)([]);
|
|
605
|
+
const [isSuggesting, setIsSuggesting] = (0, import_react7.useState)(false);
|
|
606
|
+
const [isListening, setIsListening] = (0, import_react7.useState)(false);
|
|
607
|
+
const recognitionRef = (0, import_react7.useRef)(null);
|
|
608
|
+
(0, import_react7.useEffect)(() => {
|
|
609
|
+
if (typeof window !== "undefined") {
|
|
610
|
+
const win = window;
|
|
611
|
+
const SpeechRecognition = win.SpeechRecognition || win.webkitSpeechRecognition;
|
|
612
|
+
if (SpeechRecognition) {
|
|
613
|
+
const recognition = new SpeechRecognition();
|
|
614
|
+
recognition.continuous = true;
|
|
615
|
+
recognition.interimResults = true;
|
|
616
|
+
recognition.onresult = (event) => {
|
|
617
|
+
let finalTranscript = "";
|
|
618
|
+
for (let i = event.resultIndex; i < event.results.length; ++i) {
|
|
619
|
+
if (event.results[i].isFinal) {
|
|
620
|
+
finalTranscript += event.results[i][0].transcript;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
if (finalTranscript) {
|
|
624
|
+
setInput((prev) => (prev ? prev + " " : "") + finalTranscript.trim());
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
recognition.onerror = (event) => {
|
|
628
|
+
console.error("Speech recognition error:", event.error);
|
|
629
|
+
setIsListening(false);
|
|
630
|
+
};
|
|
631
|
+
recognition.onend = () => {
|
|
632
|
+
setIsListening(false);
|
|
633
|
+
};
|
|
634
|
+
recognitionRef.current = recognition;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}, []);
|
|
638
|
+
const toggleListening = () => {
|
|
639
|
+
if (!recognitionRef.current) {
|
|
640
|
+
alert("Speech recognition is not supported in your browser.");
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
if (isListening) {
|
|
644
|
+
recognitionRef.current.stop();
|
|
645
|
+
} else {
|
|
646
|
+
try {
|
|
647
|
+
recognitionRef.current.start();
|
|
648
|
+
setIsListening(true);
|
|
649
|
+
} catch (err) {
|
|
650
|
+
console.error("Failed to start recognition:", err);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
};
|
|
603
654
|
(0, import_react7.useEffect)(() => {
|
|
604
655
|
setMounted(true);
|
|
605
656
|
}, []);
|
|
@@ -610,15 +661,21 @@ function ChatWindow({
|
|
|
610
661
|
}
|
|
611
662
|
}, [messages, isLoading]);
|
|
612
663
|
const sendMessage = (0, import_react7.useCallback)(async () => {
|
|
664
|
+
var _a2;
|
|
613
665
|
const text = input.trim();
|
|
614
666
|
if (!text || isLoading) return;
|
|
667
|
+
if (isListening) {
|
|
668
|
+
(_a2 = recognitionRef.current) == null ? void 0 : _a2.stop();
|
|
669
|
+
}
|
|
615
670
|
setInput("");
|
|
671
|
+
setSuggestions([]);
|
|
672
|
+
setIsSuggesting(false);
|
|
616
673
|
await send(text);
|
|
617
674
|
window.setTimeout(() => {
|
|
618
|
-
var
|
|
619
|
-
return (
|
|
675
|
+
var _a3;
|
|
676
|
+
return (_a3 = inputRef.current) == null ? void 0 : _a3.focus();
|
|
620
677
|
}, 50);
|
|
621
|
-
}, [input, isLoading, send]);
|
|
678
|
+
}, [input, isLoading, send, isListening]);
|
|
622
679
|
const handleKeyDown = (e) => {
|
|
623
680
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
624
681
|
e.preventDefault();
|
|
@@ -627,10 +684,36 @@ function ChatWindow({
|
|
|
627
684
|
};
|
|
628
685
|
const clearHistory = () => {
|
|
629
686
|
clear();
|
|
687
|
+
setSuggestions([]);
|
|
688
|
+
setIsSuggesting(false);
|
|
630
689
|
};
|
|
631
690
|
const isEmpty = messages.length === 0;
|
|
632
691
|
const currentRadius = BORDER_RADIUS_MAP[ui.borderRadius || "xl"];
|
|
633
692
|
const isGlass = ui.visualStyle !== "solid";
|
|
693
|
+
(0, import_react7.useEffect)(() => {
|
|
694
|
+
if (input.trim().length < 3) {
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
const timer = setTimeout(async () => {
|
|
698
|
+
setIsSuggesting(true);
|
|
699
|
+
try {
|
|
700
|
+
const response = await fetch("/api/suggestions", {
|
|
701
|
+
method: "POST",
|
|
702
|
+
headers: { "Content-Type": "application/json" },
|
|
703
|
+
body: JSON.stringify({ query: input, namespace: projectId })
|
|
704
|
+
});
|
|
705
|
+
const data = await response.json();
|
|
706
|
+
if (data.suggestions) {
|
|
707
|
+
setSuggestions(data.suggestions);
|
|
708
|
+
}
|
|
709
|
+
} catch (err) {
|
|
710
|
+
console.error("Failed to fetch suggestions:", err);
|
|
711
|
+
} finally {
|
|
712
|
+
setIsSuggesting(false);
|
|
713
|
+
}
|
|
714
|
+
}, 800);
|
|
715
|
+
return () => clearTimeout(timer);
|
|
716
|
+
}, [input, projectId]);
|
|
634
717
|
return /* @__PURE__ */ import_react7.default.createElement(
|
|
635
718
|
"div",
|
|
636
719
|
{
|
|
@@ -735,19 +818,39 @@ function ChatWindow({
|
|
|
735
818
|
)), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */ import_react7.default.createElement(
|
|
736
819
|
MessageBubble,
|
|
737
820
|
{
|
|
738
|
-
message: { role: "assistant", content: "" },
|
|
821
|
+
message: { id: "loading", role: "assistant", content: "", createdAt: (/* @__PURE__ */ new Date()).toISOString() },
|
|
739
822
|
isStreaming: true,
|
|
740
823
|
primaryColor: ui.primaryColor,
|
|
741
824
|
accentColor: ui.accentColor,
|
|
742
825
|
onAddToCart
|
|
743
826
|
}
|
|
744
827
|
), 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 })),
|
|
745
|
-
/* @__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]"}` }, /* @__PURE__ */ import_react7.default.createElement("div", { className:
|
|
828
|
+
/* @__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(
|
|
829
|
+
"button",
|
|
830
|
+
{
|
|
831
|
+
key: suggestion,
|
|
832
|
+
onClick: () => {
|
|
833
|
+
var _a2;
|
|
834
|
+
setInput(suggestion);
|
|
835
|
+
setSuggestions([]);
|
|
836
|
+
(_a2 = inputRef.current) == null ? void 0 : _a2.focus();
|
|
837
|
+
},
|
|
838
|
+
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"
|
|
839
|
+
},
|
|
840
|
+
/* @__PURE__ */ import_react7.default.createElement(import_lucide_react5.Sparkles, { className: "w-3 h-3 text-amber-400" }),
|
|
841
|
+
suggestion
|
|
842
|
+
)), 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(
|
|
746
843
|
"textarea",
|
|
747
844
|
{
|
|
748
845
|
ref: inputRef,
|
|
749
846
|
value: input,
|
|
750
|
-
onChange: (e) =>
|
|
847
|
+
onChange: (e) => {
|
|
848
|
+
const val = e.target.value;
|
|
849
|
+
setInput(val);
|
|
850
|
+
if (val.trim().length < 3) {
|
|
851
|
+
setSuggestions([]);
|
|
852
|
+
}
|
|
853
|
+
},
|
|
751
854
|
onKeyDown: handleKeyDown,
|
|
752
855
|
placeholder: ui.placeholder,
|
|
753
856
|
rows: 1,
|
|
@@ -755,6 +858,15 @@ function ChatWindow({
|
|
|
755
858
|
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",
|
|
756
859
|
style: { scrollbarWidth: "none" }
|
|
757
860
|
}
|
|
861
|
+
), ui.enableVoiceInput !== false && /* @__PURE__ */ import_react7.default.createElement(
|
|
862
|
+
"button",
|
|
863
|
+
{
|
|
864
|
+
type: "button",
|
|
865
|
+
onClick: toggleListening,
|
|
866
|
+
className: `flex-shrink-0 w-9 h-9 rounded-xl flex items-center justify-center transition-all hover:scale-105 active:scale-95 ${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"}`,
|
|
867
|
+
title: isListening ? "Stop listening" : "Start voice input"
|
|
868
|
+
},
|
|
869
|
+
isListening ? /* @__PURE__ */ import_react7.default.createElement(import_lucide_react5.MicOff, { className: "w-4 h-4" }) : /* @__PURE__ */ import_react7.default.createElement(import_lucide_react5.Mic, { className: "w-4 h-4" })
|
|
758
870
|
), /* @__PURE__ */ import_react7.default.createElement(
|
|
759
871
|
"button",
|
|
760
872
|
{
|
package/dist/index.mjs
CHANGED
|
@@ -21,7 +21,9 @@ import {
|
|
|
21
21
|
TriangleAlert,
|
|
22
22
|
RotateCcw,
|
|
23
23
|
Maximize2,
|
|
24
|
-
Minimize2
|
|
24
|
+
Minimize2,
|
|
25
|
+
Mic,
|
|
26
|
+
MicOff
|
|
25
27
|
} from "lucide-react";
|
|
26
28
|
|
|
27
29
|
// src/components/MessageBubble.tsx
|
|
@@ -281,7 +283,9 @@ function MessageBubble({
|
|
|
281
283
|
|
|
282
284
|
// src/components/ConfigProvider.tsx
|
|
283
285
|
import React5, { createContext, useContext } from "react";
|
|
284
|
-
|
|
286
|
+
|
|
287
|
+
// src/config/uiConstants.ts
|
|
288
|
+
var DEFAULT_CONFIG = {
|
|
285
289
|
projectId: "default",
|
|
286
290
|
ui: {
|
|
287
291
|
title: "AI Assistant",
|
|
@@ -297,17 +301,33 @@ var defaultConfig = {
|
|
|
297
301
|
visualStyle: "glass",
|
|
298
302
|
borderRadius: "xl",
|
|
299
303
|
allowUpload: true,
|
|
300
|
-
allowResize: true
|
|
304
|
+
allowResize: true,
|
|
305
|
+
enableVoiceInput: true
|
|
301
306
|
}
|
|
302
307
|
};
|
|
303
|
-
var
|
|
308
|
+
var BORDER_RADIUS_MAP = {
|
|
309
|
+
none: "rounded-none",
|
|
310
|
+
sm: "rounded-sm",
|
|
311
|
+
md: "rounded-md",
|
|
312
|
+
lg: "rounded-lg",
|
|
313
|
+
xl: "rounded-xl",
|
|
314
|
+
full: "rounded-3xl"
|
|
315
|
+
};
|
|
316
|
+
var CHAT_SUGGESTIONS = [
|
|
317
|
+
"What can you help me with?",
|
|
318
|
+
"Summarise the key topics",
|
|
319
|
+
"Show me an example"
|
|
320
|
+
];
|
|
321
|
+
|
|
322
|
+
// src/components/ConfigProvider.tsx
|
|
323
|
+
var ConfigContext = createContext(DEFAULT_CONFIG);
|
|
304
324
|
function ConfigProvider({
|
|
305
325
|
config,
|
|
306
326
|
children
|
|
307
327
|
}) {
|
|
308
328
|
const merged = {
|
|
309
|
-
projectId: (config == null ? void 0 : config.projectId) ||
|
|
310
|
-
ui: mergeDefined(
|
|
329
|
+
projectId: (config == null ? void 0 : config.projectId) || DEFAULT_CONFIG.projectId,
|
|
330
|
+
ui: mergeDefined(DEFAULT_CONFIG.ui, config == null ? void 0 : config.ui)
|
|
311
331
|
};
|
|
312
332
|
return /* @__PURE__ */ React5.createElement(ConfigContext.Provider, { value: merged }, children);
|
|
313
333
|
}
|
|
@@ -505,21 +525,6 @@ function useRagChat(projectId, options = {}) {
|
|
|
505
525
|
};
|
|
506
526
|
}
|
|
507
527
|
|
|
508
|
-
// src/config/uiConstants.ts
|
|
509
|
-
var BORDER_RADIUS_MAP = {
|
|
510
|
-
none: "rounded-none",
|
|
511
|
-
sm: "rounded-sm",
|
|
512
|
-
md: "rounded-md",
|
|
513
|
-
lg: "rounded-lg",
|
|
514
|
-
xl: "rounded-xl",
|
|
515
|
-
full: "rounded-3xl"
|
|
516
|
-
};
|
|
517
|
-
var CHAT_SUGGESTIONS = [
|
|
518
|
-
"What can you help me with?",
|
|
519
|
-
"Summarise the key topics",
|
|
520
|
-
"Show me an example"
|
|
521
|
-
];
|
|
522
|
-
|
|
523
528
|
// src/components/ChatWindow.tsx
|
|
524
529
|
function ChatWindow({
|
|
525
530
|
className = "",
|
|
@@ -542,6 +547,56 @@ function ChatWindow({
|
|
|
542
547
|
const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
|
|
543
548
|
namespace: projectId
|
|
544
549
|
});
|
|
550
|
+
const [suggestions, setSuggestions] = useState4([]);
|
|
551
|
+
const [isSuggesting, setIsSuggesting] = useState4(false);
|
|
552
|
+
const [isListening, setIsListening] = useState4(false);
|
|
553
|
+
const recognitionRef = useRef3(null);
|
|
554
|
+
useEffect4(() => {
|
|
555
|
+
if (typeof window !== "undefined") {
|
|
556
|
+
const win = window;
|
|
557
|
+
const SpeechRecognition = win.SpeechRecognition || win.webkitSpeechRecognition;
|
|
558
|
+
if (SpeechRecognition) {
|
|
559
|
+
const recognition = new SpeechRecognition();
|
|
560
|
+
recognition.continuous = true;
|
|
561
|
+
recognition.interimResults = true;
|
|
562
|
+
recognition.onresult = (event) => {
|
|
563
|
+
let finalTranscript = "";
|
|
564
|
+
for (let i = event.resultIndex; i < event.results.length; ++i) {
|
|
565
|
+
if (event.results[i].isFinal) {
|
|
566
|
+
finalTranscript += event.results[i][0].transcript;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
if (finalTranscript) {
|
|
570
|
+
setInput((prev) => (prev ? prev + " " : "") + finalTranscript.trim());
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
recognition.onerror = (event) => {
|
|
574
|
+
console.error("Speech recognition error:", event.error);
|
|
575
|
+
setIsListening(false);
|
|
576
|
+
};
|
|
577
|
+
recognition.onend = () => {
|
|
578
|
+
setIsListening(false);
|
|
579
|
+
};
|
|
580
|
+
recognitionRef.current = recognition;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}, []);
|
|
584
|
+
const toggleListening = () => {
|
|
585
|
+
if (!recognitionRef.current) {
|
|
586
|
+
alert("Speech recognition is not supported in your browser.");
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
if (isListening) {
|
|
590
|
+
recognitionRef.current.stop();
|
|
591
|
+
} else {
|
|
592
|
+
try {
|
|
593
|
+
recognitionRef.current.start();
|
|
594
|
+
setIsListening(true);
|
|
595
|
+
} catch (err) {
|
|
596
|
+
console.error("Failed to start recognition:", err);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
};
|
|
545
600
|
useEffect4(() => {
|
|
546
601
|
setMounted(true);
|
|
547
602
|
}, []);
|
|
@@ -552,15 +607,21 @@ function ChatWindow({
|
|
|
552
607
|
}
|
|
553
608
|
}, [messages, isLoading]);
|
|
554
609
|
const sendMessage = useCallback2(async () => {
|
|
610
|
+
var _a2;
|
|
555
611
|
const text = input.trim();
|
|
556
612
|
if (!text || isLoading) return;
|
|
613
|
+
if (isListening) {
|
|
614
|
+
(_a2 = recognitionRef.current) == null ? void 0 : _a2.stop();
|
|
615
|
+
}
|
|
557
616
|
setInput("");
|
|
617
|
+
setSuggestions([]);
|
|
618
|
+
setIsSuggesting(false);
|
|
558
619
|
await send(text);
|
|
559
620
|
window.setTimeout(() => {
|
|
560
|
-
var
|
|
561
|
-
return (
|
|
621
|
+
var _a3;
|
|
622
|
+
return (_a3 = inputRef.current) == null ? void 0 : _a3.focus();
|
|
562
623
|
}, 50);
|
|
563
|
-
}, [input, isLoading, send]);
|
|
624
|
+
}, [input, isLoading, send, isListening]);
|
|
564
625
|
const handleKeyDown = (e) => {
|
|
565
626
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
566
627
|
e.preventDefault();
|
|
@@ -569,10 +630,36 @@ function ChatWindow({
|
|
|
569
630
|
};
|
|
570
631
|
const clearHistory = () => {
|
|
571
632
|
clear();
|
|
633
|
+
setSuggestions([]);
|
|
634
|
+
setIsSuggesting(false);
|
|
572
635
|
};
|
|
573
636
|
const isEmpty = messages.length === 0;
|
|
574
637
|
const currentRadius = BORDER_RADIUS_MAP[ui.borderRadius || "xl"];
|
|
575
638
|
const isGlass = ui.visualStyle !== "solid";
|
|
639
|
+
useEffect4(() => {
|
|
640
|
+
if (input.trim().length < 3) {
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
const timer = setTimeout(async () => {
|
|
644
|
+
setIsSuggesting(true);
|
|
645
|
+
try {
|
|
646
|
+
const response = await fetch("/api/suggestions", {
|
|
647
|
+
method: "POST",
|
|
648
|
+
headers: { "Content-Type": "application/json" },
|
|
649
|
+
body: JSON.stringify({ query: input, namespace: projectId })
|
|
650
|
+
});
|
|
651
|
+
const data = await response.json();
|
|
652
|
+
if (data.suggestions) {
|
|
653
|
+
setSuggestions(data.suggestions);
|
|
654
|
+
}
|
|
655
|
+
} catch (err) {
|
|
656
|
+
console.error("Failed to fetch suggestions:", err);
|
|
657
|
+
} finally {
|
|
658
|
+
setIsSuggesting(false);
|
|
659
|
+
}
|
|
660
|
+
}, 800);
|
|
661
|
+
return () => clearTimeout(timer);
|
|
662
|
+
}, [input, projectId]);
|
|
576
663
|
return /* @__PURE__ */ React7.createElement(
|
|
577
664
|
"div",
|
|
578
665
|
{
|
|
@@ -677,19 +764,39 @@ function ChatWindow({
|
|
|
677
764
|
)), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */ React7.createElement(
|
|
678
765
|
MessageBubble,
|
|
679
766
|
{
|
|
680
|
-
message: { role: "assistant", content: "" },
|
|
767
|
+
message: { id: "loading", role: "assistant", content: "", createdAt: (/* @__PURE__ */ new Date()).toISOString() },
|
|
681
768
|
isStreaming: true,
|
|
682
769
|
primaryColor: ui.primaryColor,
|
|
683
770
|
accentColor: ui.accentColor,
|
|
684
771
|
onAddToCart
|
|
685
772
|
}
|
|
686
773
|
), error && /* @__PURE__ */ React7.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__ */ React7.createElement(TriangleAlert, { className: "w-4 h-4 flex-shrink-0" }), /* @__PURE__ */ React7.createElement("span", null, error)), /* @__PURE__ */ React7.createElement("div", { ref: bottomRef })),
|
|
687
|
-
/* @__PURE__ */ React7.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]"}` }, /* @__PURE__ */ React7.createElement("div", { className:
|
|
774
|
+
/* @__PURE__ */ React7.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__ */ React7.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__ */ React7.createElement(
|
|
775
|
+
"button",
|
|
776
|
+
{
|
|
777
|
+
key: suggestion,
|
|
778
|
+
onClick: () => {
|
|
779
|
+
var _a2;
|
|
780
|
+
setInput(suggestion);
|
|
781
|
+
setSuggestions([]);
|
|
782
|
+
(_a2 = inputRef.current) == null ? void 0 : _a2.focus();
|
|
783
|
+
},
|
|
784
|
+
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"
|
|
785
|
+
},
|
|
786
|
+
/* @__PURE__ */ React7.createElement(Sparkles, { className: "w-3 h-3 text-amber-400" }),
|
|
787
|
+
suggestion
|
|
788
|
+
)), isSuggesting && suggestions.length === 0 && /* @__PURE__ */ React7.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__ */ React7.createElement(Sparkles, { className: "w-3 h-3" }), "Thinking...")), /* @__PURE__ */ React7.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__ */ React7.createElement(
|
|
688
789
|
"textarea",
|
|
689
790
|
{
|
|
690
791
|
ref: inputRef,
|
|
691
792
|
value: input,
|
|
692
|
-
onChange: (e) =>
|
|
793
|
+
onChange: (e) => {
|
|
794
|
+
const val = e.target.value;
|
|
795
|
+
setInput(val);
|
|
796
|
+
if (val.trim().length < 3) {
|
|
797
|
+
setSuggestions([]);
|
|
798
|
+
}
|
|
799
|
+
},
|
|
693
800
|
onKeyDown: handleKeyDown,
|
|
694
801
|
placeholder: ui.placeholder,
|
|
695
802
|
rows: 1,
|
|
@@ -697,6 +804,15 @@ function ChatWindow({
|
|
|
697
804
|
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",
|
|
698
805
|
style: { scrollbarWidth: "none" }
|
|
699
806
|
}
|
|
807
|
+
), ui.enableVoiceInput !== false && /* @__PURE__ */ React7.createElement(
|
|
808
|
+
"button",
|
|
809
|
+
{
|
|
810
|
+
type: "button",
|
|
811
|
+
onClick: toggleListening,
|
|
812
|
+
className: `flex-shrink-0 w-9 h-9 rounded-xl flex items-center justify-center transition-all hover:scale-105 active:scale-95 ${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"}`,
|
|
813
|
+
title: isListening ? "Stop listening" : "Start voice input"
|
|
814
|
+
},
|
|
815
|
+
isListening ? /* @__PURE__ */ React7.createElement(MicOff, { className: "w-4 h-4" }) : /* @__PURE__ */ React7.createElement(Mic, { className: "w-4 h-4" })
|
|
700
816
|
), /* @__PURE__ */ React7.createElement(
|
|
701
817
|
"button",
|
|
702
818
|
{
|
package/dist/server.d.mts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { j as VectorDBConfig, L as LLMConfig, E as EmbeddingConfig, h as RagConfig, I as IngestDocument, C as ChatMessage, d as ChatResponse, l as RetrievalResult, i as UpsertDocument, V as VectorMatch, G as GraphDBConfig, m as GraphNode, n as Edge, o as GraphSearchResult, k as VectorDBProvider, f as LLMProvider, e as EmbeddingProvider, g as RAGConfig, U as UIConfig, c as ChatOptions } from './index-Cti1u0y1.mjs';
|
|
2
|
+
import { I as ILLMProvider, E as EmbedOptions } from './DocumentChunker-D1dg5iCi.mjs';
|
|
3
|
+
export { C as Chunk, a as ChunkOptions, D as DocumentChunker } from './DocumentChunker-D1dg5iCi.mjs';
|
|
4
|
+
import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-kUXnRvuI.mjs';
|
|
5
|
+
export { C as ConfigValidator, V as ValidationError, b as VectorPlugin, c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from './index-kUXnRvuI.mjs';
|
|
5
6
|
import 'next/server';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -166,6 +167,10 @@ declare class Pipeline {
|
|
|
166
167
|
* Rewrite the user query for better retrieval performance.
|
|
167
168
|
*/
|
|
168
169
|
private rewriteQuery;
|
|
170
|
+
/**
|
|
171
|
+
* Generate 3-5 short, relevant questions based on the vector database content.
|
|
172
|
+
*/
|
|
173
|
+
getSuggestions(query: string, namespace?: string): Promise<string[]>;
|
|
169
174
|
}
|
|
170
175
|
|
|
171
176
|
/**
|
package/dist/server.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { j as VectorDBConfig, L as LLMConfig, E as EmbeddingConfig, h as RagConfig, I as IngestDocument, C as ChatMessage, d as ChatResponse, l as RetrievalResult, i as UpsertDocument, V as VectorMatch, G as GraphDBConfig, m as GraphNode, n as Edge, o as GraphSearchResult, k as VectorDBProvider, f as LLMProvider, e as EmbeddingProvider, g as RAGConfig, U as UIConfig, c as ChatOptions } from './index-Cti1u0y1.js';
|
|
2
|
+
import { I as ILLMProvider, E as EmbedOptions } from './DocumentChunker-BXOUMKoP.js';
|
|
3
|
+
export { C as Chunk, a as ChunkOptions, D as DocumentChunker } from './DocumentChunker-BXOUMKoP.js';
|
|
4
|
+
import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-B67KQ9NN.js';
|
|
5
|
+
export { C as ConfigValidator, V as ValidationError, b as VectorPlugin, c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from './index-B67KQ9NN.js';
|
|
5
6
|
import 'next/server';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -166,6 +167,10 @@ declare class Pipeline {
|
|
|
166
167
|
* Rewrite the user query for better retrieval performance.
|
|
167
168
|
*/
|
|
168
169
|
private rewriteQuery;
|
|
170
|
+
/**
|
|
171
|
+
* Generate 3-5 short, relevant questions based on the vector database content.
|
|
172
|
+
*/
|
|
173
|
+
getSuggestions(query: string, namespace?: string): Promise<string[]>;
|
|
169
174
|
}
|
|
170
175
|
|
|
171
176
|
/**
|
package/dist/server.js
CHANGED
|
@@ -4177,6 +4177,50 @@ Optimized Search Query:`;
|
|
|
4177
4177
|
);
|
|
4178
4178
|
return rewrite.trim() || question;
|
|
4179
4179
|
}
|
|
4180
|
+
/**
|
|
4181
|
+
* Generate 3-5 short, relevant questions based on the vector database content.
|
|
4182
|
+
*/
|
|
4183
|
+
async getSuggestions(query, namespace) {
|
|
4184
|
+
if (!query || query.trim().length < 3) {
|
|
4185
|
+
return [];
|
|
4186
|
+
}
|
|
4187
|
+
await this.initialize();
|
|
4188
|
+
const ns = namespace != null ? namespace : this.config.projectId;
|
|
4189
|
+
try {
|
|
4190
|
+
const { sources } = await this.retrieve(query, { namespace: ns, topK: 3 });
|
|
4191
|
+
if (sources.length === 0) {
|
|
4192
|
+
return [];
|
|
4193
|
+
}
|
|
4194
|
+
const context = sources.map((s) => s.content).join("\n\n---\n\n");
|
|
4195
|
+
const prompt = `
|
|
4196
|
+
Based on the following snippets from a document, what are 3 short, relevant questions a user might ask?
|
|
4197
|
+
Focus on questions that can be answered by the context.
|
|
4198
|
+
Keep each question under 10 words and make them very specific to the content.
|
|
4199
|
+
Return ONLY a JSON array of strings like ["Question 1", "Question 2", "Question 3"].
|
|
4200
|
+
|
|
4201
|
+
Context:
|
|
4202
|
+
${context}
|
|
4203
|
+
|
|
4204
|
+
Suggestions:`;
|
|
4205
|
+
const response = await this.llmProvider.chat(
|
|
4206
|
+
[
|
|
4207
|
+
{ role: "system", content: "You are a helpful assistant that generates search suggestions." },
|
|
4208
|
+
{ role: "user", content: prompt }
|
|
4209
|
+
],
|
|
4210
|
+
""
|
|
4211
|
+
);
|
|
4212
|
+
const match = response.match(/\[[\s\S]*\]/);
|
|
4213
|
+
if (match) {
|
|
4214
|
+
const suggestions = JSON.parse(match[0]);
|
|
4215
|
+
if (Array.isArray(suggestions)) {
|
|
4216
|
+
return suggestions.map((s) => String(s)).slice(0, 3);
|
|
4217
|
+
}
|
|
4218
|
+
}
|
|
4219
|
+
} catch (error) {
|
|
4220
|
+
console.error("[Pipeline] Failed to generate suggestions:", error);
|
|
4221
|
+
}
|
|
4222
|
+
return [];
|
|
4223
|
+
}
|
|
4180
4224
|
};
|
|
4181
4225
|
|
|
4182
4226
|
// src/core/ProviderHealthCheck.ts
|
|
@@ -4331,6 +4375,13 @@ var VectorPlugin = class {
|
|
|
4331
4375
|
await this.validationPromise;
|
|
4332
4376
|
return this.pipeline.ingest(documents, namespace);
|
|
4333
4377
|
}
|
|
4378
|
+
/**
|
|
4379
|
+
* Get auto-suggestions based on a query prefix.
|
|
4380
|
+
*/
|
|
4381
|
+
async getSuggestions(query, namespace) {
|
|
4382
|
+
await this.validationPromise;
|
|
4383
|
+
return this.pipeline.getSuggestions(query, namespace);
|
|
4384
|
+
}
|
|
4334
4385
|
};
|
|
4335
4386
|
|
|
4336
4387
|
// src/config/ConfigBuilder.ts
|
package/dist/server.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retrivora-ai/rag-engine",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "Retrivora AI is a plug-and-play AI engine for RAG chat experiences — generic vector DB + LLM provider, embeddable or standalone.",
|
|
5
5
|
"author": "Abhinav Alkuchi",
|
|
6
6
|
"license": "MIT",
|
|
@@ -4,13 +4,7 @@ import React, { useState } from 'react';
|
|
|
4
4
|
import { MessageSquare, X } from 'lucide-react';
|
|
5
5
|
import { ChatWindow } from './ChatWindow';
|
|
6
6
|
import { useConfig } from './ConfigProvider';
|
|
7
|
-
|
|
8
|
-
interface ChatWidgetProps {
|
|
9
|
-
/** Position of the floating button. Defaults to bottom-right. */
|
|
10
|
-
position?: 'bottom-right' | 'bottom-left';
|
|
11
|
-
/** Called when the user clicks 'Add to Cart' on a product */
|
|
12
|
-
onAddToCart?: (product: any) => void;
|
|
13
|
-
}
|
|
7
|
+
import { ChatWidgetProps } from '../types';
|
|
14
8
|
|
|
15
9
|
const DEFAULT_DIMENSIONS = { width: 380, height: 600 };
|
|
16
10
|
|