diff --git a/chatbox.css b/chatbox.css new file mode 100644 index 00000000..c52918b5 --- /dev/null +++ b/chatbox.css @@ -0,0 +1,197 @@ +/* Import Google font - Poppins */ +@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap'); + +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: "Poppins", sans-serif; +} +body { + +} +.chatbot-toggler { + + position: fixed; + bottom: 30px; + right: 35px; + outline: none; + border: none; + height: 50px; + width: 50px; + display: flex; + cursor: pointer; + align-items: center; + justify-content: center; + border-radius: 50%; + background: #4178c0; + transition: all 0.2s ease; +} +body.show-chatbot .chatbot-toggler { + transform: rotate(90deg); +} +.chatbot-toggler span { + color: #fff; + position: absolute; +} +.chatbot-toggler span:last-child, +body.show-chatbot .chatbot-toggler span:first-child { + opacity: 0; +} +body.show-chatbot .chatbot-toggler span:last-child { + opacity: 1; +} +.chatbot { + z-index: 1; + position: fixed; + right: 35px; + bottom: 90px; + width: 420px; + background: #fff; + border-radius: 15px; + overflow: hidden; + opacity: 0; + pointer-events: none; + transform: scale(0.5); + transform-origin: bottom right; + box-shadow: 0 0 128px 0 rgba(0,0,0,0.1), + 0 32px 64px -48px rgba(0,0,0,0.5); + transition: all 0.1s ease; +} +body.show-chatbot .chatbot { + opacity: 1; + pointer-events: auto; + transform: scale(1); +} +.chatbot header { + padding: 16px 0; + position: relative; + text-align: center; + color: #fff; + background: #4178c0; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); +} +.chatbot header span { + position: absolute; + right: 15px; + top: 50%; + display: none; + cursor: pointer; + transform: translateY(-50%); +} +header h2 { + font-size: 1.4rem; +} +.chatbot .chatbox { + overflow-y: auto; + height: 510px; + padding: 30px 20px 100px; +} +.chatbot :where(.chatbox, textarea)::-webkit-scrollbar { + width: 6px; +} +.chatbot :where(.chatbox, textarea)::-webkit-scrollbar-track { + background: #fff; + border-radius: 25px; +} +.chatbot :where(.chatbox, textarea)::-webkit-scrollbar-thumb { + background: #ccc; + border-radius: 25px; +} +.chatbox .chat { + display: flex; + list-style: none; +} +.chatbox .outgoing { + margin: 20px 0; + justify-content: flex-end; +} +.chatbox .incoming span { + width: 32px; + height: 32px; + color: #fff; + cursor: default; + text-align: center; + line-height: 32px; + align-self: flex-end; + background: #4178c0; + border-radius: 4px; + margin: 0 10px 7px 0; +} +.chatbox .chat p { + white-space: pre-wrap; + padding: 12px 16px; + border-radius: 10px 10px 0 10px; + max-width: 75%; + color: #fff; + font-size: 0.95rem; + background: #4178c0; +} +.chatbox .incoming p { + border-radius: 10px 10px 10px 0; +} +.chatbox .chat p.error { + color: #721c24; + background: #f8d7da; +} +.chatbox .incoming p { + color: #000; + background: #f2f2f2; +} +.chatbot .chat-input { + display: flex; + gap: 5px; + position: absolute; + bottom: 0; + width: 100%; + background: #fff; + padding: 3px 20px; + border-top: 1px solid #ddd; +} +.chat-input textarea { + height: 55px; + width: 100%; + border: none; + outline: none; + resize: none; + max-height: 180px; + padding: 15px 15px 15px 0; + font-size: 0.95rem; +} +.chat-input span { + align-self: flex-end; + color: #4178c0; + cursor: pointer; + height: 55px; + display: flex; + align-items: center; + visibility: hidden; + font-size: 1.35rem; +} +.chat-input textarea:valid ~ span { + visibility: visible; +} + +@media (max-width: 490px) { + .chatbot-toggler { + right: 20px; + bottom: 20px; + } + .chatbot { + right: 0; + bottom: 0; + height: 100%; + border-radius: 0; + width: 100%; + } + .chatbot .chatbox { + height: 90%; + padding: 25px 15px 100px; + } + .chatbot .chat-input { + padding: 5px 15px; + } + .chatbot header span { + display: block; + } +} \ No newline at end of file diff --git a/chatboxx.js b/chatboxx.js new file mode 100644 index 00000000..c02fc282 --- /dev/null +++ b/chatboxx.js @@ -0,0 +1,143 @@ +const chatbotToggler = document.querySelector(".chatbot-toggler"); +const closeBtn = document.querySelector(".close-btn"); +const chatbox = document.querySelector(".chatbox"); +const chatInput = document.querySelector(".chat-input textarea"); +const sendChatBtn = document.querySelector(".chat-input span"); + +let userMessage = null; // Variable to store user's message +let appointmentStep = 0; // Variable to track the appointment scheduling steps +let selectedDoctor = null; // Variable to store the selected doctor +let appointmentDetails = {}; // Object to store appointment details + +const inputInitHeight = chatInput.scrollHeight; + +const predefinedQA = { + "Hi": "Hello", + "Hey":"Hello", + "How are you?": "I'm just a bot, but I'm doing great! How can I assist you today?", + "What is your name?": "I am a chatbot created to assist you.", + "Tell me a joke.": "Why don't scientists trust atoms? Because they make up everything!", + "What is RapiDoc?": "RapiDoc is an online platform which enables you to get information about your nearest hospitals and healthcare facilities. It aims to address health-related issues. It is a one-stop destination for all your medical needs.", + "How can RapiDoc help me?": "RapiDoc helps you find the nearest hospitals and healthcare facilities, ensuring you have access to necessary medical information and services quickly and easily.", + "What services does RapiDoc provide?": "RapiDoc provides information on nearby hospitals, healthcare facilities, and various medical services to address your health-related needs.", + "Make an appointment": "Sure, here are some doctors available for appointments:\n1. Dr. Vikas Chopra\n2. Dr. Ajay Aggarwal\n3. Dr. Soni Gupta\nPlease type the number of the doctor you want to make an appointment with." +}; + +const doctorsList = { + "1": "Dr. Vikas Chopra", + "2": "Dr. Ajay Aggarwal", + "3": "Dr. Soni Gupta" +}; + +const createChatLi = (message, className) => { + const chatLi = document.createElement("li"); + chatLi.classList.add("chat", `${className}`); + let chatContent = className === "outgoing" ? `
` : `smart_toy`; + chatLi.innerHTML = chatContent; + chatLi.querySelector("p").textContent = message; + return chatLi; +} + +const generateResponse = (chatElement) => { + const API_URL = "https://api.openai.com/v1/chat/completions"; + const messageElement = chatElement.querySelector("p"); + + const requestOptions = { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${API_KEY}` + }, + body: JSON.stringify({ + model: "gpt-3.5-turbo", + messages: [{ role: "user", content: userMessage }], + }) + } + + fetch(API_URL, requestOptions).then(res => res.json()).then(data => { + messageElement.textContent = data.choices[0].message.content.trim(); + }).catch(() => { + messageElement.classList.add("error"); + messageElement.textContent = "Oops! Something went wrong. Please try again."; + }).finally(() => chatbox.scrollTo(0, chatbox.scrollHeight)); +} + +const handleAppointment = (userMessage) => { + if (appointmentStep === 0) { + selectedDoctor = doctorsList[userMessage]; + if (!selectedDoctor) { + chatbox.appendChild(createChatLi("Invalid doctor number. Please try again.", "incoming")); + return; + } + chatbox.appendChild(createChatLi(`You selected ${selectedDoctor}. Please enter the date for your appointment (YYYY-MM-DD).`, "incoming")); + appointmentStep++; + } else if (appointmentStep === 1) { + const date = userMessage; + if (!date.match(/^\d{4}-\d{2}-\d{2}$/)) { + chatbox.appendChild(createChatLi("Invalid date format. Please enter the date in YYYY-MM-DD format.", "incoming")); + return; + } + appointmentDetails.date = date; + chatbox.appendChild(createChatLi("Please enter the time for your appointment (HH:MM).", "incoming")); + appointmentStep++; + } else if (appointmentStep === 2) { + const time = userMessage; + if (!time.match(/^\d{2}:\d{2}$/)) { + chatbox.appendChild(createChatLi("Invalid time format. Please enter the time in HH:MM format.", "incoming")); + return; + } + appointmentDetails.time = time; + chatbox.appendChild(createChatLi(`Appointment scheduled with ${selectedDoctor} on ${appointmentDetails.date} at ${appointmentDetails.time}.`, "incoming")); + appointmentStep = 0; + selectedDoctor = null; + appointmentDetails = {}; + } +} + +const handleChat = () => { + userMessage = chatInput.value.trim(); + if (!userMessage) return; + + chatInput.value = ""; + chatInput.style.height = `${inputInitHeight}px`; + + chatbox.appendChild(createChatLi(userMessage, "outgoing")); + chatbox.scrollTo(0, chatbox.scrollHeight); + + if (appointmentStep > 0) { + handleAppointment(userMessage); + } else if (predefinedQA[userMessage]) { + setTimeout(() => { + const incomingChatLi = createChatLi(predefinedQA[userMessage], "incoming"); + chatbox.appendChild(incomingChatLi); + chatbox.scrollTo(0, chatbox.scrollHeight); + }, 600); + } else if (Object.keys(doctorsList).includes(userMessage)) { + setTimeout(() => { + handleAppointment(userMessage); + }, 600); + } else { + setTimeout(() => { + const incomingChatLi = createChatLi("Thinking...", "incoming"); + chatbox.appendChild(incomingChatLi); + chatbox.scrollTo(0, chatbox.scrollHeight); + generateResponse(incomingChatLi); + }, 600); + } +} + +chatInput.addEventListener("input", () => { + chatInput.style.height = `${inputInitHeight}px`; + chatInput.style.height = `${chatInput.scrollHeight}px`; +}); + +chatInput.addEventListener("keydown", (e) => { + if (e.key === "Enter" && !e.shiftKey && window.innerWidth > 800) { + e.preventDefault(); + handleChat(); + } +}); + +sendChatBtn.addEventListener("click", handleChat); +closeBtn.addEventListener("click", () => document.body.classList.remove("show-chatbot")); +chatbotToggler.addEventListener("click", () => document.body.classList.toggle("show-chatbot")); diff --git a/index.html b/index.html index 6236a25a..9f148835 100644 --- a/index.html +++ b/index.html @@ -117,10 +117,38 @@ } + + + + + + + +Hi there 👋
How can I help you today?