Skip to content

Commit 8f775a6

Browse files
amaan-bhatiactions-user
authored andcommitted
feat: ragbot ui integration
Signed-off-by: amaan-bhati <amaanbhati49@gmail.com>
1 parent 470f18c commit 8f775a6

File tree

5 files changed

+341
-8
lines changed

5 files changed

+341
-8
lines changed

docs/components/RelatedReadList.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ export function Preview({
115115
style={{marginTop: "1rem", display: "block", fontSize: "0.75rem"}}
116116
>
117117
<a style={{color: "blue"}} href={metadata.permalink}>
118-
see full article >>
118+
see full article
119119
</a>
120120
</span>
121121
</div>

docusaurus.config.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,7 @@ module.exports = {
162162
dropdownActiveClassDisabled: true,
163163
},
164164
{
165-
href:
166-
"https://join.slack.com/t/keploy/shared_invite/zt-357qqm9b5-PbZRVu3Yt2rJIa6ofrwWNg",
165+
href: "https://join.slack.com/t/keploy/shared_invite/zt-357qqm9b5-PbZRVu3Yt2rJIa6ofrwWNg",
167166
position: "right",
168167
className: "header-slack-link",
169168
"aria-label": "Join our Slack community",
@@ -340,11 +339,17 @@ module.exports = {
340339
async: true,
341340
defer: true,
342341
},
343-
{
344-
src: "/docs/scripts/chat.js",
345-
async: true,
346-
defer: true,
347-
},
342+
343+
// {
344+
// src: "/docs/scripts/chatbot.js",
345+
// async: true,
346+
// defer: true,
347+
// },
348+
// {
349+
// src: "/docs/scripts/chat.js",
350+
// async: true,
351+
// defer: true,
352+
// },
348353
// {
349354
// src: "/scripts/fullstory.js",
350355
// async: true,

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@
3131
"prism-react-renderer": "^2.1.0",
3232
"react": "^18.2.0",
3333
"react-dom": "^18.2.0",
34+
"react-markdown": "^10.1.0",
3435
"react-player": "^2.6.0",
36+
"rehype-highlight": "^7.0.2",
37+
"remark-gfm": "^4.0.1",
3538
"remark-typescript-tools": "1.0.9",
3639
"typescript": "5",
3740
"uuid": "^8.3.2",

src/components/ChatBot.js

Lines changed: 313 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
import React, {useState, useEffect, useRef} from "react";
2+
3+
export default function Chatbot() {
4+
const [isOpen, setIsOpen] = useState(false);
5+
const [messages, setMessages] = useState([]);
6+
const [inputValue, setInputValue] = useState("");
7+
const [isLoading, setIsLoading] = useState(false);
8+
const [botStatus, setBotStatus] = useState("");
9+
const [showGreetingMessage, setShowGreetingMessage] = useState(true);
10+
const messagesEndRef = useRef(null);
11+
12+
const CHAT_STORAGE_KEY = "chat_history";
13+
14+
const toggleChat = () => setIsOpen(!isOpen);
15+
16+
// Load saved messages
17+
useEffect(() => {
18+
const saved = localStorage.getItem(CHAT_STORAGE_KEY);
19+
if (saved) setMessages(JSON.parse(saved));
20+
}, []);
21+
22+
// Save chat history
23+
useEffect(() => {
24+
if (messages.length > 0) {
25+
localStorage.setItem(CHAT_STORAGE_KEY, JSON.stringify(messages));
26+
}
27+
}, [messages]);
28+
29+
// Auto-scroll
30+
useEffect(() => {
31+
messagesEndRef.current?.scrollIntoView({behavior: "smooth"});
32+
}, [messages]);
33+
34+
// Hide greeting after 7s
35+
useEffect(() => {
36+
if (!isOpen && showGreetingMessage) {
37+
const timer = setTimeout(() => setShowGreetingMessage(false), 7000);
38+
return () => clearTimeout(timer);
39+
}
40+
}, [isOpen, showGreetingMessage]);
41+
42+
const sendMessage = async () => {
43+
if (!inputValue.trim()) return;
44+
45+
const userMsg = {
46+
id: Date.now(),
47+
text: inputValue,
48+
sender: "user",
49+
timestamp: new Date().toLocaleTimeString([], {
50+
hour: "2-digit",
51+
minute: "2-digit",
52+
}),
53+
};
54+
55+
setMessages((prev) => [...prev, userMsg]);
56+
setInputValue("");
57+
setIsLoading(true);
58+
59+
const statuses = [
60+
"Reviewing your query...",
61+
"Searching knowledge base...",
62+
"Formulating response...",
63+
];
64+
let idx = 0;
65+
const interval = setInterval(() => {
66+
setBotStatus(statuses[idx]);
67+
idx = (idx + 1) % statuses.length;
68+
}, 2000);
69+
70+
try {
71+
const res = await fetch("https://docbot.keploy.io/chat", {
72+
method: "POST",
73+
headers: {"Content-Type": "application/json"},
74+
body: JSON.stringify({question: userMsg.text}),
75+
});
76+
const data = await res.json();
77+
78+
const botMsg = {
79+
id: Date.now() + 1,
80+
text: data.answer || "I couldn't find an answer. Try rephrasing.",
81+
sender: "bot",
82+
timestamp: new Date().toLocaleTimeString([], {
83+
hour: "2-digit",
84+
minute: "2-digit",
85+
}),
86+
};
87+
88+
setMessages((prev) => [...prev, botMsg]);
89+
} catch (err) {
90+
setMessages((prev) => [
91+
...prev,
92+
{
93+
id: Date.now() + 2,
94+
text: "⚠️ Error: please try again later.",
95+
sender: "bot",
96+
timestamp: new Date().toLocaleTimeString([], {
97+
hour: "2-digit",
98+
minute: "2-digit",
99+
}),
100+
},
101+
]);
102+
} finally {
103+
clearInterval(interval);
104+
setBotStatus("");
105+
setIsLoading(false);
106+
}
107+
};
108+
109+
return (
110+
<div
111+
style={{
112+
position: "fixed",
113+
bottom: "20px",
114+
right: "20px",
115+
zIndex: 1000,
116+
fontFamily: "sans-serif",
117+
}}
118+
>
119+
{/* Floating Button */}
120+
{!isOpen && (
121+
<div style={{position: "relative"}}>
122+
{showGreetingMessage && (
123+
<div
124+
style={{
125+
position: "absolute",
126+
bottom: "75px",
127+
right: "0",
128+
background: "#fff",
129+
border: "1px solid #e5e7eb",
130+
borderRadius: "8px",
131+
padding: "10px 12px",
132+
width: "220px",
133+
fontSize: "14px",
134+
color: "#374151",
135+
boxShadow: "0 4px 10px rgba(0,0,0,0.15)",
136+
}}
137+
>
138+
<p style={{fontWeight: "600", marginBottom: "4px"}}>
139+
Hey, I'm Keploy AI Assistant!
140+
</p>
141+
<p>May I help you?</p>
142+
</div>
143+
)}
144+
145+
<button
146+
onClick={toggleChat}
147+
style={{
148+
width: "60px",
149+
height: "60px",
150+
borderRadius: "50%",
151+
background: "#FF6B35",
152+
border: "none",
153+
cursor: "pointer",
154+
boxShadow: "0 6px 12px rgba(0,0,0,0.25)",
155+
display: "flex",
156+
alignItems: "center",
157+
justifyContent: "center",
158+
transition: "transform 0.2s ease",
159+
color: "#fff",
160+
fontSize: "24px",
161+
}}
162+
onMouseOver={(e) =>
163+
(e.currentTarget.style.transform = "scale(1.05)")
164+
}
165+
onMouseOut={(e) => (e.currentTarget.style.transform = "scale(1)")}
166+
>
167+
💬
168+
</button>
169+
</div>
170+
)}
171+
172+
{/* Chat Window */}
173+
{isOpen && (
174+
<div
175+
style={{
176+
width: "360px",
177+
height: "520px",
178+
background: "#fff",
179+
border: "1px solid #e5e7eb",
180+
borderRadius: "12px",
181+
boxShadow: "0 8px 20px rgba(0,0,0,0.25)",
182+
display: "flex",
183+
flexDirection: "column",
184+
overflow: "hidden",
185+
}}
186+
>
187+
{/* Header */}
188+
<div
189+
style={{
190+
background: "#FF6B35",
191+
color: "#fff",
192+
padding: "12px",
193+
fontWeight: "600",
194+
display: "flex",
195+
justifyContent: "space-between",
196+
alignItems: "center",
197+
fontSize: "15px",
198+
}}
199+
>
200+
Keploy AI Assistant
201+
<button
202+
onClick={toggleChat}
203+
style={{
204+
background: "transparent",
205+
border: "none",
206+
color: "#fff",
207+
fontSize: "18px",
208+
cursor: "pointer",
209+
}}
210+
>
211+
212+
</button>
213+
</div>
214+
215+
{/* Messages */}
216+
<div
217+
style={{
218+
flex: 1,
219+
overflowY: "auto",
220+
padding: "12px",
221+
background: "#f9fafb",
222+
fontSize: "14px",
223+
}}
224+
>
225+
{messages.map((m) => (
226+
<div
227+
key={m.id}
228+
style={{
229+
margin: "8px 0",
230+
display: "flex",
231+
justifyContent:
232+
m.sender === "user" ? "flex-end" : "flex-start",
233+
}}
234+
>
235+
<div
236+
style={{
237+
padding: "8px 12px",
238+
borderRadius: "12px",
239+
background: m.sender === "user" ? "#ffedd5" : "#e5e7eb",
240+
color: "#1f2937",
241+
maxWidth: "75%",
242+
wordWrap: "break-word",
243+
}}
244+
>
245+
{m.text}
246+
<div
247+
style={{
248+
fontSize: "11px",
249+
color: "#6b7280",
250+
marginTop: "4px",
251+
textAlign: "right",
252+
}}
253+
>
254+
{m.timestamp}
255+
</div>
256+
</div>
257+
</div>
258+
))}
259+
260+
{isLoading && (
261+
<div
262+
style={{fontSize: "13px", color: "#6b7280", marginTop: "6px"}}
263+
>
264+
{botStatus}...
265+
</div>
266+
)}
267+
<div ref={messagesEndRef} />
268+
</div>
269+
270+
{/* Input */}
271+
<div
272+
style={{
273+
borderTop: "1px solid #e5e7eb",
274+
padding: "8px",
275+
display: "flex",
276+
}}
277+
>
278+
<input
279+
type="text"
280+
value={inputValue}
281+
onChange={(e) => setInputValue(e.target.value)}
282+
onKeyDown={(e) => e.key === "Enter" && sendMessage()}
283+
placeholder="Type your message..."
284+
style={{
285+
flex: 1,
286+
border: "1px solid #d1d5db",
287+
borderRadius: "8px",
288+
padding: "8px 10px",
289+
fontSize: "14px",
290+
outline: "none",
291+
}}
292+
/>
293+
<button
294+
onClick={sendMessage}
295+
style={{
296+
marginLeft: "8px",
297+
background: "#FF6B35",
298+
border: "none",
299+
color: "#fff",
300+
padding: "8px 14px",
301+
borderRadius: "8px",
302+
cursor: "pointer",
303+
fontWeight: "500",
304+
}}
305+
>
306+
Send
307+
</button>
308+
</div>
309+
</div>
310+
)}
311+
</div>
312+
);
313+
}

src/theme/Root.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from "react";
2+
import Chatbot from "../components/ChatBot";
3+
// import Chatbot from "../components/Chatbot";
4+
5+
export default function Root({children}) {
6+
return (
7+
<>
8+
{children}
9+
<Chatbot />
10+
</>
11+
);
12+
}

0 commit comments

Comments
 (0)