Reality123b commited on
Commit
c5ff57a
·
verified ·
1 Parent(s): 2f05038

Update application/static/js/components/uiManager.js

Browse files
application/static/js/components/uiManager.js CHANGED
@@ -1,3 +1,4 @@
 
1
  import Initialize from "./initialize.js";
2
  import Chat from "./chat.js";
3
  import RenderSymbols from "./renderSymbols.js";
@@ -10,7 +11,7 @@ class UIManager{
10
  this.hamburger = document.getElementById('hamburger');
11
  this.messagesDiv = document.getElementById('messages');
12
  this.container = document.getElementById('container')
13
- this.prevChatsCont = document.getElementById('prevChatsCont');
14
  this.textBox = document.getElementById('textBox');
15
  this.sendBtn = document.getElementById('sendBtn');
16
  this.newChat = document.getElementById('newChat');
@@ -24,6 +25,32 @@ class UIManager{
24
  this.userP;
25
  this.imageMode = false;
26
  this.dialog = null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  }
28
  async run(){
29
  await this.initializer.initialize();
@@ -35,11 +62,10 @@ class UIManager{
35
  this.send();
36
  })
37
  window.addEventListener('keydown',(e)=>{
38
- if (e.key === '/' && document.activeElement === this.textBox) {
39
  e.preventDefault();
40
  this.showDialog();
41
  }
42
-
43
  if(e.key=='Enter' && !this.sendBtn.disabled){
44
  this.send();
45
  }
@@ -54,14 +80,14 @@ class UIManager{
54
  this.webSearchBtn.style.color = 'rgba(30,30,250,0.8)';
55
  }
56
  this.webSearch = !this.webSearch;
57
-
58
  })
59
  document.getElementById('closeAlert').onclick = ()=>{
60
  document.getElementById('alert').style.display = 'none'
61
  }
62
  }
63
 
64
- showDialog() {
65
  if (this.dialog) {
66
  this.dialog.remove();
67
  this.dialog = null;
@@ -98,29 +124,22 @@ class UIManager{
98
  });
99
  }
100
 
101
-
102
-
103
  async send(){
104
- let promptText = this.textBox.value;
105
- let imageBase64 = null;
106
-
107
- if (this.imageMode) {
108
  const file = await this.getImageFile();
109
  if (file) {
110
  imageBase64 = await this.getBase64(file);
111
  }
112
  promptText = promptText.replace(/^\/image\s*/, '');
113
- this.imageMode = false;
114
  }
115
-
116
- this.appendUserMsg(promptText, imageBase64);
117
  this.appendAiMsg();
118
-
119
-
120
  await this.chat.chat();
121
  }
122
 
123
-
124
  async getImageFile() {
125
  return new Promise(resolve => {
126
  const input = document.createElement('input');
@@ -133,8 +152,7 @@ class UIManager{
133
  input.click();
134
  });
135
  }
136
-
137
- async getBase64(file) {
138
  return new Promise((resolve, reject) => {
139
  const reader = new FileReader();
140
  reader.readAsDataURL(file);
@@ -142,6 +160,44 @@ class UIManager{
142
  reader.onerror = error => reject(error);
143
  });
144
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
 
147
  appendUserMsg(msg=false, imageBase64 = null){
@@ -198,5 +254,57 @@ class UIManager{
198
  this.initializer.reInitialize(prevChat.id);
199
  })
200
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  }
202
  export default UIManager
 
1
+ // application/static/js/uiManager.js
2
  import Initialize from "./initialize.js";
3
  import Chat from "./chat.js";
4
  import RenderSymbols from "./renderSymbols.js";
 
11
  this.hamburger = document.getElementById('hamburger');
12
  this.messagesDiv = document.getElementById('messages');
13
  this.container = document.getElementById('container')
14
+ this.prevChatsCont = document.getElementById('prevChatsCont');
15
  this.textBox = document.getElementById('textBox');
16
  this.sendBtn = document.getElementById('sendBtn');
17
  this.newChat = document.getElementById('newChat');
 
25
  this.userP;
26
  this.imageMode = false;
27
  this.dialog = null;
28
+
29
+ // Add the image input element (hidden)
30
+ this.imageInput = document.createElement('input');
31
+ this.imageInput.type = 'file';
32
+ this.imageInput.id = 'imageInput';
33
+ this.imageInput.accept = 'image/*';
34
+ this.imageInput.style.display = 'none';
35
+ document.body.appendChild(this.imageInput); // Append to body
36
+
37
+ // Add the paperclip icon (label for the input)
38
+ this.imageUploadLabel = document.createElement('label');
39
+ this.imageUploadLabel.htmlFor = 'imageInput'; // Connect label to input
40
+ this.imageUploadLabel.className = 'image-upload-label';
41
+ this.imageUploadLabel.innerHTML = '<i class="fas fa-paperclip"></i>'; // FontAwesome icon
42
+ this.textBox.parentNode.insertBefore(this.imageUploadLabel, this.textBox);
43
+
44
+ // Event listener for the paperclip icon (image upload)
45
+ this.imageUploadLabel.addEventListener('click', () => {
46
+ this.imageInput.click(); // Trigger the file input
47
+ });
48
+
49
+ this.imageInput.addEventListener('change', () => {
50
+ this.handleImageUpload();
51
+ });
52
+
53
+
54
  }
55
  async run(){
56
  await this.initializer.initialize();
 
62
  this.send();
63
  })
64
  window.addEventListener('keydown',(e)=>{
65
+ if (e.key === '/' && document.activeElement === this.textBox) {
66
  e.preventDefault();
67
  this.showDialog();
68
  }
 
69
  if(e.key=='Enter' && !this.sendBtn.disabled){
70
  this.send();
71
  }
 
80
  this.webSearchBtn.style.color = 'rgba(30,30,250,0.8)';
81
  }
82
  this.webSearch = !this.webSearch;
83
+
84
  })
85
  document.getElementById('closeAlert').onclick = ()=>{
86
  document.getElementById('alert').style.display = 'none'
87
  }
88
  }
89
 
90
+ showDialog() {
91
  if (this.dialog) {
92
  this.dialog.remove();
93
  this.dialog = null;
 
124
  });
125
  }
126
 
 
 
127
  async send(){
128
+ let promptText = this.textBox.value;
129
+ let imageBase64 = null;
130
+ if (this.imageMode) {
 
131
  const file = await this.getImageFile();
132
  if (file) {
133
  imageBase64 = await this.getBase64(file);
134
  }
135
  promptText = promptText.replace(/^\/image\s*/, '');
136
+ this.imageMode = false; // Reset image mode after processing
137
  }
138
+ this.appendUserMsg(promptText, imageBase64); // Pass image data
 
139
  this.appendAiMsg();
 
 
140
  await this.chat.chat();
141
  }
142
 
 
143
  async getImageFile() {
144
  return new Promise(resolve => {
145
  const input = document.createElement('input');
 
152
  input.click();
153
  });
154
  }
155
+ async getBase64(file) {
 
156
  return new Promise((resolve, reject) => {
157
  const reader = new FileReader();
158
  reader.readAsDataURL(file);
 
160
  reader.onerror = error => reject(error);
161
  });
162
  }
163
+ async handleImageUpload() {
164
+ const file = this.imageInput.files[0];
165
+ if (!file) return;
166
+
167
+ this.imageMode = true; // Set image mode
168
+
169
+ const reader = new FileReader();
170
+ reader.onload = (e) => {
171
+ // Display image preview
172
+ if (this.userDiv) {
173
+ const imgPreview = document.createElement('img');
174
+ imgPreview.src = e.target.result;
175
+ imgPreview.className = 'uploaded-image-preview';
176
+ this.userDiv.appendChild(imgPreview); // Add to current userDiv
177
+ }
178
+
179
+ // Generate and display caption
180
+ this.generateAndDisplayCaption(e.target.result);
181
+
182
+
183
+ }
184
+ reader.readAsDataURL(file);
185
+ this.imageInput.value = ''; // Clear the input
186
+ }
187
+
188
+ async generateAndDisplayCaption(imageData) {
189
+ try {
190
+ const caption = await this.initializer.image_captioning.generate_caption(imageData);
191
+ if (this.userDiv) { // Check if userDiv exists.
192
+ const captionElement = document.createElement('div');
193
+ captionElement.className = 'image-caption';
194
+ captionElement.textContent = `Caption: ${caption}`;
195
+ this.userDiv.appendChild(captionElement);
196
+ }
197
+ } catch (error) {
198
+ console.error("Error generating caption:", error);
199
+ }
200
+ }
201
 
202
 
203
  appendUserMsg(msg=false, imageBase64 = null){
 
254
  this.initializer.reInitialize(prevChat.id);
255
  })
256
  }
257
+
258
+ addReadAloudButton(parentDiv) {
259
+ const btn = document.createElement('button');
260
+ btn.className = 'read-aloud-btn';
261
+ btn.innerHTML = '<i class="fas fa-volume-up"></i>'; // FontAwesome icon
262
+ btn.addEventListener('click', () => {
263
+ this.speakText(parentDiv.querySelector('p').innerText);
264
+ });
265
+ parentDiv.appendChild(btn);
266
+ }
267
+
268
+
269
+ async speakText(text) {
270
+ try {
271
+ const response = await fetch(`/tts?text=${encodeURIComponent(text)}`);
272
+ if (!response.ok) {
273
+ console.error("TTS request failed:", response.status, response.statusText);
274
+ return;
275
+ }
276
+ const audioBlob = await response.blob();
277
+ const audioUrl = URL.createObjectURL(audioBlob);
278
+ const audio = new Audio(audioUrl);
279
+ audio.play();
280
+ } catch (error) {
281
+ console.error("Error during TTS:", error);
282
+ }
283
+ }
284
+
285
+ displayMemory(memoryText) {
286
+ let memoryDisplay = document.querySelector('.memory-display');
287
+ if (!memoryDisplay) {
288
+ memoryDisplay = document.createElement('div');
289
+ memoryDisplay.className = 'memory-display';
290
+ this.messagesDiv.parentNode.insertBefore(memoryDisplay, this.messagesDiv); //show above messages
291
+ }
292
+ memoryDisplay.textContent = `Memory: ${memoryText}`;
293
+ }
294
+ showReasoning() {
295
+ const reasoningDisplay = document.createElement('div');
296
+ reasoningDisplay.className = 'reasoning-display';
297
+ reasoningDisplay.textContent = 'Reasoning...';
298
+ reasoningDisplay.dataset.startTime = Date.now(); // Store start time
299
+ this.messagesDiv.appendChild(reasoningDisplay); // Add to messages
300
+ return reasoningDisplay;
301
+ }
302
+
303
+ updateReasoningTime(reasoningDisplay) {
304
+ const endTime = Date.now();
305
+ const startTime = parseInt(reasoningDisplay.dataset.startTime, 10);
306
+ const duration = (endTime - startTime) / 1000; // in seconds
307
+ reasoningDisplay.textContent = `Reasoning... (${duration.toFixed(2)}s)`;
308
+ }
309
  }
310
  export default UIManager