Docfile commited on
Commit
70b1fc2
·
verified ·
1 Parent(s): 7ce6b97

Create index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +395 -0
templates/index.html ADDED
@@ -0,0 +1,395 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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">
6
+ <title>Mariam M-0 | Solution Mathématique</title>
7
+ <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
8
+ <script>
9
+ window.MathJax = {
10
+ tex: {
11
+ inlineMath: [['$', '$'], ['\\(', '\\)']],
12
+ displayMath: [['$$', '$$'], ['\\[', '\\]']],
13
+ processEscapes: true,
14
+ packages: ['base', 'ams', 'noerrors', 'noundefined']
15
+ },
16
+ options: {
17
+ ignoreHtmlClass: 'tex2jax_ignore',
18
+ processHtmlClass: 'tex2jax_process'
19
+ },
20
+ svg: {
21
+ fontCache: 'global'
22
+ }
23
+ };
24
+ </script>
25
+ <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
26
+ <style>
27
+ @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap');
28
+
29
+ body {
30
+ font-family: 'Space Grotesk', sans-serif;
31
+ background: #ffffff;
32
+ min-height: 100vh;
33
+ color: #1e3a8a;
34
+ }
35
+
36
+ .container {
37
+ max-width: 90vw !important;
38
+ width: 90vw;
39
+ margin: 0 auto;
40
+ }
41
+
42
+ .upload-area {
43
+ border: 2px dashed #3b82f6;
44
+ transition: all 0.3s ease;
45
+ background: #ffffff;
46
+ }
47
+
48
+ .upload-area:hover {
49
+ border-color: #2563eb;
50
+ background: #f8fafc;
51
+ }
52
+
53
+ .action-button {
54
+ background: #2563eb;
55
+ transition: all 0.3s ease;
56
+ color: white;
57
+ }
58
+
59
+ .action-button:hover {
60
+ background: #1d4ed8;
61
+ transform: translateY(-2px);
62
+ }
63
+
64
+ .loader {
65
+ width: 48px;
66
+ height: 48px;
67
+ border: 3px solid #3b82f6;
68
+ border-bottom-color: transparent;
69
+ border-radius: 50%;
70
+ display: inline-block;
71
+ box-sizing: border-box;
72
+ animation: rotation 1s linear infinite;
73
+ }
74
+
75
+ @keyframes rotation {
76
+ 0% { transform: rotate(0deg); }
77
+ 100% { transform: rotate(360deg); }
78
+ }
79
+
80
+ .preview-container {
81
+ margin-top: 1rem;
82
+ padding: 0 1rem;
83
+ }
84
+
85
+ .preview-image {
86
+ max-width: 100%;
87
+ max-height: 60vh;
88
+ object-fit: contain;
89
+ border-radius: 8px;
90
+ border: 2px solid #bfdbfe;
91
+ }
92
+
93
+ #thoughtsContent, #answerContent {
94
+ max-height: 80vh;
95
+ overflow-y: auto;
96
+ padding: 1rem;
97
+ }
98
+
99
+ .thought-box {
100
+ transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
101
+ max-height: 0;
102
+ overflow: hidden;
103
+ background: #ffffff;
104
+ border: 1px solid #e5e7eb;
105
+ border-radius: 0.5rem;
106
+ }
107
+
108
+ .thought-box.open {
109
+ max-height: 1000px;
110
+ margin-top: 1rem;
111
+ }
112
+
113
+ .solution-section {
114
+ border: 1px solid #e5e7eb;
115
+ border-radius: 0.5rem;
116
+ background: #ffffff;
117
+ margin-top: 1rem;
118
+ width: 100%;
119
+ }
120
+
121
+ @media (min-width: 1280px) {
122
+ .container {
123
+ max-width: 80vw !important;
124
+ }
125
+
126
+ .text-content {
127
+ font-size: 1.125rem;
128
+ line-height: 1.75;
129
+ }
130
+ }
131
+
132
+ @media (min-width: 1536px) {
133
+ .container {
134
+ max-width: 70vw !important;
135
+ }
136
+ }
137
+
138
+ @media (max-width: 640px) {
139
+ .container {
140
+ padding: 0.5rem;
141
+ }
142
+
143
+ .text-lg {
144
+ font-size: 1rem;
145
+ }
146
+ }
147
+ </style>
148
+ </head>
149
+ <body class="p-2 sm:p-4 md:p-8">
150
+ <div class="container">
151
+ <div class="text-center mb-6 sm:mb-12">
152
+ <h1 class="text-3xl sm:text-4xl md:text-5xl font-bold text-blue-900 mb-2 sm:mb-4">Mariam M-0</h1>
153
+ <p class="text-blue-600 text-base sm:text-lg">Solution Mathématique Intelligente</p>
154
+ </div>
155
+
156
+ <form id="problemForm" class="space-y-4 sm:space-y-8" enctype="multipart/form-data">
157
+ <div class="relative">
158
+ <div class="upload-area rounded-xl p-6 sm:p-12 text-center">
159
+ <input type="file" id="imageInput" name="image" accept="image/*" class="absolute inset-0 w-full h-full opacity-0 cursor-pointer">
160
+ <div class="space-y-2 sm:space-y-4">
161
+ <div class="w-16 h-16 sm:w-20 sm:h-20 mx-auto border-2 border-blue-400 rounded-full flex items-center justify-center">
162
+ <svg class="w-8 h-8 sm:w-10 sm:h-10 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
163
+ <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" />
164
+ </svg>
165
+ </div>
166
+ <div class="text-blue-600 text-base sm:text-lg font-medium">Déposez votre image ici</div>
167
+ <div class="text-blue-400 text-xs sm:text-sm">ou cliquez pour sélectionner</div>
168
+ </div>
169
+ </div>
170
+ <div id="imagePreview" class="preview-container hidden">
171
+ <img id="previewImage" src="#" alt="Prévisualisation de l'image" class="preview-image">
172
+ </div>
173
+ </div>
174
+
175
+ <button type="submit" class="action-button w-full py-3 sm:py-4 rounded-lg sm:rounded-xl font-medium text-base sm:text-lg">
176
+ Résoudre le problème
177
+ </button>
178
+ </form>
179
+
180
+ <div id="loader" class="hidden mt-8 sm:mt-12">
181
+ <div class="flex flex-col items-center justify-center space-y-4">
182
+ <span class="loader"></span>
183
+ <div class="text-blue-600 text-base sm:text-lg">Analyse en cours...</div>
184
+ </div>
185
+ </div>
186
+
187
+ <div id="solution" class="hidden mt-8 sm:mt-12 space-y-4 sm:space-y-8">
188
+ <div class="solution-section p-4 sm:p-6">
189
+ <button id="thoughtsToggle" class="w-full flex justify-between items-center text-left text-base sm:text-lg font-medium text-blue-900 hover:text-blue-600 transition-colors">
190
+ <div class="flex items-center">
191
+ <span>Processus de Réflexion</span>
192
+ <span id="timestamp" class="ml-2 text-blue-500 text-sm"></span>
193
+ </div>
194
+ <svg class="w-5 h-5 sm:w-6 sm:h-6 transform transition-transform duration-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
195
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
196
+ </svg>
197
+ </button>
198
+ <div id="thoughtsBox" class="thought-box">
199
+ <div id="thoughtsContent" class="prose max-w-none"></div>
200
+ </div>
201
+ </div>
202
+
203
+ <div class="solution-section p-4 sm:p-8">
204
+ <h3 class="text-xl sm:text-2xl font-bold text-blue-900 mb-4 sm:mb-6">Solution</h3>
205
+ <div id="answerContent" class="prose max-w-none"></div>
206
+ </div>
207
+ </div>
208
+ </div>
209
+
210
+ <script>
211
+ document.addEventListener('DOMContentLoaded', () => {
212
+ const form = document.getElementById('problemForm');
213
+ const imageInput = document.getElementById('imageInput');
214
+ const loader = document.getElementById('loader');
215
+ const solutionDiv = document.getElementById('solution');
216
+ const thoughtsContent = document.getElementById('thoughtsContent');
217
+ const answerContent = document.getElementById('answerContent');
218
+ const thoughtsToggle = document.getElementById('thoughtsToggle');
219
+ const thoughtsBox = document.getElementById('thoughtsBox');
220
+ const imagePreview = document.getElementById('imagePreview');
221
+ const previewImage = document.getElementById('previewImage');
222
+ const timestamp = document.getElementById('timestamp');
223
+
224
+ let startTime = null;
225
+ let timerInterval = null;
226
+
227
+ function updateTimestamp() {
228
+ if (startTime) {
229
+ const elapsed = Math.floor((Date.now() - startTime) / 1000);
230
+ timestamp.textContent = elapsed + "s";
231
+ }
232
+ }
233
+
234
+ function startTimer() {
235
+ startTime = Date.now();
236
+ timerInterval = setInterval(updateTimestamp, 1000);
237
+ updateTimestamp();
238
+ }
239
+
240
+ function stopTimer() {
241
+ if (timerInterval) {
242
+ clearInterval(timerInterval);
243
+ timerInterval = null;
244
+ }
245
+ startTime = null;
246
+ timestamp.textContent = "";
247
+ }
248
+
249
+ thoughtsToggle.addEventListener('click', () => {
250
+ thoughtsBox.classList.toggle('open');
251
+ thoughtsToggle.querySelector('svg').classList.toggle('rotate-180');
252
+ });
253
+
254
+ imageInput.addEventListener('change', function(e) {
255
+ const file = this.files[0];
256
+ if (file) {
257
+ const reader = new FileReader();
258
+ reader.onload = function(e) {
259
+ previewImage.src = e.target.result;
260
+ imagePreview.classList.remove('hidden');
261
+ }
262
+ reader.readAsDataURL(file);
263
+ } else {
264
+ previewImage.src = "";
265
+ imagePreview.classList.add('hidden');
266
+ }
267
+ });
268
+
269
+ const dropZone = document.querySelector('.upload-area');
270
+
271
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
272
+ dropZone.addEventListener(eventName, preventDefaults, false);
273
+ });
274
+
275
+ function preventDefaults(e) {
276
+ e.preventDefault();
277
+ e.stopPropagation();
278
+ }
279
+
280
+ ['dragenter', 'dragover'].forEach(eventName => {
281
+ dropZone.addEventListener(eventName, highlight, false);
282
+ });
283
+
284
+ ['dragleave', 'drop'].forEach(eventName => {
285
+ dropZone.addEventListener(eventName, unhighlight, false);
286
+ });
287
+
288
+ function highlight(e) {
289
+ dropZone.classList.add('border-blue-600');
290
+ dropZone.style.background = '#f8fafc';
291
+ }
292
+
293
+ function unhighlight(e) {
294
+ dropZone.classList.remove('border-blue-600');
295
+ dropZone.style.background = '#ffffff';
296
+ }
297
+
298
+ dropZone.addEventListener('drop', handleDrop, false);
299
+
300
+ function handleDrop(e) {
301
+ const dt = e.dataTransfer;
302
+ const files = dt.files;
303
+
304
+ if (files.length) {
305
+ imageInput.files = files;
306
+ const file = files[0];
307
+ const reader = new FileReader();
308
+ reader.onload = function(e) {
309
+ previewImage.src = e.target.result;
310
+ imagePreview.classList.remove('hidden');
311
+ }
312
+ reader.readAsDataURL(file);
313
+ }
314
+ }
315
+
316
+ form.addEventListener('submit', async (event) => {
317
+ event.preventDefault();
318
+ const file = imageInput.files[0];
319
+ if (!file) {
320
+ alert('Veuillez sélectionner une image.');
321
+ return;
322
+ }
323
+
324
+ startTimer();
325
+
326
+ loader.classList.remove('hidden');
327
+ solutionDiv.classList.add('hidden');
328
+ thoughtsContent.innerHTML = '';
329
+ answerContent.innerHTML = '';
330
+ thoughtsBox.classList.add('open');
331
+
332
+ const formData = new FormData();
333
+ formData.append('image', file);
334
+
335
+ try {
336
+ let currentMode = null;
337
+ const response = await fetch('/solve', {
338
+ method: 'POST',
339
+ body: formData
340
+ });
341
+
342
+ const reader = response.body.getReader();
343
+ const decoder = new TextDecoder();
344
+ let buffer = '';
345
+
346
+ while (true) {
347
+ const { done, value } = await reader.read();
348
+ if (done) {
349
+ stopTimer();
350
+ break;
351
+ }
352
+
353
+ buffer += decoder.decode(value, { stream: true });
354
+ let eolIndex;
355
+
356
+ while ((eolIndex = buffer.indexOf('\n\n')) >= 0) {
357
+ const line = buffer.slice(0, eolIndex).trim();
358
+ buffer = buffer.slice(eolIndex + 2);
359
+
360
+ if (line.startsWith('data:')) {
361
+ const data = JSON.parse(line.slice(5));
362
+
363
+ if (data.mode) {
364
+ currentMode = data.mode;
365
+ loader.classList.add('hidden');
366
+ solutionDiv.classList.remove('hidden');
367
+ }
368
+
369
+ if (data.content) {
370
+ const content = data.content;
371
+ if (currentMode === 'thinking') {
372
+ thoughtsContent.innerHTML += `<p>${content}</p>`;
373
+ thoughtsContent.scrollTop = thoughtsContent.scrollHeight;
374
+ } else if (currentMode === 'answering') {
375
+ answerContent.innerHTML += content;
376
+ if (window.MathJax) {
377
+ MathJax.typesetPromise([answerContent]).catch((err) => console.log('MathJax erro MathJax.typesetPromise([answerContent]).catch((err) => console.log('MathJax error:', err));
378
+ }
379
+ }
380
+ }
381
+ }
382
+ }
383
+ }
384
+
385
+ } catch (error) {
386
+ console.error('Erreur:', error);
387
+ alert('Une erreur est survenue lors du traitement de la requête.');
388
+ loader.classList.add('hidden');
389
+ stopTimer();
390
+ }
391
+ });
392
+ });
393
+ </script>
394
+ </body>
395
+ </html>