Spaces:
Sleeping
Sleeping
| /*document.addEventListener("DOMContentLoaded", () => { | |
| const convo = document.querySelector(".convo"); | |
| const input = document.querySelector(".qt input"); | |
| const sendBtn = document.querySelector(".sendingQA"); | |
| const fileBtn = document.querySelector(".fa-file"); | |
| const imageBtn = document.querySelector(".fa-image"); | |
| let selectedFile = null; | |
| let filePreviewBubble = null; | |
| // Create hidden file inputs for documents and images | |
| const fileUpload = document.createElement("input"); | |
| fileUpload.type = "file"; | |
| fileUpload.accept = ".pdf,.docx,.pptx,.xlsx"; | |
| fileUpload.style.display = "none"; | |
| document.body.appendChild(fileUpload); | |
| const imageUpload = document.createElement("input"); | |
| imageUpload.type = "file"; | |
| imageUpload.accept = "image/*"; | |
| imageUpload.style.display = "none"; | |
| document.body.appendChild(imageUpload); | |
| // Click on hidden inputs when buttons are clicked | |
| fileBtn.addEventListener("click", () => fileUpload.click()); | |
| imageBtn.addEventListener("click", () => imageUpload.click()); | |
| // Handle document file selection | |
| fileUpload.addEventListener("change", (e) => { | |
| handleFileSelection(e.target.files[0], "document"); | |
| }); | |
| // Handle image file selection | |
| imageUpload.addEventListener("change", (e) => { | |
| handleFileSelection(e.target.files[0], "image"); | |
| }); | |
| function handleFileSelection(file, type) { | |
| if (!file) return; | |
| const validDocTypes = [ | |
| 'application/pdf', | |
| 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', | |
| 'application/vnd.openxmlformats-officedocument.presentationml.presentation', | |
| 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' | |
| ]; | |
| const validImageTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']; | |
| const isValid = type === "document" ? validDocTypes.includes(file.type) : validImageTypes.includes(file.type); | |
| if (!isValid) { | |
| alert(`Please select a valid ${type === "document" ? "document (PDF, DOCX, PPTX, XLSX)" : "image (JPEG, PNG, GIF, WEBP)"}`); | |
| if (type === "document") fileUpload.value = ''; | |
| else imageUpload.value = ''; | |
| return; | |
| } | |
| selectedFile = file; | |
| if (filePreviewBubble) filePreviewBubble.remove(); | |
| filePreviewBubble = document.createElement("div"); | |
| filePreviewBubble.className = "file-preview-bubble bubble right"; | |
| filePreviewBubble.textContent = `${type === "document" ? "π" : "πΌοΈ"} Selected: ${file.name}`; | |
| convo.appendChild(filePreviewBubble); | |
| convo.scrollTop = convo.scrollHeight; | |
| } | |
| function createMessageBubble(text, sender = "You", audioSrc = null, fileName = null) { | |
| const bubble = document.createElement("div"); | |
| bubble.className = `bubble ${sender === "You" ? "right" : "left"}`; | |
| const label = document.createElement("div"); | |
| label.className = "label"; | |
| label.innerText = sender; | |
| const message = document.createElement("div"); | |
| message.className = "text"; | |
| message.style.whiteSpace = "pre-wrap"; | |
| if (sender === "You") { | |
| let fileLine = fileName ? `π Selected file: ${fileName}\n` : ""; | |
| message.innerText = `${fileLine}β ${text}`; | |
| } else { | |
| message.style.display = "flex"; | |
| message.style.justifyContent = "space-between"; | |
| message.style.alignItems = "center"; | |
| const msgSpan = document.createElement("span"); | |
| msgSpan.innerHTML = text; | |
| message.appendChild(msgSpan); | |
| if (audioSrc) { | |
| const icon = document.createElement("i"); | |
| icon.className = "fa-solid fa-volume-high audio-toggle"; | |
| icon.title = "Click to mute"; | |
| icon.style.cursor = "pointer"; | |
| icon.style.fontSize = "18px"; | |
| const audio = new Audio(audioSrc); | |
| audio.play(); | |
| icon.addEventListener("click", () => { | |
| if (audio.muted) { | |
| audio.currentTime = 0; | |
| audio.muted = false; | |
| icon.classList.remove("fa-volume-xmark"); | |
| icon.classList.add("fa-volume-high"); | |
| icon.title = "Click to mute"; | |
| audio.play(); | |
| } else { | |
| audio.muted = true; | |
| icon.classList.remove("fa-volume-high"); | |
| icon.classList.add("fa-volume-xmark"); | |
| icon.title = "Click to unmute"; | |
| } | |
| }); | |
| message.appendChild(icon); | |
| } | |
| } | |
| bubble.appendChild(label); | |
| bubble.appendChild(message); | |
| convo.appendChild(bubble); | |
| convo.scrollTop = convo.scrollHeight; | |
| return bubble; | |
| } | |
| async function sendMessage() { | |
| const question = input.value.trim(); | |
| if (!question) return; | |
| if (!selectedFile) { | |
| alert("Please upload a document or image first."); | |
| return; | |
| } | |
| // Remove file preview bubble | |
| if (filePreviewBubble) { | |
| filePreviewBubble.remove(); | |
| filePreviewBubble = null; | |
| } | |
| // Create user's message bubble | |
| createMessageBubble(question, "You", null, selectedFile.name); | |
| // Thinking bubble with loader | |
| const thinkingBubble = createMessageBubble("Wait, let me think π€... <div class='loader'></div>", "Aidan"); | |
| const formData = new FormData(); | |
| formData.append("question", question); | |
| formData.append("file", selectedFile); | |
| try { | |
| const response = await fetch("/predict", { | |
| method: "POST", | |
| body: formData | |
| }); | |
| const result = await response.json(); | |
| const answerText = result.answer || "No response."; | |
| const audioSrc = result.audio || null; | |
| // Update the thinking bubble to show the answer text and remove the loader | |
| const message = thinkingBubble.querySelector(".text"); | |
| message.innerHTML = answerText; // Replacing with answer | |
| // If audio exists, add audio toggle icon | |
| if (audioSrc) { | |
| const icon = document.createElement("i"); | |
| icon.className = "fa-solid fa-volume-high audio-toggle"; | |
| icon.title = "Click to mute"; | |
| icon.style.cursor = "pointer"; | |
| icon.style.fontSize = "18px"; | |
| icon.style.marginLeft = "10px"; | |
| const audio = new Audio(audioSrc); | |
| audio.play(); | |
| icon.addEventListener("click", () => { | |
| if (audio.muted) { | |
| audio.currentTime = 0; | |
| audio.muted = false; | |
| icon.classList.remove("fa-volume-xmark"); | |
| icon.classList.add("fa-volume-high"); | |
| icon.title = "Click to mute"; | |
| audio.play(); | |
| } else { | |
| audio.muted = true; | |
| icon.classList.remove("fa-volume-high"); | |
| icon.classList.add("fa-volume-xmark"); | |
| icon.title = "Click to unmute"; | |
| } | |
| }); | |
| message.style.display = "flex"; | |
| message.style.justifyContent = "space-between"; | |
| message.appendChild(icon); | |
| } | |
| } catch (err) { | |
| const message = thinkingBubble.querySelector(".text"); | |
| message.innerText = "β οΈ Aidan had trouble responding."; | |
| } | |
| input.value = ""; | |
| selectedFile = null; | |
| } | |
| sendBtn.addEventListener("click", sendMessage); | |
| input.addEventListener("keydown", (event) => { | |
| if (event.key === "Enter") { | |
| event.preventDefault(); | |
| sendMessage(); | |
| } | |
| }); | |
| const style = document.createElement('style'); | |
| style.textContent = ` | |
| .loader { | |
| display: inline-block; | |
| border: 2px solid #f3f3f3; | |
| border-top: 2px solid #3b82f6; | |
| border-radius: 50%; | |
| width: 16px; | |
| height: 16px; | |
| animation: spin 1s linear infinite; | |
| margin-left: 8px; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| `; | |
| document.head.appendChild(style); | |
| }); | |
| */ | |
| document.addEventListener("DOMContentLoaded", () => { | |
| const convo = document.querySelector(".convo"); | |
| const input = document.querySelector(".qt input"); | |
| const sendBtn = document.querySelector(".sendingQA"); | |
| const fileBtn = document.querySelector(".fa-file"); | |
| const imageBtn = document.querySelector(".fa-image"); | |
| let selectedFile = null; | |
| let filePreviewBubble = null; | |
| // Create hidden file inputs for documents and images | |
| const fileUpload = document.createElement("input"); | |
| fileUpload.type = "file"; | |
| fileUpload.accept = ".pdf,.docx,.pptx,.xlsx"; | |
| fileUpload.style.display = "none"; | |
| document.body.appendChild(fileUpload); | |
| const imageUpload = document.createElement("input"); | |
| imageUpload.type = "file"; | |
| imageUpload.accept = "image/*"; | |
| imageUpload.style.display = "none"; | |
| document.body.appendChild(imageUpload); | |
| // Click on hidden inputs when buttons are clicked | |
| fileBtn.addEventListener("click", () => fileUpload.click()); | |
| imageBtn.addEventListener("click", () => imageUpload.click()); | |
| // Handle document file selection | |
| fileUpload.addEventListener("change", (e) => { | |
| handleFileSelection(e.target.files[0], "document"); | |
| }); | |
| // Handle image file selection | |
| imageUpload.addEventListener("change", (e) => { | |
| handleFileSelection(e.target.files[0], "image"); | |
| }); | |
| function handleFileSelection(file, type) { | |
| if (!file) return; | |
| const validDocTypes = [ | |
| 'application/pdf', | |
| 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', | |
| 'application/vnd.openxmlformats-officedocument.presentationml.presentation', | |
| 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' | |
| ]; | |
| const validImageTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']; | |
| const isValid = type === "document" ? validDocTypes.includes(file.type) : validImageTypes.includes(file.type); | |
| if (!isValid) { | |
| alert(`Please select a valid ${type === "document" ? "document (PDF, DOCX, PPTX, XLSX)" : "image (JPEG, PNG, GIF, WEBP)"}`); | |
| if (type === "document") fileUpload.value = ''; | |
| else imageUpload.value = ''; | |
| return; | |
| } | |
| selectedFile = file; | |
| if (filePreviewBubble) filePreviewBubble.remove(); | |
| filePreviewBubble = document.createElement("div"); | |
| filePreviewBubble.className = "file-preview-bubble bubble right"; | |
| filePreviewBubble.style.display = "flex"; | |
| filePreviewBubble.style.flexDirection = "column"; | |
| filePreviewBubble.style.maxWidth = "50%"; | |
| const userQuestion = input.value.trim(); // Only include the question if it was entered | |
| if (file.type.startsWith('image/')) { | |
| const reader = new FileReader(); | |
| reader.onload = (e) => { | |
| const img = document.createElement("img"); | |
| img.src = e.target.result; | |
| img.style.width = "100%"; | |
| img.style.height = "200px"; | |
| img.style.objectFit = "cover"; | |
| img.style.borderRadius = "10px"; | |
| img.style.marginBottom = "8px"; | |
| const text = document.createElement("span"); | |
| text.textContent = `π Selected image: ${file.name}`; | |
| text.style.fontSize = "13px"; | |
| // If there's a user question, add the β | |
| if (userQuestion) { | |
| const question = document.createElement("span"); | |
| question.textContent = `\nβ ${userQuestion}`; | |
| question.style.fontSize = "13px"; | |
| filePreviewBubble.appendChild(question); | |
| } | |
| filePreviewBubble.appendChild(img); | |
| filePreviewBubble.appendChild(text); | |
| convo.appendChild(filePreviewBubble); | |
| convo.scrollTop = convo.scrollHeight; | |
| }; | |
| reader.readAsDataURL(file); | |
| } else { | |
| const text = document.createElement("span"); | |
| text.textContent = `π Selected file: ${file.name}`; | |
| text.style.fontSize = "13px"; | |
| // If there's a user question, add the β | |
| if (userQuestion) { | |
| const question = document.createElement("span"); | |
| question.textContent = `\nβ ${userQuestion}`; | |
| question.style.fontSize = "13px"; | |
| filePreviewBubble.appendChild(question); | |
| } | |
| filePreviewBubble.appendChild(text); | |
| convo.appendChild(filePreviewBubble); | |
| convo.scrollTop = convo.scrollHeight; | |
| } | |
| } | |
| function createMessageBubble(text, sender = "You", audioSrc = null, fileName = null, imageSrc = null) { | |
| const bubble = document.createElement("div"); | |
| bubble.className = `bubble ${sender === "You" ? "right" : "left"}`; | |
| bubble.style.maxWidth = "50%"; | |
| const label = document.createElement("div"); | |
| label.className = "label"; | |
| label.innerText = sender; | |
| const message = document.createElement("div"); | |
| message.className = "text"; | |
| message.style.whiteSpace = "pre-wrap"; | |
| const textSpan = document.createElement("span"); | |
| textSpan.innerHTML = text; | |
| message.appendChild(textSpan); | |
| // Display image if available | |
| if (imageSrc) { | |
| const img = document.createElement("img"); | |
| img.src = imageSrc; | |
| img.style.width = "100%"; | |
| img.style.height = "200px"; | |
| img.style.objectFit = "cover"; | |
| img.style.borderRadius = "10px"; | |
| img.style.marginTop = "8px"; | |
| message.appendChild(img); | |
| } | |
| bubble.appendChild(label); | |
| bubble.appendChild(message); | |
| convo.appendChild(bubble); | |
| convo.scrollTop = convo.scrollHeight; | |
| return bubble; | |
| } | |
| async function sendMessage() { | |
| const question = input.value.trim(); | |
| if (!question) return; | |
| if (!selectedFile) { | |
| alert("Please upload a document or image first."); | |
| return; | |
| } | |
| // Remove file preview bubble | |
| if (filePreviewBubble) { | |
| filePreviewBubble.remove(); | |
| filePreviewBubble = null; | |
| } | |
| // Create user's message bubble | |
| createMessageBubble(question, "You", null, selectedFile.name, selectedFile.type.startsWith('image/') ? URL.createObjectURL(selectedFile) : null); | |
| // Thinking bubble with loader | |
| const thinkingBubble = createMessageBubble("Wait, let me think π€... <div class='loader'></div>", "Aidan"); | |
| const formData = new FormData(); | |
| formData.append("question", question); | |
| formData.append("file", selectedFile); | |
| try { | |
| const response = await fetch("/predict", { | |
| method: "POST", | |
| body: formData | |
| }); | |
| const result = await response.json(); | |
| const answerText = result.answer || "No response."; | |
| const audioSrc = result.audio || null; | |
| // Update the thinking bubble to show the answer text and remove the loader | |
| const message = thinkingBubble.querySelector(".text"); | |
| message.innerHTML = answerText; | |
| // If audio exists, add audio toggle icon | |
| if (audioSrc) { | |
| const icon = document.createElement("i"); | |
| icon.className = "fa-solid fa-volume-high audio-toggle"; | |
| icon.title = "Click to mute"; | |
| icon.style.cursor = "pointer"; | |
| icon.style.fontSize = "18px"; | |
| icon.style.marginLeft = "10px"; | |
| const audio = new Audio(audioSrc); | |
| audio.play(); | |
| icon.addEventListener("click", () => { | |
| if (audio.muted) { | |
| audio.currentTime = 0; | |
| audio.muted = false; | |
| icon.classList.remove("fa-volume-xmark"); | |
| icon.classList.add("fa-volume-high"); | |
| icon.title = "Click to mute"; | |
| audio.play(); | |
| } else { | |
| audio.muted = true; | |
| icon.classList.remove("fa-volume-high"); | |
| icon.classList.add("fa-volume-xmark"); | |
| icon.title = "Click to unmute"; | |
| } | |
| }); | |
| message.style.display = "flex"; | |
| message.style.justifyContent = "space-between"; | |
| message.appendChild(icon); | |
| } | |
| } catch (err) { | |
| const message = thinkingBubble.querySelector(".text"); | |
| message.innerText = "β οΈ Aidan had trouble responding."; | |
| } | |
| input.value = ""; | |
| selectedFile = null; | |
| } | |
| sendBtn.addEventListener("click", sendMessage); | |
| input.addEventListener("keydown", (event) => { | |
| if (event.key === "Enter") { | |
| event.preventDefault(); | |
| sendMessage(); | |
| } | |
| }); | |
| const style = document.createElement('style'); | |
| style.textContent = ` | |
| .loader { | |
| display: inline-block; | |
| border: 2px solid #f3f3f3; | |
| border-top: 2px solid #3b82f6; | |
| border-radius: 50%; | |
| width: 16px; | |
| height: 16px; | |
| animation: spin 1s linear infinite; | |
| margin-left: 8px; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| `; | |
| document.head.appendChild(style); | |
| }); | |