Spaces:
Running
Running
Update static/appS.js
Browse files- static/appS.js +70 -94
static/appS.js
CHANGED
@@ -11,7 +11,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
11 |
const explainChoixDiv = document.getElementById('explainChoix');
|
12 |
|
13 |
let selectedFile = null;
|
14 |
-
let filePreviewBubble = null;
|
15 |
|
16 |
// ✅ Default mode: Summarize selected
|
17 |
const summarizeRadio = document.getElementById('summarize-radio');
|
@@ -44,14 +43,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
44 |
fileUpload.addEventListener('change', (e) => {
|
45 |
if (e.target.files.length) {
|
46 |
selectedFile = e.target.files[0];
|
47 |
-
|
48 |
}
|
49 |
});
|
50 |
|
51 |
imageUpload.addEventListener('change', (e) => {
|
52 |
if (e.target.files.length) {
|
53 |
selectedFile = e.target.files[0];
|
54 |
-
|
55 |
}
|
56 |
});
|
57 |
|
@@ -60,17 +59,70 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
60 |
explainChoixDiv.style.display = "none";
|
61 |
});
|
62 |
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
}
|
75 |
|
76 |
function createMessageBubble(text, sender = "You", audioSrc = null, fileUrl = null) {
|
@@ -86,19 +138,15 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
86 |
const message = document.createElement('div');
|
87 |
message.className = "text";
|
88 |
message.style.whiteSpace = "pre-wrap";
|
89 |
-
message.
|
90 |
-
message.style.flexDirection = "column";
|
91 |
-
|
92 |
-
const textSpan = document.createElement("span");
|
93 |
-
textSpan.innerHTML = text;
|
94 |
-
message.appendChild(textSpan);
|
95 |
|
|
|
96 |
if (sender !== "You" && (audioSrc || fileUrl)) {
|
97 |
const iconContainer = document.createElement('div');
|
98 |
iconContainer.style.marginTop = "10px";
|
99 |
iconContainer.style.display = "flex";
|
100 |
-
iconContainer.style.justifyContent = "flex-end";
|
101 |
iconContainer.style.gap = "15px";
|
|
|
102 |
|
103 |
if (audioSrc) {
|
104 |
const audio = new Audio(audioSrc);
|
@@ -111,14 +159,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
111 |
audioIcon.addEventListener("click", () => {
|
112 |
if (audio.paused) {
|
113 |
audio.play();
|
114 |
-
audioIcon.
|
115 |
-
audioIcon.classList.add("fa-volume-high");
|
116 |
-
audioIcon.title = "Mute Audio";
|
117 |
} else {
|
118 |
audio.pause();
|
119 |
-
audioIcon.
|
120 |
-
audioIcon.classList.add("fa-volume-xmark");
|
121 |
-
audioIcon.title = "Unmute Audio";
|
122 |
}
|
123 |
});
|
124 |
|
@@ -150,74 +194,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
150 |
return bubble;
|
151 |
}
|
152 |
|
153 |
-
async function handleSubmit() {
|
154 |
-
if (!selectedFile) {
|
155 |
-
alert("Please upload a file first");
|
156 |
-
return;
|
157 |
-
}
|
158 |
-
|
159 |
-
const isSummarizeMode = document.querySelector('input[name="mode"]:checked').value === 'Summarize';
|
160 |
-
const endpoint = isSummarizeMode ? '/summarize/' : '/imagecaption/';
|
161 |
-
const thinkingText = isSummarizeMode ? 'Processing document... <div class="loader"></div>' : 'Generating caption... <div class="loader"></div>';
|
162 |
-
const senderName = "Aidan";
|
163 |
-
|
164 |
-
const thinkingBubble = createMessageBubble(thinkingText, senderName);
|
165 |
-
|
166 |
-
const formData = new FormData();
|
167 |
-
formData.append('file', selectedFile);
|
168 |
-
|
169 |
-
if (isSummarizeMode) {
|
170 |
-
// Grab length choice if exists (short, medium, long)
|
171 |
-
const selectedLength = document.querySelector('input[name="length"]:checked')?.value || 'medium';
|
172 |
-
formData.append('length', selectedLength);
|
173 |
-
}
|
174 |
-
|
175 |
-
try {
|
176 |
-
const response = await fetch(endpoint, {
|
177 |
-
method: 'POST',
|
178 |
-
body: formData
|
179 |
-
});
|
180 |
-
|
181 |
-
if (!response.ok) {
|
182 |
-
let errorMessage = 'Request failed';
|
183 |
-
try {
|
184 |
-
const error = await response.json();
|
185 |
-
errorMessage = error.detail || error.error || errorMessage;
|
186 |
-
} catch (e) { }
|
187 |
-
throw new Error(errorMessage);
|
188 |
-
}
|
189 |
-
|
190 |
-
const result = await response.json();
|
191 |
-
thinkingBubble.remove();
|
192 |
-
|
193 |
-
if (isSummarizeMode) {
|
194 |
-
createMessageBubble(
|
195 |
-
result.summary || "No summary generated.",
|
196 |
-
"Aidan",
|
197 |
-
result.audioUrl,
|
198 |
-
result.pdfUrl
|
199 |
-
);
|
200 |
-
} else {
|
201 |
-
createMessageBubble(
|
202 |
-
result.caption || result.answer || "No caption generated.",
|
203 |
-
"Aidan",
|
204 |
-
result.audio,
|
205 |
-
null
|
206 |
-
);
|
207 |
-
}
|
208 |
-
} catch (error) {
|
209 |
-
thinkingBubble.remove();
|
210 |
-
createMessageBubble(`⚠️ Error: ${error.message}`, "Aidan");
|
211 |
-
} finally {
|
212 |
-
resetFileInputs();
|
213 |
-
}
|
214 |
-
}
|
215 |
-
|
216 |
function resetFileInputs() {
|
217 |
selectedFile = null;
|
218 |
fileUpload.value = '';
|
219 |
imageUpload.value = '';
|
220 |
-
// 🛑 File preview bubble stays!
|
221 |
}
|
222 |
|
223 |
// Loader CSS
|
@@ -236,10 +216,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
236 |
0% { transform: rotate(0deg); }
|
237 |
100% { transform: rotate(360deg); }
|
238 |
}
|
239 |
-
.audio-toggle {
|
240 |
-
cursor: pointer;
|
241 |
-
transition: all 0.2s;
|
242 |
-
}
|
243 |
`;
|
244 |
document.head.appendChild(style);
|
245 |
});
|
|
|
11 |
const explainChoixDiv = document.getElementById('explainChoix');
|
12 |
|
13 |
let selectedFile = null;
|
|
|
14 |
|
15 |
// ✅ Default mode: Summarize selected
|
16 |
const summarizeRadio = document.getElementById('summarize-radio');
|
|
|
43 |
fileUpload.addEventListener('change', (e) => {
|
44 |
if (e.target.files.length) {
|
45 |
selectedFile = e.target.files[0];
|
46 |
+
handleFileUpload(selectedFile);
|
47 |
}
|
48 |
});
|
49 |
|
50 |
imageUpload.addEventListener('change', (e) => {
|
51 |
if (e.target.files.length) {
|
52 |
selectedFile = e.target.files[0];
|
53 |
+
handleFileUpload(selectedFile);
|
54 |
}
|
55 |
});
|
56 |
|
|
|
59 |
explainChoixDiv.style.display = "none";
|
60 |
});
|
61 |
|
62 |
+
async function handleFileUpload(file) {
|
63 |
+
if (!file) return;
|
64 |
+
|
65 |
+
const isImage = file.type.startsWith('image/');
|
66 |
+
const icon = isImage ? '🖼️' : '📎';
|
67 |
+
|
68 |
+
// User bubble: Uploaded file
|
69 |
+
createMessageBubble(`${icon} Uploaded: ${file.name}`, "You");
|
70 |
+
|
71 |
+
const isSummarizeMode = document.querySelector('input[name="mode"]:checked').value === 'Summarize';
|
72 |
+
const endpoint = isSummarizeMode ? '/summarize/' : '/imagecaption/';
|
73 |
+
const thinkingText = isSummarizeMode ? 'Analyzing document... <div class="loader"></div>' : 'Analyzing image... <div class="loader"></div>';
|
74 |
+
|
75 |
+
// AI thinking bubble
|
76 |
+
const thinkingBubble = createMessageBubble(thinkingText, "Aidan");
|
77 |
+
|
78 |
+
const formData = new FormData();
|
79 |
+
formData.append('file', file);
|
80 |
+
|
81 |
+
if (isSummarizeMode) {
|
82 |
+
const selectedLength = document.querySelector('input[name="length"]:checked')?.value || 'medium';
|
83 |
+
formData.append('length', selectedLength);
|
84 |
+
}
|
85 |
+
|
86 |
+
try {
|
87 |
+
const response = await fetch(endpoint, {
|
88 |
+
method: 'POST',
|
89 |
+
body: formData
|
90 |
+
});
|
91 |
+
|
92 |
+
if (!response.ok) {
|
93 |
+
let errorMessage = 'Request failed';
|
94 |
+
try {
|
95 |
+
const error = await response.json();
|
96 |
+
errorMessage = error.detail || error.error || errorMessage;
|
97 |
+
} catch (e) {}
|
98 |
+
throw new Error(errorMessage);
|
99 |
+
}
|
100 |
|
101 |
+
const result = await response.json();
|
102 |
+
thinkingBubble.remove();
|
103 |
+
|
104 |
+
// Aidan's response bubble
|
105 |
+
if (isSummarizeMode) {
|
106 |
+
createMessageBubble(
|
107 |
+
result.summary || "No summary generated.",
|
108 |
+
"Aidan",
|
109 |
+
result.audioUrl,
|
110 |
+
result.pdfUrl
|
111 |
+
);
|
112 |
+
} else {
|
113 |
+
createMessageBubble(
|
114 |
+
result.caption || result.answer || "No caption generated.",
|
115 |
+
"Aidan",
|
116 |
+
result.audio,
|
117 |
+
null
|
118 |
+
);
|
119 |
+
}
|
120 |
+
} catch (error) {
|
121 |
+
thinkingBubble.remove();
|
122 |
+
createMessageBubble(`⚠️ Error: ${error.message}`, "Aidan");
|
123 |
+
} finally {
|
124 |
+
resetFileInputs();
|
125 |
+
}
|
126 |
}
|
127 |
|
128 |
function createMessageBubble(text, sender = "You", audioSrc = null, fileUrl = null) {
|
|
|
138 |
const message = document.createElement('div');
|
139 |
message.className = "text";
|
140 |
message.style.whiteSpace = "pre-wrap";
|
141 |
+
message.innerHTML = text;
|
|
|
|
|
|
|
|
|
|
|
142 |
|
143 |
+
// Extra controls (audio/PDF download)
|
144 |
if (sender !== "You" && (audioSrc || fileUrl)) {
|
145 |
const iconContainer = document.createElement('div');
|
146 |
iconContainer.style.marginTop = "10px";
|
147 |
iconContainer.style.display = "flex";
|
|
|
148 |
iconContainer.style.gap = "15px";
|
149 |
+
iconContainer.style.justifyContent = "flex-end";
|
150 |
|
151 |
if (audioSrc) {
|
152 |
const audio = new Audio(audioSrc);
|
|
|
159 |
audioIcon.addEventListener("click", () => {
|
160 |
if (audio.paused) {
|
161 |
audio.play();
|
162 |
+
audioIcon.title = "Pause Audio";
|
|
|
|
|
163 |
} else {
|
164 |
audio.pause();
|
165 |
+
audioIcon.title = "Play Audio";
|
|
|
|
|
166 |
}
|
167 |
});
|
168 |
|
|
|
194 |
return bubble;
|
195 |
}
|
196 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
197 |
function resetFileInputs() {
|
198 |
selectedFile = null;
|
199 |
fileUpload.value = '';
|
200 |
imageUpload.value = '';
|
|
|
201 |
}
|
202 |
|
203 |
// Loader CSS
|
|
|
216 |
0% { transform: rotate(0deg); }
|
217 |
100% { transform: rotate(360deg); }
|
218 |
}
|
|
|
|
|
|
|
|
|
219 |
`;
|
220 |
document.head.appendChild(style);
|
221 |
});
|