Docfile commited on
Commit
aa0630b
·
verified ·
1 Parent(s): 810c4e4

Update templates/philosophie.html

Browse files
Files changed (1) hide show
  1. templates/philosophie.html +152 -125
templates/philosophie.html CHANGED
@@ -1,5 +1,5 @@
1
  <!DOCTYPE html>
2
- <html lang="fr">
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -13,44 +13,52 @@
13
  <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/locale/fr.js"></script>
14
  <link href="https://cdnjs.cloudflare.com/ajax/libs/sweetalert2/11.7.3/sweetalert2.min.css" rel="stylesheet">
15
  <script src="https://cdn.tailwindcss.com"></script>
 
16
  <style>
17
- /* Styles de votre fichier original `philosophie (7).html` */
18
- .collapsible { cursor: pointer; padding: 18px; width: 100%; border: none; text-align: left; outline: none; font-size: 15px; background-color: #f1f1f1; display: flex; justify-content: space-between; align-items: center; }
19
- .active, .collapsible:hover { background-color: #ddd; }
20
- .content { padding: 0 18px; display: none; overflow: hidden; background-color: white; }
21
 
22
- /* Styles pour la responsivité et la lisibilité du Markdown généré */
 
 
 
 
23
  .prose { max-width: 100% !important; }
24
- .prose p { margin-top: 1.25em; margin-bottom: 1.25em; line-height: 1.75; }
25
- .prose ul, .prose ol { margin-top: 1.25em; margin-bottom: 1.25em; padding-left: 1.625em; }
26
- .prose li { margin-top: 0.5em; margin-bottom: 0.5em; padding-left: 0.375em; }
27
- .prose h1, .prose h2, .prose h3 { margin-top: 2em; margin-bottom: 1em; line-height: 1.3; }
28
- #response .prose { color: #374151; word-wrap: break-word; overflow-wrap: break-word; hyphens: auto; }
29
 
30
- /* Styles d'animation */
31
  .animate-fadeIn { animation: fadeIn 0.5s ease-out forwards; }
32
  @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
33
 
34
  /* Styles pour Select2 */
35
- .select2-container--default .select2-selection--single { border: 1px solid #e5e7eb; border-radius: 0.75rem; height: auto; padding: 0.625rem 1rem; background-color: white; box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); display: flex; align-items: center; }
36
- .select2-container--default .select2-selection--single .select2-selection__rendered { color: #374151; line-height: inherit; padding-right: 1.5rem; }
37
- .select2-results__option .course-author { font-size: 0.875rem; color: #6b7280; display: block; margin-top: 0.25rem; }
38
-
 
39
  /* Styles pour l'aperçu de l'image */
40
  #image-preview { max-height: 200px; border-radius: 0.75rem; box-shadow: 0 4px 6px -1px rgba(0,0,0,.1), 0 2px 4px -2px rgba(0,0,0,.1); }
 
 
 
 
41
  </style>
42
  </head>
43
- <body class="bg-gradient-to-br from-violet-50 to-indigo-50 min-h-screen">
44
  <!-- Navbar -->
45
- <nav class="bg-white/80 backdrop-blur-md border-b border-gray-200 fixed w-full z-50">
46
- <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
47
  <div class="flex justify-between items-center h-16">
48
- <div class="flex items-center">
49
- <div class="text-2xl font-bold bg-gradient-to-r from-violet-600 to-indigo-600 text-transparent bg-clip-text">Mariam AI</div>
 
 
 
50
  </div>
51
- <div class="flex items-center space-x-4">
52
- <span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-violet-100 text-violet-800">
53
- <span class="w-2 h-2 bg-violet-400 rounded-full animate-pulse mr-2"></span>
54
  Assistant Philosophique
55
  </span>
56
  </div>
@@ -59,91 +67,105 @@
59
  </nav>
60
 
61
  <!-- Main Content -->
62
- <div class="pt-24 pb-12 px-4 sm:px-6 lg:px-8">
63
- <div class="max-w-4xl mx-auto">
64
- <div class="bg-white/80 backdrop-blur-md rounded-2xl shadow-xl border border-gray-100 overflow-hidden">
65
- <div class="bg-gradient-to-r from-violet-600 to-indigo-600 p-6 text-white">
66
- <h2 class="text-2xl font-bold">Gen'Dissertation</h2>
67
- <p class="mt-2 opacity-90">Créez des dissertations et analyses philosophiques pertinentes et structurées</p>
 
 
68
  </div>
69
- <div class="p-8 space-y-8">
 
70
  <!-- Type Selection -->
71
- <div class="space-y-3">
72
- <label class="block text-sm font-medium text-gray-700">Type de travail</label>
73
- <select id="type-select" class="w-full rounded-xl border-gray-200 shadow-sm focus:border-violet-500 focus:ring-violet-500 appearance-none bg-white py-3 px-4 pr-10">
74
  <option value="1">Sujet Type 1</option>
75
  <option value="2">Sujet Type 2 (Citation)</option>
76
- <option value="3">Analyse d'image</option>
77
  </select>
78
  </div>
79
 
80
  <!-- Conteneur pour les champs texte (visible par défaut) -->
81
  <div id="text-input-container">
82
  <!-- Course Selection -->
83
- <div class="space-y-3">
84
- <label class="block text-sm font-medium text-gray-700">Sélection du cours</label>
85
  <select id="course-select" class="w-full">
86
  <option value="">Choisir un cours...</option>
87
  </select>
88
- <div class="course-meta hidden mt-4">
89
- <div class="bg-gradient-to-r from-gray-50 to-white rounded-xl p-4 border border-gray-100">
90
- <div class="flex justify-between items-center">
91
- <span id="course-author" class="flex items-center space-x-2"><svg class="h-5 w-5 text-violet-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" /></svg><span class="text-gray-600"></span></span>
92
- <span id="course-date" class="flex items-center space-x-2"><svg class="h-5 w-5 text-violet-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" /></svg><span class="text-gray-600"></span></span>
93
- </div>
94
- </div>
95
- </div>
96
  </div>
97
  <!-- Question Input -->
98
- <div class="space-y-3 mt-8">
99
  <label for="question" class="block text-sm font-medium text-gray-700">Sujet de dissertation</label>
100
- <textarea id="question" rows="4" class="w-full rounded-xl border-gray-200 shadow-sm focus:border-violet-500 focus:ring-violet-500 resize-none bg-white py-3 px-4" placeholder="Saisissez votre sujet de dissertation..."></textarea>
101
  </div>
102
  </div>
103
 
104
  <!-- Conteneur pour l'upload d'image (caché par défaut) -->
105
  <div id="image-input-container" class="hidden">
106
- <div class="space-y-3">
107
- <label for="image-upload" class="block text-sm font-medium text-gray-700">Charger une image pour analyse</label>
108
- <input type="file" id="image-upload" accept="image/jpeg, image/png, image/webp" class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-violet-50 file:text-violet-700 hover:file:bg-violet-100"/>
109
  <div class="mt-4 flex justify-center"><img id="image-preview" src="" alt="Aperçu de l'image" class="hidden"/></div>
110
  </div>
111
  </div>
112
 
113
  <!-- Submit Button -->
114
- <button id="submit-btn" class="w-full py-4 px-6 rounded-xl bg-gradient-to-r from-violet-600 to-indigo-600 text-white font-medium shadow-lg shadow-violet-200 hover:shadow-xl hover:shadow-violet-300 transform hover:-translate-y-0.5 transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-violet-500 focus:ring-offset-2">
115
- Générer la dissertation
116
- </button>
117
-
118
- <!-- Thinking Process Section -->
119
- <div id="thinking-container" class="hidden mt-8">
120
- <h3 class="text-md font-semibold text-gray-600 mb-2 border-b pb-2">Processus de pensée de l'IA :</h3>
121
- <div id="thinking-process" class="text-sm text-gray-500 bg-gray-50 p-4 rounded-lg prose prose-sm max-w-none"></div>
122
  </div>
123
-
124
- <!-- Response Section -->
125
- <div id="response" class="hidden mt-8 prose prose-violet max-w-none">
126
- <h3 class="text-lg font-bold text-gray-800 mb-2">Réponse :</h3>
127
- <div class="bg-gradient-to-r from-gray-50 to-white rounded-xl p-6 border border-gray-100"></div>
 
 
 
 
 
 
 
 
 
128
  </div>
129
-
130
- <!-- Copy Button -->
131
- <button id="copy-btn" class="hidden mt-8 w-full py-3 px-6 rounded-xl bg-gray-50 text-gray-700 font-medium border border-gray-200 hover:bg-gray-100 transform hover:-translate-y-0.5 transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2">
132
- Copier la dissertation
 
 
 
 
 
 
 
 
 
 
 
133
  </button>
134
-
135
- <!-- Saved Dissertations Section -->
136
- <div id="saved-dissertations" class="mt-8">
137
- <h3 class="text-lg font-medium text-gray-700 mb-4">Dissertations Sauvegardées</h3>
138
- <div id="dissertations-list" class="space-y-4"></div>
139
- </div>
 
140
  </div>
141
  </div>
142
  </div>
143
- </div>
144
 
145
  <!-- Bouton flottant DeepThink -->
146
- <button id="deepthink-btn" class="fixed bottom-6 right-6 z-50 bg-indigo-600 text-white px-4 py-2 rounded-full shadow-lg hover:bg-indigo-700 focus:outline-none">
 
147
  DeepThink
148
  </button>
149
 
@@ -151,7 +173,8 @@
151
  $(document).ready(function() {
152
  // --- Initialisations ---
153
  $('#course-select').select2({
154
- placeholder: 'Choisir un cours...',
 
155
  templateResult: function (course) { if (!course.id) { return course.text; } return $(`<span>${course.text}</span><span class="course-author">Pr. ${$(course.element).data('author')}</span>`); },
156
  templateSelection: function (course) { return course.text; },
157
  });
@@ -162,23 +185,27 @@ $(document).ready(function() {
162
  // --- Gestion de l'interface ---
163
  $('#type-select').change(function() {
164
  const type = $(this).val();
165
- if (type === '3') { // Analyse d'image
 
 
 
166
  $('#text-input-container').hide();
167
- $('#image-input-container').show();
168
  $('#deepthink-btn').hide();
169
- $('#submit-btn').text("Analyser l'image");
 
170
  } else { // Dissertation texte
171
- $('#text-input-container').show();
172
  $('#image-input-container').hide();
173
  $('#deepthink-btn').show();
174
- $('#submit-btn').text("Générer la dissertation");
175
  }
176
  }).trigger('change');
177
 
178
  $('#image-upload').change(function(e) {
179
  if (e.target.files && e.target.files[0]) {
180
  const reader = new FileReader();
181
- reader.onload = (event) => $('#image-preview').attr('src', event.target.result).removeClass('hidden');
182
  reader.readAsDataURL(e.target.files[0]);
183
  }
184
  });
@@ -187,7 +214,8 @@ $(document).ready(function() {
187
  async function handleStreamedGeneration(url, options) {
188
  Swal.fire({ title: 'Génération en cours...', html: 'Connexion au service IA...', allowOutsideClick: false, showConfirmButton: false, didOpen: () => Swal.showLoading() });
189
 
190
- $('#thinking-container, #response, #copy-btn').addClass('hidden');
 
191
  const thinkingDiv = $('#thinking-process');
192
  const responseDiv = $('#response > div');
193
  thinkingDiv.html('');
@@ -217,30 +245,37 @@ $(document).ready(function() {
217
  for (const line of lines) {
218
  if (line.trim() === '') continue;
219
  try {
220
- const data = JSON.parse(line);
221
  if (data.type === 'thought') {
222
- $('#thinking-container').removeClass('hidden');
223
  fullThinkingText += data.content;
224
  thinkingDiv.html(marked.parse(fullThinkingText));
225
  } else if (data.type === 'answer') {
226
- $('#response').removeClass('hidden');
227
  fullResponseText += data.content;
228
  responseDiv.html(marked.parse(fullResponseText));
229
  } else if (data.type === 'error') {
230
  throw new Error(data.content);
231
  }
232
- } catch (e) { console.error("Erreur JSON parse:", line); }
233
  }
234
- window.scrollTo(0, document.body.scrollHeight);
235
  }
236
 
237
- $('#copy-btn').removeClass('hidden');
238
  Toast.fire({ icon: 'success', title: 'Génération terminée !' });
239
- const title = $('#type-select').val() === '3' ? "Analyse d'image" : $('#question').val().trim();
 
 
 
 
 
 
 
240
  saveDissertation(title, fullResponseText);
241
 
242
  } catch (error) {
243
- Swal.fire({ icon: 'error', title: 'Erreur', text: error.message });
244
  }
245
  }
246
 
@@ -251,7 +286,7 @@ $(document).ready(function() {
251
 
252
  if (type === '3') {
253
  const imageFile = $('#image-upload')[0].files[0];
254
- if (!imageFile) { Swal.fire('Erreur', 'Veuillez sélectionner une image.', 'error'); return; }
255
  const formData = new FormData();
256
  formData.append('image', imageFile);
257
  handleStreamedGeneration('/stream_philo_image', { method: 'POST', body: formData });
@@ -264,7 +299,7 @@ $(document).ready(function() {
264
  }
265
  });
266
 
267
- // --- Fonctions existantes ---
268
  function loadCourses() {
269
  $.ajax({
270
  url: '/api/philosophy/courses',
@@ -283,27 +318,11 @@ $(document).ready(function() {
283
  }
284
  loadCourses();
285
 
286
- $('#course-select').on('change', function() {
287
- const courseId = $(this).val();
288
- if (courseId) {
289
- $.ajax({
290
- url: `/api/philosophy/courses/${courseId}`,
291
- method: 'GET',
292
- success: function(course) {
293
- $('.course-meta').removeClass('hidden').addClass('animate-fadeIn');
294
- $('#course-author span').text(`Pr. ${course.author}`);
295
- $('#course-date span').text(new Date(course.updated_at).toLocaleDateString('fr-FR', { day: 'numeric', month: 'long', year: 'numeric' }));
296
- }
297
- });
298
- } else {
299
- $('.course-meta').addClass('hidden');
300
- }
301
- });
302
-
303
  function saveDissertation(title, content) {
 
304
  let saved = JSON.parse(localStorage.getItem('dissertations')) || [];
305
  saved.unshift({ title, content, timestamp: Date.now() });
306
- if(saved.length > 10) saved.pop(); // Limite à 10 sauvegardes
307
  localStorage.setItem('dissertations', JSON.stringify(saved));
308
  updateSavedDissertationsList();
309
  }
@@ -321,21 +340,25 @@ $(document).ready(function() {
321
  list.empty();
322
  let saved = JSON.parse(localStorage.getItem('dissertations')) || [];
323
  if (saved.length === 0) {
324
- list.append('<p class="text-gray-500">Aucune dissertation sauvegardée.</p>');
325
  return;
326
  }
327
  saved.forEach((diss, index) => {
328
- const date = moment(diss.timestamp).format('LLL');
329
- const title = diss.title.length > 50 ? diss.title.substring(0, 50) + '...' : diss.title;
330
  const item = $(`
331
- <div class="border border-gray-100 rounded-xl">
332
- <button class="collapsible rounded-t-xl flex justify-between w-full p-4">
333
- <span class="font-medium text-gray-800">${title}</span>
334
- <span class="text-gray-500 text-sm">${date}</span>
 
 
335
  </button>
336
- <div class="content prose max-w-none p-4 border-t border-gray-200">
337
- <div class="inner-content"></div>
338
- <button class="delete-btn mt-4 text-sm text-red-600 hover:text-red-800" data-index="${index}">Supprimer</button>
 
 
339
  </div>
340
  </div>
341
  `);
@@ -345,17 +368,20 @@ $(document).ready(function() {
345
  }
346
 
347
  $('#dissertations-list').on('click', '.collapsible', function() {
348
- $(this).next('.content').slideToggle("fast");
349
- $(this).parent().toggleClass("active");
350
  });
351
 
352
- $('#dissertations-list').on('click', '.delete-btn', function() {
 
353
  const index = $(this).data('index');
354
  deleteDissertation(index);
355
  });
356
 
357
  $('#copy-btn').click(function() {
358
- const textToCopy = $('#response > div').text();
 
 
359
  navigator.clipboard.writeText(textToCopy).then(() => {
360
  Toast.fire({ icon: 'success', title: 'Copié dans le presse-papiers!' });
361
  }).catch(() => {
@@ -363,6 +389,7 @@ $(document).ready(function() {
363
  });
364
  });
365
 
 
366
  updateSavedDissertationsList();
367
  });
368
  </script>
 
1
  <!DOCTYPE html>
2
+ <html lang="fr" class="scroll-smooth">
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
 
13
  <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/locale/fr.js"></script>
14
  <link href="https://cdnjs.cloudflare.com/ajax/libs/sweetalert2/11.7.3/sweetalert2.min.css" rel="stylesheet">
15
  <script src="https://cdn.tailwindcss.com"></script>
16
+ <link rel="stylesheet" href="https://rsms.me/inter/inter.css">
17
  <style>
18
+ /* Styles pour le Glow Up */
19
+ :root { font-family: 'Inter', sans-serif; }
 
 
20
 
21
+ .collapsible { cursor: pointer; padding: 1rem; width: 100%; border: none; text-align: left; outline: none; transition: background-color 0.2s ease; }
22
+ .collapsible:hover { background-color: #f9fafb; }
23
+ .content { padding: 0 1rem; display: none; overflow: hidden; background-color: white; }
24
+
25
+ /* Styles pour la lisibilité du Markdown généré */
26
  .prose { max-width: 100% !important; }
27
+ #response .prose { color: #374151; word-wrap: break-word; overflow-wrap: break-word; }
28
+ .prose p, .prose ul, .prose ol, .prose li { line-height: 1.75; }
29
+ .prose h1, .prose h2, .prose h3 { margin-top: 1.5em; margin-bottom: 0.8em; line-height: 1.3; }
 
 
30
 
31
+ /* Animation fadeIn */
32
  .animate-fadeIn { animation: fadeIn 0.5s ease-out forwards; }
33
  @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
34
 
35
  /* Styles pour Select2 */
36
+ .select2-container--default .select2-selection--single { border: 1px solid #d1d5db; border-radius: 0.75rem; height: auto; padding: 0.75rem 1rem; background-color: white; box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); }
37
+ .select2-container--default .select2-selection--single .select2-selection__rendered { color: #111827; line-height: inherit; padding-right: 1.5rem; }
38
+ .select2-results__option .course-author { font-size: 0.875rem; color: #6b7280; display: block; margin-top: 0.1rem; }
39
+ .select2-dropdown { border-radius: 0.75rem; border: 1px solid #d1d5db; box-shadow: 0 4px 6px -1px rgba(0,0,0,.1); }
40
+
41
  /* Styles pour l'aperçu de l'image */
42
  #image-preview { max-height: 200px; border-radius: 0.75rem; box-shadow: 0 4px 6px -1px rgba(0,0,0,.1), 0 2px 4px -2px rgba(0,0,0,.1); }
43
+
44
+ /* Cacher le marqueur par défaut de <details> */
45
+ summary { list-style: none; }
46
+ summary::-webkit-details-marker { display: none; }
47
  </style>
48
  </head>
49
+ <body class="bg-gray-50 text-gray-900">
50
  <!-- Navbar -->
51
+ <nav class="bg-white/90 backdrop-blur-lg border-b border-gray-200 fixed w-full z-50">
52
+ <div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
53
  <div class="flex justify-between items-center h-16">
54
+ <div class="flex items-center space-x-3">
55
+ <svg class="h-8 w-auto text-violet-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
56
+ <path stroke-linecap="round" stroke-linejoin="round" d="M12 18v-5.25m0 0a6.01 6.01 0 001.5-.189m-1.5.189a6.01 6.01 0 01-1.5-.189m3.75 7.478a12.06 12.06 0 01-4.5 0m3.75 2.311a15.045 15.045 0 01-7.5 0C4.508 19.663 2.25 15.184 2.25 10.5 2.25 5.816 5.816 2.25 10.5 2.25c4.684 0 8.25 3.566 8.25 8.25 0 4.684-2.258 9.163-5.25 11.584z" />
57
+ </svg>
58
+ <div class="text-xl font-bold text-gray-800">Mariam AI</div>
59
  </div>
60
+ <div class="flex items-center">
61
+ <span class="inline-flex items-center px-3 py-1.5 rounded-full text-xs font-medium bg-violet-100 text-violet-800">
 
62
  Assistant Philosophique
63
  </span>
64
  </div>
 
67
  </nav>
68
 
69
  <!-- Main Content -->
70
+ <main class="pt-24 pb-16 px-4 sm:px-6 lg:px-8">
71
+ <div class="max-w-3xl mx-auto">
72
+ <div class="bg-white rounded-2xl shadow-lg border border-gray-100 overflow-hidden">
73
+ <div class="p-6 sm:p-8">
74
+ <div class="text-center">
75
+ <h1 class="text-3xl font-bold text-gray-900">Gen'Dissertation</h1>
76
+ <p class="mt-2 text-md text-gray-600">Créez des dissertations et analyses pertinentes et structurées.</p>
77
+ </div>
78
  </div>
79
+
80
+ <div class="p-6 sm:p-8 border-t border-gray-200 space-y-6">
81
  <!-- Type Selection -->
82
+ <div class="space-y-2">
83
+ <label for="type-select" class="block text-sm font-medium text-gray-700">Type de travail</label>
84
+ <select id="type-select" class="w-full rounded-xl border-gray-300 shadow-sm focus:border-violet-500 focus:ring-violet-500 bg-white py-3 px-4">
85
  <option value="1">Sujet Type 1</option>
86
  <option value="2">Sujet Type 2 (Citation)</option>
87
+ <option value="3">Sujet Type 3</option>
88
  </select>
89
  </div>
90
 
91
  <!-- Conteneur pour les champs texte (visible par défaut) -->
92
  <div id="text-input-container">
93
  <!-- Course Selection -->
94
+ <div class="space-y-2">
95
+ <label for="course-select" class="block text-sm font-medium text-gray-700">Utiliser un cours comme contexte</label>
96
  <select id="course-select" class="w-full">
97
  <option value="">Choisir un cours...</option>
98
  </select>
 
 
 
 
 
 
 
 
99
  </div>
100
  <!-- Question Input -->
101
+ <div class="space-y-2 mt-4">
102
  <label for="question" class="block text-sm font-medium text-gray-700">Sujet de dissertation</label>
103
+ <textarea id="question" rows="4" class="w-full rounded-xl border-gray-300 shadow-sm focus:border-violet-500 focus:ring-violet-500 resize-none bg-white py-3 px-4" placeholder="Saisissez votre sujet de dissertation... ex: 'La liberté consiste-t-elle à faire tout ce que l'on veut ?'"></textarea>
104
  </div>
105
  </div>
106
 
107
  <!-- Conteneur pour l'upload d'image (caché par défaut) -->
108
  <div id="image-input-container" class="hidden">
109
+ <div class="space-y-2">
110
+ <label for="image-upload" class="block text-sm font-medium text-gray-700">Charger un document pour analyse</label>
111
+ <input type="file" id="image-upload" accept="image/jpeg, image/png, image/webp" class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-violet-50 file:text-violet-700 hover:file:bg-violet-100 cursor-pointer"/>
112
  <div class="mt-4 flex justify-center"><img id="image-preview" src="" alt="Aperçu de l'image" class="hidden"/></div>
113
  </div>
114
  </div>
115
 
116
  <!-- Submit Button -->
117
+ <div class="pt-4">
118
+ <button id="submit-btn" class="w-full flex items-center justify-center py-3.5 px-6 rounded-xl bg-violet-600 text-white font-semibold shadow-md shadow-violet-200 hover:bg-violet-700 transform hover:-translate-y-0.5 transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-violet-500 focus:ring-offset-2">
119
+ <svg class="h-5 w-5 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm.75-13a.75.75 0 00-1.5 0v5c0 .414.336.75.75.75h4a.75.75 0 000-1.5h-3.25V5z" clip-rule="evenodd" /></svg>
120
+ Générer la dissertation
121
+ </button>
 
 
 
122
  </div>
123
+ </div>
124
+ </div>
125
+
126
+ <!-- Thinking Process Section (Collapsible) -->
127
+ <div id="thinking-wrapper" class="hidden mt-8">
128
+ <details id="thinking-container" class="bg-white border border-gray-200 rounded-xl shadow-sm">
129
+ <summary class="flex justify-between items-center p-4 cursor-pointer">
130
+ <h3 class="text-md font-semibold text-gray-700">Processus de pensée de l'IA</h3>
131
+ <svg class="h-5 w-5 text-gray-500 transition-transform transform open:rotate-180" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
132
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
133
+ </svg>
134
+ </summary>
135
+ <div id="thinking-process" class="p-4 border-t border-gray-200 text-sm text-gray-600 prose prose-sm max-w-none max-h-64 overflow-y-auto">
136
+ <!-- Le contenu du processus de pensée sera injecté ici -->
137
  </div>
138
+ </details>
139
+ </div>
140
+
141
+ <!-- Response Section -->
142
+ <div id="response" class="hidden mt-6">
143
+ <div class="bg-white border border-gray-200 rounded-xl shadow-sm p-6 sm:p-8 prose prose-violet max-w-none">
144
+ <!-- Le contenu de la réponse sera injecté ici -->
145
+ </div>
146
+ </div>
147
+
148
+ <!-- Action Buttons after generation -->
149
+ <div id="action-buttons" class="hidden mt-6 grid grid-cols-1 sm:grid-cols-2 gap-4">
150
+ <button id="copy-btn" class="w-full flex items-center justify-center py-3 px-6 rounded-xl bg-gray-100 text-gray-800 font-medium border border-gray-200 hover:bg-gray-200 transition-colors focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2">
151
+ <svg class="h-5 w-5 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 01-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 011.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 00-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 01-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 00-3.375-3.375h-1.5a1.125 1.125 0 01-1.125-1.125v-1.5a3.375 3.375 0 00-3.375-3.375H9.75" /></svg>
152
+ Copier le texte
153
  </button>
154
+ </div>
155
+
156
+ <!-- Saved Dissertations Section -->
157
+ <div class="mt-12">
158
+ <h3 class="text-xl font-bold text-gray-800 mb-4">Historique</h3>
159
+ <div id="dissertations-list" class="space-y-3">
160
+ <!-- La liste des dissertations sauvegardées sera injectée ici -->
161
  </div>
162
  </div>
163
  </div>
164
+ </main>
165
 
166
  <!-- Bouton flottant DeepThink -->
167
+ <button id="deepthink-btn" class="fixed bottom-6 right-6 z-50 flex items-center bg-indigo-600 text-white px-5 py-3 rounded-full shadow-lg hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition-transform hover:scale-105">
168
+ <svg class="h-5 w-5 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09zM18.259 8.715L18 9.75l-.259-1.035a3.375 3.375 0 00-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 002.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 002.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 00-2.456 2.456zM16.898 20.562L16.25 22.5l-.648-1.938a3.375 3.375 0 00-2.672-2.672L11.25 18l1.938-.648a3.375 3.375 0 002.672-2.672L16.25 13.5l.648 1.938a3.375 3.375 0 002.672 2.672L21.75 18l-1.938.648a3.375 3.375 0 00-2.672 2.672z" /></svg>
169
  DeepThink
170
  </button>
171
 
 
173
  $(document).ready(function() {
174
  // --- Initialisations ---
175
  $('#course-select').select2({
176
+ placeholder: 'Optionnel : choisir un cours...',
177
+ allowClear: true,
178
  templateResult: function (course) { if (!course.id) { return course.text; } return $(`<span>${course.text}</span><span class="course-author">Pr. ${$(course.element).data('author')}</span>`); },
179
  templateSelection: function (course) { return course.text; },
180
  });
 
185
  // --- Gestion de l'interface ---
186
  $('#type-select').change(function() {
187
  const type = $(this).val();
188
+ // Cacher les sections de résultat lors du changement de type
189
+ $('#thinking-wrapper, #response, #action-buttons').addClass('hidden');
190
+
191
+ if (type === '3') { // Sujet Type 3 (anciennement Analyse d'image)
192
  $('#text-input-container').hide();
193
+ $('#image-input-container').show().addClass('animate-fadeIn');
194
  $('#deepthink-btn').hide();
195
+ $('#submit-btn').html('<svg class="h-5 w-5 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z" /></svg>Analyser le sujet');
196
+ $('label[for="image-upload"]').text("Charger un document pour analyse (image, etc.)");
197
  } else { // Dissertation texte
198
+ $('#text-input-container').show().addClass('animate-fadeIn');
199
  $('#image-input-container').hide();
200
  $('#deepthink-btn').show();
201
+ $('#submit-btn').html('<svg class="h-5 w-5 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm.75-13a.75.75 0 00-1.5 0v5c0 .414.336.75.75.75h4a.75.75 0 000-1.5h-3.25V5z" clip-rule="evenodd" /></svg>Générer la dissertation');
202
  }
203
  }).trigger('change');
204
 
205
  $('#image-upload').change(function(e) {
206
  if (e.target.files && e.target.files[0]) {
207
  const reader = new FileReader();
208
+ reader.onload = (event) => $('#image-preview').attr('src', event.target.result).removeClass('hidden').addClass('animate-fadeIn');
209
  reader.readAsDataURL(e.target.files[0]);
210
  }
211
  });
 
214
  async function handleStreamedGeneration(url, options) {
215
  Swal.fire({ title: 'Génération en cours...', html: 'Connexion au service IA...', allowOutsideClick: false, showConfirmButton: false, didOpen: () => Swal.showLoading() });
216
 
217
+ $('#thinking-wrapper, #response, #action-buttons').addClass('hidden');
218
+ $('#thinking-container').prop('open', false); // S'assurer que le details est fermé au début
219
  const thinkingDiv = $('#thinking-process');
220
  const responseDiv = $('#response > div');
221
  thinkingDiv.html('');
 
245
  for (const line of lines) {
246
  if (line.trim() === '') continue;
247
  try {
248
+ const data = JSON.parse(line.trim());
249
  if (data.type === 'thought') {
250
+ $('#thinking-wrapper').removeClass('hidden').addClass('animate-fadeIn');
251
  fullThinkingText += data.content;
252
  thinkingDiv.html(marked.parse(fullThinkingText));
253
  } else if (data.type === 'answer') {
254
+ $('#response').removeClass('hidden').addClass('animate-fadeIn');
255
  fullResponseText += data.content;
256
  responseDiv.html(marked.parse(fullResponseText));
257
  } else if (data.type === 'error') {
258
  throw new Error(data.content);
259
  }
260
+ } catch (e) { console.error("Erreur JSON parse:", line, e); }
261
  }
262
+ $('html, body').animate({ scrollTop: $(document).height() }, 300);
263
  }
264
 
265
+ $('#action-buttons').removeClass('hidden').addClass('animate-fadeIn');
266
  Toast.fire({ icon: 'success', title: 'Génération terminée !' });
267
+
268
+ let title;
269
+ if ($('#type-select').val() === '3') {
270
+ const fileName = $('#image-upload')[0].files[0]?.name || "Analyse de document";
271
+ title = `Analyse (Sujet Type 3): ${fileName}`;
272
+ } else {
273
+ title = $('#question').val().trim();
274
+ }
275
  saveDissertation(title, fullResponseText);
276
 
277
  } catch (error) {
278
+ Swal.fire({ icon: 'error', title: 'Erreur', text: error.message || "Une erreur inconnue est survenue." });
279
  }
280
  }
281
 
 
286
 
287
  if (type === '3') {
288
  const imageFile = $('#image-upload')[0].files[0];
289
+ if (!imageFile) { Swal.fire('Erreur', 'Veuillez sélectionner un document.', 'error'); return; }
290
  const formData = new FormData();
291
  formData.append('image', imageFile);
292
  handleStreamedGeneration('/stream_philo_image', { method: 'POST', body: formData });
 
299
  }
300
  });
301
 
302
+ // --- Fonctions de gestion de l'historique ---
303
  function loadCourses() {
304
  $.ajax({
305
  url: '/api/philosophy/courses',
 
318
  }
319
  loadCourses();
320
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
321
  function saveDissertation(title, content) {
322
+ if (!title || !content) return;
323
  let saved = JSON.parse(localStorage.getItem('dissertations')) || [];
324
  saved.unshift({ title, content, timestamp: Date.now() });
325
+ if(saved.length > 10) saved.pop();
326
  localStorage.setItem('dissertations', JSON.stringify(saved));
327
  updateSavedDissertationsList();
328
  }
 
340
  list.empty();
341
  let saved = JSON.parse(localStorage.getItem('dissertations')) || [];
342
  if (saved.length === 0) {
343
+ list.append('<p class="text-gray-500 text-center py-4">Aucune dissertation dans l\'historique.</p>');
344
  return;
345
  }
346
  saved.forEach((diss, index) => {
347
+ const date = moment(diss.timestamp).fromNow();
348
+ const title = diss.title.length > 60 ? diss.title.substring(0, 60) + '...' : diss.title;
349
  const item = $(`
350
+ <div class="border border-gray-200 bg-white rounded-xl shadow-sm transition-shadow hover:shadow-md">
351
+ <button class="collapsible rounded-t-xl w-full text-left">
352
+ <div class="flex justify-between items-center w-full p-4">
353
+ <span class="font-medium text-gray-800">${title}</span>
354
+ <span class="text-gray-500 text-sm flex-shrink-0 ml-4">${date}</span>
355
+ </div>
356
  </button>
357
+ <div class="content prose max-w-none border-t border-gray-200">
358
+ <div class="inner-content p-4"></div>
359
+ <div class="p-4 border-t border-gray-200 bg-gray-50 rounded-b-xl">
360
+ <button class="delete-btn text-sm text-red-600 hover:text-red-800 font-medium" data-index="${index}">Supprimer</button>
361
+ </div>
362
  </div>
363
  </div>
364
  `);
 
368
  }
369
 
370
  $('#dissertations-list').on('click', '.collapsible', function() {
371
+ $(this).next('.content').slideToggle(250);
372
+ $(this).toggleClass("active");
373
  });
374
 
375
+ $('#dissertations-list').on('click', '.delete-btn', function(e) {
376
+ e.stopPropagation(); // Empêcher le collapsible de se fermer
377
  const index = $(this).data('index');
378
  deleteDissertation(index);
379
  });
380
 
381
  $('#copy-btn').click(function() {
382
+ const htmlToCopy = $('#response > div').html();
383
+ // Pour copier le Markdown brut (plus fidèle)
384
+ const textToCopy = new DOMParser().parseFromString(htmlToCopy, 'text/html').body.textContent || "";
385
  navigator.clipboard.writeText(textToCopy).then(() => {
386
  Toast.fire({ icon: 'success', title: 'Copié dans le presse-papiers!' });
387
  }).catch(() => {
 
389
  });
390
  });
391
 
392
+ // Init
393
  updateSavedDissertationsList();
394
  });
395
  </script>