qtAnswering / static /application.js
ikraamkb's picture
Update static/application.js
fe55f56 verified
/*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);
});