From 710f20adcf3f126fce62bd2c2cec2b020af154bb Mon Sep 17 00:00:00 2001 From: Swapnoneel Saha Date: Fri, 11 Oct 2024 00:59:09 +0530 Subject: [PATCH] added ai chatbot to the site Signed-off-by: Swapnoneel Saha --- package.json | 1 + src/components/ChatBot.js | 213 ++++++++++++++++++++++++++++++++++++++ src/pages/index.js | 3 + static/scripts/chat.js | 15 +-- 4 files changed, 225 insertions(+), 7 deletions(-) create mode 100644 src/components/ChatBot.js diff --git a/package.json b/package.json index 13522b2d8..6f58c157f 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@mdx-js/react": "^3.0.0", "clsx": "^2.0.0", "lint": "^0.8.19", + "lucide-react": "^0.451.0", "prism-react-renderer": "^2.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/src/components/ChatBot.js b/src/components/ChatBot.js new file mode 100644 index 000000000..5905bdca8 --- /dev/null +++ b/src/components/ChatBot.js @@ -0,0 +1,213 @@ +import React, {useState, useCallback, useRef, useEffect} from "react"; +import {MessageCircle, X} from "lucide-react"; + +function textFormat(text) { + let block = 0; + let code = ``; + let lang = ""; + let heading = 2; + let output = ``; + + for (let i = 0; i < text.length; i++) { + if (text.substring(i, i + 3) === "```") { + i += 2; + if (block === 0) { + block = 1; + lang = ""; + while (i < text.length && text.charAt(i) !== "\n") { + lang += text.charAt(i++); + } + } else { + output += code; + code = ``; + lang = ""; + block = 0; + } + } else if (block === 0) { + if (text.substring(i, i + 3) === "###") { + i += 2; + heading = 3; + output += `\n\n`; + } else if (text.substring(i, i + 2) === "##") { + i += 1; + heading = 2; + output += `\n\n`; + } else if (text.substring(i, i + 1) == "#") { + heading = 1; + output += `\n\n`; + } else if (text.substring(i, i + 1) == "<") { + i++; + while ( + i < text.length && + text.substring(i, i + 2) != "/>" && + text.substring(i, i + 1) != ">" + ) { + i++; + } + } else if (text.substring(i, i + 2) === "**") { + i += 1; + } else if (text.substring(i, i + 2) === "* ") { + i += 1; + output += `\n• `; + } else if (text.charAt(i) === "\n") { + output += `\n`; + } else { + output += text.charAt(i); + } + } else { + code += text.charAt(i); + } + } + + return output; +} + +export default function ChatBot() { + const [messages, setMessages] = useState([]); + const [input, setInput] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const [isOpen, setIsOpen] = useState(false); + const messagesEndRef = useRef(null); + + const scrollToBottom = () => { + messagesEndRef.current?.scrollIntoView({behavior: "smooth"}); + }; + + useEffect(() => { + scrollToBottom(); + }, [messages]); + + const sendMessage = useCallback(async () => { + if (!input.trim() || isLoading) return; + + const userMessage = {text: input, sender: "user"}; + setMessages((prevMessages) => [...prevMessages, userMessage]); + setIsLoading(true); + + try { + const apiRes = await fetch( + "https://keploy-api.abhishekkushwaha.me/chat", + { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + body: JSON.stringify({question: input}), + } + ); + + if (!apiRes.ok) { + throw new Error(`HTTP error! status: ${apiRes.status}`); + } + + const {answer} = await apiRes.json(); + + setMessages((prevMessages) => [ + ...prevMessages, + {text: answer, sender: "bot"}, + ]); + } catch (error) { + console.error("Error fetching response from Keploy API", error); + setMessages((prevMessages) => [ + ...prevMessages, + { + text: "Sorry, there was an error processing your request.", + sender: "bot", + }, + ]); + } finally { + setIsLoading(false); + setInput(""); + } + }, [input, isLoading]); + + const handleKeyPress = useCallback( + (e) => { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + sendMessage(); + } + }, + [sendMessage] + ); + + const toggleChat = useCallback(() => { + setIsOpen((prev) => !prev); + }, []); + + return ( +
+ {!isOpen && ( + + )} + {isOpen && ( +
+
+

Chat with us

+ +
+
+
+ {messages.map((msg, index) => ( +
+ + {textFormat(msg.text)} + +
+ ))} + {isLoading && ( +
+ Bot is typing... +
+ )} +
+
+ +
+
+ setInput(e.target.value)} + onKeyPress={handleKeyPress} + disabled={isLoading} + /> + +
+
+
+
+ )} +
+ ); +} diff --git a/src/pages/index.js b/src/pages/index.js index ba654a28a..a195362fc 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -4,6 +4,8 @@ import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import {Community, KeployCloud, Resources, QuickStart} from "../components"; import {GSoC} from "../components/GSoC"; import {Intro} from "../components"; +import ChatBot from "../components/ChatBot"; + export default function Home() { const context = useDocusaurusContext(); const {siteConfig = {}} = context; @@ -15,6 +17,7 @@ export default function Home() { description={`${siteConfig.tagline}`} >
+ {/* */} {/**/} diff --git a/static/scripts/chat.js b/static/scripts/chat.js index a6b4bfbec..eaac92dc4 100644 --- a/static/scripts/chat.js +++ b/static/scripts/chat.js @@ -1,8 +1,9 @@ // hubspot.js -const script = document.createElement("script"); -script.type = "text/javascript"; -script.id = "hs-script-loader"; -script.async = true; -script.defer = true; -script.src = "//js-na1.hs-scripts.com/43912677.js"; -document.head.appendChild(script); + +// const script = document.createElement("script"); +// script.type = "text/javascript"; +// script.id = "hs-script-loader"; +// script.async = true; +// script.defer = true; +// script.src = "//js-na1.hs-scripts.com/43912677.js"; +// document.head.appendChild(script);