Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Chatbox #384

Merged
merged 6 commits into from
Jun 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 197 additions & 0 deletions chatbox.css
Original file line number Diff line number Diff line change
@@ -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;
}
}
143 changes: 143 additions & 0 deletions chatboxx.js
Original file line number Diff line number Diff line change
@@ -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" ? `<p></p>` : `<span class="material-symbols-outlined">smart_toy</span><p></p>`;
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"));
Loading