ikraamkb commited on
Commit
22c1e9b
·
verified ·
1 Parent(s): 2a8891b

Update static/appS.js

Browse files
Files changed (1) hide show
  1. static/appS.js +179 -169
static/appS.js CHANGED
@@ -1,18 +1,17 @@
1
  document.addEventListener('DOMContentLoaded', () => {
2
- const GotitB = document.querySelector(".explainChoix button");
3
- const explain = document.querySelector(".explainChoix");
4
- const SummarizeInput = document.querySelector(".SummarizeInput");
5
- const CaptionInput = document.querySelector(".CaptionInput");
6
  const fileUpload = document.getElementById('file-upload');
7
  const imageUpload = document.getElementById('image-upload');
8
  const fileBtn = document.getElementById('file-btn');
9
  const imageBtn = document.getElementById('image-btn');
10
- const convo = document.querySelector('.convo');
 
 
11
 
12
- GotitB.addEventListener("click", () => {
13
- explain.style.opacity = "0";
14
- });
15
 
 
16
  document.querySelectorAll('.select-options input[type="radio"]').forEach(radio => {
17
  radio.addEventListener('change', (e) => {
18
  if (e.target.checked) {
@@ -32,20 +31,25 @@ document.addEventListener('DOMContentLoaded', () => {
32
  });
33
  });
34
 
 
35
  fileBtn.addEventListener('click', () => fileUpload.click());
36
  imageBtn.addEventListener('click', () => imageUpload.click());
37
 
38
- document.querySelectorAll('.sendingQA').forEach(button => {
39
- button.addEventListener('click', async () => {
40
- const isSummarizeMode = document.querySelector('input[name="option"]:checked').value === 'Summarize';
41
- if (isSummarizeMode) {
42
- await handleSummarize();
43
- } else {
44
- await handleCaption();
45
- }
46
- });
 
 
 
47
  });
48
 
 
49
  convo.addEventListener('dragover', (e) => {
50
  e.preventDefault();
51
  convo.classList.add('drag-over');
@@ -55,199 +59,201 @@ document.addEventListener('DOMContentLoaded', () => {
55
  convo.classList.remove('drag-over');
56
  });
57
 
58
- convo.addEventListener('drop', async (e) => {
59
  e.preventDefault();
60
  convo.classList.remove('drag-over');
61
-
62
  if (e.dataTransfer.files.length) {
63
  const file = e.dataTransfer.files[0];
64
- const isSummarizeMode = document.querySelector('input[name="option"]:checked').value === 'Summarize';
 
65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  if (isSummarizeMode) {
67
- fileUpload.files = e.dataTransfer.files;
68
  await handleSummarize();
69
  } else {
70
- imageUpload.files = e.dataTransfer.files;
71
  await handleCaption();
72
  }
73
- }
74
  });
75
 
76
- async function handleSummarize() {
77
- const file = fileUpload.files[0];
78
- if (!file) {
79
- displayError('Please upload a document first');
80
- return;
 
 
81
  }
82
 
83
- console.log("Selected file:", file.name, "Type:", file.type);
84
- const length = document.querySelector('input[name="optionS"]:checked')?.value || "medium";
 
85
 
86
- try {
87
- convo.innerHTML = '';
88
- displayFileInfo(file.name, 'document');
89
- displayThinkingMessage();
90
 
91
- console.log("Starting summarization...");
92
- const result = await summarizeDocument(file, length);
93
- console.log("Summarization result:", result);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
 
95
- displaySummaryResult(file.name, result.summary, result.audioUrl, result.pdfUrl);
96
- } catch (error) {
97
- console.error("Summarization failed:", error);
98
- displayError(error.message || 'Failed to summarize document');
 
99
  }
100
- }
101
- async function handleCaption() {
102
- const file = imageUpload.files[0];
103
- if (!file) {
104
- displayError('Please upload an image first');
105
  return;
106
  }
107
- try {
108
- convo.innerHTML = '';
109
- displayFileInfo(file.name, 'image');
110
- displayThinkingMessage();
111
 
112
- const caption = await captionImage(file);
 
 
 
 
113
 
114
- displayCaptionResult(file.name, caption);
115
- } catch (error) {
116
- displayError(error.message || 'Failed to generate caption');
117
- }
118
- }
119
 
120
- async function summarizeDocument(file, length) {
121
- const formData = new FormData();
122
- formData.append('file', file);
123
- formData.append('length', length);
124
 
125
- try {
126
- const response = await fetch('/summarize/', {
127
- method: 'POST',
128
- body: formData
129
- });
130
 
131
- const result = await response.json();
132
-
133
- if (!response.ok) {
134
- throw new Error(result.detail || result.message || "Summarization failed");
135
- }
136
 
137
- // Map backend fields to frontend expectations
138
- return {
139
- summary: result.summary,
140
- audioUrl: result.audio_url || result.audioUrl,
141
- pdfUrl: result.pdf_url || result.pdfUrl
142
- };
143
- } catch (error) {
144
- console.error("Summarization error:", error);
145
- throw error;
 
 
 
 
146
  }
147
- }
148
- async function captionImage(file) {
149
- const formData = new FormData();
150
- formData.append('file', file);
151
-
152
- const response = await fetch('/imagecaption/', {
153
- method: 'POST',
154
- body: formData
155
- });
156
 
157
- if (!response.ok) {
158
- const error = await response.json();
159
- throw new Error(error.detail || 'Captioning failed');
 
160
  }
161
 
162
- const result = await response.json();
163
- return result.caption;
164
- }
165
-
166
- function displayFileInfo(filename, type) {
167
- const bubble = document.createElement('div');
168
- bubble.className = 'bubble right';
169
- bubble.innerHTML = `
170
- <div class="label">You</div>
171
- <div class="text">${type === 'document' ? '📄' : '🖼️'} ${filename}</div>
172
- `;
173
- convo.appendChild(bubble);
174
- }
175
 
176
- function displayThinkingMessage() {
177
- const bubble = document.createElement('div');
178
- bubble.className = 'bubble left';
179
- bubble.innerHTML = `
180
- <div class="label">Aidan</div>
181
- <div class="text">
182
- <div style="display:flex;align-items:center;gap:8px">
183
- <span>Processing...</span>
184
- <div class="loader"></div>
185
- </div>
186
- </div>
187
- `;
188
- convo.appendChild(bubble);
189
- convo.scrollTop = convo.scrollHeight;
190
- }
191
 
192
- function displaySummaryResult(filename, summary, audioUrl, pdfUrl) {
193
- // Remove thinking message if it exists
194
- const lastBubble = convo.lastChild;
195
- if (lastBubble && lastBubble.querySelector('.loader')) {
196
- convo.removeChild(lastBubble);
197
- }
198
 
199
- const bubble = document.createElement('div');
200
- bubble.className = 'bubble left';
201
-
202
- // Safely handle missing summary
203
- const summaryContent = summary ? summary.replace(/\n/g, '<br>') : "No summary generated";
204
-
205
- bubble.innerHTML = `
206
- <div class="label">Aidan</div>
207
- <div class="text">
208
- <strong>Summary:</strong><br><br>
209
- ${summaryContent}
210
- ${audioUrl ? `<br><br><audio controls src="${audioUrl}" style="width: 100%;"></audio>` : ''}
211
- ${pdfUrl ? `<br><a href="${pdfUrl}" download="${filename.replace(/\.[^/.]+$/, '')}_summary.pdf" class="download-link">📥 Download PDF Summary</a>` : ''}
212
- </div>
213
- `;
214
-
215
- convo.appendChild(bubble);
216
- convo.scrollTop = convo.scrollHeight;
217
- }
218
 
219
- function displayCaptionResult(filename, caption) {
220
- convo.removeChild(convo.lastChild);
221
 
222
- const bubble = document.createElement('div');
223
- bubble.className = 'bubble left';
224
- bubble.innerHTML = `
225
- <div class="label">Aidan</div>
226
- <div class="text">
227
- <strong>Caption:</strong><br><br>
228
- ${caption}
229
- </div>
230
- `;
231
- convo.appendChild(bubble);
232
- convo.scrollTop = convo.scrollHeight;
 
233
  }
234
 
235
- function displayError(message) {
236
- const bubble = document.createElement('div');
237
- bubble.className = 'bubble left';
238
- bubble.innerHTML = `
239
- <div class="label">Aidan</div>
240
- <div class="text" style="color: #ef4444;">
241
- ⚠️ ${message}
242
- </div>
243
- `;
244
- convo.appendChild(bubble);
245
- convo.scrollTop = convo.scrollHeight;
246
  }
247
 
 
248
  const style = document.createElement('style');
249
  style.textContent = `
250
  .loader {
 
251
  border: 2px solid #f3f3f3;
252
  border-top: 2px solid #3b82f6;
253
  border-radius: 50%;
@@ -271,6 +277,10 @@ async function summarizeDocument(file, length) {
271
  .download-link:hover {
272
  background: #2563eb;
273
  }
 
 
 
 
274
  `;
275
  document.head.appendChild(style);
276
- });
 
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
+ const SummarizeInput = document.querySelector(".SummarizeInput");
9
+ const CaptionInput = document.querySelector(".CaptionInput");
10
 
11
+ let selectedFile = null;
12
+ let filePreviewBubble = null;
 
13
 
14
+ // Mode switching
15
  document.querySelectorAll('.select-options input[type="radio"]').forEach(radio => {
16
  radio.addEventListener('change', (e) => {
17
  if (e.target.checked) {
 
31
  });
32
  });
33
 
34
+ // File upload handlers
35
  fileBtn.addEventListener('click', () => fileUpload.click());
36
  imageBtn.addEventListener('click', () => imageUpload.click());
37
 
38
+ fileUpload.addEventListener('change', (e) => {
39
+ if (e.target.files.length) {
40
+ selectedFile = e.target.files[0];
41
+ displayFilePreview(selectedFile);
42
+ }
43
+ });
44
+
45
+ imageUpload.addEventListener('change', (e) => {
46
+ if (e.target.files.length) {
47
+ selectedFile = e.target.files[0];
48
+ displayFilePreview(selectedFile);
49
+ }
50
  });
51
 
52
+ // Drag and drop
53
  convo.addEventListener('dragover', (e) => {
54
  e.preventDefault();
55
  convo.classList.add('drag-over');
 
59
  convo.classList.remove('drag-over');
60
  });
61
 
62
+ convo.addEventListener('drop', (e) => {
63
  e.preventDefault();
64
  convo.classList.remove('drag-over');
 
65
  if (e.dataTransfer.files.length) {
66
  const file = e.dataTransfer.files[0];
67
+ const dataTransfer = new DataTransfer();
68
+ dataTransfer.items.add(file);
69
 
70
+ const isSummarizeMode = document.querySelector('input[name="option"]:checked').value === 'Summarize';
71
+ if (isSummarizeMode) {
72
+ fileUpload.files = dataTransfer.files;
73
+ } else {
74
+ imageUpload.files = dataTransfer.files;
75
+ }
76
+ selectedFile = file;
77
+ displayFilePreview(file);
78
+ }
79
+ });
80
+
81
+ // Send button handlers
82
+ sendButtons.forEach(button => {
83
+ button.addEventListener('click', async () => {
84
+ const isSummarizeMode = document.querySelector('input[name="option"]:checked').value === 'Summarize';
85
  if (isSummarizeMode) {
 
86
  await handleSummarize();
87
  } else {
 
88
  await handleCaption();
89
  }
90
+ });
91
  });
92
 
93
+ function displayFilePreview(file) {
94
+ if (filePreviewBubble) filePreviewBubble.remove();
95
+
96
+ filePreviewBubble = createMessageBubble(
97
+ `📎 Selected ${file.type.startsWith('image/') ? 'image' : 'document'}: ${file.name}`,
98
+ "You"
99
+ );
100
  }
101
 
102
+ function createMessageBubble(text, sender = "You", audioSrc = null) {
103
+ const bubble = document.createElement('div');
104
+ bubble.className = `bubble ${sender === "You" ? "right" : "left"}`;
105
 
106
+ const label = document.createElement('div');
107
+ label.className = "label";
108
+ label.textContent = sender;
 
109
 
110
+ const message = document.createElement('div');
111
+ message.className = "text";
112
+
113
+ if (sender === "You") {
114
+ message.textContent = text;
115
+ } else {
116
+ message.innerHTML = typeof text === 'string' ? text : 'Processing...';
117
+
118
+ if (audioSrc) {
119
+ const audioContainer = document.createElement('div');
120
+ audioContainer.style.display = 'flex';
121
+ audioContainer.style.alignItems = 'center';
122
+ audioContainer.style.gap = '10px';
123
+ audioContainer.style.marginTop = '8px';
124
+
125
+ const audio = new Audio(audioSrc);
126
+ const audioIcon = document.createElement('i');
127
+ audioIcon.className = 'fa-solid fa-volume-high audio-toggle';
128
+ audioIcon.style.cursor = 'pointer';
129
+
130
+ audioIcon.addEventListener('click', () => {
131
+ if (audio.paused) {
132
+ audio.play();
133
+ audioIcon.classList.replace('fa-volume-xmark', 'fa-volume-high');
134
+ audioIcon.title = "Click to mute";
135
+ } else {
136
+ audio.pause();
137
+ audioIcon.classList.replace('fa-volume-high', 'fa-volume-xmark');
138
+ audioIcon.title = "Click to unmute";
139
+ }
140
+ });
141
+
142
+ audioContainer.appendChild(audioIcon);
143
+ audioContainer.appendChild(document.createTextNode('Listen'));
144
+ message.appendChild(audioContainer);
145
+ }
146
+ }
147
 
148
+ bubble.appendChild(label);
149
+ bubble.appendChild(message);
150
+ convo.appendChild(bubble);
151
+ convo.scrollTop = convo.scrollHeight;
152
+ return bubble;
153
  }
154
+
155
+ async function handleSummarize() {
156
+ if (!selectedFile) {
157
+ alert("Please upload a document first");
 
158
  return;
159
  }
 
 
 
 
160
 
161
+ const length = document.querySelector('input[name="optionS"]:checked')?.value || "medium";
162
+ const thinkingBubble = createMessageBubble(
163
+ "Analyzing your document... <div class='loader'></div>",
164
+ "Aidan"
165
+ );
166
 
167
+ try {
168
+ const formData = new FormData();
169
+ formData.append('file', selectedFile);
170
+ formData.append('length', length);
 
171
 
172
+ const response = await fetch('/summarize/', {
173
+ method: 'POST',
174
+ body: formData
175
+ });
176
 
177
+ if (!response.ok) {
178
+ const error = await response.json();
179
+ throw new Error(error.detail || 'Summarization failed');
180
+ }
 
181
 
182
+ const result = await response.json();
183
+ thinkingBubble.remove();
 
 
 
184
 
185
+ createMessageBubble(
186
+ `<strong>Summary:</strong><br><br>${result.summary.replace(/\n/g, '<br>')}
187
+ ${result.audio_url ? `<br><br><audio controls src="${result.audio_url}"></audio>` : ''}
188
+ ${result.pdf_url ? `<br><a href="${result.pdf_url}" download class="download-link">📄 Download PDF</a>` : ''}`,
189
+ "Aidan",
190
+ result.audio_url
191
+ );
192
+ } catch (error) {
193
+ thinkingBubble.remove();
194
+ createMessageBubble(`⚠️ Error: ${error.message}`, "Aidan");
195
+ } finally {
196
+ resetFileInputs();
197
+ }
198
  }
 
 
 
 
 
 
 
 
 
199
 
200
+ async function handleCaption() {
201
+ if (!selectedFile) {
202
+ alert("Please upload an image first");
203
+ return;
204
  }
205
 
206
+ const thinkingBubble = createMessageBubble(
207
+ "Generating caption... <div class='loader'></div>",
208
+ "Aidan"
209
+ );
 
 
 
 
 
 
 
 
 
210
 
211
+ try {
212
+ const formData = new FormData();
213
+ formData.append('file', selectedFile);
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
+ const response = await fetch('/imagecaption/', {
216
+ method: 'POST',
217
+ body: formData
218
+ });
 
 
219
 
220
+ if (!response.ok) {
221
+ const error = await response.json();
222
+ throw new Error(error.detail || 'Captioning failed');
223
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
 
225
+ const result = await response.json();
226
+ thinkingBubble.remove();
227
 
228
+ createMessageBubble(
229
+ `<strong>Caption:</strong><br><br>${result.answer || result.caption}
230
+ ${result.audio ? `<br><audio controls src="${result.audio}"></audio>` : ''}`,
231
+ "Aidan",
232
+ result.audio
233
+ );
234
+ } catch (error) {
235
+ thinkingBubble.remove();
236
+ createMessageBubble(`⚠️ Error: ${error.message}`, "Aidan");
237
+ } finally {
238
+ resetFileInputs();
239
+ }
240
  }
241
 
242
+ function resetFileInputs() {
243
+ selectedFile = null;
244
+ fileUpload.value = '';
245
+ imageUpload.value = '';
246
+ if (filePreviewBubble) {
247
+ filePreviewBubble.remove();
248
+ filePreviewBubble = null;
249
+ }
 
 
 
250
  }
251
 
252
+ // Add loader CSS
253
  const style = document.createElement('style');
254
  style.textContent = `
255
  .loader {
256
+ display: inline-block;
257
  border: 2px solid #f3f3f3;
258
  border-top: 2px solid #3b82f6;
259
  border-radius: 50%;
 
277
  .download-link:hover {
278
  background: #2563eb;
279
  }
280
+ .audio-toggle {
281
+ cursor: pointer;
282
+ transition: all 0.2s;
283
+ }
284
  `;
285
  document.head.appendChild(style);
286
+ });