Docfile commited on
Commit
b7acc70
·
verified ·
1 Parent(s): e91d2b6

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +249 -264
templates/index.html CHANGED
@@ -6,6 +6,10 @@
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
  <link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-dark.min.css" rel="stylesheet">
 
 
 
 
9
  <style>
10
  :root {
11
  --primary-color: #4a6fa5;
@@ -126,80 +130,60 @@
126
  text-align: left;
127
  line-height: 1.8;
128
  font-size: 16px;
129
- background-color: transparent; /* Background of the container itself */
130
  box-shadow: var(--box-shadow);
131
- overflow: hidden; /* Clip children borders to parent radius */
132
  }
133
 
134
- /* Apply common padding and margin to sections */
135
  #solution > div {
136
  padding: 20px;
137
- margin: 0; /* Remove default margin */
138
- border-radius: 0; /* Reset radius, applied to first/last children */
139
  overflow-x: auto;
140
- background-color: #f9f9f9; /* Default background */
141
- border-left: 4px solid var(--primary-color); /* Default left border */
142
- /* Added border-bottom to create separation between sections */
143
  border-bottom: 1px solid #eee;
144
  }
145
 
146
  .code-section {
147
- background-color: transparent !important; /* Background handled by code-content */
148
- padding: 0 !important; /* Padding handled by code-content */
149
- border-left: none !important; /* No left border for code section parent */
150
- border-bottom: none !important; /* No border bottom on code section parent */
151
  }
152
 
153
  .output-section {
154
- background-color: var(--output-bg) !important; /* Override default section background */
155
- border-left: none !important; /* No left border for output section parent */
156
  }
157
 
158
-
159
  .step-section {
160
- /* Specific styles for steps */
161
- border-left: 4px solid var(--primary-color);
162
- padding-left: calc(20px - 4px); /* Adjust padding to account for border */
163
- background-color: #f9f9f9;
164
- font-size: 16px;
165
- line-height: 1.8;
166
- }
167
-
168
- /* Improved LaTeX styling (MathJax v3 specific) */
169
- .step-section .mjx-chtml {
170
- display: inline-block;
171
- line-height: 0;
172
- text-indent: 0;
173
- text-align: left;
174
- text-transform: none;
175
- font-size: 1em !important; /* Ensure inline MathJax respects container font size */
176
- font-style: normal;
177
- font-weight: normal;
178
- font-family: MJXZERO, MJXTEX;
179
- direction: ltr;
180
- vertical-align: -0.25em; /* Standard vertical alignment */
181
- margin: 0 0.2em; /* Small horizontal margin */
182
- }
183
-
184
- .step-section .mjx-container.MJX-display {
185
- display: block !important;
186
- margin: 1em auto !important;
187
- text-align: center !important;
188
- max-width: 100%;
189
- overflow-x: auto; /* Allow horizontal scrolling for large block equations */
190
- overflow-y: hidden;
191
  }
192
 
 
 
 
 
 
 
 
193
 
194
- /* Fix for inline math to prevent weird line breaks */
195
- .step-section p {
196
- display: block; /* Paragraphs should be block elements */
197
- margin-block-start: 1em;
198
- margin-block-end: 1em;
199
- margin-inline-start: 0px;
200
- margin-inline-end: 0px;
201
  }
202
 
 
 
 
 
 
203
 
204
  .code-header {
205
  background-color: #343a40;
@@ -210,7 +194,6 @@
210
  display: flex;
211
  justify-content: space-between;
212
  align-items: center;
213
- /* Border radius handled by first child rules below */
214
  border-top-left-radius: 0;
215
  border-top-right-radius: 0;
216
  }
@@ -224,99 +207,76 @@
224
  font-family: 'Courier New', monospace;
225
  font-size: 14px;
226
  line-height: 1.5;
227
- /* Border radius handled by last child rules below */
228
- border-bottom-left-radius: 0;
229
- border-bottom-right-radius: 0;
230
  }
231
 
232
-
233
- /* Add border-radius back to the very first and very last child INSIDE #solution */
234
-
235
- /* First child in #solution */
236
  #solution > div:first-child {
237
- border-top-left-radius: 8px;
238
- border-top-right-radius: 8px;
239
  }
240
- /* Special handling for the first child if it's a code section (header needs radius) */
241
  #solution > .code-section:first-child .code-header {
242
- border-top-left-radius: 8px;
243
- border-top-right-radius: 8px;
244
- }
245
- /* Special handling for the first child if it's an output section */
246
- #solution > .output-section:first-child {
247
- border-top-left-radius: 8px;
248
- border-top-right-radius: 8px;
249
  }
250
 
 
 
 
 
251
 
252
- /* Last child in #solution */
253
  #solution > div:last-child {
254
- border-bottom-left-radius: 8px;
255
- border-bottom-right-radius: 8px;
256
- border-bottom: none; /* Remove the bottom border on the very last section */
257
  }
258
- /* Special handling for the last child if it's a code section (content needs radius) */
259
  #solution > .code-section:last-child .code-content {
260
- border-bottom-left-radius: 8px;
261
- border-bottom-right-radius: 8px;
262
- }
263
- /* Special handling for the last child if it's an output section */
264
- #solution > .output-section:last-child {
265
- border-bottom-left-radius: 8px;
266
- border-bottom-right-radius: 8px;
267
- border-bottom: none;
268
  }
269
 
 
 
 
 
 
270
 
271
- /* Specific case for a single child (both first and last) */
272
  #solution > div:only-child {
273
  border-radius: 8px;
274
  border-bottom: none;
275
  }
 
276
  #solution > .code-section:only-child .code-header {
277
- border-top-left-radius: 8px;
278
- border-top-right-radius: 8px;
279
  }
 
280
  #solution > .code-section:only-child .code-content {
281
- border-bottom-left-radius: 8px;
282
- border-bottom-right-radius: 8px;
283
- }
284
- #solution > .output-section:only-child {
285
- border-radius: 8px;
286
- border-bottom: none;
287
  }
288
 
 
 
 
 
289
 
290
- /* Remove bottom border for sections that are not the last child,
291
- to make them appear connected to the next section */
292
  #solution > div:not(:last-child) {
293
  border-bottom: 1px solid #eee;
294
  }
295
 
296
- /* Code section should not have a bottom border even if not last */
297
- #solution > .code-section {
298
- border-bottom: none;
299
- }
300
-
301
- /* Output section should not have a bottom border even if not last */
302
- #solution > .output-section:not(:last-child) {
303
- border-bottom: 1px solid #ddd; /* Keep the separator line */
304
- }
305
-
306
-
307
- /* Fixed display of MathJax content */
308
- .mjx-container {
309
- display: inline-block !important;
310
- margin: 0 !important;
311
- text-align: center !important;
312
- overflow-x: auto; /* Allow horizontal scrolling for large inline equations */
313
- overflow-y: hidden;
314
- padding: 0 !important;
315
- vertical-align: middle; /* Better vertical alignment for inline math */
316
  }
317
 
 
 
 
318
 
319
- /* Fix markdown list rendering */
320
  .step-section ul, .step-section ol {
321
  display: block;
322
  margin-block-start: 1em;
@@ -331,6 +291,55 @@
331
  margin-bottom: 0.5em;
332
  }
333
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
  .thinking-indicator, .executing-indicator, .answering-indicator {
335
  display: flex;
336
  align-items: center;
@@ -357,22 +366,31 @@
357
  100% { opacity: 0.6; }
358
  }
359
 
360
- /* Fix assistive MML elements */
361
- mjx-assistive-mml {
362
- position: absolute !important;
363
- top: 0 !important;
364
- left: 0 !important;
365
- clip: rect(1px, 1px, 1px, 1px) !important;
366
- padding: 1px 0 0 0 !important;
367
- display: block !important;
368
  }
369
 
370
- /* Unified consistent LaTeX size for all equations */
371
- /* Ensure MathJax respects container font size */
372
- .step-section .mjx-container {
373
- font-size: 1em !important; /* Use relative units */
 
 
 
 
 
374
  }
375
 
 
 
 
 
376
  </style>
377
  </head>
378
  <body>
@@ -443,45 +461,35 @@
443
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
444
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/python.min.js"></script>
445
 
446
- <!-- MathJax Configuration -->
447
- <script>
448
- window.MathJax = {
449
- tex: {
450
- inlineMath: [['$', '$'], ['\\(', '\\)']], // Standard inline delimiters
451
- displayMath: [['$$', '$$'], ['\\[', '\\]']], // Standard block delimiters
452
- processEscapes: true,
453
- processEnvironments: true,
454
- packages: {'[+]': ['noerrors', 'physics', 'cancel', 'color']}
455
- },
456
- options: {
457
- enableMenu: false,
458
- ignoreHtmlClass: 'code-content', // Don't process code blocks
459
- processHtmlClass: 'step-section|latex-display', // Only process step and latex-display sections
460
- skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
461
- },
462
- loader: {
463
- load: ['input/tex-full', 'output/svg'] // Load full TeX input and SVG output
464
- },
465
- svg: {
466
- fontCache: 'global',
467
- scale: 1, // Global scaling factor
468
- minScale: 1, // Minimum scaling factor
469
- mtextInheritFont: true, // mtext uses surrounding font
470
- merrorInheritFont: true, // merror uses surrounding font
471
- mathmlSpacing: false // TeX spacing rules
472
- },
473
- chtml: { // Also configure for CHTML output as a fallback or alternative
474
- scale: 1,
475
- minScale: 1,
476
- mtextInheritFont: true,
477
- merrorInheritFont: true
478
- }
479
- };
480
- </script>
481
- <!-- MathJax v3 Script -->
482
- <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
483
 
484
  <script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
485
  document.getElementById('imageInput').addEventListener('change', function(event) {
486
  const file = event.target.files[0];
487
  if (file) {
@@ -504,15 +512,15 @@
504
 
505
  solutionOutput.style.display = 'block';
506
  loadingIndicator.style.display = 'flex';
507
- solutionContainer.innerHTML = ''; // Clear previous solution
508
 
509
- fetch('/solved', { // Assuming the Flask endpoint is '/solved'
510
  method: 'POST',
511
  body: formData
512
  })
513
  .then(response => {
514
  if (!response.ok) {
515
- // Attempt to read error message from body if available
516
  return response.text().then(text => {
517
  throw new Error(`Erreur serveur: ${response.status} ${response.statusText}\n${text}`);
518
  });
@@ -524,173 +532,144 @@
524
  function processStream({ done, value }) {
525
  if (done) {
526
  loadingIndicator.style.display = 'none';
527
- // Force MathJax to reprocess entire solution when done
528
- // Use the specific container element
529
- if (typeof MathJax !== 'undefined') {
530
- MathJax.typesetPromise([solutionContainer]).catch(e => console.error('MathJax final typesetting error:', e));
 
531
  }
532
  return;
533
  }
534
 
535
  buffer += decoder.decode(value, { stream: true });
536
- // Split by double newline to separate SSE messages, but keep the last incomplete chunk in buffer
537
  const messages = buffer.split(/\r?\n\r?\n/);
538
- buffer = messages.pop(); // Store the last potentially incomplete chunk
539
 
540
  for (const message of messages) {
541
- // Only process lines that start with 'data: ' for SSE
542
  if (message.startsWith('data: ')) {
543
  try {
544
- const data = JSON.parse(message.substr(6)); // Extract JSON after 'data: '
545
 
546
- // Handle mode updates
547
  if (data.mode) {
548
  const modes = {
549
  thinking: { icon: 'fa-brain', text: 'Je réfléchis...', class: 'thinking-indicator' },
550
  answering: { icon: 'fa-pencil-alt', text: 'Rédaction...', class: 'answering-indicator' },
551
  executing_code: { icon: 'fa-code', text: 'Exécution...', class: 'executing-indicator' },
552
- code_result: { icon: 'fa-terminal', text: 'Résultats...', class: 'executing-indicator' } // Use executing indicator for results too, or create a new one
553
  };
554
  const modeInfo = modes[data.mode];
555
  if (modeInfo) {
556
- loadingIndicator.className = modeInfo.class; // Update class for styling
557
- loadingIndicator.innerHTML = `<i class="fas ${modeInfo.icon} indicator-icon"></i><span>${modeInfo.text}</span>`; // Update icon and text
558
- loadingIndicator.style.display = 'flex'; // Ensure indicator is visible when a mode is set
559
  } else {
560
- // Default or unknown mode
561
- loadingIndicator.className = 'thinking-indicator';
562
- loadingIndicator.innerHTML = `<i class="fas fa-sync-alt indicator-icon fa-spin"></i><span>Traitement...</span>`;
563
- loadingIndicator.style.display = 'flex';
564
  }
565
  }
566
 
567
- // Handle content blocks
568
  if (data.content) {
569
  const content = data.content;
570
  const tempDiv = document.createElement('div');
571
- tempDiv.innerHTML = content; // Parse HTML chunk received from server
572
 
573
  const codeSection = tempDiv.querySelector('.code-section');
574
  const outputSection = tempDiv.querySelector('.output-section');
575
 
576
  if (codeSection) {
577
  solutionContainer.appendChild(codeSection);
578
- // Highlight code within the added section
579
  codeSection.querySelectorAll('pre code').forEach((block) => {
580
  hljs.highlightElement(block);
581
  });
582
- // MathJax should ignore code blocks based on options
583
  } else if (outputSection) {
584
  solutionContainer.appendChild(outputSection);
585
- // MathJax should ignore output blocks based on options
586
  } else {
587
- // Process regular text/LaTeX step section
588
  const stepDiv = document.createElement('div');
589
  stepDiv.className = 'step-section';
590
-
591
- // Basic markdown processing for lists (more robust processing might need a library)
592
- let processedContent = content;
593
-
594
- // Convert markdown lists to HTML lists
595
- // This is a basic approach and might not cover all markdown complexities
596
- const lines = processedContent.split('\n');
597
- let htmlOutput = '';
598
- let inList = false;
599
- let listType = ''; // 'ul' or 'ol'
600
-
601
- for (const line of lines) {
602
- const trimmedLine = line.trim();
603
- if (trimmedLine.match(/^(-|\*|\+)\s/)) { // Unordered list item
604
- if (!inList) {
605
- htmlOutput += '<ul>';
606
- inList = true;
607
- listType = 'ul';
608
- } else if (listType !== 'ul') {
609
- htmlOutput += `</${listType}><ul>`;
610
- listType = 'ul';
611
- }
612
- htmlOutput += `<li>${trimmedLine.replace(/^(-|\*|\+)\s+/, '')}</li>`;
613
- } else if (trimmedLine.match(/^(\d+)\.\s/)) { // Ordered list item
614
- if (!inList) {
615
- htmlOutput += '<ol>';
616
- inList = true;
617
- listType = 'ol';
618
- } else if (listType !== 'ol') {
619
- htmlOutput += `</${listType}><ol>`;
620
- listType = 'ol';
621
- }
622
- htmlOutput += `<li>${trimmedLine.replace(/^(\d+)\.\s+/, '')}</li>`;
623
- } else {
624
- if (inList) {
625
- htmlOutput += `</${listType}>`;
626
- inList = false;
627
- }
628
- // Add non-list content wrapped in paragraphs, handling double newlines
629
- if (line.trim() !== '') {
630
- htmlOutput += `<p>${line}</p>`;
631
- }
632
- }
633
  }
634
-
635
- if (inList) {
636
- htmlOutput += `</${listType}>`;
637
- }
638
-
639
- // Remove empty paragraph tags that might have been created
640
- htmlOutput = htmlOutput.replace(/<p>\s*<\/p>/g, '');
641
-
642
- stepDiv.innerHTML = htmlOutput; // Use the processed HTML
643
  solutionContainer.appendChild(stepDiv);
644
-
645
- // Process MathJax for this specific section (will process the new content)
646
- if (typeof MathJax !== 'undefined') {
647
- // Use typesetPromise and target the newly added stepDiv
648
- MathJax.typesetPromise([stepDiv]).catch(e => console.error('MathJax typesetting error:', e));
 
649
  }
650
  }
651
- // Hide the loading indicator once content starts arriving (optional, but can feel more responsive)
652
- // loadingIndicator.style.display = 'none'; // Keep it visible to show mode changes
653
  }
654
 
655
- // Handle error messages
656
  if (data.error) {
657
  const errorDiv = document.createElement('div');
658
- errorDiv.className = 'step-section'; // Use step section styling for errors
659
  errorDiv.style.color = 'red';
660
  errorDiv.style.backgroundColor = '#ffeeee';
661
  errorDiv.style.borderColor = 'red';
662
  errorDiv.textContent = `Erreur: ${data.error}`;
663
  solutionContainer.appendChild(errorDiv);
664
- loadingIndicator.style.display = 'none'; // Hide loading indicator on error
665
  }
666
  } catch (e) {
667
- console.error('Error parsing JSON or processing message:', e, message);
668
- // Display a client-side processing error message
669
  const errorDiv = document.createElement('div');
670
  errorDiv.className = 'step-section';
671
  errorDiv.style.color = 'orange';
672
- errorDiv.textContent = `Erreur traitement message: ${message.substring(0, 100)}...`; // Show a snippet of the problematic line
673
  solutionContainer.appendChild(errorDiv);
674
  loadingIndicator.style.display = 'none';
675
  }
676
- } else {
677
- // Handle potential non-data lines if necessary, or ignore
678
- // console.warn("Received non-data line:", message); // Uncomment for debugging
679
  }
680
  }
681
 
682
- // Scroll to the bottom of the solution container as new content arrives
683
  solutionOutput.scrollTop = solutionOutput.scrollHeight;
684
 
685
- // Continue reading the stream
686
  return reader.read().then(processStream);
687
  }
688
 
689
- // Start processing the stream
690
  return reader.read().then(processStream);
691
  })
692
  .catch(error => {
693
- // Handle errors during the fetch or from the initial response check
694
  const errorDiv = document.createElement('div');
695
  errorDiv.className = 'step-section';
696
  errorDiv.style.color = 'red';
@@ -699,10 +678,16 @@
699
  errorDiv.textContent = `Erreur de connexion ou du serveur: ${error}`;
700
  solutionContainer.appendChild(errorDiv);
701
  loadingIndicator.style.display = 'none';
702
- console.error('Fetch error:', error);
703
  });
704
  });
705
 
 
 
 
 
 
 
706
  </script>
707
  </body>
708
  </html>
 
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
  <link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-dark.min.css" rel="stylesheet">
9
+ <!-- Ajout de Marked.js pour le traitement Markdown -->
10
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.3.0/marked.min.js"></script>
11
+ <!-- CSS pour KaTeX -->
12
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.8/katex.min.css">
13
  <style>
14
  :root {
15
  --primary-color: #4a6fa5;
 
130
  text-align: left;
131
  line-height: 1.8;
132
  font-size: 16px;
133
+ background-color: transparent;
134
  box-shadow: var(--box-shadow);
135
+ overflow: hidden;
136
  }
137
 
 
138
  #solution > div {
139
  padding: 20px;
140
+ margin: 0;
141
+ border-radius: 0;
142
  overflow-x: auto;
143
+ background-color: #f9f9f9;
144
+ border-left: 4px solid var(--primary-color);
 
145
  border-bottom: 1px solid #eee;
146
  }
147
 
148
  .code-section {
149
+ background-color: transparent !important;
150
+ padding: 0 !important;
151
+ border-left: none !important;
152
+ border-bottom: none !important;
153
  }
154
 
155
  .output-section {
156
+ background-color: var(--output-bg) !important;
157
+ border-left: none !important;
158
  }
159
 
 
160
  .step-section {
161
+ border-left: 4px solid var(--primary-color);
162
+ padding-left: calc(20px - 4px);
163
+ background-color: #f9f9f9;
164
+ font-size: 16px;
165
+ line-height: 1.8;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  }
167
 
168
+ /* Amélioration du rendu LaTeX avec KaTeX */
169
+ .step-section .katex {
170
+ font-size: 1.1em;
171
+ line-height: 1.2;
172
+ text-indent: 0;
173
+ text-rendering: auto;
174
+ }
175
 
176
+ .step-section .katex-display {
177
+ margin: 1em 0;
178
+ display: block;
179
+ text-align: center;
 
 
 
180
  }
181
 
182
+ .step-section .katex-display > .katex {
183
+ display: inline-block;
184
+ text-align: center;
185
+ max-width: 100%;
186
+ }
187
 
188
  .code-header {
189
  background-color: #343a40;
 
194
  display: flex;
195
  justify-content: space-between;
196
  align-items: center;
 
197
  border-top-left-radius: 0;
198
  border-top-right-radius: 0;
199
  }
 
207
  font-family: 'Courier New', monospace;
208
  font-size: 14px;
209
  line-height: 1.5;
210
+ border-bottom-left-radius: 0;
211
+ border-bottom-right-radius: 0;
 
212
  }
213
 
214
+ /* Règles pour les coins arrondis */
 
 
 
215
  #solution > div:first-child {
216
+ border-top-left-radius: 8px;
217
+ border-top-right-radius: 8px;
218
  }
219
+
220
  #solution > .code-section:first-child .code-header {
221
+ border-top-left-radius: 8px;
222
+ border-top-right-radius: 8px;
 
 
 
 
 
223
  }
224
 
225
+ #solution > .output-section:first-child {
226
+ border-top-left-radius: 8px;
227
+ border-top-right-radius: 8px;
228
+ }
229
 
 
230
  #solution > div:last-child {
231
+ border-bottom-left-radius: 8px;
232
+ border-bottom-right-radius: 8px;
233
+ border-bottom: none;
234
  }
235
+
236
  #solution > .code-section:last-child .code-content {
237
+ border-bottom-left-radius: 8px;
238
+ border-bottom-right-radius: 8px;
 
 
 
 
 
 
239
  }
240
 
241
+ #solution > .output-section:last-child {
242
+ border-bottom-left-radius: 8px;
243
+ border-bottom-right-radius: 8px;
244
+ border-bottom: none;
245
+ }
246
 
 
247
  #solution > div:only-child {
248
  border-radius: 8px;
249
  border-bottom: none;
250
  }
251
+
252
  #solution > .code-section:only-child .code-header {
253
+ border-top-left-radius: 8px;
254
+ border-top-right-radius: 8px;
255
  }
256
+
257
  #solution > .code-section:only-child .code-content {
258
+ border-bottom-left-radius: 8px;
259
+ border-bottom-right-radius: 8px;
 
 
 
 
260
  }
261
 
262
+ #solution > .output-section:only-child {
263
+ border-radius: 8px;
264
+ border-bottom: none;
265
+ }
266
 
 
 
267
  #solution > div:not(:last-child) {
268
  border-bottom: 1px solid #eee;
269
  }
270
 
271
+ #solution > .code-section {
272
+ border-bottom: none;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
  }
274
 
275
+ #solution > .output-section:not(:last-child) {
276
+ border-bottom: 1px solid #ddd;
277
+ }
278
 
279
+ /* Amélioration du rendu Markdown */
280
  .step-section ul, .step-section ol {
281
  display: block;
282
  margin-block-start: 1em;
 
291
  margin-bottom: 0.5em;
292
  }
293
 
294
+ /* Meilleur espacement pour les listes imbriquées */
295
+ .step-section ul ul,
296
+ .step-section ol ol,
297
+ .step-section ul ol,
298
+ .step-section ol ul {
299
+ margin-block-start: 0.5em;
300
+ margin-block-end: 0.5em;
301
+ }
302
+
303
+ /* Amélioration des tables en Markdown */
304
+ .step-section table {
305
+ border-collapse: collapse;
306
+ width: 100%;
307
+ margin: 1em 0;
308
+ }
309
+
310
+ .step-section th,
311
+ .step-section td {
312
+ border: 1px solid #ddd;
313
+ padding: 8px 12px;
314
+ text-align: left;
315
+ }
316
+
317
+ .step-section th {
318
+ background-color: #f2f2f2;
319
+ font-weight: bold;
320
+ }
321
+
322
+ .step-section tr:nth-child(even) {
323
+ background-color: #f9f9f9;
324
+ }
325
+
326
+ /* Meilleur rendu des blocs de code en Markdown */
327
+ .step-section pre {
328
+ background-color: #f5f5f5;
329
+ border-radius: 4px;
330
+ padding: 12px;
331
+ overflow-x: auto;
332
+ margin: 1em 0;
333
+ }
334
+
335
+ .step-section code {
336
+ font-family: 'Courier New', Courier, monospace;
337
+ background-color: #f5f5f5;
338
+ padding: 2px 4px;
339
+ border-radius: 3px;
340
+ font-size: 0.9em;
341
+ }
342
+
343
  .thinking-indicator, .executing-indicator, .answering-indicator {
344
  display: flex;
345
  align-items: center;
 
366
  100% { opacity: 0.6; }
367
  }
368
 
369
+ /* Améliorations supplémentaires pour Markdown */
370
+ .step-section blockquote {
371
+ border-left: 4px solid #ddd;
372
+ margin: 1em 0;
373
+ padding: 0.5em 10px;
374
+ color: #666;
375
+ font-style: italic;
376
+ background-color: #f9f9f9;
377
  }
378
 
379
+ .step-section h1,
380
+ .step-section h2,
381
+ .step-section h3,
382
+ .step-section h4,
383
+ .step-section h5,
384
+ .step-section h6 {
385
+ margin-top: 1.5em;
386
+ margin-bottom: 0.5em;
387
+ color: var(--primary-color);
388
  }
389
 
390
+ .step-section h1 { font-size: 1.8em; }
391
+ .step-section h2 { font-size: 1.6em; }
392
+ .step-section h3 { font-size: 1.4em; }
393
+ .step-section h4 { font-size: 1.2em; }
394
  </style>
395
  </head>
396
  <body>
 
461
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
462
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/python.min.js"></script>
463
 
464
+ <!-- KaTeX Scripts (remplacement de MathJax pour de meilleures performances) -->
465
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.8/katex.min.js"></script>
466
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.8/contrib/auto-render.min.js"></script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
467
 
468
  <script>
469
+ // Configuration de marked pour le rendu Markdown
470
+ marked.setOptions({
471
+ gfm: true, // GitHub Flavored Markdown
472
+ breaks: true, // Convertit les retours à la ligne en <br>
473
+ smartLists: true, // Listes intelligentes
474
+ smartypants: true, // Typographie intelligente (guillemets, tirets, etc.)
475
+ xhtml: true // XHTML conforme
476
+ });
477
+
478
+ // Fonction pour rendre le LaTeX avec KaTeX dans un élément
479
+ function renderMathInElement(element) {
480
+ renderMathInElement(element, {
481
+ delimiters: [
482
+ {left: '$$', right: '$$', display: true},
483
+ {left: '$', right: '$', display: false},
484
+ {left: '\\(', right: '\\)', display: false},
485
+ {left: '\\[', right: '\\]', display: true}
486
+ ],
487
+ throwOnError: false,
488
+ trust: true,
489
+ strict: false
490
+ });
491
+ }
492
+
493
  document.getElementById('imageInput').addEventListener('change', function(event) {
494
  const file = event.target.files[0];
495
  if (file) {
 
512
 
513
  solutionOutput.style.display = 'block';
514
  loadingIndicator.style.display = 'flex';
515
+ solutionContainer.innerHTML = ''; // Effacer la solution précédente
516
 
517
+ fetch('/solved', { // En supposant que l'endpoint Flask est '/solved'
518
  method: 'POST',
519
  body: formData
520
  })
521
  .then(response => {
522
  if (!response.ok) {
523
+ // Tenter de lire le message d'erreur du corps si disponible
524
  return response.text().then(text => {
525
  throw new Error(`Erreur serveur: ${response.status} ${response.statusText}\n${text}`);
526
  });
 
532
  function processStream({ done, value }) {
533
  if (done) {
534
  loadingIndicator.style.display = 'none';
535
+ // Forcer le retraitement du LaTeX lorsque terminé pour la solution entière
536
+ try {
537
+ renderMathInElement(solutionContainer);
538
+ } catch (e) {
539
+ console.error('Erreur de rendu LaTeX final:', e);
540
  }
541
  return;
542
  }
543
 
544
  buffer += decoder.decode(value, { stream: true });
545
+ // Séparer par double saut de ligne pour les messages SSE, mais garder le dernier morceau incomplet
546
  const messages = buffer.split(/\r?\n\r?\n/);
547
+ buffer = messages.pop(); // Stocker le dernier morceau potentiellement incomplet
548
 
549
  for (const message of messages) {
550
+ // Traiter uniquement les lignes commençant par 'data: ' pour SSE
551
  if (message.startsWith('data: ')) {
552
  try {
553
+ const data = JSON.parse(message.substr(6)); // Extraire JSON après 'data: '
554
 
555
+ // Gérer les mises à jour de mode
556
  if (data.mode) {
557
  const modes = {
558
  thinking: { icon: 'fa-brain', text: 'Je réfléchis...', class: 'thinking-indicator' },
559
  answering: { icon: 'fa-pencil-alt', text: 'Rédaction...', class: 'answering-indicator' },
560
  executing_code: { icon: 'fa-code', text: 'Exécution...', class: 'executing-indicator' },
561
+ code_result: { icon: 'fa-terminal', text: 'Résultats...', class: 'executing-indicator' }
562
  };
563
  const modeInfo = modes[data.mode];
564
  if (modeInfo) {
565
+ loadingIndicator.className = modeInfo.class;
566
+ loadingIndicator.innerHTML = `<i class="fas ${modeInfo.icon} indicator-icon"></i><span>${modeInfo.text}</span>`;
567
+ loadingIndicator.style.display = 'flex';
568
  } else {
569
+ loadingIndicator.className = 'thinking-indicator';
570
+ loadingIndicator.innerHTML = `<i class="fas fa-sync-alt indicator-icon fa-spin"></i><span>Traitement...</span>`;
571
+ loadingIndicator.style.display = 'flex';
 
572
  }
573
  }
574
 
575
+ // Gérer les blocs de contenu
576
  if (data.content) {
577
  const content = data.content;
578
  const tempDiv = document.createElement('div');
579
+ tempDiv.innerHTML = content; // Analyser le fragment HTML reçu du serveur
580
 
581
  const codeSection = tempDiv.querySelector('.code-section');
582
  const outputSection = tempDiv.querySelector('.output-section');
583
 
584
  if (codeSection) {
585
  solutionContainer.appendChild(codeSection);
586
+ // Surligner le code dans la section ajoutée
587
  codeSection.querySelectorAll('pre code').forEach((block) => {
588
  hljs.highlightElement(block);
589
  });
 
590
  } else if (outputSection) {
591
  solutionContainer.appendChild(outputSection);
 
592
  } else {
593
+ // Traiter la section d'étape de texte/LaTeX normale avec Markdown amélioré
594
  const stepDiv = document.createElement('div');
595
  stepDiv.className = 'step-section';
596
+
597
+ // Traitement Markdown avancé avec marked.js
598
+ // Conversion du contenu en Markdown valide pour les listes, les tableaux, etc.
599
+ const markdownContent = content
600
+ // Préservation des délimiteurs LaTeX
601
+ .replace(/\$\$([\s\S]*?)\$\$/g, (match) => {
602
+ return match.replace(/\n/g, '\\n');
603
+ })
604
+ .replace(/\$([\s\S]*?)\$/g, (match) => {
605
+ return match.replace(/\n/g, '\\n');
606
+ });
607
+
608
+ try {
609
+ // Conversion Markdown vers HTML
610
+ const htmlContent = marked.parse(markdownContent);
611
+
612
+ // Restauration des sauts de ligne dans les formules LaTeX
613
+ const fixedHtmlContent = htmlContent
614
+ .replace(/\$\$([\s\S]*?)\$\$/g, (match) => {
615
+ return match.replace(/\\n/g, '\n');
616
+ })
617
+ .replace(/\$([\s\S]*?)\$/g, (match) => {
618
+ return match.replace(/\\n/g, '\n');
619
+ });
620
+
621
+ stepDiv.innerHTML = fixedHtmlContent;
622
+ } catch (e) {
623
+ console.error('Erreur de traitement Markdown:', e);
624
+ stepDiv.innerHTML = content; // Fallback en cas d'erreur
 
 
 
 
 
 
 
 
 
 
 
 
 
 
625
  }
626
+
 
 
 
 
 
 
 
 
627
  solutionContainer.appendChild(stepDiv);
628
+
629
+ // Rendu LaTeX avec KaTeX dans cette section spécifique
630
+ try {
631
+ renderMathInElement(stepDiv);
632
+ } catch (e) {
633
+ console.error('Erreur de rendu LaTeX:', e);
634
  }
635
  }
 
 
636
  }
637
 
638
+ // Gérer les messages d'erreur
639
  if (data.error) {
640
  const errorDiv = document.createElement('div');
641
+ errorDiv.className = 'step-section';
642
  errorDiv.style.color = 'red';
643
  errorDiv.style.backgroundColor = '#ffeeee';
644
  errorDiv.style.borderColor = 'red';
645
  errorDiv.textContent = `Erreur: ${data.error}`;
646
  solutionContainer.appendChild(errorDiv);
647
+ loadingIndicator.style.display = 'none';
648
  }
649
  } catch (e) {
650
+ console.error('Erreur d\'analyse JSON ou de traitement du message:', e, message);
 
651
  const errorDiv = document.createElement('div');
652
  errorDiv.className = 'step-section';
653
  errorDiv.style.color = 'orange';
654
+ errorDiv.textContent = `Erreur traitement message: ${message.substring(0, 100)}...`;
655
  solutionContainer.appendChild(errorDiv);
656
  loadingIndicator.style.display = 'none';
657
  }
 
 
 
658
  }
659
  }
660
 
661
+ // Défiler vers le bas du conteneur de solution à mesure que du nouveau contenu arrive
662
  solutionOutput.scrollTop = solutionOutput.scrollHeight;
663
 
664
+ // Continuer à lire le flux
665
  return reader.read().then(processStream);
666
  }
667
 
668
+ // Commencer à traiter le flux
669
  return reader.read().then(processStream);
670
  })
671
  .catch(error => {
672
+ // Gérer les erreurs pendant le fetch ou de la vérification de réponse initiale
673
  const errorDiv = document.createElement('div');
674
  errorDiv.className = 'step-section';
675
  errorDiv.style.color = 'red';
 
678
  errorDiv.textContent = `Erreur de connexion ou du serveur: ${error}`;
679
  solutionContainer.appendChild(errorDiv);
680
  loadingIndicator.style.display = 'none';
681
+ console.error('Erreur fetch:', error);
682
  });
683
  });
684
 
685
+ // Auto-render KaTeX function
686
+ document.addEventListener('DOMContentLoaded', function() {
687
+ document.querySelectorAll('.step-section').forEach(function(element) {
688
+ renderMathInElement(element);
689
+ });
690
+ });
691
  </script>
692
  </body>
693
  </html>