Docfile commited on
Commit
158b9d6
·
verified ·
1 Parent(s): b1f0e3c

Create index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +544 -0
templates/index.html ADDED
@@ -0,0 +1,544 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ processEnvironments: true,
15
+ packages: ['base', 'ams', 'noerrors', 'noundefined', 'autoload', 'require'],
16
+ macros: {
17
+ RR: "{\\mathbb{R}}",
18
+ NN: "{\\mathbb{N}}",
19
+ ZZ: "{\\mathbb{Z}}",
20
+ QQ: "{\\mathbb{Q}}",
21
+ CC: "{\\mathbb{C}}",
22
+ brackets: ['{\\left[ #1 \\right]}', 1],
23
+ set: ['{\\left\\{ #1 \\right\\}}', 1]
24
+ },
25
+ environments: {
26
+ aligned: ['AMSmath'],
27
+ array: ['AMSmath'],
28
+ bmatrix: ['AMSmath'],
29
+ cases: ['AMSmath'],
30
+ matrix: ['AMSmath'],
31
+ pmatrix: ['AMSmath'],
32
+ vmatrix: ['AMSmath']
33
+ }
34
+ },
35
+ options: {
36
+ ignoreHtmlClass: 'tex2jax_ignore',
37
+ processHtmlClass: 'tex2jax_process',
38
+ renderActions: {
39
+ findScript: [10, function (doc) {
40
+ document.querySelectorAll('script[type^="math/tex"]').forEach(function (node) {
41
+ const display = !!node.type.match(/; *mode=display/);
42
+ const math = new doc.options.MathItem(node.textContent, doc.inputJax[0], display);
43
+ const text = document.createTextNode('');
44
+ node.parentNode.replaceChild(text, node);
45
+ math.start = { node: text, delim: '', n: 0 };
46
+ math.end = { node: text, delim: '', n: 0 };
47
+ doc.math.push(math);
48
+ });
49
+ }, '']
50
+ }
51
+ },
52
+ svg: {
53
+ fontCache: 'global',
54
+ scale: 1,
55
+ minScale: .5
56
+ },
57
+ loader: {
58
+ load: ['[tex]/autoload', '[tex]/ams', '[tex]/require']
59
+ }
60
+ };
61
+ </script>
62
+ <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
63
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/marked.min.js"></script>
64
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.24.1/prism.min.js"></script>
65
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.24.1/themes/prism.min.css" rel="stylesheet">
66
+ <style>
67
+ @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap');
68
+
69
+ body {
70
+ font-family: 'Space Grotesk', sans-serif;
71
+ background-color: white;
72
+ }
73
+
74
+ .uploadArea {
75
+ background: #f3f4f6;
76
+ border: 2px dashed #d1d5db;
77
+ }
78
+
79
+ .uploadArea:hover {
80
+ border-color: #3b82f6;
81
+ transform: translateY(-2px);
82
+ }
83
+
84
+ .blue-button {
85
+ background: #3b82f6;
86
+ transition: all 0.3s ease;
87
+ }
88
+
89
+ .blue-button:hover {
90
+ background: #2563eb;
91
+ transform: translateY(-2px);
92
+ }
93
+
94
+ .loader {
95
+ width: 48px;
96
+ height: 48px;
97
+ border: 3px solid #3b82f6;
98
+ border-bottom-color: transparent;
99
+ border-radius: 50%;
100
+ display: inline-block;
101
+ box-sizing: border-box;
102
+ animation: rotation 1s linear infinite;
103
+ }
104
+
105
+ @keyframes rotation {
106
+ 0% { transform: rotate(0deg); }
107
+ 100% { transform: rotate(360deg); }
108
+ }
109
+
110
+ .thought-box {
111
+ transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
112
+ max-height: 0;
113
+ overflow: hidden;
114
+ }
115
+
116
+ .thought-box.open {
117
+ max-height: 1000px;
118
+ }
119
+
120
+ .preview-container {
121
+ display: flex;
122
+ justify-content: center;
123
+ align-items: center;
124
+ margin-top: 20px;
125
+ }
126
+
127
+ .preview-image {
128
+ max-width: 300px;
129
+ max-height: 300px;
130
+ border-radius: 8px;
131
+ }
132
+
133
+ #thoughtsContent, #answerContent {
134
+ max-height: 500px;
135
+ overflow-y: auto;
136
+ }
137
+
138
+ .timestamp {
139
+ color: #3b82f6;
140
+ margin-left: 10px;
141
+ font-size: 0.9em;
142
+ }
143
+
144
+ /* Styles Markdown */
145
+ .markdown-content {
146
+ line-height: 1.6;
147
+ }
148
+
149
+ .markdown-content h1 {
150
+ font-size: 2em;
151
+ font-weight: bold;
152
+ margin-top: 1.5em;
153
+ margin-bottom: 1em;
154
+ }
155
+
156
+ .markdown-content h2 {
157
+ font-size: 1.5em;
158
+ font-weight: bold;
159
+ margin-top: 1.25em;
160
+ margin-bottom: 0.75em;
161
+ }
162
+
163
+ .markdown-content h3 {
164
+ font-size: 1.25em;
165
+ font-weight: bold;
166
+ margin-top: 1em;
167
+ margin-bottom: 0.5em;
168
+ }
169
+
170
+ .markdown-content p {
171
+ margin: 1em 0;
172
+ }
173
+
174
+ .markdown-content ul {
175
+ list-style-type: disc;
176
+ margin-left: 1em;
177
+ margin-top: 1em;
178
+ margin-bottom: 1em;
179
+ }
180
+
181
+ .markdown-content ol {
182
+ list-style-type: decimal;
183
+ margin-left: 1em;
184
+ margin-top: 1em;
185
+ margin-bottom: 1em;
186
+ }
187
+
188
+ .markdown-content blockquote {
189
+ border-left: 4px solid #e5e7eb;
190
+ padding-left: 1em;
191
+ margin: 1em 0;
192
+ font-style: italic;
193
+ }
194
+
195
+ .markdown-content code:not([class*="language-"]) {
196
+ background-color: #f3f4f6;
197
+ border-radius: 0.25em;
198
+ padding: 0.2em 0.4em;
199
+ font-family: monospace;
200
+ font-size: 0.9em;
201
+ }
202
+
203
+ .markdown-content pre {
204
+ background-color: #f3f4f6;
205
+ border-radius: 0.375em;
206
+ padding: 1em;
207
+ margin: 1em 0;
208
+ overflow-x: auto;
209
+ }
210
+
211
+ /* Styles LaTeX */
212
+ .math-display {
213
+ margin: 1em 0;
214
+ overflow-x: auto;
215
+ text-align: center;
216
+ }
217
+
218
+ .math-inline {
219
+ margin: 0 0.2em;
220
+ vertical-align: middle;
221
+ }
222
+
223
+ /* Tables */
224
+ .markdown-content table {
225
+ border-collapse: collapse;
226
+ width: 100%;
227
+ margin: 1em 0;
228
+ }
229
+
230
+ .markdown-content th,
231
+ .markdown-content td {
232
+ border: 1px solid #e5e7eb;
233
+ padding: 0.5em;
234
+ }
235
+
236
+ .markdown-content th {
237
+ background-color: #f3f4f6;
238
+ font-weight: bold;
239
+ }
240
+
241
+ /* Images */
242
+ .markdown-content img {
243
+ max-width: 100%;
244
+ height: auto;
245
+ margin: 1em 0;
246
+ border-radius: 0.375em;
247
+ }
248
+ </style>
249
+ </head>
250
+ <body class="p-4">
251
+ <div class="w-full">
252
+ <div class="p-8">
253
+ <div class="text-center mb-12">
254
+ <h1 class="text-4xl font-bold text-blue-600 mb-4">Mariam M-0</h1>
255
+ <p class="text-gray-600 text-lg">Solution Mathématique Intelligente</p>
256
+ </div>
257
+
258
+ <form id="problemForm" class="space-y-8" enctype="multipart/form-data">
259
+ <div class="relative">
260
+ <div class="uploadArea p-12 text-center transition-all duration-300 cursor-pointer">
261
+ <input type="file" id="imageInput" name="image" accept="image/*" class="absolute inset-0 w-full h-full opacity-0 cursor-pointer">
262
+ <div class="space-y-4">
263
+ <div class="w-20 h-20 mx-auto border-2 border-blue-400 rounded-full flex items-center justify-center">
264
+ <svg class="w-10 h-10 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
265
+ <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" />
266
+ </svg>
267
+ </div>
268
+ <div class="text-gray-700 text-lg font-medium">Déposez votre image ici</div>
269
+ <div class="text-gray-500 text-sm">ou cliquez pour sélectionner</div>
270
+ </div>
271
+ </div>
272
+ <div id="imagePreview" class="preview-container hidden">
273
+ <img id="previewImage" src="#" alt="Prévisualisation de l'image" class="preview-image">
274
+ </div>
275
+ </div>
276
+
277
+ <button type="submit" class="blue-button w-full py-4 text-white font-medium text-lg transition-all duration-300">
278
+ Résoudre le problème
279
+ </button>
280
+ </form>
281
+
282
+ <div id="loader" class="hidden mt-12">
283
+ <div class="flex flex-col items-center justify-center space-y-4">
284
+ <span class="loader"></span>
285
+ <div class="text-gray-600 text-lg">Analyse en cours...</div>
286
+ </div>
287
+ </div>
288
+
289
+ <div id="solution" class="hidden mt-12 space-y-8">
290
+ <div class="border-t pt-6">
291
+ <button id="thoughtsToggle" class="w-full flex justify-between items-center text-left text-lg font-medium text-gray-700 hover:text-blue-600 transition-colors">
292
+ <div class="flex items-center">
293
+ <span>Processus de Réflexion</span>
294
+ <span id="timestamp" class="timestamp"></span>
295
+ </div>
296
+ <svg class="w-6 h-6 transform transition-transform duration-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
297
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
298
+ </svg>
299
+ </button>
300
+ <div id="thoughtsBox" class="thought-box">
301
+ <div id="thoughtsContent" class="prose max-w-none text-gray-600 mt-4 markdown-content"></div>
302
+ </div>
303
+ </div>
304
+
305
+ <div class="border-t pt-8">
306
+ <h3 class="text-2xl font-bold text-gray-800 mb-6">Solution</h3>
307
+ <div id="answerContent" class="prose max-w-none text-gray-700 markdown-content"></div>
308
+ </div>
309
+ </div>
310
+ </div>
311
+ </div>
312
+
313
+ <script>
314
+ document.addEventListener('DOMContentLoaded', () => {
315
+ const form = document.getElementById('problemForm');
316
+ const imageInput = document.getElementById('imageInput');
317
+ const loader = document.getElementById('loader');
318
+ const solutionDiv = document.getElementById('solution');
319
+ const thoughtsContent = document.getElementById('thoughtsContent');
320
+ const answerContent = document.getElementById('answerContent');
321
+ const thoughtsToggle = document.getElementById('thoughtsToggle');
322
+ const thoughtsBox = document.getElementById('thoughtsBox');
323
+ const imagePreview = document.getElementById('imagePreview');
324
+ const previewImage = document.getElementById('previewImage');
325
+ const timestamp = document.getElementById('timestamp');
326
+
327
+ let startTime = null;
328
+ let timerInterval = null;
329
+
330
+ // Configuration de Marked
331
+ marked.setOptions({
332
+ renderer: new marked.Renderer(),
333
+ highlight: function(code, lang) {
334
+ if (Prism.languages[lang]) {
335
+ return Prism.highlight(code, Prism.languages[lang], lang);
336
+ }
337
+ return code;
338
+ },
339
+ pedantic: false,
340
+ gfm: true,
341
+ breaks: true,
342
+ sanitize: false,
343
+ smartypants: true,
344
+ xhtml: true
345
+ });
346
+
347
+ // Extension du renderer Marked pour LaTeX
348
+ const renderer = new marked.Renderer();
349
+ const originalParagraph = renderer.paragraph.bind(renderer);
350
+
351
+ renderer.paragraph = (text) => {
352
+ // Gestion des blocs LaTeX display
353
+ text = text.replace(/\$\$([\s\S]+?)\$\$/g, (_, formula) => {
354
+ return `<div class="math-display">\\[${formula}\\]</div>`;
355
+ });
356
+
357
+ // Gestion des formules LaTeX inline
358
+ text = text.replace(/\$(.+?)\$/g, (_, formula) => {
359
+ return `<span class="math-inline">\\(${formula}\\)</span>`;
360
+ });
361
+
362
+ return originalParagraph(text);
363
+ };
364
+
365
+ marked.use({ renderer });
366
+
367
+ function updateTimestamp() {
368
+ if (startTime) {
369
+ const elapsed = Math.floor((Date.now() - startTime) / 1000);
370
+ timestamp.textContent = elapsed + "s";
371
+ }
372
+ }
373
+
374
+ function startTimer() {
375
+ startTime = Date.now();
376
+ timerInterval = setInterval(updateTimestamp, 1000);
377
+ updateTimestamp();
378
+ }
379
+
380
+ function stopTimer() {
381
+ if (timerInterval) {
382
+ clearInterval(timerInterval);
383
+ timerInterval = null;
384
+ }
385
+ startTime = null;
386
+ timestamp.textContent = "";
387
+ }
388
+
389
+ // Fonction de rendu du contenu
390
+ function renderContent(content, element) {
391
+ const renderedContent = marked(content);
392
+ element.innerHTML = renderedContent;
393
+
394
+ // Déclenche le rendu MathJax
395
+ if (window.MathJax) {
396
+ MathJax.typesetPromise([element]).catch((err) => {
397
+ console.error('MathJax error:', err);
398
+ });
399
+ }
400
+ }
401
+
402
+ thoughtsToggle.addEventListener('click', () => {
403
+ thoughtsBox.classList.toggle('open');
404
+ thoughtsToggle.querySelector('svg').classList.toggle('rotate-180');
405
+ });
406
+
407
+ imageInput.addEventListener('change', function(e) {
408
+ const file = this.files[0];
409
+ if (file) {
410
+ const reader = new FileReader();
411
+ reader.onload = function(e) {
412
+ previewImage.src = e.target.result;
413
+ imagePreview.classList.remove('hidden');
414
+ }
415
+ reader.readAsDataURL(file);
416
+ } else {
417
+ previewImage.src = "";
418
+ imagePreview.classList.add('hidden');
419
+ }
420
+ });
421
+
422
+ const dropZone = document.querySelector('.uploadArea');
423
+
424
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
425
+ dropZone.addEventListener(eventName, preventDefaults, false);
426
+ });
427
+
428
+ function preventDefaults(e) {
429
+ e.preventDefault();
430
+ e.stopPropagation();
431
+ }
432
+
433
+ ['dragenter', 'dragover'].forEach(eventName => {
434
+ dropZone.addEventListener(eventName, highlight, false);
435
+ });
436
+
437
+ ['dragleave', 'drop'].forEach(eventName => {
438
+ dropZone.addEventListener(eventName, unhighlight, false);
439
+ });
440
+
441
+ function highlight(e) {
442
+ dropZone.classList.add('border-blue-400');
443
+ }
444
+
445
+ function unhighlight(e) {
446
+ dropZone.classList.remove('border-blue-400');
447
+ }
448
+
449
+ dropZone.addEventListener('drop', handleDrop, false);
450
+
451
+ function handleDrop(e) {
452
+ const dt = e.dataTransfer;
453
+ const files = dt.files;
454
+
455
+ if (files.length) {
456
+ imageInput.files = files;
457
+ const file = files[0];
458
+ const reader = new FileReader();
459
+ reader.onload = function(e) {
460
+ previewImage.src = e.target.result;
461
+ imagePreview.classList.remove('hidden');
462
+ }
463
+ reader.readAsDataURL(file);
464
+ }
465
+ }
466
+
467
+ form.addEventListener('submit', async (event) => {
468
+ event.preventDefault();
469
+ const file = imageInput.files[0];
470
+ if (!file) {
471
+ alert('Veuillez sélectionner une image.');
472
+ return;
473
+ }
474
+
475
+ startTimer();
476
+
477
+ loader.classList.remove('hidden');
478
+ solutionDiv.classList.add('hidden');
479
+ thoughtsContent.innerHTML = '';
480
+ answerContent.innerHTML = '';
481
+ thoughtsBox.classList.add('open');
482
+
483
+ const formData = new FormData();
484
+ formData.append('image', file);
485
+
486
+ try {
487
+ let currentMode = null;
488
+ const response = await fetch('/solve', {
489
+ method: 'POST',
490
+ body: formData
491
+ });
492
+
493
+ const reader = response.body.getReader();
494
+ const decoder = new TextDecoder();
495
+ let buffer = '';
496
+
497
+ while (true) {
498
+ const { done, value } = await reader.read();
499
+ if (done) {
500
+ stopTimer();
501
+ break;
502
+ }
503
+
504
+ buffer += decoder.decode(value, { stream: true });
505
+ let eolIndex;
506
+
507
+ while ((eolIndex = buffer.indexOf('\n\n')) >= 0) {
508
+ const line = buffer.slice(0, eolIndex).trim();
509
+ buffer = buffer.slice(eolIndex + 2);
510
+
511
+ if (line.startsWith('data:')) {
512
+ const data = JSON.parse(line.slice(5));
513
+
514
+ if (data.mode) {
515
+ currentMode = data.mode;
516
+ loader.classList.add('hidden');
517
+ solutionDiv.classList.remove('hidden');
518
+ }
519
+
520
+ if (data.content) {
521
+ const content = data.content;
522
+ if (currentMode === 'thinking') {
523
+ renderContent(content, thoughtsContent);
524
+ thoughtsContent.scrollTop = thoughtsContent.scrollHeight;
525
+ } else if (currentMode === 'answering') {
526
+ renderContent(content, answerContent);
527
+ answerContent.scrollTop = answerContent.scrollHeight;
528
+ }
529
+ }
530
+ }
531
+ }
532
+ }
533
+
534
+ } catch (error) {
535
+ console.error('Erreur:', error);
536
+ alert('Une erreur est survenue lors du traitement de la requête.');
537
+ loader.classList.add('hidden');
538
+ stopTimer();
539
+ }
540
+ });
541
+ });
542
+ </script>
543
+ </body>
544
+ </html>