Docfile commited on
Commit
2c305d8
·
verified ·
1 Parent(s): d38dba1

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +29 -100
templates/index.html CHANGED
@@ -3,8 +3,7 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>AI Assistant - Flat Black & White</title>
7
- <script src="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css"></script>
8
  <script src="https://cdn.tailwindcss.com"></script>
9
  <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.3.0/marked.min.js"></script>
10
  <script>
@@ -26,47 +25,25 @@
26
  </script>
27
  <style>
28
  /* Configuration Marked pour le markdown */
29
- .markdown-content {
30
- @apply text-dark-text leading-relaxed;
31
- }
32
- .markdown-content h1, .markdown-content h2, .markdown-content h3 {
33
- @apply font-bold mb-2 mt-4;
34
- }
35
  .markdown-content h1 { @apply text-xl; }
36
  .markdown-content h2 { @apply text-lg; }
37
  .markdown-content h3 { @apply text-base; }
38
  .markdown-content p { @apply mb-2; }
39
- .markdown-content ul, .markdown-content ol {
40
- @apply ml-4 mb-2;
41
- }
42
  .markdown-content li { @apply mb-1; }
43
- .markdown-content code {
44
- @apply bg-gray-700 px-2 py-1 rounded text-sm font-mono;
45
- }
46
- .markdown-content pre {
47
- @apply bg-gray-800 p-4 rounded-lg overflow-x-auto mb-4;
48
- }
49
- .markdown-content pre code {
50
- @apply bg-transparent p-0;
51
- }
52
- .markdown-content blockquote {
53
- @apply border-l-4 border-gray-600 pl-4 italic text-gray-300 mb-4;
54
- }
55
  .markdown-content strong { @apply font-semibold; }
56
  .markdown-content em { @apply italic; }
57
- .markdown-content a {
58
- @apply text-blue-400 hover:text-blue-300 underline;
59
- }
60
 
61
  /* Animations et styles personnalisés */
62
- @keyframes typing {
63
- 0%, 60%, 100% { transform: scale(0.8); opacity: 0.5; }
64
- 30% { transform: scale(1.2); opacity: 1; }
65
- }
66
- @keyframes fadeIn {
67
- from { opacity: 0; transform: translateY(10px); }
68
- to { opacity: 1; transform: translateY(0); }
69
- }
70
  .animate-typing { animation: typing 1.4s infinite ease-in-out; }
71
  .animate-fade-in { animation: fadeIn 0.3s ease; }
72
 
@@ -77,40 +54,23 @@
77
  .custom-scrollbar::-webkit-scrollbar-thumb:hover { background: #777; }
78
 
79
  /* Style pour les pensées déroulantes */
80
- .thoughts-toggle:checked + .thoughts-content {
81
- max-height: 1000px;
82
- opacity: 1;
83
- }
84
- .thoughts-content {
85
- max-height: 0;
86
- opacity: 0;
87
- overflow: hidden;
88
- transition: max-height 0.3s ease, opacity 0.3s ease;
89
- }
90
  </style>
91
  </head>
92
  <body class="bg-dark-bg text-dark-text min-h-screen flex justify-center items-center p-0 md:p-5">
93
  <div class="w-full max-w-4xl h-screen md:h-[90vh] bg-dark-card flex flex-col overflow-hidden md:rounded-xl md:border md:border-dark-border">
94
- <!-- Header -->
95
- <div class="bg-dark-card text-white p-5 text-center border-b border-dark-border flex-shrink-0">
96
- <h1 class="text-xl font-semibold mb-1">Mariam AI Assistant</h1>
97
- <p class="text-sm text-dark-muted">❤️</p>
98
- <div class="flex justify-center items-center gap-5 mt-4">
99
- <div class="flex items-center gap-3 text-sm text-gray-300">
100
- <span>Réflexion Mode:</span>
101
- <label class="relative inline-block w-12 h-7">
102
- <input type="checkbox" id="thinkingToggle" checked class="opacity-0 w-0 h-0">
103
- <span class="absolute cursor-pointer top-0 left-0 right-0 bottom-0 bg-gray-600 transition-all duration-200 rounded-full before:absolute before:content-[''] before:h-5 before:w-5 before:left-1 before:bottom-1 before:bg-white before:transition-all before:duration-200 before:rounded-full checked:bg-gray-500 checked:before:translate-x-5"></span>
104
- </label>
105
- </div>
106
- <button class="bg-transparent border border-gray-600 text-gray-300 px-4 py-2 rounded-full text-sm hover:bg-gray-700 transition-colors" onclick="resetConversation()">
107
- 🔄 Reset
108
- </button>
109
- </div>
110
- </div>
111
 
112
  <!-- Messages -->
113
- <div class="flex-1 overflow-y-auto p-4 md:p-6 flex flex-col gap-4 custom-scrollbar" id="messages">
114
  <div class="max-w-[85%] p-4 rounded-2xl bg-dark-elevated text-gray-200 self-start rounded-bl-sm animate-fade-in">
115
  <div class="markdown-content">👋 Bonjour, sur quoi allons-nous travailler aujourd'hui ?</div>
116
  </div>
@@ -155,7 +115,6 @@
155
  let currentFiles = [];
156
  let conversationId = 'session_' + Date.now();
157
 
158
- // Configuration de marked pour le markdown
159
  marked.setOptions({
160
  breaks: true,
161
  gfm: true
@@ -185,7 +144,6 @@
185
  const formData = new FormData();
186
  formData.append('file', file);
187
 
188
- // Show immediate preview for images
189
  if (file.type.startsWith('image/')) {
190
  const reader = new FileReader();
191
  reader.onload = function(e) {
@@ -266,7 +224,8 @@
266
  messageInput.value = '';
267
  autoResize(messageInput);
268
 
269
- const thinkingEnabled = document.getElementById('thinkingToggle').checked;
 
270
  const endpoint = currentFiles.length > 0 ? '/chat_with_file' : '/chat';
271
  const payload = {
272
  message: message || 'Analyse ces fichiers',
@@ -299,9 +258,7 @@
299
 
300
  function processStream() {
301
  return reader.read().then(({ done, value }) => {
302
- if (done) {
303
- return;
304
- }
305
 
306
  buffer += decoder.decode(value, { stream: true });
307
  const lines = buffer.split('\n');
@@ -311,41 +268,28 @@
311
  if (line.startsWith('data: ')) {
312
  try {
313
  const data = JSON.parse(line.substring(6));
314
- console.log('Received data:', data);
315
 
316
  if (data.type === 'text') {
317
- console.log('Processing text:', data.content);
318
  messageContent += data.content;
319
  if (!messageElement) {
320
  messageElement = addMessage('assistant', '');
321
- console.log('Created message element:', messageElement);
322
  }
323
- // Rendu markdown en temps réel
324
  const markdownHtml = marked.parse(messageContent);
325
  const markdownElement = messageElement.querySelector('.markdown-content');
326
  if (markdownElement) {
327
  markdownElement.innerHTML = markdownHtml;
328
- console.log('Updated markdown content to:', markdownHtml);
329
- // Forcer un re-render
330
  markdownElement.style.display = 'block';
331
- } else {
332
- console.error('No .markdown-content element found');
333
- console.log('Message element HTML:', messageElement.innerHTML);
334
  }
335
  } else if (data.type === 'thought' && thinkingEnabled) {
336
- console.log('Processing thought:', data.content);
337
  thoughtsContent += data.content;
338
  if (!thoughtsContainer) {
339
  thoughtsContainer = addThoughtsContainer();
340
  }
341
- // Rendu markdown des pensées
342
  const thoughtsHtml = marked.parse(thoughtsContent);
343
  thoughtsContainer.querySelector('.thoughts-content .markdown-content').innerHTML = thoughtsHtml;
344
  } else if (data.type === 'error') {
345
- console.log('Received error:', data.content);
346
  showError(data.content);
347
  } else if (data.type === 'end') {
348
- console.log('Stream ended');
349
  typingIndicator.classList.add('hidden');
350
  typingIndicator.classList.remove('flex');
351
  messageInput.disabled = false;
@@ -353,8 +297,6 @@
353
  messageInput.focus();
354
  removeFile();
355
  return;
356
- } else {
357
- console.log('Unknown data type:', data.type);
358
  }
359
 
360
  const messagesContainer = document.getElementById('messages');
@@ -381,10 +323,8 @@
381
  }
382
 
383
  function addMessage(role, content, fileData = null) {
384
- console.log('addMessage called with role:', role, 'content:', content);
385
  const messagesContainer = document.getElementById('messages');
386
  const messageDiv = document.createElement('div');
387
-
388
  let messageContent = '';
389
 
390
  if (fileData) {
@@ -397,20 +337,14 @@
397
  });
398
  }
399
 
400
- // Toujours créer la structure markdown-content, même si content est vide
401
  const markdownHtml = marked.parse(content || '');
402
  messageContent += `<div class="markdown-content">${markdownHtml}</div>`;
403
- console.log('Message content HTML:', messageContent);
404
 
405
- if (role === 'user') {
406
- messageDiv.className = 'max-w-[85%] p-4 rounded-2xl bg-gray-600 text-gray-100 self-end rounded-br-sm animate-fade-in';
407
- } else {
408
- messageDiv.className = 'max-w-[85%] p-4 rounded-2xl bg-dark-elevated text-gray-200 self-start rounded-bl-sm animate-fade-in';
409
- }
410
 
411
  messageDiv.innerHTML = messageContent;
412
- console.log('Message div created:', messageDiv);
413
-
414
  messagesContainer.appendChild(messageDiv);
415
  messagesContainer.scrollTop = messagesContainer.scrollHeight;
416
  return messageDiv;
@@ -446,12 +380,7 @@
446
  const arrow = element.querySelector('svg');
447
 
448
  checkbox.checked = !checkbox.checked;
449
-
450
- if (checkbox.checked) {
451
- arrow.style.transform = 'rotate(180deg)';
452
- } else {
453
- arrow.style.transform = 'rotate(0deg)';
454
- }
455
  }
456
 
457
  function showError(message) {
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>AI Assistant</title>
 
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.3.0/marked.min.js"></script>
9
  <script>
 
25
  </script>
26
  <style>
27
  /* Configuration Marked pour le markdown */
28
+ .markdown-content { @apply text-dark-text leading-relaxed; }
29
+ .markdown-content h1, .markdown-content h2, .markdown-content h3 { @apply font-bold mb-2 mt-4; }
 
 
 
 
30
  .markdown-content h1 { @apply text-xl; }
31
  .markdown-content h2 { @apply text-lg; }
32
  .markdown-content h3 { @apply text-base; }
33
  .markdown-content p { @apply mb-2; }
34
+ .markdown-content ul, .markdown-content ol { @apply ml-4 mb-2 list-disc; }
 
 
35
  .markdown-content li { @apply mb-1; }
36
+ .markdown-content code { @apply bg-gray-700 px-2 py-1 rounded text-sm font-mono; }
37
+ .markdown-content pre { @apply bg-gray-800 p-4 rounded-lg overflow-x-auto mb-4; }
38
+ .markdown-content pre code { @apply bg-transparent p-0; }
39
+ .markdown-content blockquote { @apply border-l-4 border-gray-600 pl-4 italic text-gray-300 mb-4; }
 
 
 
 
 
 
 
 
40
  .markdown-content strong { @apply font-semibold; }
41
  .markdown-content em { @apply italic; }
42
+ .markdown-content a { @apply text-blue-400 hover:text-blue-300 underline; }
 
 
43
 
44
  /* Animations et styles personnalisés */
45
+ @keyframes typing { 0%, 60%, 100% { transform: scale(0.8); opacity: 0.5; } 30% { transform: scale(1.2); opacity: 1; } }
46
+ @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
 
 
 
 
 
 
47
  .animate-typing { animation: typing 1.4s infinite ease-in-out; }
48
  .animate-fade-in { animation: fadeIn 0.3s ease; }
49
 
 
54
  .custom-scrollbar::-webkit-scrollbar-thumb:hover { background: #777; }
55
 
56
  /* Style pour les pensées déroulantes */
57
+ .thoughts-toggle:checked + .thoughts-content { max-height: 1000px; opacity: 1; }
58
+ .thoughts-content { max-height: 0; opacity: 0; overflow: hidden; transition: max-height 0.3s ease, opacity 0.3s ease; }
 
 
 
 
 
 
 
 
59
  </style>
60
  </head>
61
  <body class="bg-dark-bg text-dark-text min-h-screen flex justify-center items-center p-0 md:p-5">
62
  <div class="w-full max-w-4xl h-screen md:h-[90vh] bg-dark-card flex flex-col overflow-hidden md:rounded-xl md:border md:border-dark-border">
63
+
64
+ <!-- Header simplifié pour un design plus aéré -->
65
+ <header class="flex justify-between items-center p-4 md:px-6 border-b border-dark-border flex-shrink-0">
66
+ <h1 class="text-xl font-semibold">Mariam AI Assistant</h1>
67
+ <button class="bg-transparent border border-gray-600 text-gray-300 px-4 py-2 rounded-full text-sm hover:bg-gray-700 transition-colors" onclick="resetConversation()">
68
+ 🔄 Reset
69
+ </button>
70
+ </header>
 
 
 
 
 
 
 
 
 
71
 
72
  <!-- Messages -->
73
+ <div class="flex-1 overflow-y-auto p-4 md:p-6 flex flex-col gap-5 custom-scrollbar" id="messages">
74
  <div class="max-w-[85%] p-4 rounded-2xl bg-dark-elevated text-gray-200 self-start rounded-bl-sm animate-fade-in">
75
  <div class="markdown-content">👋 Bonjour, sur quoi allons-nous travailler aujourd'hui ?</div>
76
  </div>
 
115
  let currentFiles = [];
116
  let conversationId = 'session_' + Date.now();
117
 
 
118
  marked.setOptions({
119
  breaks: true,
120
  gfm: true
 
144
  const formData = new FormData();
145
  formData.append('file', file);
146
 
 
147
  if (file.type.startsWith('image/')) {
148
  const reader = new FileReader();
149
  reader.onload = function(e) {
 
224
  messageInput.value = '';
225
  autoResize(messageInput);
226
 
227
+ // Le toggle a été retiré, on active la réflexion par défaut.
228
+ const thinkingEnabled = true;
229
  const endpoint = currentFiles.length > 0 ? '/chat_with_file' : '/chat';
230
  const payload = {
231
  message: message || 'Analyse ces fichiers',
 
258
 
259
  function processStream() {
260
  return reader.read().then(({ done, value }) => {
261
+ if (done) { return; }
 
 
262
 
263
  buffer += decoder.decode(value, { stream: true });
264
  const lines = buffer.split('\n');
 
268
  if (line.startsWith('data: ')) {
269
  try {
270
  const data = JSON.parse(line.substring(6));
 
271
 
272
  if (data.type === 'text') {
 
273
  messageContent += data.content;
274
  if (!messageElement) {
275
  messageElement = addMessage('assistant', '');
 
276
  }
 
277
  const markdownHtml = marked.parse(messageContent);
278
  const markdownElement = messageElement.querySelector('.markdown-content');
279
  if (markdownElement) {
280
  markdownElement.innerHTML = markdownHtml;
 
 
281
  markdownElement.style.display = 'block';
 
 
 
282
  }
283
  } else if (data.type === 'thought' && thinkingEnabled) {
 
284
  thoughtsContent += data.content;
285
  if (!thoughtsContainer) {
286
  thoughtsContainer = addThoughtsContainer();
287
  }
 
288
  const thoughtsHtml = marked.parse(thoughtsContent);
289
  thoughtsContainer.querySelector('.thoughts-content .markdown-content').innerHTML = thoughtsHtml;
290
  } else if (data.type === 'error') {
 
291
  showError(data.content);
292
  } else if (data.type === 'end') {
 
293
  typingIndicator.classList.add('hidden');
294
  typingIndicator.classList.remove('flex');
295
  messageInput.disabled = false;
 
297
  messageInput.focus();
298
  removeFile();
299
  return;
 
 
300
  }
301
 
302
  const messagesContainer = document.getElementById('messages');
 
323
  }
324
 
325
  function addMessage(role, content, fileData = null) {
 
326
  const messagesContainer = document.getElementById('messages');
327
  const messageDiv = document.createElement('div');
 
328
  let messageContent = '';
329
 
330
  if (fileData) {
 
337
  });
338
  }
339
 
 
340
  const markdownHtml = marked.parse(content || '');
341
  messageContent += `<div class="markdown-content">${markdownHtml}</div>`;
 
342
 
343
+ messageDiv.className = role === 'user'
344
+ ? 'max-w-[85%] p-4 rounded-2xl bg-gray-600 text-gray-100 self-end rounded-br-sm animate-fade-in'
345
+ : 'max-w-[85%] p-4 rounded-2xl bg-dark-elevated text-gray-200 self-start rounded-bl-sm animate-fade-in';
 
 
346
 
347
  messageDiv.innerHTML = messageContent;
 
 
348
  messagesContainer.appendChild(messageDiv);
349
  messagesContainer.scrollTop = messagesContainer.scrollHeight;
350
  return messageDiv;
 
380
  const arrow = element.querySelector('svg');
381
 
382
  checkbox.checked = !checkbox.checked;
383
+ arrow.style.transform = checkbox.checked ? 'rotate(180deg)' : 'rotate(0deg)';
 
 
 
 
 
384
  }
385
 
386
  function showError(message) {