ikraamkb commited on
Commit
2c0fbc1
·
verified ·
1 Parent(s): c319660

Update static/appS.js

Browse files
Files changed (1) hide show
  1. static/appS.js +136 -274
static/appS.js CHANGED
@@ -1,310 +1,172 @@
1
  document.addEventListener('DOMContentLoaded', () => {
2
- // UI Elements
3
- const GotitB = document.querySelector(".explainChoix button");
4
- const explain = document.querySelector(".explainChoix");
5
- const SummarizeInput = document.querySelector(".SummarizeInput");
6
- const CaptionInput = document.querySelector(".CaptionInput");
7
  const fileUpload = document.getElementById('file-upload');
8
  const imageUpload = document.getElementById('image-upload');
9
  const fileBtn = document.getElementById('file-btn');
10
  const imageBtn = document.getElementById('image-btn');
11
- const convo = document.querySelector('.convo');
12
 
13
- // Hide explanation after click
14
- GotitB.addEventListener("click", () => {
15
- explain.style.opacity = "0";
16
- });
17
-
18
- // Handle mode switching
19
- document.querySelectorAll('.select-options input[type="radio"]').forEach(radio => {
20
- radio.addEventListener('change', (e) => {
21
- if (e.target.checked) {
22
- const selectedValue = e.target.value;
23
- if (selectedValue === "Summarize") {
24
- SummarizeInput.classList.add("active");
25
- SummarizeInput.classList.remove("innactive");
26
- CaptionInput.classList.remove("active");
27
- CaptionInput.classList.add("innactive");
28
- } else {
29
- SummarizeInput.classList.add("innactive");
30
- SummarizeInput.classList.remove("active");
31
- CaptionInput.classList.remove("innactive");
32
- CaptionInput.classList.add("active");
33
- }
34
- }
35
- });
36
- });
37
 
38
  // File upload handlers
39
  fileBtn.addEventListener('click', () => fileUpload.click());
40
  imageBtn.addEventListener('click', () => imageUpload.click());
41
 
42
- // Send button handlers
43
- document.querySelectorAll('.sendingQA').forEach(button => {
44
- button.addEventListener('click', async () => {
45
- const isSummarizeMode = document.querySelector('input[name="option"]:checked').value === 'Summarize';
46
-
47
- if (isSummarizeMode) {
48
- await handleSummarize();
49
- } else {
50
- await handleCaption();
51
- }
52
- });
53
  });
54
 
55
- // Handle document summarization
56
- async function handleSummarize() {
57
- const file = fileUpload.files[0];
58
- if (!file) {
59
- displayError('Please upload a document first');
60
- return;
61
  }
 
62
 
63
- const length = document.querySelector('input[name="optionS"]:checked')?.value || 'medium';
 
64
 
65
- try {
66
- // Show loading state
67
- convo.innerHTML = '';
68
- displayFileInfo(file.name, 'document');
69
- displayThinkingMessage();
70
-
71
- // Call API
72
- const result = await summarizeDocument(file, length);
73
-
74
- // Display results
75
- displaySummaryResult(file.name, result.summary, result.audio_url, result.pdf_url);
76
- } catch (error) {
77
- displayError(error.message || 'Failed to summarize document');
78
- }
79
- }
80
-
81
- // Handle image captioning
82
- async function handleCaption() {
83
- const file = imageUpload.files[0];
84
- if (!file) {
85
- displayError('Please upload an image first');
86
- return;
87
- }
88
-
89
- try {
90
- // Show loading state
91
- convo.innerHTML = '';
92
- displayFileInfo(file.name, 'image');
93
- displayThinkingMessage();
94
-
95
- // Call API
96
- const result = await captionImage(file);
97
-
98
- // Display results
99
- displayCaptionResult(file.name, result.answer, result.audio);
100
- } catch (error) {
101
- displayError(error.message || 'Failed to generate caption');
102
- }
103
  }
104
 
105
- // API Functions
106
- async function summarizeDocument(file, length) {
107
- const formData = new FormData();
108
- formData.append('file', file);
109
- formData.append('length', length);
110
-
111
- const response = await fetch('/summarize/', {
112
- method: 'POST',
113
- body: formData
114
- });
115
-
116
- if (!response.ok) {
117
- const error = await response.json();
118
- throw new Error(error.error || 'Summarization failed');
119
- }
120
-
121
- return await response.json();
122
- }
123
 
124
- async function captionImage(file) {
125
- const formData = new FormData();
126
- formData.append('file', file);
127
 
128
- const response = await fetch('/imagecaption/', {
129
- method: 'POST',
130
- body: formData
131
- });
132
 
133
- if (!response.ok) {
134
- const error = await response.json();
135
- throw new Error(error.error || 'Captioning failed');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  }
137
-
138
- return await response.json();
139
- }
140
-
141
- // UI Helper Functions
142
- function displayFileInfo(filename, type) {
143
- const bubble = document.createElement('div');
144
- bubble.className = 'bubble right';
145
- bubble.innerHTML = `
146
- <div class="label">You</div>
147
- <div class="text">${type === 'document' ? '📄' : '🖼️'} ${filename}</div>
148
- `;
149
- convo.appendChild(bubble);
150
- }
151
 
152
- function displayThinkingMessage() {
153
- const bubble = document.createElement('div');
154
- bubble.className = 'bubble left';
155
- bubble.innerHTML = `
156
- <div class="label">Aidan</div>
157
- <div class="text">
158
- <div style="display:flex;align-items:center;gap:8px">
159
- <span>Processing your ${document.querySelector('input[name="option"]:checked').value.toLowerCase()}...</span>
160
- <div class="loader"></div>
161
- </div>
162
- </div>
163
- `;
164
  convo.appendChild(bubble);
165
  convo.scrollTop = convo.scrollHeight;
 
166
  }
167
 
168
- function displaySummaryResult(filename, summary, audioUrl, pdfUrl) {
169
- // Remove thinking message
170
- convo.removeChild(convo.lastChild);
171
-
172
- const bubble = document.createElement('div');
173
- bubble.className = 'bubble left';
174
- bubble.innerHTML = `
175
- <div class="label">Aidan</div>
176
- <div class="text">
177
- <strong>Summary:</strong><br><br>
178
- ${summary.replace(/\n/g, '<br>')}
179
- <div class="action-buttons" style="margin-top: 10px; display: flex; gap: 10px;">
180
- ${audioUrl ? `
181
- <button class="audio-control" data-audio="${audioUrl}">
182
- <i class="fa-solid fa-volume-high"></i> Audio
183
- </button>` : ''}
184
- ${pdfUrl ? `
185
- <a href="${pdfUrl}" download="${filename.split('.')[0]}_summary.pdf" class="download-btn">
186
- <i class="fa-solid fa-download"></i> PDF
187
- </a>` : ''}
188
- </div>
189
- </div>
190
- `;
191
- convo.appendChild(bubble);
192
- setupAudioControls();
193
- convo.scrollTop = convo.scrollHeight;
194
- }
195
 
196
- function displayCaptionResult(filename, caption, audioUrl) {
197
- // Remove thinking message
198
- convo.removeChild(convo.lastChild);
199
 
200
- const bubble = document.createElement('div');
201
- bubble.className = 'bubble left';
202
- bubble.innerHTML = `
203
- <div class="label">Aidan</div>
204
- <div class="text">
205
- <strong>Caption:</strong><br><br>
206
- ${caption}
207
- ${audioUrl ? `
208
- <div class="action-buttons" style="margin-top: 10px;">
209
- <button class="audio-control" data-audio="${audioUrl}">
210
- <i class="fa-solid fa-volume-high"></i> Audio
211
- </button>
212
- </div>` : ''}
213
- </div>
214
- `;
215
- convo.appendChild(bubble);
216
- setupAudioControls();
217
- convo.scrollTop = convo.scrollHeight;
218
- }
219
 
220
- function setupAudioControls() {
221
- document.querySelectorAll('.audio-control').forEach(button => {
222
- const audioUrl = button.getAttribute('data-audio');
223
- const audio = new Audio(audioUrl);
224
- const icon = button.querySelector('i');
225
 
226
- button.addEventListener('click', () => {
227
- if (audio.paused) {
228
- audio.play();
229
- icon.classList.remove('fa-volume-xmark');
230
- icon.classList.add('fa-volume-high');
231
- } else {
232
- audio.pause();
233
- icon.classList.remove('fa-volume-high');
234
- icon.classList.add('fa-volume-xmark');
235
- }
236
  });
237
- });
238
- }
239
 
240
- function displayError(message) {
241
- const bubble = document.createElement('div');
242
- bubble.className = 'bubble left';
243
- bubble.innerHTML = `
244
- <div class="label">Aidan</div>
245
- <div class="text" style="color: #ef4444;">
246
- ⚠️ ${message}
247
- </div>
248
- `;
249
- convo.appendChild(bubble);
250
- convo.scrollTop = convo.scrollHeight;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  }
252
 
253
- // Add loader CSS
254
- const style = document.createElement('style');
255
- style.textContent = `
256
- .loader {
257
- border: 2px solid #f3f3f3;
258
- border-top: 2px solid #3b82f6;
259
- border-radius: 50%;
260
- width: 16px;
261
- height: 16px;
262
- animation: spin 1s linear infinite;
263
- }
264
- @keyframes spin {
265
- 0% { transform: rotate(0deg); }
266
- 100% { transform: rotate(360deg); }
267
- }
268
- .download-btn, .audio-control {
269
- display: inline-flex;
270
- align-items: center;
271
- gap: 5px;
272
- padding: 5px 10px;
273
- background: #3b82f6;
274
- color: white;
275
- border: none;
276
- border-radius: 5px;
277
- cursor: pointer;
278
- text-decoration: none;
279
- font-size: 14px;
280
- }
281
- .download-btn:hover, .audio-control:hover {
282
- background: #2563eb;
283
- }
284
- .bubble {
285
- max-width: 80%;
286
- padding: 12px 16px;
287
- margin: 8px 0;
288
- border-radius: 18px;
289
- position: relative;
290
- clear: both;
291
- }
292
- .bubble.left {
293
- background: #f1f1f1;
294
- float: left;
295
- margin-right: auto;
296
- }
297
- .bubble.right {
298
- background: #3b82f6;
299
- color: white;
300
- float: right;
301
- margin-left: auto;
302
- }
303
- .label {
304
- font-weight: bold;
305
- font-size: 12px;
306
- margin-bottom: 4px;
307
- }
308
- `;
309
- document.head.appendChild(style);
310
  });
 
1
  document.addEventListener('DOMContentLoaded', () => {
2
+ const convo = document.querySelector(".convo");
 
 
 
 
3
  const fileUpload = document.getElementById('file-upload');
4
  const imageUpload = document.getElementById('image-upload');
5
  const fileBtn = document.getElementById('file-btn');
6
  const imageBtn = document.getElementById('image-btn');
7
+ const sendButtons = document.querySelectorAll('.sendingQA');
8
 
9
+ let selectedFile = null;
10
+ let filePreviewBubble = null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
  // File upload handlers
13
  fileBtn.addEventListener('click', () => fileUpload.click());
14
  imageBtn.addEventListener('click', () => imageUpload.click());
15
 
16
+ fileUpload.addEventListener('change', (e) => {
17
+ if (e.target.files.length) {
18
+ selectedFile = e.target.files[0];
19
+ displayFilePreview(selectedFile);
20
+ }
 
 
 
 
 
 
21
  });
22
 
23
+ imageUpload.addEventListener('change', (e) => {
24
+ if (e.target.files.length) {
25
+ selectedFile = e.target.files[0];
26
+ displayFilePreview(selectedFile);
 
 
27
  }
28
+ });
29
 
30
+ function displayFilePreview(file) {
31
+ if (filePreviewBubble) filePreviewBubble.remove();
32
 
33
+ filePreviewBubble = document.createElement('div');
34
+ filePreviewBubble.className = 'file-preview-bubble bubble right';
35
+ filePreviewBubble.innerHTML = `
36
+ <div class="label">You</div>
37
+ <div class="text">📎 Selected: ${file.name}</div>
38
+ `;
39
+ convo.appendChild(filePreviewBubble);
40
+ convo.scrollTop = convo.scrollHeight;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  }
42
 
43
+ function createMessageBubble(text, sender = "You", audioSrc = null) {
44
+ const bubble = document.createElement('div');
45
+ bubble.className = `bubble ${sender === "You" ? "right" : "left"}`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
+ const label = document.createElement('div');
48
+ label.className = "label";
49
+ label.innerText = sender;
50
 
51
+ const message = document.createElement('div');
52
+ message.className = "text";
 
 
53
 
54
+ if (sender === "You") {
55
+ message.innerText = text;
56
+ } else {
57
+ message.innerHTML = text;
58
+
59
+ if (audioSrc) {
60
+ const audioContainer = document.createElement('div');
61
+ audioContainer.style.display = 'flex';
62
+ audioContainer.style.alignItems = 'center';
63
+ audioContainer.style.gap = '10px';
64
+ audioContainer.style.marginTop = '8px';
65
+
66
+ const audio = new Audio(audioSrc);
67
+ const audioIcon = document.createElement('i');
68
+ audioIcon.className = 'fa-solid fa-volume-high audio-toggle';
69
+ audioIcon.style.cursor = 'pointer';
70
+
71
+ audioIcon.addEventListener('click', () => {
72
+ if (audio.paused) {
73
+ audio.play();
74
+ audioIcon.classList.remove('fa-volume-xmark');
75
+ audioIcon.classList.add('fa-volume-high');
76
+ } else {
77
+ audio.pause();
78
+ audioIcon.classList.remove('fa-volume-high');
79
+ audioIcon.classList.add('fa-volume-xmark');
80
+ }
81
+ });
82
+
83
+ audioContainer.appendChild(audioIcon);
84
+ audioContainer.appendChild(document.createTextNode('Listen'));
85
+ message.appendChild(audioContainer);
86
+ }
87
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
+ bubble.appendChild(label);
90
+ bubble.appendChild(message);
 
 
 
 
 
 
 
 
 
 
91
  convo.appendChild(bubble);
92
  convo.scrollTop = convo.scrollHeight;
93
+ return bubble;
94
  }
95
 
96
+ async function handleSend() {
97
+ if (!selectedFile) {
98
+ alert("Please upload a file first");
99
+ return;
100
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
 
102
+ const isSummarizeMode = document.querySelector('input[name="option"]:checked').value === 'Summarize';
 
 
103
 
104
+ // User message
105
+ createMessageBubble(
106
+ isSummarizeMode ? "Please summarize this document" : "Please caption this image",
107
+ "You"
108
+ );
109
+
110
+ // Thinking message
111
+ const thinkingBubble = createMessageBubble(
112
+ isSummarizeMode ? "Summarizing your document..." : "Generating caption for your image...",
113
+ "Aidan"
114
+ );
 
 
 
 
 
 
 
 
115
 
116
+ try {
117
+ const formData = new FormData();
118
+ formData.append('file', selectedFile);
 
 
119
 
120
+ if (isSummarizeMode) {
121
+ const length = document.querySelector('input[name="optionS"]:checked').value;
122
+ formData.append('length', length);
123
+ }
124
+
125
+ const endpoint = isSummarizeMode ? '/summarize/' : '/imagecaption/';
126
+ const response = await fetch(endpoint, {
127
+ method: 'POST',
128
+ body: formData
 
129
  });
 
 
130
 
131
+ const result = await response.json();
132
+
133
+ // Replace thinking message with actual result
134
+ thinkingBubble.remove();
135
+
136
+ if (isSummarizeMode) {
137
+ createMessageBubble(
138
+ `<strong>Summary:</strong><br><br>${result.summary.replace(/\n/g, '<br>')}` +
139
+ (result.pdf_url ? `<br><br><a href="${result.pdf_url}" download target="_blank">Download PDF</a>` : ''),
140
+ "Aidan",
141
+ result.audio_url
142
+ );
143
+ } else {
144
+ createMessageBubble(
145
+ `<strong>Caption:</strong><br><br>${result.answer}`,
146
+ "Aidan",
147
+ result.audio
148
+ );
149
+ }
150
+ } catch (error) {
151
+ thinkingBubble.remove();
152
+ createMessageBubble(
153
+ "⚠️ Sorry, I encountered an error processing your request",
154
+ "Aidan"
155
+ );
156
+ console.error(error);
157
+ } finally {
158
+ selectedFile = null;
159
+ fileUpload.value = '';
160
+ imageUpload.value = '';
161
+ if (filePreviewBubble) {
162
+ filePreviewBubble.remove();
163
+ filePreviewBubble = null;
164
+ }
165
+ }
166
  }
167
 
168
+ // Attach send handlers
169
+ sendButtons.forEach(button => {
170
+ button.addEventListener('click', handleSend);
171
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  });