|
<!DOCTYPE html> |
|
|
|
<html lang="en" dir="ltr"> |
|
<head> |
|
<meta charset="utf-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" /> |
|
<style> |
|
|
|
@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; |
|
} |
|
:root { |
|
--text-color: #FFFFFF; |
|
--icon-color: #ACACBE; |
|
--icon-hover-bg: #5b5e71; |
|
--placeholder-color: #dcdcdc; |
|
--outgoing-chat-bg: #343541; |
|
--incoming-chat-bg: #444654; |
|
--outgoing-chat-border: #343541; |
|
--incoming-chat-border: #444654; |
|
} |
|
.light-mode { |
|
--text-color: #343541; |
|
--icon-color: #a9a9bc; |
|
--icon-hover-bg: #f1f1f3; |
|
--placeholder-color: #6c6c6c; |
|
--outgoing-chat-bg: #FFFFFF; |
|
--incoming-chat-bg: #F7F7F8; |
|
--outgoing-chat-border: #FFFFFF; |
|
--incoming-chat-border: #D9D9E3; |
|
} |
|
body { |
|
background: var(--outgoing-chat-bg); |
|
} |
|
|
|
|
|
.chat-container { |
|
overflow-y: auto; |
|
max-height: 100vh; |
|
padding-bottom: 150px; |
|
} |
|
:where(.chat-container, textarea)::-webkit-scrollbar { |
|
width: 6px; |
|
} |
|
:where(.chat-container, textarea)::-webkit-scrollbar-track { |
|
background: var(--incoming-chat-bg); |
|
border-radius: 25px; |
|
} |
|
:where(.chat-container, textarea)::-webkit-scrollbar-thumb { |
|
background: var(--icon-color); |
|
border-radius: 25px; |
|
} |
|
.default-text { |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
flex-direction: column; |
|
height: 70vh; |
|
padding: 0 10px; |
|
text-align: center; |
|
color: var(--text-color); |
|
} |
|
.default-text h1 { |
|
font-size: 3.3rem; |
|
} |
|
.default-text p { |
|
margin-top: 10px; |
|
font-size: 1.1rem; |
|
} |
|
.chat-container .chat { |
|
padding: 25px 10px; |
|
display: flex; |
|
justify-content: center; |
|
color: var(--text-color); |
|
} |
|
.chat-container .chat.outgoing { |
|
background: var(--outgoing-chat-bg); |
|
border: 1px solid var(--outgoing-chat-border); |
|
} |
|
.chat-container .chat.incoming { |
|
background: var(--incoming-chat-bg); |
|
border: 1px solid var(--incoming-chat-border); |
|
} |
|
.chat .chat-content { |
|
display: flex; |
|
max-width: 1200px; |
|
width: 100%; |
|
align-items: flex-start; |
|
justify-content: space-between; |
|
} |
|
span.material-symbols-rounded { |
|
user-select: none; |
|
cursor: pointer; |
|
} |
|
.chat .chat-content span { |
|
cursor: pointer; |
|
font-size: 1.3rem; |
|
color: var(--icon-color); |
|
visibility: hidden; |
|
} |
|
.chat:hover .chat-content:not(:has(.typing-animation), :has(.error)) span { |
|
visibility: visible; |
|
} |
|
.chat .chat-details { |
|
display: flex; |
|
align-items: center; |
|
} |
|
.chat .chat-details img { |
|
width: 35px; |
|
height: 35px; |
|
align-self: flex-start; |
|
object-fit: cover; |
|
border-radius: 2px; |
|
} |
|
.chat .chat-details p { |
|
white-space: pre-wrap; |
|
font-size: 1.05rem; |
|
padding: 0 50px 0 25px; |
|
color: var(--text-color); |
|
word-break: break-word; |
|
} |
|
.chat .chat-details p.error { |
|
color: #e55865; |
|
} |
|
.chat .typing-animation { |
|
padding-left: 25px; |
|
display: inline-flex; |
|
} |
|
.typing-animation .typing-dot { |
|
height: 7px; |
|
width: 7px; |
|
border-radius: 50%; |
|
margin: 0 3px; |
|
opacity: 0.7; |
|
background: var(--text-color); |
|
animation: animateDots 1.5s var(--delay) ease-in-out infinite; |
|
} |
|
.typing-animation .typing-dot:first-child { |
|
margin-left: 0; |
|
} |
|
@keyframes animateDots { |
|
0%, |
|
44% { |
|
transform: translateY(0px); |
|
} |
|
28% { |
|
opacity: 0.4; |
|
transform: translateY(-6px); |
|
} |
|
44% { |
|
opacity: 0.2; |
|
} |
|
} |
|
|
|
|
|
.typing-container { |
|
position: fixed; |
|
bottom: 0; |
|
width: 100%; |
|
display: flex; |
|
padding: 20px 10px; |
|
justify-content: center; |
|
background: var(--outgoing-chat-bg); |
|
border-top: 1px solid var(--incoming-chat-border); |
|
} |
|
.typing-container .typing-content { |
|
display: flex; |
|
max-width: 950px; |
|
width: 100%; |
|
align-items: flex-end; |
|
} |
|
.typing-container .typing-textarea { |
|
width: 100%; |
|
display: flex; |
|
position: relative; |
|
} |
|
.typing-textarea textarea { |
|
resize: none; |
|
height: 55px; |
|
width: 100%; |
|
border: none; |
|
padding: 15px 45px 15px 20px; |
|
color: var(--text-color); |
|
font-size: 1rem; |
|
border-radius: 4px; |
|
max-height: 250px; |
|
overflow-y: auto; |
|
background: var(--incoming-chat-bg); |
|
outline: 1px solid var(--incoming-chat-border); |
|
} |
|
.typing-textarea textarea::placeholder { |
|
color: var(--placeholder-color); |
|
} |
|
.typing-content span { |
|
width: 55px; |
|
height: 55px; |
|
display: flex; |
|
border-radius: 4px; |
|
font-size: 1.35rem; |
|
align-items: center; |
|
justify-content: center; |
|
color: var(--icon-color); |
|
} |
|
.typing-textarea span { |
|
position: absolute; |
|
right: 0; |
|
bottom: 0; |
|
visibility: hidden; |
|
} |
|
.typing-textarea textarea:valid ~ span { |
|
visibility: visible; |
|
} |
|
.typing-controls { |
|
display: flex; |
|
} |
|
.typing-controls span { |
|
margin-left: 7px; |
|
font-size: 1.4rem; |
|
background: var(--incoming-chat-bg); |
|
outline: 1px solid var(--incoming-chat-border); |
|
} |
|
.typing-controls span:hover { |
|
background: var(--icon-hover-bg); |
|
} |
|
|
|
|
|
@media screen and (max-width: 600px) { |
|
.default-text h1 { |
|
font-size: 2.3rem; |
|
} |
|
:where(.default-text p, textarea, .chat p) { |
|
font-size: 0.95rem!important; |
|
} |
|
.chat-container .chat { |
|
padding: 20px 10px; |
|
} |
|
.chat-container .chat img { |
|
height: 32px; |
|
width: 32px; |
|
} |
|
.chat-container .chat p { |
|
padding: 0 20px; |
|
} |
|
.chat .chat-content:not(:has(.typing-animation), :has(.error)) span { |
|
visibility: visible; |
|
} |
|
.typing-container { |
|
padding: 15px 10px; |
|
} |
|
.typing-textarea textarea { |
|
height: 45px; |
|
padding: 10px 40px 10px 10px; |
|
} |
|
.typing-content span { |
|
height: 45px; |
|
width: 45px; |
|
margin-left: 5px; |
|
} |
|
span.material-symbols-rounded { |
|
font-size: 1.25rem!important; |
|
} |
|
} |
|
|
|
.copied-message { |
|
font-size: 0.5rem; |
|
} |
|
.message-box { |
|
height: calc(50vh - 5rem); |
|
overflow-y: auto; |
|
} |
|
|
|
.messagebar { |
|
position: fixed; |
|
bottom: 0; |
|
height: 5rem; |
|
width: 100%; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
border-top: 1px solid #494b59; |
|
background-color: #33343f; |
|
} |
|
.messagebar .bar-wrapper { |
|
background-color: #494b59; |
|
border-radius: 5px; |
|
width: 60vw; |
|
padding: 10px; |
|
display: flex; |
|
align-items: center; |
|
justify-content: space-between; |
|
} |
|
.bar-wrapper input { |
|
width: 100%; |
|
padding: 5px; |
|
border: none; |
|
outline: none; |
|
font-size: 14px; |
|
background: none; |
|
color: #ccc; |
|
} |
|
.bar-wrapper input::placeholder { |
|
color: #ccc; |
|
} |
|
.messagebar button { |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
background: none; |
|
border: none; |
|
color: #fff; |
|
cursor: pointer; |
|
} |
|
.message-box { |
|
height: calc(100vh - 5rem); |
|
overflow-y: auto; |
|
} |
|
.chat { |
|
display: flex; |
|
gap: 20px; |
|
padding: 25px; |
|
color: #fff; |
|
font-size: 15px; |
|
font-weight: 300; |
|
} |
|
.chat img { |
|
width: 35px; |
|
height: 35px; |
|
} |
|
.response { |
|
background-color: #494b59; |
|
} |
|
.chatbox-wrapper { |
|
margin-bottom: 0; |
|
} |
|
.copied-text { |
|
font-size: 0.4rem; |
|
} |
|
|
|
|
|
</style> |
|
</head> |
|
<body> |
|
<div class="chatbox-wrapper"> |
|
<div class="message-box"> |
|
<div class="chat response"> |
|
<img src="img/chatbot.jpg"> |
|
<span>Hello there! <br> How can I help you today.</span> |
|
</div> |
|
|
|
|
|
<div class="chat-container"></div> |
|
|
|
|
|
<div class="typing-container"> |
|
<div class="typing-content"> |
|
<div class="typing-textarea"> |
|
<textarea id="chat-input" spellcheck="false" placeholder="Enter a prompt here" required></textarea> |
|
<span id="send-btn" class="material-symbols-rounded">send</span> |
|
</div> |
|
<div class="typing-controls"> |
|
<span id="theme-btn" class="material-symbols-rounded">light_mode</span> |
|
<span id="delete-btn" class="material-symbols-rounded">delete</span> |
|
|
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
<script> |
|
|
|
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"); |
|
const copyButton = document.querySelector("#copy-btn"); |
|
|
|
|
|
const API_URL = "/generate/"; |
|
|
|
|
|
let chatHistory = []; |
|
|
|
|
|
const loadDataFromLocalStorage = () => { |
|
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"; |
|
|
|
chatContainer.innerHTML = localStorage.getItem("all-chats") || '<div class="default-text"><h1>Welcome</h1><p>Start a conversation by typing a message.</p></div>'; |
|
chatContainer.scrollTo(0, chatContainer.scrollHeight); |
|
} |
|
|
|
|
|
const createChatElement = (content, className) => { |
|
const chatDiv = document.createElement("div"); |
|
chatDiv.classList.add("chat", className); |
|
chatDiv.innerHTML = content; |
|
return chatDiv; |
|
} |
|
|
|
|
|
const getChatResponse = async (message) => { |
|
try { |
|
const response = await fetch(API_URL, { |
|
method: "POST", |
|
headers: { |
|
"Content-Type": "application/x-www-form-urlencoded" |
|
}, |
|
body: new URLSearchParams({ |
|
prompt: message, |
|
history: "[]", |
|
temperature: "0.9", |
|
max_new_tokens: "512", |
|
top_p: "0.95", |
|
repetition_penalty: "1.0" |
|
}) |
|
}); |
|
|
|
if (!response.ok) { |
|
throw new Error(`HTTP error! Status: ${response.status}`); |
|
} |
|
|
|
const data = await response.json(); |
|
return data.response; |
|
} catch (error) { |
|
console.error("Error fetching data:", error); |
|
return "Oops! Something went wrong while fetching the response."; |
|
} |
|
} |
|
|
|
|
|
const showResponse = async (userMessage) => { |
|
const userHtml = `<div class="chat-content"> |
|
<div class="chat-details"> |
|
<img src="img/user.jpg"> |
|
<p>${userMessage}</p> |
|
</div> |
|
</div>`; |
|
|
|
const outgoingChatDiv = createChatElement(userHtml, "outgoing"); |
|
chatContainer.querySelector(".default-text")?.remove(); |
|
chatContainer.appendChild(outgoingChatDiv); |
|
chatContainer.scrollTo(0, chatContainer.scrollHeight); |
|
|
|
const botResponse = await getChatResponse(userMessage); |
|
|
|
const botHtml = `<div class="chat-content"> |
|
<div class="chat-details"> |
|
<img src="img/chatbot.jpg"><span class="new">...</span> |
|
<p contenteditable="false" class="copy-text">${botResponse}</p> |
|
</div> |
|
<span class="material-symbols-rounded copy-icon">content_copy</span> |
|
</div>`; |
|
|
|
const incomingChatDiv = createChatElement(botHtml, "incoming"); |
|
chatContainer.appendChild(incomingChatDiv); |
|
chatContainer.scrollTo(0, chatContainer.scrollHeight); |
|
|
|
|
|
chatHistory.push([userMessage, botResponse]); |
|
localStorage.setItem("all-chats", chatContainer.innerHTML); |
|
|
|
|
|
const copyIcons = document.querySelectorAll(".copy-icon"); |
|
copyIcons.forEach(copyIcon => { |
|
copyIcon.addEventListener("click", () => { |
|
const textToCopy = copyIcon.previousElementSibling.textContent; |
|
navigator.clipboard.writeText(textToCopy); |
|
copyIcon.textContent = "Copied"; |
|
copyIcon.classList.add("copied-text"); |
|
|
|
setTimeout(() => { |
|
copyIcon.textContent = "content_copy"; |
|
}, 1000); |
|
}); |
|
}); |
|
} |
|
|
|
|
|
const handleOutgoingChat = () => { |
|
const userMessage = chatInput.value.trim(); |
|
if (!userMessage) return; |
|
|
|
chatInput.value = ""; |
|
chatInput.style.height = `${initialInputHeight}px`; |
|
|
|
showResponse(userMessage); |
|
} |
|
|
|
|
|
sendButton.addEventListener("click", handleOutgoingChat); |
|
|
|
deleteButton.addEventListener("click", () => { |
|
localStorage.removeItem("all-chats"); |
|
loadDataFromLocalStorage(); |
|
}); |
|
|
|
themeButton.addEventListener("click", () => { |
|
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", () => { |
|
chatInput.style.height = `${initialInputHeight}px`; |
|
chatInput.style.height = `${chatInput.scrollHeight}px`; |
|
}); |
|
|
|
chatInput.addEventListener("keydown", (e) => { |
|
if (e.key === "Enter" && !e.shiftKey && window.innerWidth > 800) { |
|
e.preventDefault(); |
|
handleOutgoingChat(); |
|
} |
|
}); |
|
|
|
|
|
loadDataFromLocalStorage(); |
|
</script> |
|
</body> |
|
</html> |
|
|
|
|
|
|
|
|