Spaces:
Runtime error
Runtime error
| ; | |
| // First, let's add the Marked library for markdown parsing | |
| const markedScript = document.createElement("script"); | |
| markedScript.src = | |
| "https://cdnjs.cloudflare.com/ajax/libs/marked/4.2.12/marked.min.js"; | |
| document.head.appendChild(markedScript); | |
| // Initialize toggle button functionality immediately | |
| const chatToggleBtn = document.getElementById("chatToggleBtn"); | |
| const chatBox = document.querySelector(".chat-box"); | |
| const notificationBadge = document.querySelector(".notification-badge"); | |
| chatToggleBtn.addEventListener("click", function () { | |
| chatBox.classList.toggle("active"); | |
| if (notificationBadge) { | |
| notificationBadge.remove(); | |
| } | |
| }); | |
| // Wait for marked to load before initializing chat | |
| markedScript.onload = function () { | |
| initializeChat(); | |
| }; | |
| function initializeChat() { | |
| var chatInput = document.querySelector("#chat_input"); | |
| var typing = document.querySelector("#typing"); | |
| var send = document.querySelector("#send"); | |
| var chatMessages = document.querySelector("#chat_messages"); | |
| var chatBoxBody = document.querySelector("#chat_box_body"); | |
| var chatForm = document.querySelector("#chat-form"); | |
| // Profile configuration | |
| const profile = { | |
| my: { | |
| name: "You", | |
| pic: "https://imgproxy.attic.sh/unsafe/rs:fit:540:540:1:1/t:1:FF00FF:false:false/aHR0cHM6Ly9hdHRp/Yy5zaC9sYmxjODRn/OTcxeXV5bnQwcXMz/NjNmbGNrZTQ5.webp", | |
| }, | |
| other: { | |
| name: "Assistant", | |
| pic: "/static/favicon.PNG", | |
| }, | |
| }; | |
| // Configure marked options | |
| marked.setOptions({ | |
| breaks: true, | |
| gfm: true, | |
| smartLists: true, | |
| smartypants: true, | |
| xhtml: true, | |
| }); | |
| function sanitizeHTML(str) { | |
| const div = document.createElement("div"); | |
| div.textContent = str; | |
| return div.innerHTML; | |
| } | |
| function renderMarkdown(text) { | |
| try { | |
| const rawHtml = marked.parse(text); | |
| const tempDiv = document.createElement("div"); | |
| tempDiv.innerHTML = rawHtml; | |
| tempDiv.querySelectorAll("pre code").forEach((block) => { | |
| block.textContent = block.innerHTML; | |
| }); | |
| return tempDiv.innerHTML; | |
| } catch (e) { | |
| console.error("Markdown parsing error:", e); | |
| return sanitizeHTML(text); | |
| } | |
| } | |
| function renderProfile(p) { | |
| return ` | |
| <div class="profile ${p}-profile hide"> | |
| <img src="${profile[p].pic}" alt="${profile[p].name}" width="30" height="30" /> | |
| <span>${profile[p].name}</span> | |
| </div> | |
| `; | |
| } | |
| function renderMessage(p, m) { | |
| const messageContent = p === "other" ? renderMarkdown(m) : sanitizeHTML(m); | |
| return `<div class="message ${p}-message hide">${messageContent}</div>`; | |
| } | |
| function appendMessage(p, message) { | |
| const messageHtml = renderProfile(p) + renderMessage(p, message); | |
| chatMessages.insertAdjacentHTML("beforeend", messageHtml); | |
| // Reveal new elements with animation | |
| const newElements = document.querySelectorAll( | |
| ".profile.hide, .message.hide" | |
| ); | |
| newElements.forEach((elm) => { | |
| if (elm.classList.contains("profile")) { | |
| elm.style.height = "auto"; | |
| } | |
| elm.classList.remove("hide"); | |
| }); | |
| // Scroll to bottom | |
| chatBoxBody.scrollTop = chatBoxBody.scrollHeight; | |
| // Initialize syntax highlighting if available | |
| if (window.hljs) { | |
| document.querySelectorAll("pre code").forEach((block) => { | |
| hljs.highlightBlock(block); | |
| }); | |
| } | |
| } | |
| // Auto-resize textarea | |
| chatInput.addEventListener("input", function () { | |
| this.style.height = "0"; | |
| this.style.height = this.scrollHeight + 1 + "px"; | |
| }); | |
| // Handle enter key | |
| chatInput.addEventListener("keydown", function (evt) { | |
| if (evt.keyCode == 13 && !evt.shiftKey) { | |
| handleSubmit(); | |
| evt.preventDefault(); | |
| } | |
| }); | |
| // Handle form submission | |
| if (chatForm) { | |
| chatForm.addEventListener("submit", function (evt) { | |
| evt.preventDefault(); | |
| handleSubmit(); | |
| }); | |
| } | |
| async function handleSubmit() { | |
| const message = chatInput.value.trim(); | |
| if (!message) return; | |
| // Show user message | |
| appendMessage("my", message); | |
| // Clear input | |
| chatInput.value = ""; | |
| chatInput.style.height = "40px"; | |
| // Show typing indicator | |
| typing.classList.add("active"); | |
| try { | |
| // Send message to backend | |
| const formData = new FormData(); | |
| formData.append("text", message); | |
| const response = await fetch("/get", { | |
| method: "POST", | |
| body: formData, | |
| }); | |
| const data = await response.text(); | |
| // Hide typing indicator | |
| typing.classList.remove("active"); | |
| // Show bot response | |
| appendMessage("other", data); | |
| } catch (error) { | |
| console.error("Error:", error); | |
| typing.classList.remove("active"); | |
| appendMessage( | |
| "other", | |
| "Sorry, I encountered an error. Please try again." | |
| ); | |
| } | |
| } | |
| // Initialize scroll position | |
| chatBoxBody.scrollTop = chatBoxBody.scrollHeight; | |
| } | |