Spaces:
Running
Running
Update static/application.js
Browse files- static/application.js +111 -37
static/application.js
CHANGED
@@ -79,74 +79,148 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
79 |
const fileBtn = document.querySelector(".fa-file");
|
80 |
const imageBtn = document.querySelector(".fa-image");
|
81 |
|
82 |
-
|
|
|
|
|
|
|
83 |
const fileInput = document.createElement("input");
|
84 |
fileInput.type = "file";
|
|
|
85 |
fileInput.style.display = "none";
|
86 |
document.body.appendChild(fileInput);
|
87 |
|
|
|
88 |
fileBtn.addEventListener("click", () => fileInput.click());
|
|
|
89 |
|
|
|
90 |
fileInput.addEventListener("change", () => {
|
91 |
const file = fileInput.files[0];
|
92 |
if (file) {
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
|
|
|
|
|
|
97 |
convo.scrollTop = convo.scrollHeight;
|
98 |
}
|
99 |
});
|
100 |
|
101 |
-
function createMessageBubble(
|
102 |
const bubble = document.createElement("div");
|
103 |
-
bubble.className = `bubble ${
|
104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
|
106 |
-
|
|
|
|
|
|
|
107 |
const audio = document.createElement("audio");
|
108 |
audio.src = audioSrc;
|
109 |
audio.autoplay = true;
|
110 |
-
audio.
|
111 |
-
|
112 |
-
const audioIcon = document.createElement("i");
|
113 |
-
audioIcon.className = "fa-solid fa-volume-high audio-toggle";
|
114 |
-
audioIcon.style.marginLeft = "10px";
|
115 |
-
audioIcon.title = "Click to mute";
|
116 |
|
117 |
-
|
118 |
-
|
|
|
|
|
|
|
119 |
|
120 |
-
|
121 |
-
audioIcon.addEventListener("click", () => {
|
122 |
audio.muted = !audio.muted;
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
} else {
|
127 |
-
audioIcon.classList.replace("fa-volume-xmark", "fa-volume-high");
|
128 |
-
audioIcon.title = "Click to mute";
|
129 |
-
}
|
130 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
131 |
}
|
132 |
|
133 |
convo.appendChild(bubble);
|
134 |
convo.scrollTop = convo.scrollHeight;
|
135 |
}
|
136 |
|
137 |
-
sendBtn.addEventListener("click", () => {
|
138 |
-
const question = input.value
|
139 |
if (!question) return;
|
140 |
|
141 |
-
|
142 |
-
|
143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
151 |
});
|
152 |
});
|
|
|
79 |
const fileBtn = document.querySelector(".fa-file");
|
80 |
const imageBtn = document.querySelector(".fa-image");
|
81 |
|
82 |
+
let selectedFile = null;
|
83 |
+
let filePreviewBubble = null;
|
84 |
+
|
85 |
+
// Create hidden file input
|
86 |
const fileInput = document.createElement("input");
|
87 |
fileInput.type = "file";
|
88 |
+
fileInput.accept = ".pdf,.docx,.pptx,.xlsx,image/*";
|
89 |
fileInput.style.display = "none";
|
90 |
document.body.appendChild(fileInput);
|
91 |
|
92 |
+
// Handle file icon click
|
93 |
fileBtn.addEventListener("click", () => fileInput.click());
|
94 |
+
imageBtn.addEventListener("click", () => fileInput.click());
|
95 |
|
96 |
+
// Handle file selection
|
97 |
fileInput.addEventListener("change", () => {
|
98 |
const file = fileInput.files[0];
|
99 |
if (file) {
|
100 |
+
selectedFile = file;
|
101 |
+
if (filePreviewBubble) filePreviewBubble.remove();
|
102 |
+
|
103 |
+
filePreviewBubble = document.createElement("div");
|
104 |
+
filePreviewBubble.className = "file-preview-bubble bubble right";
|
105 |
+
filePreviewBubble.textContent = `📎 Selected: ${file.name}`;
|
106 |
+
convo.appendChild(filePreviewBubble);
|
107 |
convo.scrollTop = convo.scrollHeight;
|
108 |
}
|
109 |
});
|
110 |
|
111 |
+
function createMessageBubble(text, sender = "You", audioSrc = null) {
|
112 |
const bubble = document.createElement("div");
|
113 |
+
bubble.className = `bubble ${sender === "You" ? "right" : "left"}`;
|
114 |
+
|
115 |
+
const label = document.createElement("div");
|
116 |
+
label.className = "label";
|
117 |
+
label.innerText = sender;
|
118 |
+
|
119 |
+
const message = document.createElement("div");
|
120 |
+
message.className = "text";
|
121 |
+
message.innerText = text;
|
122 |
|
123 |
+
bubble.appendChild(label);
|
124 |
+
bubble.appendChild(message);
|
125 |
+
|
126 |
+
if (audioSrc && sender === "Chris") {
|
127 |
const audio = document.createElement("audio");
|
128 |
audio.src = audioSrc;
|
129 |
audio.autoplay = true;
|
130 |
+
audio.controls = true;
|
|
|
|
|
|
|
|
|
|
|
131 |
|
132 |
+
const icon = document.createElement("i");
|
133 |
+
icon.className = "fa-solid fa-volume-high audio-toggle";
|
134 |
+
icon.style.cursor = "pointer";
|
135 |
+
icon.title = "Click to mute";
|
136 |
+
icon.style.marginLeft = "10px";
|
137 |
|
138 |
+
icon.addEventListener("click", () => {
|
|
|
139 |
audio.muted = !audio.muted;
|
140 |
+
icon.classList.toggle("fa-volume-high", !audio.muted);
|
141 |
+
icon.classList.toggle("fa-volume-xmark", audio.muted);
|
142 |
+
icon.title = audio.muted ? "Click to unmute" : "Click to mute";
|
|
|
|
|
|
|
|
|
143 |
});
|
144 |
+
|
145 |
+
const audioWrap = document.createElement("div");
|
146 |
+
audioWrap.style.display = "flex";
|
147 |
+
audioWrap.style.alignItems = "center";
|
148 |
+
audioWrap.style.gap = "8px";
|
149 |
+
audioWrap.appendChild(icon);
|
150 |
+
audioWrap.appendChild(audio);
|
151 |
+
|
152 |
+
bubble.appendChild(audioWrap);
|
153 |
}
|
154 |
|
155 |
convo.appendChild(bubble);
|
156 |
convo.scrollTop = convo.scrollHeight;
|
157 |
}
|
158 |
|
159 |
+
sendBtn.addEventListener("click", async () => {
|
160 |
+
const question = input.value.trim();
|
161 |
if (!question) return;
|
162 |
|
163 |
+
if (!selectedFile) {
|
164 |
+
alert("Please upload a document or image first.");
|
165 |
+
return;
|
166 |
+
}
|
167 |
+
|
168 |
+
// Remove file preview
|
169 |
+
if (filePreviewBubble) {
|
170 |
+
filePreviewBubble.remove();
|
171 |
+
filePreviewBubble = null;
|
172 |
+
}
|
173 |
+
|
174 |
+
createMessageBubble(question, "You", null);
|
175 |
+
|
176 |
+
// Simulate "thinking"
|
177 |
+
const thinkingBubble = createMessageBubble("Chris is thinking...", "Chris");
|
178 |
+
|
179 |
+
const formData = new FormData();
|
180 |
+
formData.append("question", question);
|
181 |
+
formData.append("file", selectedFile);
|
182 |
|
183 |
+
try {
|
184 |
+
const response = await fetch("/predict", {
|
185 |
+
method: "POST",
|
186 |
+
body: formData
|
187 |
+
});
|
188 |
+
const result = await response.json();
|
189 |
+
|
190 |
+
thinkingBubble.querySelector(".text").innerText = result.answer || "No response.";
|
191 |
+
if (result.audio) {
|
192 |
+
const audioWrap = document.createElement("div");
|
193 |
+
const audio = document.createElement("audio");
|
194 |
+
audio.src = result.audio;
|
195 |
+
audio.controls = true;
|
196 |
+
audio.autoplay = true;
|
197 |
+
|
198 |
+
const icon = document.createElement("i");
|
199 |
+
icon.className = "fa-solid fa-volume-high audio-toggle";
|
200 |
+
icon.title = "Click to mute";
|
201 |
+
icon.style.cursor = "pointer";
|
202 |
+
icon.style.marginLeft = "10px";
|
203 |
+
|
204 |
+
icon.addEventListener("click", () => {
|
205 |
+
audio.muted = !audio.muted;
|
206 |
+
icon.classList.toggle("fa-volume-high", !audio.muted);
|
207 |
+
icon.classList.toggle("fa-volume-xmark", audio.muted);
|
208 |
+
icon.title = audio.muted ? "Click to unmute" : "Click to mute";
|
209 |
+
});
|
210 |
+
|
211 |
+
audioWrap.style.display = "flex";
|
212 |
+
audioWrap.style.alignItems = "center";
|
213 |
+
audioWrap.style.gap = "8px";
|
214 |
+
audioWrap.appendChild(icon);
|
215 |
+
audioWrap.appendChild(audio);
|
216 |
+
thinkingBubble.appendChild(audioWrap);
|
217 |
+
}
|
218 |
+
|
219 |
+
} catch (err) {
|
220 |
+
thinkingBubble.querySelector(".text").innerText = "⚠️ Chris had trouble responding.";
|
221 |
+
}
|
222 |
+
|
223 |
+
input.value = "";
|
224 |
+
selectedFile = null;
|
225 |
});
|
226 |
});
|