From 8f775a66415e3a4c3c10b77ff325ce7b8f93a766 Mon Sep 17 00:00:00 2001 From: amaan-bhati Date: Wed, 3 Sep 2025 18:19:57 +0530 Subject: [PATCH] feat: ragbot ui integration Signed-off-by: amaan-bhati --- docs/components/RelatedReadList.js | 2 +- docusaurus.config.js | 19 +- package.json | 3 + src/components/ChatBot.js | 313 +++++++++++++++++++++++++++++ src/theme/Root.js | 12 ++ 5 files changed, 341 insertions(+), 8 deletions(-) create mode 100644 src/components/ChatBot.js create mode 100644 src/theme/Root.js diff --git a/docs/components/RelatedReadList.js b/docs/components/RelatedReadList.js index 781ce8fa0..92d2b84d6 100644 --- a/docs/components/RelatedReadList.js +++ b/docs/components/RelatedReadList.js @@ -115,7 +115,7 @@ export function Preview({ style={{marginTop: "1rem", display: "block", fontSize: "0.75rem"}} > - see full article >> + see full article diff --git a/docusaurus.config.js b/docusaurus.config.js index 89ca483a1..1b3344ccd 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -162,8 +162,7 @@ module.exports = { dropdownActiveClassDisabled: true, }, { - href: - "https://join.slack.com/t/keploy/shared_invite/zt-357qqm9b5-PbZRVu3Yt2rJIa6ofrwWNg", + href: "https://join.slack.com/t/keploy/shared_invite/zt-357qqm9b5-PbZRVu3Yt2rJIa6ofrwWNg", position: "right", className: "header-slack-link", "aria-label": "Join our Slack community", @@ -340,11 +339,17 @@ module.exports = { async: true, defer: true, }, - { - src: "/docs/scripts/chat.js", - async: true, - defer: true, - }, + + // { + // src: "/docs/scripts/chatbot.js", + // async: true, + // defer: true, + // }, + // { + // src: "/docs/scripts/chat.js", + // async: true, + // defer: true, + // }, // { // src: "/scripts/fullstory.js", // async: true, diff --git a/package.json b/package.json index 2f50f0cbe..f4fccf853 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,10 @@ "prism-react-renderer": "^2.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-markdown": "^10.1.0", "react-player": "^2.6.0", + "rehype-highlight": "^7.0.2", + "remark-gfm": "^4.0.1", "remark-typescript-tools": "1.0.9", "typescript": "5", "uuid": "^8.3.2", diff --git a/src/components/ChatBot.js b/src/components/ChatBot.js new file mode 100644 index 000000000..730c766ec --- /dev/null +++ b/src/components/ChatBot.js @@ -0,0 +1,313 @@ +import React, {useState, useEffect, useRef} from "react"; + +export default function Chatbot() { + const [isOpen, setIsOpen] = useState(false); + const [messages, setMessages] = useState([]); + const [inputValue, setInputValue] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const [botStatus, setBotStatus] = useState(""); + const [showGreetingMessage, setShowGreetingMessage] = useState(true); + const messagesEndRef = useRef(null); + + const CHAT_STORAGE_KEY = "chat_history"; + + const toggleChat = () => setIsOpen(!isOpen); + + // Load saved messages + useEffect(() => { + const saved = localStorage.getItem(CHAT_STORAGE_KEY); + if (saved) setMessages(JSON.parse(saved)); + }, []); + + // Save chat history + useEffect(() => { + if (messages.length > 0) { + localStorage.setItem(CHAT_STORAGE_KEY, JSON.stringify(messages)); + } + }, [messages]); + + // Auto-scroll + useEffect(() => { + messagesEndRef.current?.scrollIntoView({behavior: "smooth"}); + }, [messages]); + + // Hide greeting after 7s + useEffect(() => { + if (!isOpen && showGreetingMessage) { + const timer = setTimeout(() => setShowGreetingMessage(false), 7000); + return () => clearTimeout(timer); + } + }, [isOpen, showGreetingMessage]); + + const sendMessage = async () => { + if (!inputValue.trim()) return; + + const userMsg = { + id: Date.now(), + text: inputValue, + sender: "user", + timestamp: new Date().toLocaleTimeString([], { + hour: "2-digit", + minute: "2-digit", + }), + }; + + setMessages((prev) => [...prev, userMsg]); + setInputValue(""); + setIsLoading(true); + + const statuses = [ + "Reviewing your query...", + "Searching knowledge base...", + "Formulating response...", + ]; + let idx = 0; + const interval = setInterval(() => { + setBotStatus(statuses[idx]); + idx = (idx + 1) % statuses.length; + }, 2000); + + try { + const res = await fetch("https://docbot.keploy.io/chat", { + method: "POST", + headers: {"Content-Type": "application/json"}, + body: JSON.stringify({question: userMsg.text}), + }); + const data = await res.json(); + + const botMsg = { + id: Date.now() + 1, + text: data.answer || "I couldn't find an answer. Try rephrasing.", + sender: "bot", + timestamp: new Date().toLocaleTimeString([], { + hour: "2-digit", + minute: "2-digit", + }), + }; + + setMessages((prev) => [...prev, botMsg]); + } catch (err) { + setMessages((prev) => [ + ...prev, + { + id: Date.now() + 2, + text: "⚠️ Error: please try again later.", + sender: "bot", + timestamp: new Date().toLocaleTimeString([], { + hour: "2-digit", + minute: "2-digit", + }), + }, + ]); + } finally { + clearInterval(interval); + setBotStatus(""); + setIsLoading(false); + } + }; + + return ( +
+ {/* Floating Button */} + {!isOpen && ( +
+ {showGreetingMessage && ( +
+

+ Hey, I'm Keploy AI Assistant! +

+

May I help you?

+
+ )} + + +
+ )} + + {/* Chat Window */} + {isOpen && ( +
+ {/* Header */} +
+ Keploy AI Assistant + +
+ + {/* Messages */} +
+ {messages.map((m) => ( +
+
+ {m.text} +
+ {m.timestamp} +
+
+
+ ))} + + {isLoading && ( +
+ {botStatus}... +
+ )} +
+
+ + {/* Input */} +
+ setInputValue(e.target.value)} + onKeyDown={(e) => e.key === "Enter" && sendMessage()} + placeholder="Type your message..." + style={{ + flex: 1, + border: "1px solid #d1d5db", + borderRadius: "8px", + padding: "8px 10px", + fontSize: "14px", + outline: "none", + }} + /> + +
+
+ )} +
+ ); +} diff --git a/src/theme/Root.js b/src/theme/Root.js new file mode 100644 index 000000000..05395b225 --- /dev/null +++ b/src/theme/Root.js @@ -0,0 +1,12 @@ +import React from "react"; +import Chatbot from "../components/ChatBot"; +// import Chatbot from "../components/Chatbot"; + +export default function Root({children}) { + return ( + <> + {children} + + + ); +}