Skip to content

Commit b8866df

Browse files
Merge pull request #1597 from AnimeshKumarRai/adding-ChatBot
Added ChatBot Project
2 parents 97dc72d + 6a9f5e1 commit b8866df

5 files changed

Lines changed: 484 additions & 0 deletions

File tree

73.6 KB
Loading

Projects/ChatBot/images/user.png

26.9 KB
Loading

Projects/ChatBot/index.html

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE html>
2+
<html lang="en" dir="ltr">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>ChatGPT Clone</title>
6+
<link rel="stylesheet" href="style.css">
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
8+
<link rel="stylesheet"
9+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
10+
<script src="script.js" defer></script>
11+
</head>
12+
13+
<body>
14+
<div class="chat-container"></div>
15+
<div class="typing-container">
16+
<div class="typing-content">
17+
<div class="typing-textarea">
18+
<textarea id="chat-input" spellcheck="false" placeholder="Enter a prompt here" required></textarea>
19+
<span id="send-btn" class="material-symbols-rounded">send</span>
20+
</div>
21+
<div class="typing-controls">
22+
<span id="theme-btn" class="material-symbols-rounded">light_mode</span>
23+
<span id="delete-btn" class="material-symbols-rounded">delete</span>
24+
</div>
25+
</div>
26+
27+
</body>
28+
29+
</html>

Projects/ChatBot/script.js

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
const chatInput = document.querySelector("#chat-input");
2+
const sendButton = document.querySelector("#send-btn");
3+
const chatContainer = document.querySelector(".chat-container");
4+
const themeButton = document.querySelector("#theme-btn");
5+
const deleteButton = document.querySelector("#delete-btn");
6+
7+
let userText = null;
8+
const API_KEY = "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"; // Paste your API key here
9+
10+
const loadDataFromLocalstorage = () => {
11+
// Load saved chats and theme from local storage and apply/add on the page
12+
const themeColor = localStorage.getItem("themeColor");
13+
14+
document.body.classList.toggle("light-mode", themeColor === "light_mode");
15+
themeButton.innerText = document.body.classList.contains("light-mode") ? "dark_mode" : "light_mode";
16+
17+
const defaultText = `<div class="default-text">
18+
<h1>ChatGPT Clone</h1>
19+
<p>Start a conversation and explore the power of AI.<br> Your chat history will be displayed here.</p>
20+
</div>`
21+
22+
chatContainer.innerHTML = localStorage.getItem("all-chats") || defaultText;
23+
chatContainer.scrollTo(0, chatContainer.scrollHeight); // Scroll to bottom of the chat container
24+
}
25+
26+
const createChatElement = (content, className) => {
27+
// Create new div and apply chat, specified class and set html content of div
28+
const chatDiv = document.createElement("div");
29+
chatDiv.classList.add("chat", className);
30+
chatDiv.innerHTML = content;
31+
return chatDiv; // Return the created chat div
32+
}
33+
34+
const getChatResponse = async (incomingChatDiv) => {
35+
const API_URL = "https://api.openai.com/v1/completions";
36+
const pElement = document.createElement("p");
37+
38+
// Define the properties and data for the API request
39+
const requestOptions = {
40+
method: "POST",
41+
headers: {
42+
"Content-Type": "application/json",
43+
"Authorization": `Bearer ${API_KEY}`
44+
},
45+
body: JSON.stringify({
46+
model: "text-davinci-003",
47+
prompt: userText,
48+
max_tokens: 2048,
49+
temperature: 0.2,
50+
n: 1,
51+
stop: null
52+
})
53+
}
54+
55+
// Send POST request to API, get response and set the reponse as paragraph element text
56+
try {
57+
const response = await (await fetch(API_URL, requestOptions)).json();
58+
pElement.textContent = response.choices[0].text.trim();
59+
} catch (error) { // Add error class to the paragraph element and set error text
60+
pElement.classList.add("error");
61+
pElement.textContent = "Oops! Something went wrong while retrieving the response. Please try again.";
62+
}
63+
64+
// Remove the typing animation, append the paragraph element and save the chats to local storage
65+
incomingChatDiv.querySelector(".typing-animation").remove();
66+
incomingChatDiv.querySelector(".chat-details").appendChild(pElement);
67+
localStorage.setItem("all-chats", chatContainer.innerHTML);
68+
chatContainer.scrollTo(0, chatContainer.scrollHeight);
69+
}
70+
71+
const copyResponse = (copyBtn) => {
72+
// Copy the text content of the response to the clipboard
73+
const reponseTextElement = copyBtn.parentElement.querySelector("p");
74+
navigator.clipboard.writeText(reponseTextElement.textContent);
75+
copyBtn.textContent = "done";
76+
setTimeout(() => copyBtn.textContent = "content_copy", 1000);
77+
}
78+
79+
const showTypingAnimation = () => {
80+
// Display the typing animation and call the getChatResponse function
81+
const html = `<div class="chat-content">
82+
<div class="chat-details">
83+
<img src="images/chatbot.png" alt="chatbot-img">
84+
<div class="typing-animation">
85+
<div class="typing-dot" style="--delay: 0.2s"></div>
86+
<div class="typing-dot" style="--delay: 0.3s"></div>
87+
<div class="typing-dot" style="--delay: 0.4s"></div>
88+
</div>
89+
</div>
90+
<span onclick="copyResponse(this)" class="material-symbols-rounded">content_copy</span>
91+
</div>`;
92+
// Create an incoming chat div with typing animation and append it to chat container
93+
const incomingChatDiv = createChatElement(html, "incoming");
94+
chatContainer.appendChild(incomingChatDiv);
95+
chatContainer.scrollTo(0, chatContainer.scrollHeight);
96+
getChatResponse(incomingChatDiv);
97+
}
98+
99+
const handleOutgoingChat = () => {
100+
userText = chatInput.value.trim();
101+
if (!userText) return;
102+
103+
chatInput.value = "";
104+
chatInput.style.height = `${initialInputHeight}px`;
105+
106+
const html = `<div class="chat-content">
107+
<div class="chat-details">
108+
<img src="images/user.png" alt="user-img">
109+
<p>${userText}</p>
110+
</div>
111+
</div>`;
112+
113+
const outgoingChatDiv = createChatElement(html, "outgoing");
114+
chatContainer.querySelector(".default-text")?.remove();
115+
chatContainer.appendChild(outgoingChatDiv);
116+
chatContainer.scrollTo(0, chatContainer.scrollHeight);
117+
setTimeout(showTypingAnimation, 500);
118+
}
119+
120+
deleteButton.addEventListener("click", () => {
121+
if (confirm("Are you sure you want to delete all the chats?")) {
122+
localStorage.removeItem("all-chats");
123+
loadDataFromLocalstorage();
124+
}
125+
});
126+
127+
themeButton.addEventListener("click", () => {
128+
document.body.classList.toggle("light-mode");
129+
localStorage.setItem("themeColor", themeButton.innerText);
130+
themeButton.innerText = document.body.classList.contains("light-mode") ? "dark_mode" : "light_mode";
131+
});
132+
133+
const initialInputHeight = chatInput.scrollHeight;
134+
135+
chatInput.addEventListener("input", () => {
136+
chatInput.style.height = `${initialInputHeight}px`;
137+
chatInput.style.height = `${chatInput.scrollHeight}px`;
138+
});
139+
140+
chatInput.addEventListener("keydown", (e) => {
141+
142+
if (e.key === "Enter" && !e.shiftKey && window.innerWidth > 800) {
143+
e.preventDefault();
144+
handleOutgoingChat();
145+
}
146+
});
147+
148+
loadDataFromLocalstorage();
149+
sendButton.addEventListener("click", handleOutgoingChat);

0 commit comments

Comments
 (0)