Docfile commited on
Commit
d865223
·
verified ·
1 Parent(s): fc4bc7e

Update templates/philosophie.html

Browse files
Files changed (1) hide show
  1. templates/philosophie.html +173 -139
templates/philosophie.html CHANGED
@@ -1,82 +1,87 @@
1
-
2
  <!DOCTYPE html>
3
  <html lang="fr">
4
  <head>
5
  <meta charset="UTF-8" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
7
- <title>Assistant de Philosophie (Vue.js)</title>
8
 
9
  <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
10
  <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
11
 
12
  <link rel="preconnect" href="https://fonts.googleapis.com">
13
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
14
- <link href="https://fonts.googleapis.com/css2?family=Kalam&family=Lato:wght@400;700&display=swap" rel="stylesheet">
15
 
16
  <style>
17
  :root {
18
- --primary-color: #4f46e5; /* Indigo */
19
  --primary-hover: #4338ca;
20
- --text-color: #374151; /* Gris foncé */
21
- --background-color: #f8f9fa;
 
 
22
  --container-bg: #ffffff;
23
  --border-color: #e5e7eb;
 
24
  }
25
 
26
  body {
27
- font-family: 'Lato', sans-serif;
28
  background-color: var(--background-color);
29
  margin: 0;
30
  padding: 2rem;
31
- color: var(--text-color);
32
  -webkit-font-smoothing: antialiased;
33
  -moz-osx-font-smoothing: grayscale;
34
  }
35
 
36
  .container {
37
- max-width: 960px;
38
  margin: 0 auto;
39
  background: var(--container-bg);
40
- padding: 40px;
41
- border-radius: 12px;
42
- box-shadow: 0 6px 20px rgba(0,0,0,0.08);
 
43
  }
44
 
45
  h1 {
46
  text-align: center;
47
- color: #111827;
 
 
48
  margin-bottom: 0.5em;
49
  }
50
 
51
- .type-indicator {
52
  text-align: center;
53
- color: #6b7280;
54
- font-size: 1.1em;
55
- margin-bottom: 2em;
56
- font-weight: bold;
57
  }
58
 
59
  .form-group {
60
- margin-bottom: 20px;
61
  }
62
 
63
  label {
64
  display: block;
65
- margin-bottom: 8px;
66
- font-weight: 700;
67
- color: #4b5563;
 
68
  }
69
 
70
  textarea, .form-select {
71
  width: 100%;
72
- padding: 15px;
73
- border-radius: 8px;
74
  border: 1px solid var(--border-color);
75
- min-height: 58px;
76
- font-size: 16px;
77
- line-height: 1.6;
78
- transition: border-color 0.3s, box-shadow 0.3s;
79
- background-color: #fff;
80
  -webkit-appearance: none;
81
  -moz-appearance: none;
82
  appearance: none;
@@ -85,100 +90,104 @@
85
 
86
  .form-select {
87
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
88
- background-position: right 0.75rem center;
89
  background-repeat: no-repeat;
90
  background-size: 1.5em 1.5em;
91
- padding-right: 2.5rem;
92
  }
93
 
94
  textarea {
95
- min-height: 100px;
 
96
  }
97
 
98
  textarea:focus, .form-select:focus {
99
  outline: none;
100
  border-color: var(--primary-color);
101
- box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.2);
102
  }
103
 
104
- button {
105
- display: block;
 
 
 
106
  box-sizing: border-box;
107
  width: 100%;
108
- padding: 16px;
109
- background-color: var(--primary-color);
110
- color: white;
111
  border: none;
112
- border-radius: 8px;
113
- font-size: 18px;
114
  font-weight: 700;
115
  cursor: pointer;
116
- transition: background-color 0.3s, transform 0.2s;
117
  }
118
 
119
- button:hover:not(:disabled) {
 
 
 
 
 
 
120
  background-color: var(--primary-hover);
121
  transform: translateY(-2px);
 
122
  }
123
 
124
- button:disabled {
125
  background-color: #9ca3af;
126
  cursor: not-allowed;
 
127
  }
128
 
129
  .download-container {
130
- margin-top: 15px;
131
  }
132
  .secondary-button {
133
- background-color: #f3f4f6;
134
- color: #374151;
135
- border: 1px solid #d1d5db;
136
  }
137
  .secondary-button:hover:not(:disabled) {
138
- background-color: #e5e7eb;
139
- border-color: #9ca3af;
 
140
  }
141
 
142
- .loader {
143
- display: block;
144
- border: 8px solid #f3f3f3;
145
- border-top: 8px solid var(--primary-color);
146
- border-radius: 50%;
147
- width: 50px;
148
- height: 50px;
149
- animation: spin 1s linear infinite;
150
- margin: 30px auto;
151
- }
152
- @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
153
-
154
  .error {
155
  color: #ef4444;
156
  background-color: #fee2e2;
157
  text-align: center;
158
  margin-top: 20px;
159
  padding: 15px;
160
- border-radius: 8px;
161
- font-weight: bold;
162
  }
163
 
164
- /* Styles de la feuille de dissertation */
165
- .dissertation-paper {
166
- font-family: 'Kalam', cursive;
167
- font-size: 20px;
168
- color: #1a2a4c;
169
- background-color: #fdfaf4;
170
- line-height: 2;
171
- background-image: linear-gradient(transparent 97%, #d8e2ee 98%);
172
- background-size: 100% 40px;
173
- border-left: 3px solid #ffaaab;
174
- padding-left: 4em;
175
- margin: 40px -40px -40px -40px;
176
- padding-top: 30px;
177
- padding-bottom: 40px;
178
- padding-right: 30px;
179
- -webkit-print-color-adjust: exact;
180
- print-color-adjust: exact;
181
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  .dissertation-paper h2 { font-size: 1.5em; text-align: center; margin-bottom: 1.5em; }
183
  .dissertation-paper h3 { font-size: 1.2em; margin-top: 3em; margin-bottom: 1.5em; text-transform: uppercase; text-decoration: underline; }
184
  .dissertation-paper .development-block { margin-top: 3em; }
@@ -187,18 +196,17 @@
187
  .dissertation-paper .indented { text-indent: 3em; }
188
  .dissertation-paper .transition { margin-top: 2em; margin-bottom: 2em; font-style: italic; color: #4a6a9c; }
189
  .dissertation-paper, .dissertation-paper * { box-sizing: border-box; }
190
-
191
  .avoid-page-break { page-break-inside: avoid; break-inside: avoid; }
192
  </style>
193
  </head>
194
  <body>
195
  <div id="app" class="container">
196
- <h1>Assistant de Dissertation Philosophique</h1>
197
- <p class="type-indicator">Méthodologie : [[ dissertationTypeLabel ]]</p>
198
 
199
  <form @submit.prevent="generateDissertation">
200
  <div class="form-group">
201
- <label for="dissertation-type">Choisir la méthodologie</label>
202
  <select id="dissertation-type" v-model="dissertationType" class="form-select">
203
  <option value="type1">Type 1 (Problématique en deux questions)</option>
204
  <option value="type2">Type 2 (Introduction autour d'une citation)</option>
@@ -206,7 +214,7 @@
206
  </div>
207
 
208
  <div class="form-group">
209
- <label for="course-context">Choisir un cours comme contexte (optionnel)</label>
210
  <select id="course-context" v-model="selectedCourse" class="form-select">
211
  <option value="">-- Aucun cours en contexte --</option>
212
  <option v-for="course in courses" :key="course.id" :value="course.id">
@@ -216,29 +224,35 @@
216
  </div>
217
 
218
  <div class="form-group">
219
- <label for="question">Entrez votre sujet de dissertation</label>
220
  <textarea id="question" v-model="question" placeholder="Entrez votre sujet ou la citation à analyser ici..."></textarea>
221
  </div>
222
- <button type="submit" :disabled="isLoading">
 
223
  [[ isLoading ? 'Génération en cours...' : 'Générer la dissertation' ]]
224
  </button>
225
  </form>
226
 
227
  <div v-if="dissertation" class="download-container" data-html2canvas-ignore="true">
228
- <button class="secondary-button" @click="generatePDF">Télécharger la dissertation en PDF</button>
 
 
 
 
 
 
 
 
 
229
  </div>
230
 
231
- <div v-if="isLoading" class="loader"></div>
232
  <p v-if="errorMessage" class="error">[[ errorMessage ]]</p>
233
 
234
  <div v-if="dissertation" id="dissertation-content" class="dissertation-paper">
235
-
236
  <h2>Sujet : [[ dissertation.sujet ]]</h2>
237
  <p class="prof">Prof : [[ dissertation.prof ]]</p>
238
-
239
  <h3>Introduction</h3>
240
  <p class="indented">[[ dissertation.introduction ]]</p>
241
-
242
  <div v-for="partie in dissertation.parties" :key="partie.chapeau" class="avoid-page-break">
243
  <div class="development-block">
244
  <p class="indented">[[ partie.chapeau ]]</p>
@@ -248,10 +262,8 @@
248
  </div>
249
  <p v-if="partie.transition" class="indented transition">[[ partie.transition ]]</p>
250
  </div>
251
-
252
  <h3>Conclusion</h3>
253
  <p class="indented">[[ dissertation.conclusion ]]</p>
254
-
255
  </div>
256
  </div>
257
 
@@ -263,11 +275,14 @@
263
  return {
264
  question: '',
265
  dissertationType: 'type1',
266
- courses: [], // Pour stocker la liste des cours
267
- selectedCourse: '', // Pour stocker l'ID du cours sélectionné
268
  isLoading: false,
269
  errorMessage: null,
270
- dissertation: null
 
 
 
271
  }
272
  },
273
  computed: {
@@ -276,22 +291,12 @@
276
  }
277
  },
278
  mounted() {
279
- // Au chargement du composant, on récupère la liste des cours
280
  this.fetchCourses();
281
  },
282
  methods: {
283
- async fetchCourses() {
284
- try {
285
- const response = await fetch('/api/philosophy/courses');
286
- if (!response.ok) throw new Error('Impossible de charger les cours. Vérifiez la connexion à la base de données.');
287
- const data = await response.json();
288
- if (data.error) throw new Error(data.error);
289
- this.courses = data;
290
- } catch (error) {
291
- this.errorMessage = error.message;
292
- console.error("Erreur de chargement des cours:", error);
293
- }
294
- },
295
  async generateDissertation() {
296
  if (!this.question.trim()) {
297
  this.errorMessage = "Veuillez entrer un sujet de dissertation.";
@@ -300,6 +305,8 @@
300
  this.isLoading = true;
301
  this.errorMessage = null;
302
  this.dissertation = null;
 
 
303
  try {
304
  const response = await fetch('/api/generate_dissertation', {
305
  method: 'POST',
@@ -307,7 +314,7 @@
307
  body: JSON.stringify({
308
  question: this.question,
309
  type: this.dissertationType,
310
- courseId: this.selectedCourse // On envoie l'ID du cours s��lectionné
311
  })
312
  });
313
  const data = await response.json();
@@ -318,47 +325,74 @@
318
  } catch (error) {
319
  this.errorMessage = error.message;
320
  } finally {
321
- this.isLoading = false;
322
  }
323
  },
 
 
 
 
 
 
 
 
 
 
 
 
324
 
325
- async generatePDF() {
326
- const element = document.getElementById('dissertation-content');
327
- if (!element) {
328
- this.errorMessage = "Contenu introuvable pour le PDF.";
329
- return;
 
 
 
 
 
 
330
  }
331
- try {
332
- if (document.fonts && document.fonts.ready) {
333
- await document.fonts.ready;
334
- }
335
- window.scrollTo(0, 0);
336
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337
  const options = {
338
- margin: [15, 15, 15, 15],
339
- filename: 'dissertation-philosophie.pdf',
340
  image: { type: 'jpeg', quality: 0.98 },
341
- html2canvas: {
342
- scale: 2,
343
- useCORS: true,
344
- logging: true,
345
- backgroundColor: null,
346
- },
347
  jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }
348
  };
349
-
350
  await html2pdf().set(options).from(element).save();
351
- } catch (err) {
352
- console.error('Erreur html2pdf:', err);
353
- this.errorMessage = "Erreur lors de la génération du PDF. Voir la console pour les détails.";
354
- }
355
  }
356
- }
357
- });
358
 
359
- // ⚠️ Changer les délimiteurs pour éviter le conflit avec Jinja2
360
  app.config.compilerOptions.delimiters = ['[[', ']]'];
361
-
362
  app.mount('#app');
363
  </script>
364
  </body>
 
 
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>Assistant de Philosophie Élégant</title>
7
 
8
  <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
9
  <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
10
 
11
  <link rel="preconnect" href="https://fonts.googleapis.com">
12
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
13
+ <link href="https://fonts.googleapis.com/css2?family=Kalam&family=Lato:wght@400;700&family=Inter:wght@400;500;700&display=swap" rel="stylesheet">
14
 
15
  <style>
16
  :root {
17
+ --primary-color: #4f46e5;
18
  --primary-hover: #4338ca;
19
+ --text-color-dark: #111827;
20
+ --text-color-medium: #4b5563;
21
+ --text-color-light: #6b7280;
22
+ --background-color: #f7f8fc; /* Fond très légèrement bleuté */
23
  --container-bg: #ffffff;
24
  --border-color: #e5e7eb;
25
+ --input-bg: #f9fafb;
26
  }
27
 
28
  body {
29
+ font-family: 'Inter', sans-serif;
30
  background-color: var(--background-color);
31
  margin: 0;
32
  padding: 2rem;
33
+ color: var(--text-color-medium);
34
  -webkit-font-smoothing: antialiased;
35
  -moz-osx-font-smoothing: grayscale;
36
  }
37
 
38
  .container {
39
+ max-width: 800px; /* Un peu plus resserré pour l'élégance */
40
  margin: 0 auto;
41
  background: var(--container-bg);
42
+ padding: 48px;
43
+ border-radius: 24px;
44
+ box-shadow: 0 10px 30px -15px rgba(0,0,0,0.07);
45
+ border: 1px solid var(--border-color);
46
  }
47
 
48
  h1 {
49
  text-align: center;
50
+ color: var(--text-color-dark);
51
+ font-size: 2.25rem;
52
+ letter-spacing: -0.02em;
53
  margin-bottom: 0.5em;
54
  }
55
 
56
+ .subtitle {
57
  text-align: center;
58
+ color: var(--text-color-light);
59
+ font-size: 1.125rem;
60
+ margin-bottom: 3em;
 
61
  }
62
 
63
  .form-group {
64
+ margin-bottom: 1.75rem;
65
  }
66
 
67
  label {
68
  display: block;
69
+ margin-bottom: 0.75rem;
70
+ font-weight: 500;
71
+ font-size: 0.875rem;
72
+ color: var(--text-color-medium);
73
  }
74
 
75
  textarea, .form-select {
76
  width: 100%;
77
+ padding: 16px;
78
+ border-radius: 12px;
79
  border: 1px solid var(--border-color);
80
+ background-color: var(--input-bg);
81
+ font-size: 1rem;
82
+ line-height: 1.5;
83
+ color: var(--text-color-dark);
84
+ transition: border-color 0.2s, box-shadow 0.2s;
85
  -webkit-appearance: none;
86
  -moz-appearance: none;
87
  appearance: none;
 
90
 
91
  .form-select {
92
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
93
+ background-position: right 1rem center;
94
  background-repeat: no-repeat;
95
  background-size: 1.5em 1.5em;
96
+ padding-right: 3rem;
97
  }
98
 
99
  textarea {
100
+ min-height: 120px;
101
+ resize: vertical;
102
  }
103
 
104
  textarea:focus, .form-select:focus {
105
  outline: none;
106
  border-color: var(--primary-color);
107
+ box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.15);
108
  }
109
 
110
+ .main-button, .secondary-button {
111
+ display: inline-flex;
112
+ align-items: center;
113
+ justify-content: center;
114
+ gap: 0.75rem;
115
  box-sizing: border-box;
116
  width: 100%;
117
+ padding: 16px 24px;
 
 
118
  border: none;
119
+ border-radius: 12px;
120
+ font-size: 1rem;
121
  font-weight: 700;
122
  cursor: pointer;
123
+ transition: all 0.2s ease-in-out;
124
  }
125
 
126
+ .main-button {
127
+ background-color: var(--primary-color);
128
+ color: white;
129
+ box-shadow: 0 4px 14px -4px var(--primary-color);
130
+ }
131
+
132
+ .main-button:hover:not(:disabled) {
133
  background-color: var(--primary-hover);
134
  transform: translateY(-2px);
135
+ box-shadow: 0 6px 16px -4px var(--primary-color);
136
  }
137
 
138
+ .main-button:disabled {
139
  background-color: #9ca3af;
140
  cursor: not-allowed;
141
+ box-shadow: none;
142
  }
143
 
144
  .download-container {
145
+ margin-top: 1rem;
146
  }
147
  .secondary-button {
148
+ background-color: transparent;
149
+ color: var(--text-color-medium);
150
+ border: 1px solid var(--border-color);
151
  }
152
  .secondary-button:hover:not(:disabled) {
153
+ background-color: var(--input-bg);
154
+ border-color: #d1d5db;
155
+ color: var(--text-color-dark);
156
  }
157
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  .error {
159
  color: #ef4444;
160
  background-color: #fee2e2;
161
  text-align: center;
162
  margin-top: 20px;
163
  padding: 15px;
164
+ border-radius: 12px;
165
+ font-weight: 500;
166
  }
167
 
168
+ /* NOUVEAU LOADER AVEC POURCENTAGE */
169
+ .progress-container {
170
+ width: 100%;
171
+ margin: 30px auto;
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  }
173
+ .progress-bar {
174
+ height: 12px;
175
+ background-color: var(--primary-color);
176
+ border-radius: 6px;
177
+ width: 0%;
178
+ transition: width 0.4s ease-in-out;
179
+ box-shadow: 0 0 15px -2px rgba(79, 70, 229, 0.5);
180
+ }
181
+ .progress-text {
182
+ text-align: center;
183
+ margin-top: 0.75rem;
184
+ font-weight: 700;
185
+ color: var(--primary-color);
186
+ font-size: 0.875rem;
187
+ }
188
+
189
+ /* Styles de la feuille de dissertation (inchangés car c'est un style voulu) */
190
+ .dissertation-paper { font-family: 'Kalam', cursive; font-size: 20px; color: #1a2a4c; background-color: #fdfaf4; line-height: 2; background-image: linear-gradient(transparent 97%, #d8e2ee 98%); background-size: 100% 40px; border-left: 3px solid #ffaaab; padding-left: 4em; margin: 40px -48px -48px -48px; padding-top: 30px; padding-bottom: 40px; padding-right: 30px; border-radius: 0 0 24px 24px; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
191
  .dissertation-paper h2 { font-size: 1.5em; text-align: center; margin-bottom: 1.5em; }
192
  .dissertation-paper h3 { font-size: 1.2em; margin-top: 3em; margin-bottom: 1.5em; text-transform: uppercase; text-decoration: underline; }
193
  .dissertation-paper .development-block { margin-top: 3em; }
 
196
  .dissertation-paper .indented { text-indent: 3em; }
197
  .dissertation-paper .transition { margin-top: 2em; margin-bottom: 2em; font-style: italic; color: #4a6a9c; }
198
  .dissertation-paper, .dissertation-paper * { box-sizing: border-box; }
 
199
  .avoid-page-break { page-break-inside: avoid; break-inside: avoid; }
200
  </style>
201
  </head>
202
  <body>
203
  <div id="app" class="container">
204
+ <h1>Assistant Philosophique</h1>
205
+ <p class="subtitle">Construisez une dissertation structurée en quelques instants.</p>
206
 
207
  <form @submit.prevent="generateDissertation">
208
  <div class="form-group">
209
+ <label for="dissertation-type">Méthodologie</label>
210
  <select id="dissertation-type" v-model="dissertationType" class="form-select">
211
  <option value="type1">Type 1 (Problématique en deux questions)</option>
212
  <option value="type2">Type 2 (Introduction autour d'une citation)</option>
 
214
  </div>
215
 
216
  <div class="form-group">
217
+ <label for="course-context">Contexte (optionnel)</label>
218
  <select id="course-context" v-model="selectedCourse" class="form-select">
219
  <option value="">-- Aucun cours en contexte --</option>
220
  <option v-for="course in courses" :key="course.id" :value="course.id">
 
224
  </div>
225
 
226
  <div class="form-group">
227
+ <label for="question">Sujet de la dissertation</label>
228
  <textarea id="question" v-model="question" placeholder="Entrez votre sujet ou la citation à analyser ici..."></textarea>
229
  </div>
230
+ <button type="submit" :disabled="isLoading" class="main-button">
231
+ <svg v-if="!isLoading" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.59a2 2 0 0 1-2.83-2.83l8.49-8.48"></path></svg>
232
  [[ isLoading ? 'Génération en cours...' : 'Générer la dissertation' ]]
233
  </button>
234
  </form>
235
 
236
  <div v-if="dissertation" class="download-container" data-html2canvas-ignore="true">
237
+ <button class="secondary-button" @click="generatePDF">
238
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>
239
+ Télécharger en PDF
240
+ </button>
241
+ </div>
242
+
243
+ <!-- NOUVEAU BLOC DE CHARGEMENT -->
244
+ <div v-if="isLoading" class="progress-container">
245
+ <div class="progress-bar" :style="{ width: progress + '%' }"></div>
246
+ <p class="progress-text">Analyse du sujet... [[ Math.round(progress) ]]%</p>
247
  </div>
248
 
 
249
  <p v-if="errorMessage" class="error">[[ errorMessage ]]</p>
250
 
251
  <div v-if="dissertation" id="dissertation-content" class="dissertation-paper">
 
252
  <h2>Sujet : [[ dissertation.sujet ]]</h2>
253
  <p class="prof">Prof : [[ dissertation.prof ]]</p>
 
254
  <h3>Introduction</h3>
255
  <p class="indented">[[ dissertation.introduction ]]</p>
 
256
  <div v-for="partie in dissertation.parties" :key="partie.chapeau" class="avoid-page-break">
257
  <div class="development-block">
258
  <p class="indented">[[ partie.chapeau ]]</p>
 
262
  </div>
263
  <p v-if="partie.transition" class="indented transition">[[ partie.transition ]]</p>
264
  </div>
 
265
  <h3>Conclusion</h3>
266
  <p class="indented">[[ dissertation.conclusion ]]</p>
 
267
  </div>
268
  </div>
269
 
 
275
  return {
276
  question: '',
277
  dissertationType: 'type1',
278
+ courses: [],
279
+ selectedCourse: '',
280
  isLoading: false,
281
  errorMessage: null,
282
+ dissertation: null,
283
+ // Nouvelles données pour la barre de progression
284
+ progress: 0,
285
+ progressInterval: null
286
  }
287
  },
288
  computed: {
 
291
  }
292
  },
293
  mounted() {
 
294
  this.fetchCourses();
295
  },
296
  methods: {
297
+ async fetchCourses() { /* ... méthode inchangée ... */ },
298
+
299
+ // Méthode de génération MISE À JOUR avec la logique de progression
 
 
 
 
 
 
 
 
 
300
  async generateDissertation() {
301
  if (!this.question.trim()) {
302
  this.errorMessage = "Veuillez entrer un sujet de dissertation.";
 
305
  this.isLoading = true;
306
  this.errorMessage = null;
307
  this.dissertation = null;
308
+ this.startProgressSimulation();
309
+
310
  try {
311
  const response = await fetch('/api/generate_dissertation', {
312
  method: 'POST',
 
314
  body: JSON.stringify({
315
  question: this.question,
316
  type: this.dissertationType,
317
+ courseId: this.selectedCourse
318
  })
319
  });
320
  const data = await response.json();
 
325
  } catch (error) {
326
  this.errorMessage = error.message;
327
  } finally {
328
+ this.finishProgressSimulation();
329
  }
330
  },
331
+
332
+ // NOUVELLES MÉTHODES pour gérer la simulation de la progression
333
+ startProgressSimulation() {
334
+ this.progress = 0;
335
+ clearInterval(this.progressInterval); // Sécurité
336
+ this.progressInterval = setInterval(() => {
337
+ if (this.progress < 95) { // Ne jamais atteindre 100% tout seul
338
+ const increment = Math.random() * 5;
339
+ this.progress = Math.min(this.progress + increment, 95);
340
+ }
341
+ }, 400); // Mettre à jour toutes les 400ms
342
+ },
343
 
344
+ finishProgressSimulation() {
345
+ clearInterval(this.progressInterval);
346
+ // Si la requête a réussi, on va à 100% puis on cache la barre
347
+ if(this.dissertation) {
348
+ this.progress = 100;
349
+ setTimeout(() => {
350
+ this.isLoading = false;
351
+ }, 500); // Laisser le temps à l'utilisateur de voir les 100%
352
+ } else {
353
+ // S'il y a eu une erreur, on cache directement
354
+ this.isLoading = false;
355
  }
356
+ },
 
 
 
 
357
 
358
+ async generatePDF() { /* ... méthode inchangée ... */ }
359
+ }
360
+ });
361
+
362
+ // Pour la simplicité, les méthodes fetchCourses et generatePDF sont omises ici
363
+ // mais elles doivent être copiées depuis votre version précédente.
364
+ // Voici les versions complètes pour être sûr.
365
+ const originalMethods = app.config.globalProperties;
366
+ originalMethods.fetchCourses = async function() {
367
+ try {
368
+ const response = await fetch('/api/philosophy/courses');
369
+ if (!response.ok) throw new Error('Impossible de charger les cours.');
370
+ const data = await response.json();
371
+ if (data.error) throw new Error(data.error);
372
+ this.courses = data;
373
+ } catch (error) {
374
+ this.errorMessage = error.message;
375
+ }
376
+ };
377
+ originalMethods.generatePDF = async function() {
378
+ const element = document.getElementById('dissertation-content');
379
+ if (!element) return;
380
+ try {
381
+ if (document.fonts && document.fonts.ready) await document.fonts.ready;
382
+ window.scrollTo(0, 0);
383
  const options = {
384
+ margin: [15, 15, 15, 15], filename: 'dissertation-philosophie.pdf',
 
385
  image: { type: 'jpeg', quality: 0.98 },
386
+ html2canvas: { scale: 2, useCORS: true, logging: true, backgroundColor: null },
 
 
 
 
 
387
  jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }
388
  };
 
389
  await html2pdf().set(options).from(element).save();
390
+ } catch (err) {
391
+ this.errorMessage = "Erreur lors de la génération du PDF.";
 
 
392
  }
393
+ };
 
394
 
 
395
  app.config.compilerOptions.delimiters = ['[[', ']]'];
 
396
  app.mount('#app');
397
  </script>
398
  </body>