Docfile commited on
Commit
dfc761c
·
verified ·
1 Parent(s): 460bd1d

Upload index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +111 -239
templates/index.html CHANGED
@@ -1,302 +1,174 @@
1
  <!DOCTYPE html>
2
  <html lang="fr">
3
- <!-- Le head reste identique jusqu'au script -->
4
  <head>
5
  <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
  <title>Mariam AI - Section Commentaire Composé</title>
 
8
  <script src="https://cdn.tailwindcss.com?plugins=typography"></script>
 
9
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
10
- <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.0/gsap.min.js"></script>
11
  <style>
12
- @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
13
-
14
- body {
15
- font-family: 'Poppins', sans-serif;
16
- background: linear-gradient(135deg, #f6f9fc 0%, #edf2f7 100%);
17
- min-height: 100vh;
18
- }
19
-
20
  .spinner {
21
- border: 3px solid rgba(79, 70, 229, 0.1);
22
- width: 2.5rem;
23
- height: 2.5rem;
24
  border-radius: 50%;
25
  border-left-color: #4f46e5;
26
- animation: spin 1s cubic-bezier(0.4, 0, 0.2, 1) infinite;
27
  }
28
-
29
  @keyframes spin {
30
  to { transform: rotate(360deg); }
31
  }
32
-
33
- .card-shadow {
34
- box-shadow: 0 10px 40px -10px rgba(0, 0, 0, 0.1);
35
- }
36
-
37
  .prose table {
38
  width: 100%;
39
- border-collapse: separate;
40
- border-spacing: 0;
41
- border-radius: 8px;
42
- overflow: hidden;
43
  }
44
-
45
  .prose th,
46
  .prose td {
47
- border: 1px solid #e5e7eb;
48
- padding: 1rem;
49
- background: white;
50
  }
51
-
52
  .prose th {
53
- background: #f8fafc;
54
  font-weight: 600;
55
- text-transform: uppercase;
56
- font-size: 0.875rem;
57
- letter-spacing: 0.05em;
58
- }
59
-
60
- .file-upload-area {
61
- border: 2px dashed #e2e8f0;
62
- border-radius: 1rem;
63
- transition: all 0.3s ease;
64
- }
65
-
66
- .file-upload-area:hover {
67
- border-color: #4f46e5;
68
- background: rgba(79, 70, 229, 0.05);
69
- }
70
-
71
- .animated-button {
72
- transition: transform 0.2s;
73
- }
74
-
75
- .animated-button:hover {
76
- transform: translateY(-2px);
77
  }
78
  </style>
79
  </head>
80
- <body class="py-8 px-4">
81
- <!-- Le HTML reste identique -->
82
- <div class="max-w-4xl mx-auto">
83
- <header class="text-center mb-12">
84
- <h1 class="text-5xl font-bold bg-gradient-to-r from-indigo-600 to-blue-500 bg-clip-text text-transparent">
85
- Mariam AI
86
- </h1>
87
- <p class="text-xl text-gray-600 mt-2">Section Commentaire Composé</p>
88
  </header>
89
 
90
- <div class="bg-white rounded-2xl card-shadow p-8">
91
- <form id="uploadForm" class="mb-8">
92
- <div class="file-upload-area p-8 text-center">
93
- <label for="imageInput" class="block cursor-pointer">
94
- <div class="mb-4">
95
- <svg class="w-12 h-12 mx-auto text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
96
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
97
- </svg>
98
- </div>
99
- <span class="text-lg font-medium text-gray-700">Sélectionnez une image</span>
100
- <p class="text-sm text-gray-500 mt-1">ou glissez-déposez votre fichier ici</p>
101
- </label>
102
- <input type="file" id="imageInput" name="image" accept="image/*" required class="hidden">
103
- </div>
104
-
105
- <div id="previewContainer" class="mt-6 hidden">
106
- <p class="text-gray-700 font-medium mb-3">Aperçu :</p>
107
- <div class="relative rounded-xl overflow-hidden shadow-lg">
108
- <img id="previewImage" src="#" alt="Prévisualisation" class="w-full max-h-80 object-contain">
109
- </div>
110
  </div>
111
-
112
- <button type="submit" class="animated-button w-full mt-6 bg-gradient-to-r from-indigo-600 to-blue-500 text-white font-semibold py-3 px-6 rounded-xl shadow-lg hover:shadow-xl transition-all duration-300">
113
- Lancer l'analyse
114
  </button>
115
  </form>
116
 
117
- <div id="loading" class="hidden">
118
- <div class="flex flex-col items-center space-y-4 py-8">
119
- <div class="spinner"></div>
120
- <span class="text-gray-700 font-medium">Analyse en cours...</span>
121
- </div>
122
  </div>
123
 
124
- <button id="toggleButton" class="animated-button hidden w-full mb-6 bg-gradient-to-r from-green-500 to-emerald-500 text-white font-semibold py-3 px-6 rounded-xl shadow-lg hover:shadow-xl transition-all duration-300">
 
125
  Afficher le Tableau
126
  </button>
127
 
128
- <div id="result" class="hidden space-y-8">
129
- <section>
 
 
130
  <h2 class="text-2xl font-semibold text-gray-800 mb-4">Dissertation</h2>
131
- <div id="dissertationContent" class="prose prose-lg max-w-none bg-gray-50 rounded-xl p-8"></div>
132
  </section>
133
-
134
  <section id="tableauSection" class="hidden">
135
  <h2 class="text-2xl font-semibold text-gray-800 mb-4">Tableau d'analyse</h2>
136
- <div id="tableauContent" class="prose prose-lg max-w-none bg-gray-50 rounded-xl p-8"></div>
137
  </section>
138
  </div>
139
  </div>
140
  </div>
141
 
 
142
  <script>
143
- // Configuration des variables
144
- const config = {
145
- uploadForm: document.getElementById('uploadForm'),
146
- imageInput: document.getElementById('imageInput'),
147
- previewContainer: document.getElementById('previewContainer'),
148
- previewImage: document.getElementById('previewImage'),
149
- loadingIndicator: document.getElementById('loading'),
150
- resultDiv: document.getElementById('result'),
151
- toggleButton: document.getElementById('toggleButton'),
152
- tableauSection: document.getElementById('tableauSection'),
153
- tableauContent: document.getElementById('tableauContent'),
154
- dissertationContent: document.getElementById('dissertationContent')
155
- };
156
-
157
- // Gestion de l'aperçu des fichiers
158
- function handleFilePreview(file) {
159
  if (file) {
160
  const reader = new FileReader();
161
  reader.onload = function(e) {
162
- config.previewImage.src = e.target.result;
163
- config.previewContainer.classList.remove('hidden');
164
- gsap.from(config.previewContainer, {
165
- opacity: 0,
166
- y: 20,
167
- duration: 0.3
168
- });
169
- };
170
  reader.readAsDataURL(file);
171
- }
172
- }
173
-
174
- // Gestionnaire d'événements pour l'input file
175
- config.imageInput.addEventListener('change', (e) => {
176
- handleFilePreview(e.target.files[0]);
177
- });
178
-
179
- // Fonction pour afficher/masquer le loading
180
- function toggleLoading(show) {
181
- if (show) {
182
- config.loadingIndicator.classList.remove('hidden');
183
- config.resultDiv.classList.add('hidden');
184
- config.toggleButton.classList.add('hidden');
185
- config.tableauSection.classList.add('hidden');
186
  } else {
187
- config.loadingIndicator.classList.add('hidden');
188
  }
189
- }
190
 
191
- // Fonction pour gérer la soumission du formulaire
192
- async function handleFormSubmit(e) {
193
  e.preventDefault();
194
-
195
- toggleLoading(true);
196
-
197
- try {
198
- const formData = new FormData(config.uploadForm);
199
- const response = await fetch('/analyze', {
200
- method: 'POST',
201
- body: formData
202
- });
203
-
204
- const data = await response.json();
205
 
206
- if (!response.ok) {
207
- throw new Error(data.error || 'Une erreur est survenue');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  }
 
 
 
 
 
 
 
209
 
210
- // Mise à jour du contenu
211
- config.dissertationContent.innerHTML = marked.parse(data.dissertation);
212
- config.tableauContent.innerHTML = marked.parse(data.tableau);
213
-
214
- // Affichage des résultats
215
- config.resultDiv.classList.remove('hidden');
216
- config.toggleButton.classList.remove('hidden');
217
- config.tableauSection.classList.add('hidden');
218
- config.toggleButton.textContent = 'Afficher le Tableau';
219
-
220
- // Animation des résultats
221
- gsap.from([config.resultDiv, config.toggleButton], {
222
- opacity: 0,
223
- y: 20,
224
- duration: 0.3,
225
- stagger: 0.1
226
- });
227
-
228
- } catch (error) {
229
- console.error('Erreur:', error);
230
- alert(error.message || "Une erreur est survenue lors de l'analyse.");
231
- } finally {
232
- toggleLoading(false);
233
- }
234
- }
235
-
236
- // Gestionnaire de soumission du formulaire
237
- config.uploadForm.addEventListener('submit', handleFormSubmit);
238
-
239
- // Gestion du toggle du tableau
240
- config.toggleButton.addEventListener('click', function() {
241
- const isHidden = config.tableauSection.classList.contains('hidden');
242
-
243
- if (isHidden) {
244
- config.tableauSection.classList.remove('hidden');
245
- this.textContent = 'Masquer le Tableau';
246
- gsap.from(config.tableauSection, {
247
- opacity: 0,
248
- y: 20,
249
- duration: 0.3
250
- });
251
  } else {
252
- gsap.to(config.tableauSection, {
253
- opacity: 0,
254
- y: 20,
255
- duration: 0.2,
256
- onComplete: () => {
257
- config.tableauSection.classList.add('hidden');
258
- this.textContent = 'Afficher le Tableau';
259
- }
260
- });
261
  }
262
  });
263
-
264
- // Gestion du drag & drop
265
- function initDragAndDrop() {
266
- const dropArea = document.querySelector('.file-upload-area');
267
-
268
- ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
269
- dropArea.addEventListener(eventName, (e) => {
270
- e.preventDefault();
271
- e.stopPropagation();
272
- });
273
- });
274
-
275
- function highlight() {
276
- dropArea.classList.add('border-indigo-600', 'bg-indigo-50');
277
- }
278
-
279
- function unhighlight() {
280
- dropArea.classList.remove('border-indigo-600', 'bg-indigo-50');
281
- }
282
-
283
- ['dragenter', 'dragover'].forEach(eventName => {
284
- dropArea.addEventListener(eventName, highlight);
285
- });
286
-
287
- ['dragleave', 'drop'].forEach(eventName => {
288
- dropArea.addEventListener(eventName, unhighlight);
289
- });
290
-
291
- dropArea.addEventListener('drop', (e) => {
292
- const dt = e.dataTransfer;
293
- config.imageInput.files = dt.files;
294
- handleFilePreview(dt.files[0]);
295
- });
296
- }
297
-
298
- // Initialisation du drag & drop
299
- initDragAndDrop();
300
  </script>
301
  </body>
302
- </html>
 
1
  <!DOCTYPE html>
2
  <html lang="fr">
 
3
  <head>
4
  <meta charset="UTF-8">
 
5
  <title>Mariam AI - Section Commentaire Composé</title>
6
+ <!-- Intégration de Tailwind CSS via CDN avec le plugin Typography activé -->
7
  <script src="https://cdn.tailwindcss.com?plugins=typography"></script>
8
+ <!-- Intégration de Marked.js pour la conversion Markdown -->
9
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
 
10
  <style>
11
+ /* Spinner personnalisé pour l'indicateur de chargement */
 
 
 
 
 
 
 
12
  .spinner {
13
+ border: 4px solid rgba(0, 0, 0, 0.1);
14
+ width: 3rem;
15
+ height: 3rem;
16
  border-radius: 50%;
17
  border-left-color: #4f46e5;
18
+ animation: spin 1s linear infinite;
19
  }
 
20
  @keyframes spin {
21
  to { transform: rotate(360deg); }
22
  }
23
+ /* Optionnel : style personnalisé pour les tableaux générés en Markdown */
 
 
 
 
24
  .prose table {
25
  width: 100%;
26
+ border-collapse: collapse;
 
 
 
27
  }
 
28
  .prose th,
29
  .prose td {
30
+ border: 1px solid #e5e7eb; /* gris clair */
31
+ padding: 0.75rem;
32
+ text-align: left;
33
  }
 
34
  .prose th {
35
+ background-color: #f3f4f6;
36
  font-weight: 600;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  }
38
  </style>
39
  </head>
40
+ <body class="bg-gray-100">
41
+ <div class="max-w-3xl mx-auto p-4">
42
+ <!-- En-tête de l'application -->
43
+ <header class="mb-8 text-center">
44
+ <h1 class="text-4xl font-extrabold text-gray-800">Mariam AI</h1>
45
+ <p class="text-xl text-gray-600">Section Commentaire Composé</p>
 
 
46
  </header>
47
 
48
+ <div class="bg-white rounded-lg shadow-lg p-6">
49
+ <!-- Formulaire d'upload et prévisualisation -->
50
+ <form id="uploadForm" enctype="multipart/form-data" class="mb-6">
51
+ <label for="imageInput" class="block text-lg font-medium text-gray-700 mb-2">
52
+ Sélectionnez une image :
53
+ </label>
54
+ <input type="file" name="image" id="imageInput" accept="image/*" required
55
+ class="block w-full border border-gray-300 rounded-md p-2 mb-4 focus:ring focus:ring-blue-300">
56
+ <!-- Prévisualisation de l'image -->
57
+ <div id="previewContainer" class="mb-4 hidden">
58
+ <p class="text-gray-700 font-medium mb-2">Prévisualisation :</p>
59
+ <img id="previewImage" src="#" alt="Prévisualisation" class="w-full max-h-64 object-contain rounded-lg shadow-md">
 
 
 
 
 
 
 
 
60
  </div>
61
+ <button type="submit" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded transition-colors">
62
+ Analyser
 
63
  </button>
64
  </form>
65
 
66
+ <!-- Indicateur de chargement -->
67
+ <div id="loading" class="flex flex-col items-center space-y-2 mb-6 hidden">
68
+ <div class="spinner"></div>
69
+ <span class="text-gray-700 font-medium">Analyse en cours...</span>
 
70
  </div>
71
 
72
+ <!-- Bouton pour afficher/masquer le tableau d'analyse -->
73
+ <button id="toggleButton" class="hidden bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded w-full mb-4 transition-colors">
74
  Afficher le Tableau
75
  </button>
76
 
77
+ <!-- Zone de résultats -->
78
+ <div id="result" class="hidden">
79
+ <!-- Section Dissertation -->
80
+ <section class="mb-8">
81
  <h2 class="text-2xl font-semibold text-gray-800 mb-4">Dissertation</h2>
82
+ <div id="dissertationContent" class="prose prose-sm sm:prose lg:prose-xl bg-gray-50 border border-gray-200 rounded p-6 text-gray-800"></div>
83
  </section>
84
+ <!-- Section Tableau d'analyse -->
85
  <section id="tableauSection" class="hidden">
86
  <h2 class="text-2xl font-semibold text-gray-800 mb-4">Tableau d'analyse</h2>
87
+ <div id="tableauContent" class="prose prose-sm sm:prose lg:prose-xl bg-gray-50 border border-gray-200 rounded p-6 text-gray-800"></div>
88
  </section>
89
  </div>
90
  </div>
91
  </div>
92
 
93
+ <!-- Script JavaScript pour la gestion des interactions -->
94
  <script>
95
+ const uploadForm = document.getElementById('uploadForm');
96
+ const imageInput = document.getElementById('imageInput');
97
+ const previewContainer = document.getElementById('previewContainer');
98
+ const previewImage = document.getElementById('previewImage');
99
+ const loadingIndicator = document.getElementById('loading');
100
+ const resultDiv = document.getElementById('result');
101
+ const toggleButton = document.getElementById('toggleButton');
102
+ const tableauSection = document.getElementById('tableauSection');
103
+ const tableauContent = document.getElementById('tableauContent');
104
+ const dissertationContent = document.getElementById('dissertationContent');
105
+
106
+ // Prévisualisation de l'image sélectionnée
107
+ imageInput.addEventListener('change', function() {
108
+ const file = this.files[0];
 
 
109
  if (file) {
110
  const reader = new FileReader();
111
  reader.onload = function(e) {
112
+ previewImage.src = e.target.result;
113
+ previewContainer.classList.remove('hidden');
114
+ }
 
 
 
 
 
115
  reader.readAsDataURL(file);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  } else {
117
+ previewContainer.classList.add('hidden');
118
  }
119
+ });
120
 
121
+ // Gestion de la soumission du formulaire
122
+ uploadForm.addEventListener('submit', function(e) {
123
  e.preventDefault();
 
 
 
 
 
 
 
 
 
 
 
124
 
125
+ // Afficher l'indicateur de chargement et masquer les zones de résultats
126
+ loadingIndicator.classList.remove('hidden');
127
+ resultDiv.classList.add('hidden');
128
+ toggleButton.classList.add('hidden');
129
+ tableauSection.classList.add('hidden');
130
+
131
+ const formData = new FormData(uploadForm);
132
+
133
+ fetch('/analyze', {
134
+ method: 'POST',
135
+ body: formData
136
+ })
137
+ .then(response => response.json())
138
+ .then(data => {
139
+ loadingIndicator.classList.add('hidden');
140
+ if (data.error) {
141
+ alert("Erreur : " + data.error);
142
+ } else {
143
+ // Convertir les réponses Markdown en HTML via Marked.js
144
+ dissertationContent.innerHTML = marked.parse(data.dissertation);
145
+ tableauContent.innerHTML = marked.parse(data.tableau);
146
+
147
+ // Afficher la zone de résultats et le bouton Toggle
148
+ resultDiv.classList.remove('hidden');
149
+ toggleButton.classList.remove('hidden');
150
+ // Masquer le tableau par défaut
151
+ tableauSection.classList.add('hidden');
152
+ toggleButton.textContent = 'Afficher le Tableau';
153
  }
154
+ })
155
+ .catch(error => {
156
+ loadingIndicator.classList.add('hidden');
157
+ console.error(error);
158
+ alert("Une erreur est survenue lors de l'analyse.");
159
+ });
160
+ });
161
 
162
+ // Gestion du bouton d'affichage/masquage du tableau
163
+ toggleButton.addEventListener('click', function() {
164
+ if (tableauSection.classList.contains('hidden')) {
165
+ tableauSection.classList.remove('hidden');
166
+ toggleButton.textContent = 'Masquer le Tableau';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  } else {
168
+ tableauSection.classList.add('hidden');
169
+ toggleButton.textContent = 'Afficher le Tableau';
 
 
 
 
 
 
 
170
  }
171
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  </script>
173
  </body>
174
+ </html>