Spaces:
Running
Running
Update static/application.js
Browse files- static/application.js +240 -1
static/application.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
document.addEventListener("DOMContentLoaded", () => {
|
2 |
const convo = document.querySelector(".convo");
|
3 |
const input = document.querySelector(".qt input");
|
4 |
const sendBtn = document.querySelector(".sendingQA");
|
@@ -236,3 +236,242 @@ style.textContent = `
|
|
236 |
document.head.appendChild(style);
|
237 |
|
238 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*document.addEventListener("DOMContentLoaded", () => {
|
2 |
const convo = document.querySelector(".convo");
|
3 |
const input = document.querySelector(".qt input");
|
4 |
const sendBtn = document.querySelector(".sendingQA");
|
|
|
236 |
document.head.appendChild(style);
|
237 |
|
238 |
});
|
239 |
+
*/
|
240 |
+
document.addEventListener("DOMContentLoaded", () => {
|
241 |
+
const convo = document.querySelector(".convo");
|
242 |
+
const input = document.querySelector(".qt input");
|
243 |
+
const sendBtn = document.querySelector(".sendingQA");
|
244 |
+
const fileBtn = document.querySelector(".fa-file");
|
245 |
+
const imageBtn = document.querySelector(".fa-image");
|
246 |
+
|
247 |
+
let selectedFile = null;
|
248 |
+
let filePreviewBubble = null;
|
249 |
+
|
250 |
+
// Create hidden file inputs for documents and images
|
251 |
+
const fileUpload = document.createElement("input");
|
252 |
+
fileUpload.type = "file";
|
253 |
+
fileUpload.accept = ".pdf,.docx,.pptx,.xlsx";
|
254 |
+
fileUpload.style.display = "none";
|
255 |
+
document.body.appendChild(fileUpload);
|
256 |
+
|
257 |
+
const imageUpload = document.createElement("input");
|
258 |
+
imageUpload.type = "file";
|
259 |
+
imageUpload.accept = "image/*";
|
260 |
+
imageUpload.style.display = "none";
|
261 |
+
document.body.appendChild(imageUpload);
|
262 |
+
|
263 |
+
// Click on hidden inputs when buttons are clicked
|
264 |
+
fileBtn.addEventListener("click", () => fileUpload.click());
|
265 |
+
imageBtn.addEventListener("click", () => imageUpload.click());
|
266 |
+
|
267 |
+
// Handle document file selection
|
268 |
+
fileUpload.addEventListener("change", (e) => {
|
269 |
+
handleFileSelection(e.target.files[0], "document");
|
270 |
+
});
|
271 |
+
|
272 |
+
// Handle image file selection
|
273 |
+
imageUpload.addEventListener("change", (e) => {
|
274 |
+
handleFileSelection(e.target.files[0], "image");
|
275 |
+
});
|
276 |
+
|
277 |
+
function handleFileSelection(file, type) {
|
278 |
+
if (!file) return;
|
279 |
+
|
280 |
+
const validDocTypes = [
|
281 |
+
'application/pdf',
|
282 |
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
283 |
+
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
284 |
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
285 |
+
];
|
286 |
+
const validImageTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
287 |
+
|
288 |
+
const isValid = type === "document" ? validDocTypes.includes(file.type) : validImageTypes.includes(file.type);
|
289 |
+
|
290 |
+
if (!isValid) {
|
291 |
+
alert(`Please select a valid ${type === "document" ? "document (PDF, DOCX, PPTX, XLSX)" : "image (JPEG, PNG, GIF, WEBP)"}`);
|
292 |
+
if (type === "document") fileUpload.value = '';
|
293 |
+
else imageUpload.value = '';
|
294 |
+
return;
|
295 |
+
}
|
296 |
+
|
297 |
+
selectedFile = file;
|
298 |
+
|
299 |
+
if (filePreviewBubble) filePreviewBubble.remove();
|
300 |
+
|
301 |
+
filePreviewBubble = document.createElement("div");
|
302 |
+
filePreviewBubble.className = "file-preview-bubble bubble right";
|
303 |
+
filePreviewBubble.textContent = `${type === "document" ? "π" : "πΌοΈ"} Selected: ${file.name}`;
|
304 |
+
convo.appendChild(filePreviewBubble);
|
305 |
+
convo.scrollTop = convo.scrollHeight;
|
306 |
+
}
|
307 |
+
|
308 |
+
function createMessageBubble(text, sender = "You", audioSrc = null, fileName = null) {
|
309 |
+
const bubble = document.createElement("div");
|
310 |
+
bubble.className = `bubble ${sender === "You" ? "right" : "left"}`;
|
311 |
+
|
312 |
+
const label = document.createElement("div");
|
313 |
+
label.className = "label";
|
314 |
+
label.innerText = sender;
|
315 |
+
|
316 |
+
const message = document.createElement("div");
|
317 |
+
message.className = "text";
|
318 |
+
message.style.whiteSpace = "pre-wrap";
|
319 |
+
|
320 |
+
if (sender === "You") {
|
321 |
+
let fileLine = fileName ? `π Selected file: ${fileName}\n` : "";
|
322 |
+
message.innerText = `${fileLine}β ${text}`;
|
323 |
+
} else {
|
324 |
+
message.style.display = "flex";
|
325 |
+
message.style.justifyContent = "space-between";
|
326 |
+
message.style.alignItems = "center";
|
327 |
+
|
328 |
+
const msgSpan = document.createElement("span");
|
329 |
+
msgSpan.innerHTML = text;
|
330 |
+
message.appendChild(msgSpan);
|
331 |
+
|
332 |
+
if (audioSrc) {
|
333 |
+
const icon = document.createElement("i");
|
334 |
+
icon.className = "fa-solid fa-volume-high audio-toggle";
|
335 |
+
icon.title = "Click to mute";
|
336 |
+
icon.style.cursor = "pointer";
|
337 |
+
icon.style.fontSize = "18px";
|
338 |
+
|
339 |
+
const audio = new Audio(audioSrc);
|
340 |
+
audio.play();
|
341 |
+
|
342 |
+
icon.addEventListener("click", () => {
|
343 |
+
if (audio.muted) {
|
344 |
+
audio.currentTime = 0;
|
345 |
+
audio.muted = false;
|
346 |
+
icon.classList.remove("fa-volume-xmark");
|
347 |
+
icon.classList.add("fa-volume-high");
|
348 |
+
icon.title = "Click to mute";
|
349 |
+
audio.play();
|
350 |
+
} else {
|
351 |
+
audio.muted = true;
|
352 |
+
icon.classList.remove("fa-volume-high");
|
353 |
+
icon.classList.add("fa-volume-xmark");
|
354 |
+
icon.title = "Click to unmute";
|
355 |
+
}
|
356 |
+
});
|
357 |
+
|
358 |
+
message.appendChild(icon);
|
359 |
+
}
|
360 |
+
}
|
361 |
+
|
362 |
+
bubble.appendChild(label);
|
363 |
+
bubble.appendChild(message);
|
364 |
+
convo.appendChild(bubble);
|
365 |
+
convo.scrollTop = convo.scrollHeight;
|
366 |
+
return bubble;
|
367 |
+
}
|
368 |
+
|
369 |
+
async function sendMessage() {
|
370 |
+
const question = input.value.trim();
|
371 |
+
if (!question) return;
|
372 |
+
|
373 |
+
if (!selectedFile) {
|
374 |
+
alert("Please upload a document or image first.");
|
375 |
+
return;
|
376 |
+
}
|
377 |
+
|
378 |
+
// Remove file preview bubble
|
379 |
+
if (filePreviewBubble) {
|
380 |
+
filePreviewBubble.remove();
|
381 |
+
filePreviewBubble = null;
|
382 |
+
}
|
383 |
+
|
384 |
+
// Create user's message bubble
|
385 |
+
createMessageBubble(question, "You", null, selectedFile.name);
|
386 |
+
|
387 |
+
// Thinking bubble with loader
|
388 |
+
const thinkingBubble = createMessageBubble("Wait, let me think π€... <div class='loader'></div>", "Aidan");
|
389 |
+
|
390 |
+
const formData = new FormData();
|
391 |
+
formData.append("question", question);
|
392 |
+
formData.append("file", selectedFile);
|
393 |
+
|
394 |
+
try {
|
395 |
+
const response = await fetch("/predict", {
|
396 |
+
method: "POST",
|
397 |
+
body: formData
|
398 |
+
});
|
399 |
+
|
400 |
+
const result = await response.json();
|
401 |
+
const answerText = result.answer || "No response.";
|
402 |
+
const audioSrc = result.audio || null;
|
403 |
+
|
404 |
+
// Update the thinking bubble to show the answer text and remove the loader
|
405 |
+
const message = thinkingBubble.querySelector(".text");
|
406 |
+
message.innerHTML = answerText; // Replacing with answer
|
407 |
+
|
408 |
+
// If audio exists, add audio toggle icon
|
409 |
+
if (audioSrc) {
|
410 |
+
const icon = document.createElement("i");
|
411 |
+
icon.className = "fa-solid fa-volume-high audio-toggle";
|
412 |
+
icon.title = "Click to mute";
|
413 |
+
icon.style.cursor = "pointer";
|
414 |
+
icon.style.fontSize = "18px";
|
415 |
+
icon.style.marginLeft = "10px";
|
416 |
+
|
417 |
+
const audio = new Audio(audioSrc);
|
418 |
+
audio.play();
|
419 |
+
|
420 |
+
icon.addEventListener("click", () => {
|
421 |
+
if (audio.muted) {
|
422 |
+
audio.currentTime = 0;
|
423 |
+
audio.muted = false;
|
424 |
+
icon.classList.remove("fa-volume-xmark");
|
425 |
+
icon.classList.add("fa-volume-high");
|
426 |
+
icon.title = "Click to mute";
|
427 |
+
audio.play();
|
428 |
+
} else {
|
429 |
+
audio.muted = true;
|
430 |
+
icon.classList.remove("fa-volume-high");
|
431 |
+
icon.classList.add("fa-volume-xmark");
|
432 |
+
icon.title = "Click to unmute";
|
433 |
+
}
|
434 |
+
});
|
435 |
+
|
436 |
+
message.style.display = "flex";
|
437 |
+
message.style.justifyContent = "space-between";
|
438 |
+
message.appendChild(icon);
|
439 |
+
}
|
440 |
+
} catch (err) {
|
441 |
+
const message = thinkingBubble.querySelector(".text");
|
442 |
+
message.innerText = "β οΈ Aidan had trouble responding.";
|
443 |
+
}
|
444 |
+
|
445 |
+
input.value = "";
|
446 |
+
selectedFile = null;
|
447 |
+
}
|
448 |
+
|
449 |
+
sendBtn.addEventListener("click", sendMessage);
|
450 |
+
|
451 |
+
input.addEventListener("keydown", (event) => {
|
452 |
+
if (event.key === "Enter") {
|
453 |
+
event.preventDefault();
|
454 |
+
sendMessage();
|
455 |
+
}
|
456 |
+
});
|
457 |
+
|
458 |
+
const style = document.createElement('style');
|
459 |
+
style.textContent = `
|
460 |
+
.loader {
|
461 |
+
display: inline-block;
|
462 |
+
border: 2px solid #f3f3f3;
|
463 |
+
border-top: 2px solid #3b82f6;
|
464 |
+
border-radius: 50%;
|
465 |
+
width: 16px;
|
466 |
+
height: 16px;
|
467 |
+
animation: spin 1s linear infinite;
|
468 |
+
margin-left: 8px;
|
469 |
+
}
|
470 |
+
@keyframes spin {
|
471 |
+
0% { transform: rotate(0deg); }
|
472 |
+
100% { transform: rotate(360deg); }
|
473 |
+
}
|
474 |
+
`;
|
475 |
+
document.head.appendChild(style);
|
476 |
+
|
477 |
+
});
|