Skip to content

Commit

Permalink
Merge pull request #275 from Sambit-Mondal/ChatbotJSextension
Browse files Browse the repository at this point in the history
Fixes #159 : Chatbot
  • Loading branch information
Sulagna-Dutta-Roy authored May 18, 2024
2 parents 5903b13 + 7ecf53b commit f710ea9
Show file tree
Hide file tree
Showing 4 changed files with 375 additions and 0 deletions.
37 changes: 37 additions & 0 deletions Chatbot/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<!DOCTYPE html>
<!-- Coding By CodingNepal - www.codingnepalweb.com -->
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Chatbot</title>
<link rel="stylesheet" href="src/style.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Google Fonts Link For Icons -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@48,400,1,0" />
<script src="scripts/script.js" defer></script>
</head>
<body>
<button class="chatbot-toggler">
<span class="material-symbols-rounded">mode_comment</span>
<span class="material-symbols-outlined">close</span>
</button>
<div class="chatbot">
<header>
<h2>Chatbot</h2>
<span class="close-btn material-symbols-outlined">close</span>
</header>
<ul class="chatbox">
<li class="chat incoming">
<span class="material-symbols-outlined">smart_toy</span>
<p>Hi there 👋<br>How can I help you today?</p>
</li>
</ul>
<div class="chat-input">
<textarea placeholder="Enter a message..." spellcheck="false" required></textarea>
<span id="send-btn" class="material-symbols-rounded">send</span>
</div>
</div>

</body>
</html>
28 changes: 28 additions & 0 deletions Chatbot/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"manifest_version": 3,
"name": "Chatbot Extension JS",
"version": "1.0",
"description": "Chatbot extension built in pure HTML CSS JS...",
"author" : "sambitmondal2005@gmail.com",
"icons": {
"48": "images/icon-48.png",
"128": "images/icon-128.png"
},
"permissions": [
"storage"
],
"optional-permissions" : ["tabs"],
"action": {
"default_popup": "index.html"
},
"web_accessible_resources": [
{
"resources": [
"index.html"
],
"matches": [
"<all_urls>"
]
}
]
}
85 changes: 85 additions & 0 deletions Chatbot/scripts/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
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
const API_KEY = "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"; // Paste your API key here
const inputInitHeight = chatInput.scrollHeight;

const createChatLi = (message, className) => {
// Create a chat <li> element with passed message and 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; // return chat <li> element
}

const generateResponse = (chatElement) => {
const API_URL = "https://api.openai.com/v1/chat/completions";
const messageElement = chatElement.querySelector("p");

// Define the properties and message for the API request
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}],
})
}

// Send POST request to API, get response and set the reponse as paragraph text
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 handleChat = () => {
userMessage = chatInput.value.trim(); // Get user entered message and remove extra whitespace
if(!userMessage) return;

// Clear the input textarea and set its height to default
chatInput.value = "";
chatInput.style.height = `${inputInitHeight}px`;

// Append the user's message to the chatbox
chatbox.appendChild(createChatLi(userMessage, "outgoing"));
chatbox.scrollTo(0, chatbox.scrollHeight);

setTimeout(() => {
// Display "Thinking..." message while waiting for the response
const incomingChatLi = createChatLi("Thinking...", "incoming");
chatbox.appendChild(incomingChatLi);
chatbox.scrollTo(0, chatbox.scrollHeight);
generateResponse(incomingChatLi);
}, 600);
}

chatInput.addEventListener("input", () => {
// Adjust the height of the input textarea based on its content
chatInput.style.height = `${inputInitHeight}px`;
chatInput.style.height = `${chatInput.scrollHeight}px`;
});

chatInput.addEventListener("keydown", (e) => {
// If Enter key is pressed without Shift key and the window
// width is greater than 800px, handle the chat
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"));
225 changes: 225 additions & 0 deletions Chatbot/src/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
/* 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 {
background: #E3F2FD;
}

.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: #724ae8;
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 {
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: #724ae8;
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: 380px;
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: #724ae8;
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: #724ae8;
}

.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: #724ae8;
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;
}
}

0 comments on commit f710ea9

Please sign in to comment.