const chatInput = document.querySelector("#chat-input"); const sendButton = document.querySelector("#send-btn"); const chatContainer = document.querySelector(".chat-container"); const themeButton = document.querySelector("#theme-btn"); const deleteButton = document.querySelector("#delete-btn"); // The API KEY is in an encrypted file, the unecrypted version is also available in the same directory but with no API keys installed // If you fork this and want to use your own api key, remember to just follow the instructions in the index.html file let userText = null; const API_KEY = result; const loadDataFromLocalstorage = () => { // Load saved chats and theme from local storage and apply/add on the page const themeColor = localStorage.getItem("themeColor"); document.body.classList.toggle("light-mode", themeColor === "light_mode"); themeButton.innerText = document.body.classList.contains("light-mode") ? "dark_mode" : "light_mode"; const defaultText = `

TheDoggyBrad Chat

Start a conversation and explore the power of ChatGPT's AI.
Your chat history will be displayed here and can be easily be deleted.

Limitation: 2500 Characters per response

Note: Refresh using the button below, if the chatbot failed to produce a response and try again

` chatContainer.innerHTML = localStorage.getItem("all-chats-thedoggybrad") || defaultText; chatContainer.scrollTo(0, chatContainer.scrollHeight); // Scroll to bottom of the chat container } const createChatElement = (content, className) => { // Create new div and apply chat, specified class and set html content of div const chatDiv = document.createElement("div"); chatDiv.classList.add("chat", className); chatDiv.innerHTML = content; return chatDiv; // Return the created chat div } const getChatResponse = async (incomingChatDiv) => { const API_URL = "https://api.openai.com/v1/chat/completions"; const pElement = document.createElement("p"); // Define the properties and data 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: `${userText}`}], max_tokens: 2500, temperature: 0.3, top_p: 0.2, presence_penalty: 1.0, frequency_penalty: 1.0, n: 1, stop: null }) } // Send POST request to API, get response and set the reponse as paragraph element text try { const response = await (await fetch(API_URL, requestOptions)).json(); pElement.textContent = response.choices[0].message.content.trim(); } catch (error) { // Add error class to the paragraph element and set error text pElement.classList.add("error"); pElement.textContent = "The project's API keys expired, kindly fork the project and use your own API keys at https://github.com/thedoggybrad/chat."; } // Remove the typing animation, append the paragraph element and save the chats to local storage incomingChatDiv.querySelector(".typing-animation").remove(); incomingChatDiv.querySelector(".chat-details").appendChild(pElement); localStorage.setItem("all-chats-thedoggybrad", chatContainer.innerHTML); chatContainer.scrollTo(0, chatContainer.scrollHeight); } const copyResponse = (copyBtn) => { // Copy the text content of the response to the clipboard const reponseTextElement = copyBtn.parentElement.querySelector("p"); navigator.clipboard.writeText(reponseTextElement.textContent); copyBtn.textContent = "done"; setTimeout(() => copyBtn.textContent = "content_copy", 1000); } const showTypingAnimation = () => { // Display the typing animation and call the getChatResponse function const html = `
chatbot-img
content_copy
`; // Create an incoming chat div with typing animation and append it to chat container const incomingChatDiv = createChatElement(html, "incoming"); chatContainer.appendChild(incomingChatDiv); chatContainer.scrollTo(0, chatContainer.scrollHeight); getChatResponse(incomingChatDiv); } const handleOutgoingChat = () => { userText = chatInput.value.trim(); // Get chatInput value and remove extra spaces if(!userText) return; // If chatInput is empty return from here // Clear the input field and reset its height chatInput.value = ""; chatInput.style.height = `${initialInputHeight}px`; const html = `
user-img

${userText}

`; // Create an outgoing chat div with user's message and append it to chat container const outgoingChatDiv = createChatElement(html, "outgoing"); chatContainer.querySelector(".default-text")?.remove(); chatContainer.appendChild(outgoingChatDiv); chatContainer.scrollTo(0, chatContainer.scrollHeight); setTimeout(showTypingAnimation, 500); } deleteButton.addEventListener("click", () => { // Remove the chats from local storage and call loadDataFromLocalstorage function if(confirm("Are you sure you want to delete all the chats?")) { localStorage.removeItem("all-chats-thedoggybrad"); loadDataFromLocalstorage(); } }); themeButton.addEventListener("click", () => { // Toggle body's class for the theme mode and save the updated theme to the local storage document.body.classList.toggle("light-mode"); localStorage.setItem("themeColor", themeButton.innerText); themeButton.innerText = document.body.classList.contains("light-mode") ? "dark_mode" : "light_mode"; }); const initialInputHeight = chatInput.scrollHeight; chatInput.addEventListener("input", () => { // Adjust the height of the input field dynamically based on its content chatInput.style.height = `${initialInputHeight}px`; chatInput.style.height = `${chatInput.scrollHeight}px`; }); chatInput.addEventListener("keydown", (e) => { // If the Enter key is pressed without Shift and the window width is larger // than 800 pixels, handle the outgoing chat if (e.key === "Enter" && !e.shiftKey && window.innerWidth > 800) { e.preventDefault(); handleOutgoingChat(); } }); loadDataFromLocalstorage(); sendButton.addEventListener("click", handleOutgoingChat);