Docfile commited on
Commit
abf0cb6
·
verified ·
1 Parent(s): 12d4886

Update templates/maj.html

Browse files
Files changed (1) hide show
  1. templates/maj.html +276 -404
templates/maj.html CHANGED
@@ -1,416 +1,288 @@
1
-
2
-
3
  <!DOCTYPE html>
4
  <html lang="fr">
5
  <head>
6
- <meta charset="UTF-8">
7
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
8
- <title>Mariam M-0 | Solution Mathématique</title>
9
- <!-- Tailwind CSS -->
10
- <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
11
-
12
- <!-- SweetAlert2 -->
13
- <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
14
-
15
- <!-- Configuration de MathJax -->
16
- <script>
17
- window.MathJax = {
18
- tex: {
19
- inlineMath: [['$', '$']],
20
- displayMath: [['$$', '$$']],
21
- processEscapes: true,
22
- packages: {'[+]': ['autoload', 'ams']}
23
- },
24
- options: {
25
- enableMenu: false,
26
- messageStyle: 'none'
27
- },
28
- startup: {
29
- pageReady: () => { window.mathJaxReady = true; }
30
- }
31
- };
32
- </script>
33
- <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" id="MathJax-script" async></script>
34
- <script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/marked.umd.min.js"></script>
35
-
36
- <style>
37
- @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;700&display=swap');
38
- body { font-family: 'Space Grotesk', sans-serif; }
39
-
40
- .uploadArea {
41
- background: #f3f4f6;
42
- border: 2px dashed #d1d5db;
43
- transition: border-color 0.2s ease;
44
- }
45
- .uploadArea:hover { border-color: #3b82f6; }
46
-
47
- .blue-button { background: #3b82f6; transition: background-color 0.2s ease; }
48
- .blue-button:hover { background: #2563eb; }
49
-
50
- .loader {
51
- width: 48px;
52
- height: 48px;
53
- border: 3px solid #3b82f6;
54
- border-bottom-color: transparent;
55
- border-radius: 50%;
56
- display: inline-block;
57
- animation: rotation 1s linear infinite;
58
- }
59
- @keyframes rotation { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
60
-
61
- .thought-box {
62
- transition: max-height 0.3s ease-out;
63
- max-height: 0;
64
- overflow: hidden;
65
- }
66
- .thought-box.open { max-height: 500px; }
67
-
68
- #thoughtsContent, #answerContent {
69
- max-height: 500px;
70
- overflow-y: auto;
71
- scroll-behavior: smooth;
72
- white-space: pre-wrap;
73
- }
74
-
75
- .preview-image { max-width: 300px; max-height: 300px; object-fit: contain; }
76
-
77
- .timestamp { color: #3b82f6; font-size: 0.9em; margin-left: 8px; }
78
-
79
- table {
80
- border-collapse: collapse;
81
- width: 100%;
82
- margin-bottom: 1rem;
83
- }
84
- th, td {
85
- border: 1px solid #d1d5db;
86
- padding: 0.5rem;
87
- text-align: left;
88
- }
89
- th { background-color: #f3f4f6; font-weight: 600; }
90
- .table-responsive { overflow-x: auto; }
91
-
92
- /* Style pour le bouton Sauvegarder afin de le mettre en évidence */
93
- #saveButton {
94
- background: #3b82f6;
95
- color: white;
96
- padding: 0.5rem 1rem;
97
- border-radius: 0.375rem;
98
- transition: background-color 0.2s ease;
99
- }
100
- #saveButton:hover { background: #2563eb; }
101
-
102
- /* Modal plein écran pour les sauvegardes */
103
- #savedModal {
104
- display: none;
105
- position: fixed;
106
- inset: 0;
107
- background: rgba(0,0,0,0.5);
108
- z-index: 50;
109
- }
110
- #savedModal.active { display: block; }
111
- #savedModalContent {
112
- background: #fff;
113
- width: 100%;
114
- height: 100%;
115
- overflow-y: auto;
116
- }
117
- </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  </head>
119
- <body class="p-4">
120
- <div class="max-w-4xl mx-auto">
121
- <header class="p-6 text-center mb-8">
122
- <h1 class="text-4xl font-bold text-blue-600">Mariam M-0</h1>
123
- <p class="text-gray-600">Solution Mathématique/Physique/Chimie Intelligente</p>
124
- <p class="performance-warning">
125
- Vous utilisez actuellement les modèles/performances moyens. Accédez à des performances supérieures avec un abonnement premium !
126
- </p>
127
-
128
- <div class="mt-4 flex justify-end">
129
- <button id="openSaved" class="blue-button px-4 py-2 text-white rounded">Sauvegardes</button>
130
- </div>
131
- </header>
132
-
133
- <main id="mainContent">
134
- <form id="problemForm" class="space-y-6" novalidate>
135
- <!-- Zone de dépôt / sélection d'image -->
136
- <div class="uploadArea p-8 text-center relative" aria-label="Zone de dépôt d'image">
137
- <input type="file" id="imageInput" accept="image/*" class="absolute inset-0 w-full h-full opacity-0 cursor-pointer" aria-label="Choisir une image">
138
- <div class="space-y-3">
139
- <div class="w-16 h-16 mx-auto border-2 border-blue-400 rounded-full flex items-center justify-center">
140
- <svg class="w-8 h-8 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
141
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
142
- 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" />
143
- </svg>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  </div>
145
- <p class="text-gray-700 font-medium">Déposez votre image ici</p>
146
- <p class="text-gray-500 text-sm">ou cliquez pour sélectionner</p>
147
- </div>
148
- </div>
149
- <!-- Aperçu de l'image -->
150
- <div id="imagePreview" class="hidden text-center">
151
- <img id="previewImage" class="preview-image mx-auto" alt="Prévisualisation de l'image">
152
- </div>
153
- <button type="submit" class="blue-button w-full py-3 text-white font-medium rounded-lg">
154
- Résoudre le problème
155
- </button>
156
- </form>
157
-
158
- <!-- Loader -->
159
- <div id="loader" class="hidden mt-8 text-center">
160
- <span class="loader"></span>
161
- <p class="mt-4 text-gray-600">Analyse en cours...</p>
162
- </div>
163
-
164
- <!-- Zone d'affichage de la solution -->
165
- <section id="solution" class="hidden mt-8 space-y-6 relative">
166
- <div class="border-t pt-4">
167
- <button id="thoughtsToggle" type="button" class="w-full flex justify-between items-center p-2">
168
- <span class="font-medium text-gray-700">Processus de Réflexion</span>
169
- <span id="timestamp" class="timestamp"></span>
170
- </button>
171
- <div id="thoughtsBox" class="thought-box">
172
- <div id="thoughtsContent" class="p-4 text-gray-600"></div>
173
- </div>
174
- </div>
175
- <div class="border-t pt-6">
176
- <div class="flex justify-between items-center">
177
- <h3 class="text-xl font-bold text-gray-800 mb-4">Solution</h3>
178
- <!-- Bouton Sauvegarder mis en évidence -->
179
- <button id="saveButton">Sauvegarder</button>
180
- </div>
181
- <div id="answerContent" class="text-gray-700 table-responsive"></div>
182
  </div>
183
- </section>
184
- </main>
185
- </div>
186
-
187
- <!-- Modal plein écran pour les sauvegardes -->
188
- <div id="savedModal">
189
- <div id="savedModalContent" class="p-6">
190
- <header class="flex justify-between items-center border-b pb-4">
191
- <h2 class="text-2xl font-bold">Sauvegardes</h2>
192
- <button id="closeSaved" class="text-3xl text-gray-600">&times;</button>
193
- </header>
194
- <div id="savedListContainer" class="mt-4">
195
- <ul id="savedList" class="space-y-4">
196
- <!-- Liste des sauvegardes insérée dynamiquement -->
197
- </ul>
198
- </div>
199
- <div class="mt-6">
200
- <button id="newExercise" class="blue-button w-full py-3 text-white font-medium rounded-lg">
201
- Résoudre un nouvel exercice
202
- </button>
203
- </div>
204
  </div>
205
- </div>
206
-
207
- <script>
208
- document.addEventListener('DOMContentLoaded', () => {
209
- // Récupération des éléments
210
- const form = document.getElementById('problemForm');
211
- const imageInput = document.getElementById('imageInput');
212
- const loader = document.getElementById('loader');
213
- const solutionSection = document.getElementById('solution');
214
- const thoughtsContent = document.getElementById('thoughtsContent');
215
- const answerContent = document.getElementById('answerContent');
216
- const thoughtsToggle = document.getElementById('thoughtsToggle');
217
- const thoughtsBox = document.getElementById('thoughtsBox');
218
- const imagePreview = document.getElementById('imagePreview');
219
- const previewImage = document.getElementById('previewImage');
220
- const timestamp = document.getElementById('timestamp');
221
- const saveButton = document.getElementById('saveButton');
222
- const openSaved = document.getElementById('openSaved');
223
- const closeSaved = document.getElementById('closeSaved');
224
- const savedModal = document.getElementById('savedModal');
225
- const savedList = document.getElementById('savedList');
226
- const newExercise = document.getElementById('newExercise');
227
- const mainContent = document.getElementById('mainContent');
228
-
229
- let startTime = null;
230
- let timerInterval = null;
231
- let thoughtsBuffer = '';
232
- let answerBuffer = '';
233
- let currentMode = null;
234
- let updateTimeout = null;
235
-
236
- // Mise à jour du temps écoulé
237
- const updateTimestamp = () => {
238
- if (startTime) {
239
- const seconds = Math.floor((Date.now() - startTime) / 1000);
240
- timestamp.textContent = `${seconds}s`;
241
- }
242
- };
243
- const startTimer = () => { startTime = Date.now(); timerInterval = setInterval(updateTimestamp, 1000); updateTimestamp(); };
244
- const stopTimer = () => { clearInterval(timerInterval); startTime = null; timestamp.textContent = ''; };
245
-
246
- // Affichage de l'image sélectionnée
247
- const handleFileSelect = file => {
248
- if (!file) return;
249
- const reader = new FileReader();
250
- reader.onload = e => {
251
- previewImage.src = e.target.result;
252
- imagePreview.classList.remove('hidden');
253
- };
254
- reader.readAsDataURL(file);
255
- };
256
-
257
- thoughtsToggle.addEventListener('click', () => { thoughtsBox.classList.toggle('open'); });
258
- imageInput.addEventListener('change', e => handleFileSelect(e.target.files[0]));
259
-
260
- // Gestion du glisser-déposer
261
- const dropZone = document.querySelector('.uploadArea');
262
- dropZone.addEventListener('dragover', e => { e.preventDefault(); dropZone.classList.add('border-blue-400'); });
263
- dropZone.addEventListener('dragleave', e => { e.preventDefault(); dropZone.classList.remove('border-blue-400'); });
264
- dropZone.addEventListener('drop', e => { e.preventDefault(); dropZone.classList.remove('border-blue-400'); handleFileSelect(e.dataTransfer.files[0]); });
265
-
266
- // Rendu MathJax et mise à jour de l'affichage
267
- const typesetAnswerIfReady = async () => {
268
- if (window.mathJaxReady) {
269
- MathJax.startup.document.elements = [document.getElementById('answerContent')];
270
- await MathJax.typesetPromise();
271
- answerContent.scrollTop = answerContent.scrollHeight;
272
- } else { setTimeout(typesetAnswerIfReady, 200); }
273
- };
274
- const updateDisplay = async () => {
275
- thoughtsContent.innerHTML = marked.parse(thoughtsBuffer);
276
- answerContent.innerHTML = marked.parse(answerBuffer);
277
- await typesetAnswerIfReady();
278
- updateTimeout = null;
279
- };
280
- const scheduleUpdate = () => { if (!updateTimeout) updateTimeout = setTimeout(updateDisplay, 200); };
281
-
282
- marked.setOptions({ gfm: true, breaks: true });
283
-
284
- // Envoi de l'image pour résolution
285
- form.addEventListener('submit', async e => {
286
- e.preventDefault();
287
- const file = imageInput.files[0];
288
- if (!file) { alert('Veuillez sélectionner une image.'); return; }
289
- startTimer();
290
- loader.classList.remove('hidden');
291
- solutionSection.classList.add('hidden');
292
- thoughtsContent.innerHTML = '';
293
- answerContent.innerHTML = '';
294
- thoughtsBuffer = '';
295
- answerBuffer = '';
296
- currentMode = null;
297
- thoughtsBox.classList.add('open');
298
-
299
- const formData = new FormData();
300
- formData.append('image', file);
301
- try {
302
- const response = await fetch('/solved', { method: 'POST', body: formData });
303
- const reader = response.body.getReader();
304
- const decoder = new TextDecoder();
305
- let buffer = '';
306
- const processChunk = async chunk => {
307
- buffer += decoder.decode(chunk, { stream: true });
308
- const lines = buffer.split('\n\n');
309
- buffer = lines.pop();
310
- for (const line of lines) {
311
- if (!line.startsWith('data:')) continue;
312
- const data = JSON.parse(line.slice(5));
313
- if (data.mode) {
314
- currentMode = data.mode;
315
- loader.classList.add('hidden');
316
- solutionSection.classList.remove('hidden');
317
- }
318
- if (data.content) {
319
- if (currentMode === 'thinking') { thoughtsBuffer += data.content; }
320
- else if (currentMode === 'answering') { answerBuffer += data.content; }
321
- }
322
  }
323
- scheduleUpdate();
324
- };
325
- while (true) {
326
- const { done, value } = await reader.read();
327
- if (done) {
328
- if (buffer) {
329
- const data = JSON.parse(buffer.slice(5));
330
- if (data.content) {
331
- if (currentMode === 'thinking') { thoughtsBuffer += data.content; }
332
- else if (currentMode === 'answering') { answerBuffer += data.content; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
  }
334
- }
335
- scheduleUpdate();
336
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337
  }
338
- await processChunk(value);
339
- }
340
- stopTimer();
341
- } catch (error) {
342
- console.error('Erreur:', error);
343
- alert('Une erreur est survenue.');
344
- loader.classList.add('hidden');
345
- stopTimer();
346
- }
347
- });
348
-
349
- // Sauvegarde de la solution avec SweetAlert2
350
- saveButton.addEventListener('click', () => {
351
- const saveName = prompt("Entrez un nom pour la sauvegarde :");
352
- if (!saveName) return;
353
- const saveData = {
354
- answer: answerContent.innerHTML,
355
- thinking: thoughtsContent.innerHTML,
356
- date: new Date().toLocaleString()
357
  };
358
- let savedExercises = JSON.parse(localStorage.getItem('savedExercises') || '{}');
359
- savedExercises[saveName] = saveData;
360
- localStorage.setItem('savedExercises', JSON.stringify(savedExercises));
361
- Swal.fire({
362
- icon: 'success',
363
- title: 'Sauvegarde réussie',
364
- text: 'Votre solution a bien été sauvegardée !',
365
- timer: 2000,
366
- showConfirmButton: false
367
- });
368
- });
369
-
370
- // Chargement des sauvegardes dans le modal
371
- const loadSavedList = () => {
372
- savedList.innerHTML = '';
373
- const savedExercises = JSON.parse(localStorage.getItem('savedExercises') || '{}');
374
- for (const [name, data] of Object.entries(savedExercises)) {
375
- const li = document.createElement('li');
376
- li.innerHTML = `<button class="w-full text-left text-blue-600 hover:underline" data-save="${name}">${name} <span class="text-gray-500 text-xs">(${data.date})</span></button>`;
377
- savedList.appendChild(li);
378
- }
379
- };
380
-
381
- savedList.addEventListener('click', (e) => {
382
- if (e.target && e.target.dataset.save) {
383
- const saveName = e.target.dataset.save;
384
- const savedExercises = JSON.parse(localStorage.getItem('savedExercises') || '{}');
385
- const data = savedExercises[saveName];
386
- if (data) {
387
- form.classList.add('hidden');
388
- loader.classList.add('hidden');
389
- solutionSection.classList.remove('hidden');
390
- thoughtsContent.innerHTML = data.thinking;
391
- answerContent.innerHTML = data.answer;
392
- savedModal.classList.remove('active');
393
- }
394
- }
395
- });
396
-
397
- // Ouverture / fermeture du modal de sauvegardes
398
- openSaved.addEventListener('click', () => { loadSavedList(); savedModal.classList.add('active'); });
399
- closeSaved.addEventListener('click', () => { savedModal.classList.remove('active'); });
400
-
401
- // Bouton présent uniquement dans le modal pour lancer un nouvel exercice
402
- newExercise.addEventListener('click', () => {
403
- form.reset();
404
- form.classList.remove('hidden');
405
- solutionSection.classList.add('hidden');
406
- imagePreview.classList.add('hidden');
407
- thoughtsContent.innerHTML = '';
408
- answerContent.innerHTML = '';
409
- thoughtsBuffer = '';
410
- answerBuffer = '';
411
- savedModal.classList.remove('active');
412
- });
413
- });
414
- </script>
415
  </body>
416
- </html>
 
 
 
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>Math Solver - Version Gratuite</title>
7
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
8
+ <style>
9
+ :root {
10
+ --primary-color: #4a6fa5;
11
+ --secondary-color: #166088;
12
+ --accent-color: #4fc3f7;
13
+ --background-color: #f8f9fa;
14
+ --text-color: #333;
15
+ --box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
16
+ }
17
+
18
+ body {
19
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
20
+ line-height: 1.6;
21
+ margin: 0;
22
+ padding: 0;
23
+ background-color: var(--background-color);
24
+ color: var(--text-color);
25
+ }
26
+
27
+ .container {
28
+ max-width: 1000px;
29
+ margin: 0 auto;
30
+ padding: 20px;
31
+ }
32
+
33
+ header {
34
+ text-align: center;
35
+ padding: 20px 0;
36
+ margin-bottom: 30px;
37
+ }
38
+
39
+ .logo {
40
+ font-size: 2.5rem;
41
+ font-weight: bold;
42
+ color: var(--primary-color);
43
+ margin-bottom: 10px;
44
+ }
45
+
46
+ .subtitle {
47
+ font-size: 1.2rem;
48
+ color: var(--secondary-color);
49
+ margin-bottom: 20px;
50
+ }
51
+
52
+ .content-box {
53
+ background-color: white;
54
+ border-radius: 10px;
55
+ box-shadow: var(--box-shadow);
56
+ padding: 30px;
57
+ margin-bottom: 30px;
58
+ text-align: center;
59
+ }
60
+
61
+ h1 {
62
+ color: var(--primary-color);
63
+ margin-top: 0;
64
+ }
65
+
66
+ .feature-list {
67
+ list-style-type: none;
68
+ padding: 0;
69
+ margin: 30px 0;
70
+ text-align: left;
71
+ }
72
+
73
+ .feature-list li {
74
+ padding: 10px 0;
75
+ margin-bottom: 10px;
76
+ display: flex;
77
+ align-items: center;
78
+ }
79
+
80
+ .feature-list i {
81
+ color: var(--accent-color);
82
+ margin-right: 10px;
83
+ font-size: 1.2rem;
84
+ }
85
+
86
+ .cta-button {
87
+ display: inline-block;
88
+ background-color: var(--primary-color);
89
+ color: white;
90
+ padding: 12px 25px;
91
+ border-radius: 5px;
92
+ text-decoration: none;
93
+ font-weight: bold;
94
+ transition: all 0.3s ease;
95
+ margin: 20px 10px;
96
+ border: none;
97
+ cursor: pointer;
98
+ }
99
+
100
+ .cta-button:hover {
101
+ background-color: var(--secondary-color);
102
+ transform: translateY(-2px);
103
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
104
+ }
105
+
106
+ .upgrade-section {
107
+ margin-top: 30px;
108
+ padding: 20px;
109
+ border-top: 1px solid #ddd;
110
+ }
111
+
112
+ footer {
113
+ text-align: center;
114
+ padding: 20px 0;
115
+ color: #666;
116
+ font-size: 0.9rem;
117
+ }
118
+
119
+ @media (max-width: 768px) {
120
+ .container {
121
+ padding: 15px;
122
+ }
123
+
124
+ .content-box {
125
+ padding: 20px;
126
+ }
127
+ }
128
+ </style>
129
  </head>
130
+ <body>
131
+ <div class="container">
132
+ <header>
133
+ <div class="logo">Math Solver</div>
134
+ <div class="subtitle">La solution intelligente pour vos problèmes mathématiques</div>
135
+ </header>
136
+
137
+ <div class="content-box">
138
+ <h1>Version Gratuite</h1>
139
+ <p>Vous utilisez actuellement la version gratuite de Math Solver qui vous permet de résoudre 3 problèmes par jour.</p>
140
+
141
+ <div class="feature-list">
142
+ <h2>Fonctionnalités disponibles :</h2>
143
+ <ul class="feature-list">
144
+ <li><i class="fas fa-check-circle"></i> Résolution de problèmes mathématiques basiques</li>
145
+ <li><i class="fas fa-check-circle"></i> 3 résolutions gratuites par jour</li>
146
+ <li><i class="fas fa-check-circle"></i> Explication des étapes de résolution</li>
147
+ <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Mode d'exécution de code avancé (version Pro)</span></li>
148
+ <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Résolutions illimitées (version Pro)</span></li>
149
+ <li><i class="fas fa-times-circle"></i> <span style="color: #999;">Support prioritaire (version Pro)</span></li>
150
+ </ul>
151
+ </div>
152
+
153
+ <div class="upload-section">
154
+ <form id="imageForm" enctype="multipart/form-data">
155
+ <input type="file" id="imageInput" name="image" accept="image/*" style="display: none;">
156
+ <button type="button" id="uploadButton" class="cta-button" onclick="document.getElementById('imageInput').click()">
157
+ <i class="fas fa-upload"></i> Télécharger une image
158
+ </button>
159
+ </form>
160
+
161
+ <p id="uploadStatus"></p>
162
+ <div id="imagePreview" style="display: none; margin: 20px auto; max-width: 500px;">
163
+ <img id="preview" style="width: 100%; border-radius: 8px; box-shadow: var(--box-shadow);">
164
+ </div>
165
+
166
+ <button id="solveButton" class="cta-button" style="display: none; background-color: var(--secondary-color);">
167
+ <i class="fas fa-calculator"></i> Résoudre ce problème
168
+ </button>
169
+ </div>
170
+
171
+ <div id="solutionOutput" style="margin-top: 30px; text-align: left; display: none;">
172
+ <h3>Solution :</h3>
173
+ <div id="loadingIndicator" style="display: none; text-align: center;">
174
+ <p><i class="fas fa-spinner fa-spin"></i> Analyse et résolution en cours...</p>
175
+ </div>
176
+ <div id="solution" style="background: #f9f9f9; padding: 20px; border-radius: 8px; white-space: pre-wrap;"></div>
177
+ </div>
178
+
179
+ <div class="upgrade-section">
180
+ <h2>Besoin de plus de puissance ?</h2>
181
+ <p>Passez à la version Pro pour des fonctionnalités avancées et des résolutions illimitées.</p>
182
+ <a href="#" class="cta-button">Passer à la version Pro</a>
183
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  </div>
185
+
186
+ <footer>
187
+ <p>&copy; 2025 Math Solver. Tous droits réservés.</p>
188
+ </footer>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  </div>
190
+
191
+ <script>
192
+ document.getElementById('imageInput').addEventListener('change', function(event) {
193
+ const file = event.target.files[0];
194
+ if (file) {
195
+ const reader = new FileReader();
196
+ reader.onload = function(e) {
197
+ document.getElementById('preview').src = e.target.result;
198
+ document.getElementById('imagePreview').style.display = 'block';
199
+ document.getElementById('solveButton').style.display = 'inline-block';
200
+ document.getElementById('uploadStatus').textContent = `Image sélectionnée : ${file.name}`;
201
+ }
202
+ reader.readAsDataURL(file);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  }
204
+ });
205
+
206
+ document.getElementById('solveButton').addEventListener('click', function() {
207
+ const formData = new FormData(document.getElementById('imageForm'));
208
+ const solutionOutput = document.getElementById('solutionOutput');
209
+ const loadingIndicator = document.getElementById('loadingIndicator');
210
+ const solution = document.getElementById('solution');
211
+
212
+ solutionOutput.style.display = 'block';
213
+ loadingIndicator.style.display = 'block';
214
+ solution.innerHTML = '';
215
+
216
+ fetch('/solved', {
217
+ method: 'POST',
218
+ body: formData
219
+ })
220
+ .then(response => {
221
+ const reader = response.body.getReader();
222
+ const decoder = new TextDecoder();
223
+
224
+ function processStream({ done, value }) {
225
+ if (done) {
226
+ loadingIndicator.style.display = 'none';
227
+ return;
228
+ }
229
+
230
+ const chunk = decoder.decode(value, { stream: true });
231
+ const lines = chunk.split('\n\n');
232
+
233
+ for (const line of lines) {
234
+ if (line.startsWith('data: ')) {
235
+ try {
236
+ const data = JSON.parse(line.substr(6));
237
+
238
+ if (data.mode === 'thinking') {
239
+ loadingIndicator.innerHTML = '<p><i class="fas fa-brain"></i> Je réfléchis au problème...</p>';
240
+ } else if (data.mode === 'answering') {
241
+ loadingIndicator.innerHTML = '<p><i class="fas fa-pencil-alt"></i> Rédaction de la solution...</p>';
242
+ } else if (data.mode === 'executing_code') {
243
+ loadingIndicator.innerHTML = '<p><i class="fas fa-code"></i> Exécution de code pour la résolution...</p>';
244
+ }
245
+
246
+ if (data.content) {
247
+ solution.innerHTML += data.content;
248
+ MathJax.typeset([solution]);
249
+ }
250
+
251
+ if (data.error) {
252
+ solution.innerHTML += `<div style="color: red;">Erreur: ${data.error}</div>`;
253
+ loadingIndicator.style.display = 'none';
254
+ }
255
+ } catch (e) {
256
+ console.error('Error parsing JSON:', e);
257
+ }
258
+ }
259
+ }
260
+
261
+ return reader.read().then(processStream);
262
  }
263
+
264
+ return reader.read().then(processStream);
265
+ })
266
+ .catch(error => {
267
+ solution.innerHTML += `<div style="color: red;">Erreur de connexion: ${error}</div>`;
268
+ loadingIndicator.style.display = 'none';
269
+ });
270
+ });
271
+ </script>
272
+
273
+ <!-- MathJax pour le rendu LaTeX -->
274
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.0/es5/tex-mml-chtml.js"></script>
275
+ <script>
276
+ window.MathJax = {
277
+ tex: {
278
+ inlineMath: [['$', '$'], ['\\(', '\\)']],
279
+ displayMath: [['$$', '$$'], ['\\[', '\\]']],
280
+ processEscapes: true
281
+ },
282
+ options: {
283
+ skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre']
284
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
  };
286
+ </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
  </body>
288
+ </html>