Docfile commited on
Commit
ff4e0c9
·
verified ·
1 Parent(s): da94c69

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +78 -26
templates/index.html CHANGED
@@ -12,7 +12,6 @@
12
  <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🤖</text></svg>">
13
 
14
  <style>
15
- /* Assurer la hauteur minimale et permettre le scroll de la page sur mobile */
16
  html, body {
17
  min-height: 100vh;
18
  margin: 0;
@@ -34,7 +33,6 @@
34
  overflow-y: auto;
35
  min-height: 0;
36
  }
37
- /* Styles de la scrollbar */
38
  ::-webkit-scrollbar {
39
  width: 8px;
40
  }
@@ -88,13 +86,40 @@
88
  color: #1d4ed8;
89
  text-decoration-color: #60a5fa;
90
  }
91
- /* Chargement initial de l'historique */
92
  #history-loading {
93
  padding: 20px;
94
  text-align: center;
95
  color: #6b7280;
96
  font-style: italic;
97
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  </style>
99
  </head>
100
  <body class="bg-gray-100 flex flex-col min-h-screen">
@@ -138,7 +163,7 @@
138
  <p id="error-text">Le message d'erreur détaillé ira ici.</p>
139
  </div>
140
 
141
- <!-- Barre d'options et d'upload -->
142
  <div class="bg-gray-50 border-t border-gray-200 px-4 py-2 flex-shrink-0">
143
  <div class="flex items-center justify-between text-sm">
144
  <label for="web_search_toggle" class="flex items-center space-x-2 cursor-pointer text-gray-600 hover:text-gray-800 select-none" title="Activer/Désactiver la recherche web pour le prochain message">
@@ -162,6 +187,8 @@
162
  </button>
163
  </div>
164
  </div>
 
 
165
  </div>
166
 
167
  <!-- Formulaire d'entrée du message -->
@@ -180,7 +207,6 @@
180
  <!-- Script JavaScript pour l'interaction -->
181
  <script>
182
  document.addEventListener('DOMContentLoaded', () => {
183
- // Références aux éléments du DOM
184
  const chatForm = document.getElementById('chat-form');
185
  const promptInput = document.getElementById('prompt');
186
  const chatMessages = document.getElementById('chat-messages');
@@ -192,10 +218,10 @@
192
  const fileUpload = document.getElementById('file_upload');
193
  const fileNameSpan = document.getElementById('file-name');
194
  const clearFileButton = document.getElementById('clear-file');
 
195
  const sendButton = document.getElementById('send-button');
196
  const clearForm = document.getElementById('clear-form');
197
 
198
- // Endpoints de l'API Backend
199
  const API_CHAT_ENDPOINT = '/api/chat';
200
  const API_HISTORY_ENDPOINT = '/api/history';
201
  const CLEAR_ENDPOINT = '/clear';
@@ -230,7 +256,7 @@
230
  function addMessageToChat(role, text, isHtml = false) {
231
  errorMessageDiv.style.display = 'none';
232
  const messageWrapper = document.createElement('div');
233
- messageWrapper.classList.add('flex', role === 'user' ? 'justify-end' : 'justify-start', 'mb-4');
234
 
235
  const bubbleDiv = document.createElement('div');
236
  bubbleDiv.classList.add('p-3', 'rounded-lg', 'max-w-[85%]', 'sm:max-w-[75%]', 'shadow-md', 'relative');
@@ -251,11 +277,38 @@
251
  proseDiv.textContent = text;
252
  }
253
  bubbleDiv.appendChild(proseDiv);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
  }
255
 
256
  messageWrapper.appendChild(bubbleDiv);
257
  chatMessages.insertBefore(messageWrapper, loadingIndicator);
258
-
259
  if (historyLoadingIndicator.parentNode !== chatMessages) {
260
  scrollToBottom();
261
  }
@@ -308,6 +361,7 @@
308
  fileNameSpan.textContent = '';
309
  fileNameSpan.title = '';
310
  clearFileButton.style.display = 'none';
 
311
  }
312
 
313
  fileUpload.addEventListener('change', () => {
@@ -317,6 +371,16 @@
317
  fileNameSpan.textContent = name.length > 20 ? name.substring(0, 17) + '...' : name;
318
  fileNameSpan.title = name;
319
  clearFileButton.style.display = 'inline-block';
 
 
 
 
 
 
 
 
 
 
320
  } else {
321
  clearFileInput();
322
  }
@@ -331,31 +395,26 @@
331
  const prompt = promptInput.value.trim();
332
  const file = fileUpload.files[0];
333
  const useWebSearch = webSearchToggle.checked;
334
-
335
  if (!prompt && !file) {
336
  displayError("Veuillez entrer un message ou sélectionner un fichier.");
337
  promptInput.focus();
338
  return;
339
  }
340
-
341
  errorMessageDiv.style.display = 'none';
342
  let userMessageText = prompt;
343
  if (file) {
344
  userMessageText = prompt ? `[${file.name}] ${prompt}` : `[${file.name}]`;
345
  }
346
  addMessageToChat('user', userMessageText);
347
-
348
  const formData = new FormData();
349
  formData.append('prompt', prompt);
350
  formData.append('web_search', useWebSearch);
351
  if (file) {
352
  formData.append('file', file);
353
  }
354
-
355
  showLoading(true);
356
  promptInput.value = '';
357
  clearFileInput();
358
-
359
  try {
360
  const response = await fetch(API_CHAT_ENDPOINT, {
361
  method: 'POST',
@@ -385,20 +444,13 @@
385
  e.target.querySelector('button').textContent = '...';
386
  e.target.querySelector('button').disabled = true;
387
  try {
388
-
389
-
390
-
391
- const response = await fetch(CLEAR_ENDPOINT, {
392
- method: 'POST',
393
- headers: {
394
- 'X-Requested-With': 'XMLHttpRequest'
395
- }
396
- });
397
  const data = await response.json();
398
-
399
-
400
-
401
-
402
  if (response.ok && data.success) {
403
  chatMessages.innerHTML = '';
404
  chatMessages.appendChild(loadingIndicator);
 
12
  <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🤖</text></svg>">
13
 
14
  <style>
 
15
  html, body {
16
  min-height: 100vh;
17
  margin: 0;
 
33
  overflow-y: auto;
34
  min-height: 0;
35
  }
 
36
  ::-webkit-scrollbar {
37
  width: 8px;
38
  }
 
86
  color: #1d4ed8;
87
  text-decoration-color: #60a5fa;
88
  }
 
89
  #history-loading {
90
  padding: 20px;
91
  text-align: center;
92
  color: #6b7280;
93
  font-style: italic;
94
  }
95
+ /* Zone de prévisualisation des images */
96
+ #file-preview {
97
+ margin-top: 8px;
98
+ }
99
+ #file-preview img {
100
+ max-width: 100%;
101
+ max-height: 150px;
102
+ border: 1px solid #ddd;
103
+ border-radius: 4px;
104
+ padding: 4px;
105
+ }
106
+ /* Bouton de copie (positionné en haut à droite de la bulle de réponse) */
107
+ .copy-btn {
108
+ position: absolute;
109
+ top: 4px;
110
+ right: 4px;
111
+ background: rgba(255, 255, 255, 0.8);
112
+ border: none;
113
+ border-radius: 4px;
114
+ padding: 2px 4px;
115
+ cursor: pointer;
116
+ font-size: 0.75rem;
117
+ display: none;
118
+ }
119
+ /* Afficher le bouton au survol de la bulle */
120
+ .message-wrapper:hover .copy-btn {
121
+ display: block;
122
+ }
123
  </style>
124
  </head>
125
  <body class="bg-gray-100 flex flex-col min-h-screen">
 
163
  <p id="error-text">Le message d'erreur détaillé ira ici.</p>
164
  </div>
165
 
166
+ <!-- Barre d'options, d'upload et de prévisualisation -->
167
  <div class="bg-gray-50 border-t border-gray-200 px-4 py-2 flex-shrink-0">
168
  <div class="flex items-center justify-between text-sm">
169
  <label for="web_search_toggle" class="flex items-center space-x-2 cursor-pointer text-gray-600 hover:text-gray-800 select-none" title="Activer/Désactiver la recherche web pour le prochain message">
 
187
  </button>
188
  </div>
189
  </div>
190
+ <!-- Zone de prévisualisation des images -->
191
+ <div id="file-preview"></div>
192
  </div>
193
 
194
  <!-- Formulaire d'entrée du message -->
 
207
  <!-- Script JavaScript pour l'interaction -->
208
  <script>
209
  document.addEventListener('DOMContentLoaded', () => {
 
210
  const chatForm = document.getElementById('chat-form');
211
  const promptInput = document.getElementById('prompt');
212
  const chatMessages = document.getElementById('chat-messages');
 
218
  const fileUpload = document.getElementById('file_upload');
219
  const fileNameSpan = document.getElementById('file-name');
220
  const clearFileButton = document.getElementById('clear-file');
221
+ const filePreview = document.getElementById('file-preview');
222
  const sendButton = document.getElementById('send-button');
223
  const clearForm = document.getElementById('clear-form');
224
 
 
225
  const API_CHAT_ENDPOINT = '/api/chat';
226
  const API_HISTORY_ENDPOINT = '/api/history';
227
  const CLEAR_ENDPOINT = '/clear';
 
256
  function addMessageToChat(role, text, isHtml = false) {
257
  errorMessageDiv.style.display = 'none';
258
  const messageWrapper = document.createElement('div');
259
+ messageWrapper.classList.add('message-wrapper', 'flex', role === 'user' ? 'justify-end' : 'justify-start', 'mb-4');
260
 
261
  const bubbleDiv = document.createElement('div');
262
  bubbleDiv.classList.add('p-3', 'rounded-lg', 'max-w-[85%]', 'sm:max-w-[75%]', 'shadow-md', 'relative');
 
277
  proseDiv.textContent = text;
278
  }
279
  bubbleDiv.appendChild(proseDiv);
280
+
281
+ // Ajout du bouton de copie
282
+ const copyBtn = document.createElement('button');
283
+ copyBtn.textContent = 'Copier';
284
+ copyBtn.classList.add('copy-btn');
285
+ copyBtn.title = "Copier la réponse";
286
+ copyBtn.addEventListener('click', (e) => {
287
+ e.stopPropagation();
288
+ e.preventDefault();
289
+ // Copier le texte sans le bouton
290
+ let textToCopy = '';
291
+ if (isHtml) {
292
+ textToCopy = proseDiv.innerText;
293
+ } else {
294
+ textToCopy = text;
295
+ }
296
+ navigator.clipboard.writeText(textToCopy)
297
+ .then(() => {
298
+ copyBtn.textContent = 'Copié';
299
+ setTimeout(() => {
300
+ copyBtn.textContent = 'Copier';
301
+ }, 2000);
302
+ })
303
+ .catch(err => {
304
+ console.error('Erreur lors de la copie :', err);
305
+ });
306
+ });
307
+ bubbleDiv.appendChild(copyBtn);
308
  }
309
 
310
  messageWrapper.appendChild(bubbleDiv);
311
  chatMessages.insertBefore(messageWrapper, loadingIndicator);
 
312
  if (historyLoadingIndicator.parentNode !== chatMessages) {
313
  scrollToBottom();
314
  }
 
361
  fileNameSpan.textContent = '';
362
  fileNameSpan.title = '';
363
  clearFileButton.style.display = 'none';
364
+ filePreview.innerHTML = '';
365
  }
366
 
367
  fileUpload.addEventListener('change', () => {
 
371
  fileNameSpan.textContent = name.length > 20 ? name.substring(0, 17) + '...' : name;
372
  fileNameSpan.title = name;
373
  clearFileButton.style.display = 'inline-block';
374
+ // Si le fichier est une image, afficher la prévisualisation
375
+ if (file.type.startsWith('image/')) {
376
+ const reader = new FileReader();
377
+ reader.onload = (e) => {
378
+ filePreview.innerHTML = `<img src="${e.target.result}" alt="Prévisualisation de l'image">`;
379
+ };
380
+ reader.readAsDataURL(file);
381
+ } else {
382
+ filePreview.innerHTML = '';
383
+ }
384
  } else {
385
  clearFileInput();
386
  }
 
395
  const prompt = promptInput.value.trim();
396
  const file = fileUpload.files[0];
397
  const useWebSearch = webSearchToggle.checked;
 
398
  if (!prompt && !file) {
399
  displayError("Veuillez entrer un message ou sélectionner un fichier.");
400
  promptInput.focus();
401
  return;
402
  }
 
403
  errorMessageDiv.style.display = 'none';
404
  let userMessageText = prompt;
405
  if (file) {
406
  userMessageText = prompt ? `[${file.name}] ${prompt}` : `[${file.name}]`;
407
  }
408
  addMessageToChat('user', userMessageText);
 
409
  const formData = new FormData();
410
  formData.append('prompt', prompt);
411
  formData.append('web_search', useWebSearch);
412
  if (file) {
413
  formData.append('file', file);
414
  }
 
415
  showLoading(true);
416
  promptInput.value = '';
417
  clearFileInput();
 
418
  try {
419
  const response = await fetch(API_CHAT_ENDPOINT, {
420
  method: 'POST',
 
444
  e.target.querySelector('button').textContent = '...';
445
  e.target.querySelector('button').disabled = true;
446
  try {
447
+ const response = await fetch(CLEAR_ENDPOINT, {
448
+ method: 'POST',
449
+ headers: {
450
+ 'X-Requested-With': 'XMLHttpRequest'
451
+ }
452
+ });
 
 
 
453
  const data = await response.json();
 
 
 
 
454
  if (response.ok && data.success) {
455
  chatMessages.innerHTML = '';
456
  chatMessages.appendChild(loadingIndicator);