Luigi commited on
Commit
b498cb0
·
1 Parent(s): ae778ed

feat: add Markdown rendering support for summaries

Browse files

- Add Marked.js library for proper Markdown-to-HTML conversion
- Replace manual regex-based Markdown parser with robust library
- Update CSS styling for rendered HTML elements (headers, lists, code blocks)
- Configure Marked.js with secure options (breaks, GFM, no header IDs)
- Create test file demonstrating Markdown rendering capabilities

The summary output now properly renders Markdown formatting including:
- Headers (# ## ###)
- Bold and italic text
- Lists (ordered/unordered)
- Code blocks and inline code
- Links
- Proper HTML structure with styling

frontend/app.js CHANGED
@@ -65,6 +65,20 @@ const SUMMARY_FORMATS = ['Markdown', 'Plain Text'];
65
  let activeTab = 'podcast-tab';
66
  let activeUtteranceIndex = -1;
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  function setStatus(message, tone = 'info') {
69
  elements.statusText.textContent = message;
70
  elements.statusText.dataset.tone = tone;
@@ -508,7 +522,7 @@ async function handleSummaryGeneration() {
508
  if (!line.trim()) continue;
509
  const event = JSON.parse(line);
510
  if (event.type === 'partial' && event.content) {
511
- elements.summaryOutput.textContent = event.content;
512
  }
513
  }
514
  }
 
65
  let activeTab = 'podcast-tab';
66
  let activeUtteranceIndex = -1;
67
 
68
+ // Configuration de Marked pour un rendu sécurisé
69
+ marked.setOptions({
70
+ breaks: true, // Convertir les sauts de ligne simples en <br>
71
+ gfm: true, // GitHub Flavored Markdown
72
+ headerIds: false, // Pas d'IDs automatiques sur les headers
73
+ mangle: false, // Pas de mangling des emails
74
+ });
75
+
76
+ // Fonction simple pour convertir Markdown en HTML
77
+ function renderMarkdown(markdown) {
78
+ if (!markdown) return '';
79
+ return marked.parse(markdown);
80
+ }
81
+
82
  function setStatus(message, tone = 'info') {
83
  elements.statusText.textContent = message;
84
  elements.statusText.dataset.tone = tone;
 
522
  if (!line.trim()) continue;
523
  const event = JSON.parse(line);
524
  if (event.type === 'partial' && event.content) {
525
+ elements.summaryOutput.innerHTML = renderMarkdown(event.content);
526
  }
527
  }
528
  }
frontend/index.html CHANGED
@@ -4,7 +4,8 @@
4
  <meta charset="UTF-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
  <title>VoxSum Studio</title>
7
- <link rel="stylesheet" href="/styles.css" />
 
8
  </head>
9
  <body>
10
  <header class="app-header">
 
4
  <meta charset="UTF-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
  <title>VoxSum Studio</title>
7
+ <link rel="stylesheet" href="/styles.css" />
8
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
9
  </head>
10
  <body>
11
  <header class="app-header">
frontend/styles.css CHANGED
@@ -406,7 +406,70 @@ button:hover {
406
  border-radius: 12px;
407
  padding: 1rem;
408
  border: 1px solid rgba(148, 163, 184, 0.15);
409
- white-space: pre-wrap;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
410
  }
411
 
412
  .export-grid {
 
406
  border-radius: 12px;
407
  padding: 1rem;
408
  border: 1px solid rgba(148, 163, 184, 0.15);
409
+ line-height: 1.6;
410
+ }
411
+
412
+ .summary h1, .summary h2, .summary h3 {
413
+ margin-top: 1.5rem;
414
+ margin-bottom: 0.5rem;
415
+ color: #e2e8f0;
416
+ }
417
+
418
+ .summary h1 { font-size: 1.5rem; }
419
+ .summary h2 { font-size: 1.25rem; }
420
+ .summary h3 { font-size: 1.1rem; }
421
+
422
+ .summary p {
423
+ margin-bottom: 1rem;
424
+ }
425
+
426
+ .summary strong {
427
+ font-weight: 600;
428
+ color: #f1f5f9;
429
+ }
430
+
431
+ .summary em {
432
+ font-style: italic;
433
+ color: #cbd5e1;
434
+ }
435
+
436
+ .summary code {
437
+ background: rgba(100, 116, 139, 0.3);
438
+ padding: 0.125rem 0.25rem;
439
+ border-radius: 4px;
440
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
441
+ font-size: 0.9em;
442
+ }
443
+
444
+ .summary pre {
445
+ background: rgba(15, 23, 42, 0.8);
446
+ padding: 1rem;
447
+ border-radius: 8px;
448
+ overflow-x: auto;
449
+ margin: 1rem 0;
450
+ }
451
+
452
+ .summary pre code {
453
+ background: none;
454
+ padding: 0;
455
+ }
456
+
457
+ .summary ul, .summary ol {
458
+ margin: 1rem 0;
459
+ padding-left: 1.5rem;
460
+ }
461
+
462
+ .summary li {
463
+ margin-bottom: 0.25rem;
464
+ }
465
+
466
+ .summary a {
467
+ color: #60a5fa;
468
+ text-decoration: underline;
469
+ }
470
+
471
+ .summary a:hover {
472
+ color: #93c5fd;
473
  }
474
 
475
  .export-grid {
test_markdown.html ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Test Markdown Rendering with Marked.js</title>
6
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
7
+ <style>
8
+ .summary {
9
+ min-height: 120px;
10
+ background: rgba(15, 23, 42, 0.5);
11
+ border-radius: 12px;
12
+ padding: 1rem;
13
+ border: 1px solid rgba(148, 163, 184, 0.15);
14
+ line-height: 1.6;
15
+ color: white;
16
+ }
17
+
18
+ .summary h1, .summary h2, .summary h3 {
19
+ margin-top: 1.5rem;
20
+ margin-bottom: 0.5rem;
21
+ color: #e2e8f0;
22
+ }
23
+
24
+ .summary strong { font-weight: 600; color: #f1f5f9; }
25
+ .summary em { font-style: italic; color: #cbd5e1; }
26
+ .summary code {
27
+ background: rgba(100, 116, 139, 0.3);
28
+ padding: 0.125rem 0.25rem;
29
+ border-radius: 4px;
30
+ }
31
+ .summary pre {
32
+ background: rgba(15, 23, 42, 0.8);
33
+ padding: 1rem;
34
+ border-radius: 8px;
35
+ overflow-x: auto;
36
+ }
37
+ .summary ul, .summary ol { margin: 1rem 0; padding-left: 1.5rem; }
38
+ .summary a { color: #60a5fa; text-decoration: underline; }
39
+ </style>
40
+ </head>
41
+ <body style="background: #0f172a; padding: 20px;">
42
+ <h1 style="color: white;">Test du rendu Markdown avec Marked.js</h1>
43
+ <div id="summary-output" class="summary"></div>
44
+
45
+ <script>
46
+ // Configuration de Marked
47
+ marked.setOptions({
48
+ breaks: true,
49
+ gfm: true,
50
+ headerIds: false,
51
+ mangle: false,
52
+ });
53
+
54
+ // Test avec du contenu Markdown
55
+ const testMarkdown = `# Résumé du Podcast
56
+
57
+ Voici un **résumé important** avec du *texte en italique*.
58
+
59
+ ## Points clés
60
+
61
+ - Premier point important
62
+ - **Deuxième point** en gras
63
+ - \`Code inline\` et blocs de code:
64
+
65
+ \`\`\`python
66
+ def hello():
67
+ print("Hello World!")
68
+ \`\`\`
69
+
70
+ ## Conclusion
71
+
72
+ Le podcast traite de sujets intéressants. [Lien vers plus d'infos](https://example.com)`;
73
+
74
+ document.getElementById('summary-output').innerHTML = marked.parse(testMarkdown);
75
+ </script>
76
+ </body>
77
+ </html>