Docfile commited on
Commit
e24119e
·
verified ·
1 Parent(s): 9d6bc65

Update templates/gere.html

Browse files
Files changed (1) hide show
  1. templates/gere.html +556 -417
templates/gere.html CHANGED
@@ -4,16 +4,19 @@
4
  <meta charset="UTF-8">
5
  <title>Gestion des Données</title>
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
8
- <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet">
 
 
9
  <style>
10
  body {
11
  background-color: #f8f9fa;
12
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
13
  }
14
-
15
  .container {
16
- max-width: 1200px;
 
17
  margin: 0 auto;
18
  padding: 2rem;
19
  }
@@ -32,45 +35,51 @@
32
  }
33
 
34
  .card:hover {
35
- transform: translateY(-2px);
36
  }
37
 
38
  .card-header {
39
- background-color: #f8f9fa;
40
  border-bottom: 2px solid #e9ecef;
41
  font-weight: 600;
42
  padding: 1rem 1.25rem;
 
 
43
  }
44
 
45
  .nav-tabs {
46
  border-bottom: 2px solid #dee2e6;
47
- margin-bottom: 1rem;
48
  }
49
 
50
  .nav-tabs .nav-link {
51
  border: none;
 
52
  color: #6c757d;
53
  font-weight: 500;
54
  padding: 1rem 1.5rem;
55
  transition: all 0.2s ease-in-out;
 
 
 
56
  }
57
 
58
  .nav-tabs .nav-link:hover {
59
- border: none;
60
  color: #007bff;
61
  }
62
 
63
  .nav-tabs .nav-link.active {
64
  background-color: transparent;
65
- border: none;
66
  border-bottom: 2px solid #007bff;
67
  color: #007bff;
 
68
  }
69
 
70
  .list-group-item {
71
  border: none;
72
  border-bottom: 1px solid #e9ecef;
73
- padding: 1rem;
74
  }
75
 
76
  .list-group-item:last-child {
@@ -82,29 +91,19 @@
82
  padding: 0.5rem 1rem;
83
  transition: all 0.2s ease-in-out;
84
  }
 
 
 
 
 
 
 
85
 
86
- .btn-warning {
87
- background-color: #ffc107;
88
- border-color: #ffc107;
89
- color: #212529;
90
- }
91
-
92
- .btn-danger {
93
- background-color: #dc3545;
94
- border-color: #dc3545;
95
- color: #fff;
96
- }
97
-
98
- .btn-success {
99
- background-color: #28a745;
100
- border-color: #28a745;
101
- color: #fff;
102
- }
103
 
104
  .form-control {
105
  border-radius: 4px;
106
  border: 1px solid #ced4da;
107
- padding: 0.5rem;
108
  }
109
 
110
  .form-control:focus {
@@ -114,123 +113,176 @@
114
 
115
  .alert {
116
  border-radius: 4px;
117
- margin-bottom: 1rem;
118
- animation: fadeInOut 5s ease-in-out;
119
  }
120
 
121
  @keyframes fadeInOut {
122
  0% { opacity: 0; }
123
  10% { opacity: 1; }
124
- 90% { opacity: 1; }
125
- 100% { opacity: 0; }
126
  }
127
 
128
  .editable {
129
  display: none;
130
- background-color: #f8f9fa;
131
  padding: 1rem;
 
132
  border-radius: 4px;
133
- margin-top: 0.5rem;
134
  }
135
 
136
  .display-mode {
137
  line-height: 1.5;
 
 
 
 
 
 
 
 
 
138
  }
139
 
140
  .action-buttons {
141
  display: flex;
142
  gap: 0.5rem;
 
143
  }
144
 
145
  .text-muted {
 
146
  font-size: 0.875rem;
147
  }
 
 
 
 
148
 
149
  .btn-icon {
150
  display: inline-flex;
151
  align-items: center;
152
- gap: 0.5rem;
 
 
 
 
 
 
153
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  </style>
155
  </head>
156
  <body>
157
  <div class="container mt-4">
158
- <h1 class="page-title">Gestion des Données</h1>
159
-
160
- {% with messages = get_flashed_messages(with_categories=true) %}
161
- {% if messages %}
162
- {% for category, message in messages %}
163
- <div class="alert alert-{{ category }} alert-dismissible fade show" role="alert">
164
- {{ message }}
165
- <button type="button" class="close" data-dismiss="alert" aria-label="Fermer">
166
- <span aria-hidden="true">&times;</span>
167
- </button>
168
- </div>
169
- {% endfor %}
170
- {% endif %}
171
- {% endwith %}
 
 
 
172
 
 
173
  <ul class="nav nav-tabs" id="gestionTab" role="tablist">
174
- <li class="nav-item">
175
- <a class="nav-link active" id="matieres-tab" data-toggle="tab" href="#matieres" role="tab">
176
  <i class="fas fa-book"></i> Matières
177
  </a>
178
  </li>
179
- <li class="nav-item">
180
- <a class="nav-link" id="sous-categories-tab" data-toggle="tab" href="#sous-categories" role="tab">
181
  <i class="fas fa-list"></i> Sous-Catégories
182
  </a>
183
  </li>
184
- <li class="nav-item">
185
- <a class="nav-link" id="textes-tab" data-toggle="tab" href="#textes" role="tab">
186
  <i class="fas fa-file-alt"></i> Textes
187
  </a>
188
  </li>
189
- <li class="nav-item">
190
- <a class="nav-link" id="ajouter-tab" data-toggle="tab" href="#ajouter" role="tab">
191
  <i class="fas fa-plus-circle"></i> Ajouter
192
  </a>
193
  </li>
194
  </ul>
195
 
 
196
  <div class="tab-content" id="gestionTabContent">
 
197
  <!-- Onglet Matières -->
198
- <div class="tab-pane fade show active" id="matieres" role="tabpanel">
199
  <div class="card">
200
  <div class="card-header">
201
  <i class="fas fa-book mr-2"></i>Liste des Matières
202
  </div>
203
  <ul class="list-group list-group-flush">
204
  {% for matiere in matieres %}
205
- <li class="list-group-item">
206
  <div class="d-flex justify-content-between align-items-center">
207
  <span class="display-mode">{{ matiere.nom }}</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  <div class="action-buttons">
209
  <button class="btn btn-warning btn-sm btn-icon edit-button">
210
  <i class="fas fa-edit"></i> Modifier
211
  </button>
212
- <form method="post" class="d-inline">
213
  <input type="hidden" name="action" value="delete_matiere_{{ matiere.id }}">
214
- <button type="submit" class="btn btn-danger btn-sm btn-icon" onclick="return confirm('Êtes-vous sûr de vouloir supprimer cette matière ?');">
215
  <i class="fas fa-trash"></i> Supprimer
216
  </button>
217
  </form>
218
  </div>
219
  </div>
220
- <form method="post" class="editable">
221
- <input type="hidden" name="action" value="edit_matiere_{{ matiere.id }}">
222
- <div class="input-group">
223
- <input type="text" name="edit_nom_matiere_{{ matiere.id }}" value="{{ matiere.nom }}" class="form-control">
224
- <div class="input-group-append">
225
- <button type="submit" class="btn btn-success btn-icon">
226
- <i class="fas fa-check"></i> Enregistrer
227
- </button>
228
- <button type="button" class="btn btn-secondary btn-icon cancel-edit">
229
- <i class="fas fa-times"></i> Annuler
230
- </button>
231
- </div>
232
- </div>
233
- </form>
234
  </li>
235
  {% else %}
236
  <li class="list-group-item text-center text-muted">Aucune matière trouvée.</li>
@@ -240,60 +292,60 @@
240
  </div>
241
 
242
  <!-- Onglet Sous-Catégories -->
243
- <div class="tab-pane fade" id="sous-categories" role="tabpanel">
244
  <div class="card">
245
  <div class="card-header">
246
  <i class="fas fa-list mr-2"></i>Liste des Sous-Catégories
247
  </div>
248
  <ul class="list-group list-group-flush">
249
  {% for sous_categorie in sous_categories %}
250
- <li class="list-group-item">
251
  <div class="d-flex justify-content-between align-items-center">
252
- <span class="display-mode">
253
- {{ sous_categorie.nom }}
254
- <small class="text-muted">
255
- <i class="fas fa-book mr-1"></i>{{ sous_categorie.matiere.nom }}
256
- </small>
257
- </span>
258
- <div class="action-buttons">
259
- <button class="btn btn-warning btn-sm btn-icon edit-button">
260
- <i class="fas fa-edit"></i> Modifier
261
- </button>
262
- <form method="post" class="d-inline">
263
- <input type="hidden" name="action" value="delete_sous_categorie_{{ sous_categorie.id }}">
264
- <button type="submit" class="btn btn-danger btn-sm btn-icon" onclick="return confirm('Êtes-vous sûr de vouloir supprimer cette sous-catégorie ?');">
265
- <i class="fas fa-trash"></i> Supprimer
266
- </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
  </form>
268
- </div>
269
- </div>
270
- <form method="post" class="editable">
271
- <input type="hidden" name="action" value="edit_sous_categorie_{{ sous_categorie.id }}">
272
- <div class="form-row">
273
- <div class="col-md-6 mb-2">
274
- <input type="text" name="edit_nom_sous_categorie_{{ sous_categorie.id }}" value="{{ sous_categorie.nom }}" class="form-control" placeholder="Nom">
275
- </div>
276
- <div class="col-md-4 mb-2">
277
- <select name="edit_matiere_id_{{ sous_categorie.id }}" class="form-control">
278
- {% for matiere in matieres %}
279
- <option value="{{ matiere.id }}" {% if matiere.id == sous_categorie.matiere_id %}selected{% endif %}>
280
- {{ matiere.nom }}
281
- </option>
282
- {% endfor %}
283
- </select>
284
- </div>
285
- <div class="col-md-2">
286
- <div class="btn-group">
287
- <button type="submit" class="btn btn-success btn-icon">
288
- <i class="fas fa-check"></i> Enregistrer
289
  </button>
290
- <button type="button" class="btn btn-secondary btn-icon cancel-edit">
291
- <i class="fas fa-times"></i> Annuler
 
 
292
  </button>
293
- </div>
294
  </div>
295
- </div>
296
- </form>
297
  </li>
298
  {% else %}
299
  <li class="list-group-item text-center text-muted">Aucune sous-catégorie trouvée.</li>
@@ -303,65 +355,71 @@
303
  </div>
304
 
305
  <!-- Onglet Textes -->
306
- <div class="tab-pane fade" id="textes" role="tabpanel">
307
  <div class="card">
308
  <div class="card-header">
309
  <i class="fas fa-file-alt mr-2"></i>Liste des Textes
310
  </div>
311
  <ul class="list-group list-group-flush">
312
  {% for texte in textes %}
313
- <li class="list-group-item">
314
- <div class="d-flex justify-content-between align-items-center">
315
- <span class="display-mode">
316
- <strong>{{ texte.titre }}</strong>
317
- <br>
318
- <small class="text-muted">
319
- <i class="fas fa-list mr-1"></i>{{ texte.sous_categorie.nom }}
320
- <i class="fas fa-book ml-2 mr-1"></i>{{ texte.sous_categorie.matiere.nom }}
321
- </small>
322
- </span>
323
- <div class="action-buttons">
324
- <button class="btn btn-warning btn-sm btn-icon edit-button">
325
- <i class="fas fa-edit"></i> Modifier
326
- </button>
327
- <form method="post" class="d-inline">
328
- <input type="hidden" name="action" value="delete_texte_{{ texte.id }}">
329
- <button type="submit" class="btn btn-danger btn-sm btn-icon" onclick="return confirm('Êtes-vous sûr de vouloir supprimer ce texte ?');">
330
- <i class="fas fa-trash"></i> Supprimer
331
- </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
332
  </form>
333
- </div>
334
- </div>
335
- <form method="post" class="editable">
336
- <input type="hidden" name="action" value="edit_texte_{{ texte.id }}">
337
- <div class="form-group">
338
- <input type="text" name="edit_titre_texte_{{ texte.id }}" value="{{ texte.titre }}" class="form-control" placeholder="Titre">
339
- </div>
340
- <div class="form-group">
341
- <textarea name="edit_contenu_texte_{{ texte.id }}" class="form-control" rows="3" placeholder="Contenu">{{ texte.contenu }}</textarea>
342
- </div>
343
- <div class="form-row">
344
- <div class="col-md-8 mb-2">
345
- <select name="edit_sous_categorie_id_{{ texte.id }}" class="form-control">
346
- {% for sous_categorie in sous_categories %}
347
- <option value="{{ sous_categorie.id }}" {% if sous_categorie.id == texte.sous_categorie_id %}selected{% endif %}>
348
- {{ sous_categorie.nom }} ({{ sous_categorie.matiere.nom }})
349
- </option>
350
- {% endfor %}
351
- </select>
352
- </div>
353
- <div class="col-md-4">
354
- <div class="btn-group">
355
- <button type="submit" class="btn btn-success btn-icon">
356
- <i class="fas fa-check"></i> Enregistrer
357
  </button>
358
- <button type="button" class="btn btn-secondary btn-icon cancel-edit">
359
- <i class="fas fa-times"></i> Annuler
 
 
360
  </button>
361
- </div>
362
  </div>
363
- </div>
364
- </form>
365
  </li>
366
  {% else %}
367
  <li class="list-group-item text-center text-muted">Aucun texte trouvé.</li>
@@ -371,284 +429,365 @@
371
  </div>
372
 
373
  <!-- Onglet Ajouter -->
374
- <div class="tab-pane fade" id="ajouter" role="tabpanel">
375
- <!-- Formulaire d'ajout d'une matière -->
376
- <div class="card mt-3">
377
- <div class="card-header">
378
- <i class="fas fa-plus-circle mr-2"></i>Ajouter une Matière
379
- </div>
380
- <div class="card-body">
381
- <form method="post">
382
- <input type="hidden" name="action" value="add_matiere">
383
- <div class="form-group">
384
- <label for="nom_matiere">Nom de la Matière</label>
385
- <input type="text" id="nom_matiere" name="nom_matiere" class="form-control" required>
386
  </div>
387
- <button type="submit" class="btn btn-primary btn-icon">
388
- <i class="fas fa-plus"></i> Ajouter
389
- </button>
390
- </form>
391
- </div>
392
- </div>
 
 
 
 
 
 
 
393
 
394
- <!-- Formulaire d'ajout d'une sous-catégorie -->
395
- <div class="card mt-3">
396
- <div class="card-header">
397
- <i class="fas fa-plus-circle mr-2"></i>Ajouter une Sous-Catégorie
398
- </div>
399
- <div class="card-body">
400
- <form method="post">
401
- <input type="hidden" name="action" value="add_sous_categorie">
402
- <div class="form-group">
403
- <label for="nom_sous_categorie">Nom de la Sous-Catégorie</label>
404
- <input type="text" id="nom_sous_categorie" name="nom_sous_categorie" class="form-control" required>
405
  </div>
406
- <div class="form-group">
407
- <label for="matiere_id">Matière associée</label>
408
- <select id="matiere_id" name="matiere_id" class="form-control" required>
409
- {% for matiere in matieres %}
410
- <option value="{{ matiere.id }}">{{ matiere.nom }}</option>
411
- {% endfor %}
412
- </select>
 
 
 
 
 
 
 
 
 
 
 
 
 
413
  </div>
414
- <button type="submit" class="btn btn-primary btn-icon">
415
- <i class="fas fa-plus"></i> Ajouter
416
- </button>
417
- </form>
418
- </div>
419
- </div>
420
-
421
- <!-- Formulaire d'ajout d'un texte avec module IA -->
422
- <div class="card mt-3">
423
- <div class="card-header">
424
- <i class="fas fa-plus-circle mr-2"></i>Ajouter un Texte
425
- </div>
426
- <div class="card-body">
427
- <ul class="nav nav-tabs" id="textInputTabs" role="tablist">
428
- <li class="nav-item">
429
- <a class="nav-link active" id="manual-tab" data-toggle="tab" href="#manual-input" role="tab">
430
- <i class="fas fa-edit"></i> Saisie Manuelle
431
- </a>
432
- </li>
433
- <li class="nav-item">
434
- <a class="nav-link" id="ia-tab" data-toggle="tab" href="#ia-input" role="tab">
435
- <i class="fas fa-robot"></i> Génération IA
436
- </a>
437
- </li>
438
- </ul>
439
-
440
- <div class="tab-content mt-3" id="textInputTabContent">
441
- <!-- Onglet Saisie Manuelle -->
442
- <div class="tab-pane fade show active" id="manual-input" role="tabpanel">
443
- <form method="post">
444
- <input type="hidden" name="action" value="add_texte">
445
- <div class="form-group">
446
- <label for="titre_texte">Titre du Texte</label>
447
- <input type="text" id="titre_texte" name="titre_texte" class="form-control" required>
448
- </div>
449
- <div class="form-group">
450
- <label for="contenu_texte">Contenu du Texte</label>
451
- <textarea id="contenu_texte" name="contenu_texte" class="form-control" rows="5" required></textarea>
452
- </div>
453
- <div class="form-group">
454
- <label for="sous_categorie_id">Sous-Catégorie</label>
455
- <select id="sous_categorie_id" name="sous_categorie_id" class="form-control" required>
456
- {% for sous_categorie in sous_categories %}
457
- <option value="{{ sous_categorie.id }}">{{ sous_categorie.nom }} ({{ sous_categorie.matiere.nom }})</option>
458
- {% endfor %}
459
- </select>
460
- </div>
461
- <button type="submit" class="btn btn-primary btn-icon">
462
- <i class="fas fa-plus"></i> Ajouter
463
- </button>
464
- </form>
465
- </div>
466
-
467
- <!-- Onglet Génération IA -->
468
- <div class="tab-pane fade" id="ia-input" role="tabpanel">
469
- <form method="post" id="ia-generation-form">
470
- <input type="hidden" name="action" value="generate_ia_content">
471
- <div class="form-group">
472
- <label for="ia_titre_texte">Titre du Texte</label>
473
- <input type="text" id="ia_titre_texte" name="ia_titre_texte" class="form-control" required>
474
- </div>
475
- <div class="form-group">
476
- <label for="youtube_url">URL de la vidéo YouTube</label>
477
- <input type="url" id="youtube_url" name="youtube_url" class="form-control" placeholder="https://www.youtube.com/watch?v=..." required>
478
- </div>
479
- <div class="form-group">
480
- <label for="ia_prompt">Prompt pour l'IA</label>
481
- <textarea id="ia_prompt" name="ia_prompt" class="form-control" rows="3" placeholder="Exemple: Faire un résumé détaillé de cette vidéo avec les points clés" required></textarea>
482
- </div>
483
- <div class="form-group">
484
- <label for="ia_model">Modèle Gemini</label>
485
- <select id="ia_model" name="ia_model" class="form-control">
486
- <option value="gemini-2.5-pro-exp-03-25">gemini-2.5-pro-exp-03-25</option>
487
- <option value="gemini-1.5-pro">gemini-2.0-flash</option>
488
- <option value="gemini-1.5-flash">gemini-1.5-flash</option>
489
- </select>
490
- </div>
491
- <div class="form-group">
492
- <label for="ia_sous_categorie_id">Sous-Catégorie</label>
493
- <select id="ia_sous_categorie_id" name="ia_sous_categorie_id" class="form-control" required>
494
- {% for sous_categorie in sous_categories %}
495
- <option value="{{ sous_categorie.id }}">{{ sous_categorie.nom }} ({{ sous_categorie.matiere.nom }})</option>
496
- {% endfor %}
497
- </select>
498
- </div>
499
- <button type="submit" id="generate-content-btn" class="btn btn-info btn-icon">
500
- <i class="fas fa-magic"></i> Générer le Contenu
501
- </button>
502
- <div id="ia-loading" class="mt-3 d-none">
503
- <div class="spinner-border text-primary" role="status">
504
- <span class="sr-only">Génération en cours...</span>
505
  </div>
506
- <span class="ml-2">Analyse de la vidéo en cours, veuillez patienter...</span>
507
  </div>
508
- <div id="ia-result-container" class="mt-3 d-none">
509
- <div class="form-group">
510
- <label for="ia_generated_content">Contenu Généré</label>
511
- <textarea id="ia_generated_content" name="ia_generated_content" class="form-control" rows="10" readonly></textarea>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
512
  </div>
513
- <button type="button" id="use-content-btn" class="btn btn-success btn-icon">
514
- <i class="fas fa-check"></i> Utiliser ce Contenu
515
- </button>
516
- <button type="button" id="modify-content-btn" class="btn btn-warning btn-icon ml-2">
517
- <i class="fas fa-edit"></i> Modifier avant Utilisation
518
- </button>
519
  </div>
520
- </form>
521
- <form method="post" id="submit-ia-content-form" class="d-none">
522
- <input type="hidden" name="action" value="add_texte">
523
- <input type="hidden" id="final_titre_texte" name="titre_texte">
524
- <input type="hidden" id="final_contenu_texte" name="contenu_texte">
525
- <input type="hidden" id="final_sous_categorie_id" name="sous_categorie_id">
526
- </form>
527
- </div>
528
- </div>
529
- </div>
530
- </div>
531
-
532
 
533
-
 
534
 
535
  <!-- Scripts -->
536
- <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
537
- <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
538
- <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
 
 
 
 
539
  <script>
540
  $(document).ready(function() {
541
- // Gestion des boutons Modifier
 
 
 
 
 
 
 
 
 
 
 
542
  $(document).on('click', '.edit-button', function(e) {
543
  e.preventDefault();
544
- const listItem = $(this).closest('li');
 
 
 
 
545
  listItem.find('.editable').slideDown();
546
- listItem.find('.display-mode').hide();
547
- $(this).hide();
 
548
  });
549
 
550
- // Gestion des boutons Annuler
551
  $(document).on('click', '.cancel-edit', function(e) {
552
  e.preventDefault();
553
- const listItem = $(this).closest('li');
554
  listItem.find('.editable').slideUp();
555
- listItem.find('.display-mode').show();
556
- listItem.find('.edit-button').show();
 
557
  });
558
 
559
- // Animation pour les alertes
560
- $('.alert').delay(4000).fadeOut(500);
561
 
562
- // Confirmation personnalisée pour la suppression
563
- $('form[method="post"]').on('submit', function(e) {
564
- if ($(this).find('button[type="submit"]').hasClass('btn-danger')) {
565
- if (!confirm('Êtes-vous sûr de vouloir supprimer cet élément ?')) {
566
- e.preventDefault();
 
 
 
567
  }
 
568
  }
569
  });
570
- });
571
-
572
- // Ajouter ce code à la fin de votre script existant dans gere.html (avant la balise </script> finale)
573
-
574
- // Fonctionnalité pour la génération de contenu IA
575
- $(document).ready(function() {
576
- // Gestionnaire pour le formulaire de génération IA
577
- $('#ia-generation-form').on('submit', function(e) {
578
- e.preventDefault();
579
-
580
- const youtubeUrl = $('#youtube_url').val();
581
- const prompt = $('#ia_prompt').val();
582
- const model = $('#ia_model').val();
583
-
584
- if (!youtubeUrl || !prompt) {
585
- alert('Veuillez remplir tous les champs requis.');
586
- return;
587
- }
588
-
589
- // Afficher l'indicateur de chargement
590
- $('#generate-content-btn').prop('disabled', true);
591
- $('#ia-loading').removeClass('d-none');
592
- $('#ia-result-container').addClass('d-none');
593
-
594
- // Appel AJAX pour générer le contenu
595
- $.ajax({
596
- url: '/generate-content',
597
- type: 'POST',
598
- contentType: 'application/json',
599
- data: JSON.stringify({
600
- youtube_url: youtubeUrl,
601
- prompt: prompt,
602
- model: model
603
- }),
604
- success: function(response) {
605
- $('#generate-content-btn').prop('disabled', false);
606
- $('#ia-loading').addClass('d-none');
607
-
608
- if (response.success) {
609
- // Afficher le résultat
610
- $('#ia_generated_content').val(response.text);
611
- $('#ia-result-container').removeClass('d-none');
612
- } else {
613
- alert('Erreur lors de la génération du contenu: ' + response.error);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
614
  }
615
- },
616
- error: function(xhr, status, error) {
617
- $('#generate-content-btn').prop('disabled', false);
618
- $('#ia-loading').addClass('d-none');
619
- alert('Erreur lors de la communication avec le serveur: ' + error);
620
- }
621
- });
622
- });
623
-
624
- // Utiliser le contenu généré tel quel
625
- $('#use-content-btn').on('click', function() {
626
- const titre = $('#ia_titre_texte').val();
627
- const contenu = $('#ia_generated_content').val();
628
- const sousCategorie = $('#ia_sous_categorie_id').val();
629
-
630
- // Remplir le formulaire caché et le soumettre
631
- $('#final_titre_texte').val(titre);
632
- $('#final_contenu_texte').val(contenu);
633
- $('#final_sous_categorie_id').val(sousCategorie);
634
- $('#submit-ia-content-form').submit();
635
- });
636
-
637
- // Modifier le contenu avant utilisation
638
- $('#modify-content-btn').on('click', function() {
639
- const titre = $('#ia_titre_texte').val();
640
- const contenu = $('#ia_generated_content').val();
641
- const sousCategorie = $('#ia_sous_categorie_id').val();
642
-
643
- // Basculer vers l'onglet manuel et préremplir les champs
644
- $('#titre_texte').val(titre);
645
- $('#contenu_texte').val(contenu);
646
- $('#sous_categorie_id').val(sousCategorie);
647
- $('#manual-tab').tab('show');
648
- });
649
- });
650
-
651
-
652
  </script>
653
  </body>
654
  </html>
 
4
  <meta charset="UTF-8">
5
  <title>Gestion des Données</title>
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <!-- Bootstrap CSS with SRI -->
8
+ <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
9
+ <!-- Font Awesome CSS with SRI -->
10
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet" integrity="sha512-1ycn6IcaQQ40/MKBW2W4Rhis/DbILU74C1vSrLJxCq57o941Ym01SwNsOMqvEBFlcgUa6xLiPY/NS5R+E6ztJQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
11
  <style>
12
  body {
13
  background-color: #f8f9fa;
14
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
15
  }
16
+
17
  .container {
18
+ /* Utilisation de container-fluid pour une meilleure largeur sur grand écran, ou garder max-width */
19
+ /* max-width: 1200px; */
20
  margin: 0 auto;
21
  padding: 2rem;
22
  }
 
35
  }
36
 
37
  .card:hover {
38
+ transform: translateY(-2px); /* Subtile effet au survol */
39
  }
40
 
41
  .card-header {
42
+ background-color: #f8f9fa; /* Ou une couleur contrastante comme #e9ecef */
43
  border-bottom: 2px solid #e9ecef;
44
  font-weight: 600;
45
  padding: 1rem 1.25rem;
46
+ display: flex; /* Pour aligner icône et texte */
47
+ align-items: center;
48
  }
49
 
50
  .nav-tabs {
51
  border-bottom: 2px solid #dee2e6;
52
+ margin-bottom: 1.5rem; /* Un peu plus d'espace */
53
  }
54
 
55
  .nav-tabs .nav-link {
56
  border: none;
57
+ border-bottom: 2px solid transparent; /* Préparer pour l'état actif */
58
  color: #6c757d;
59
  font-weight: 500;
60
  padding: 1rem 1.5rem;
61
  transition: all 0.2s ease-in-out;
62
+ display: inline-flex; /* Pour aligner icône et texte */
63
+ align-items: center;
64
+ gap: 0.5rem; /* Espace entre icône et texte */
65
  }
66
 
67
  .nav-tabs .nav-link:hover {
68
+ border-bottom-color: #adb5bd; /* Léger indicateur au survol */
69
  color: #007bff;
70
  }
71
 
72
  .nav-tabs .nav-link.active {
73
  background-color: transparent;
 
74
  border-bottom: 2px solid #007bff;
75
  color: #007bff;
76
+ font-weight: 600; /* Rendre l'onglet actif plus visible */
77
  }
78
 
79
  .list-group-item {
80
  border: none;
81
  border-bottom: 1px solid #e9ecef;
82
+ padding: 1rem 1.25rem; /* Harmoniser padding avec card-header */
83
  }
84
 
85
  .list-group-item:last-child {
 
91
  padding: 0.5rem 1rem;
92
  transition: all 0.2s ease-in-out;
93
  }
94
+ /* Amélioration couleurs boutons (Bootstrap 4 utilise déjà ces couleurs, mais on peut affiner) */
95
+ .btn-warning { color: #212529; }
96
+ .btn-danger { color: #fff; }
97
+ .btn-success { color: #fff; }
98
+ .btn-info { color: #fff; }
99
+ .btn-primary { color: #fff; }
100
+ .btn-secondary { color: #fff; }
101
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
  .form-control {
104
  border-radius: 4px;
105
  border: 1px solid #ced4da;
106
+ padding: 0.5rem 0.75rem; /* Ajustement padding */
107
  }
108
 
109
  .form-control:focus {
 
113
 
114
  .alert {
115
  border-radius: 4px;
116
+ margin-bottom: 1.5rem; /* Cohérence espacement */
117
+ animation: fadeInOut 5s ease-in-out forwards; /* 'forwards' garde l'état final (opacity: 0) */
118
  }
119
 
120
  @keyframes fadeInOut {
121
  0% { opacity: 0; }
122
  10% { opacity: 1; }
123
+ 90% { opacity: 1; transform: translateY(0); }
124
+ 100% { opacity: 0; transform: translateY(-10px); } /* Légère animation de sortie */
125
  }
126
 
127
  .editable {
128
  display: none;
129
+ background-color: #f0f2f5; /* Légèrement différent pour le mode édition */
130
  padding: 1rem;
131
+ border: 1px dashed #ced4da; /* Indicateur visuel */
132
  border-radius: 4px;
133
+ margin-top: 1rem; /* Espace entre l'affichage et l'édition */
134
  }
135
 
136
  .display-mode {
137
  line-height: 1.5;
138
+ flex-grow: 1; /* Permet au texte de prendre l'espace disponible */
139
+ margin-right: 1rem; /* Espace avant les boutons */
140
+ }
141
+ .display-mode strong {
142
+ color: #343a40; /* Rendre le titre plus distinct */
143
+ }
144
+ .display-mode small {
145
+ display: block; /* Mettre les détails sur une nouvelle ligne si nécessaire */
146
+ margin-top: 0.25rem;
147
  }
148
 
149
  .action-buttons {
150
  display: flex;
151
  gap: 0.5rem;
152
+ flex-shrink: 0; /* Empêche les boutons de rétrécir */
153
  }
154
 
155
  .text-muted {
156
+ color: #6c757d !important; /* Forcer la couleur si nécessaire */
157
  font-size: 0.875rem;
158
  }
159
+ .text-muted i {
160
+ margin-left: 0.25rem; /* Espace avant l'icône dans small */
161
+ }
162
+
163
 
164
  .btn-icon {
165
  display: inline-flex;
166
  align-items: center;
167
+ gap: 0.5rem; /* Espace entre icône et texte dans le bouton */
168
+ }
169
+
170
+ /* Styles spécifiques pour la partie IA */
171
+ #ia-loading .spinner-border {
172
+ width: 1.5rem;
173
+ height: 1.5rem;
174
  }
175
+ #ia-result-container {
176
+ border: 1px solid #e9ecef;
177
+ padding: 1rem;
178
+ background-color: #fff;
179
+ border-radius: 4px;
180
+ }
181
+ #ia_generated_content {
182
+ font-family: monospace; /* Utile pour du contenu potentiellement formaté */
183
+ background-color: #e9ecef; /* Indiquer que c'est en lecture seule */
184
+ font-size: 0.9rem;
185
+ }
186
+ .btn-group .btn { /* Assurer que les boutons dans btn-group s'affichent correctement */
187
+ margin-right: -1px; /* Correction pour Bootstrap 4 btn-group */
188
+ }
189
+ .btn-group .btn:not(:last-child) {
190
+ border-top-right-radius: 0;
191
+ border-bottom-right-radius: 0;
192
+ }
193
+ .btn-group .btn:not(:first-child) {
194
+ border-top-left-radius: 0;
195
+ border-bottom-left-radius: 0;
196
+ }
197
+
198
  </style>
199
  </head>
200
  <body>
201
  <div class="container mt-4">
202
+ <h1 class="page-title text-center"><i class="fas fa-database mr-2"></i>Gestion des Données</h1>
203
+
204
+ <!-- Zone pour les messages flash -->
205
+ <div id="flash-message-container">
206
+ {% with messages = get_flashed_messages(with_categories=true) %}
207
+ {% if messages %}
208
+ {% for category, message in messages %}
209
+ <div class="alert alert-{{ category }} alert-dismissible fade show" role="alert">
210
+ {{ message }}
211
+ <button type="button" class="close" data-dismiss="alert" aria-label="Fermer">
212
+ <span aria-hidden="true">×</span>
213
+ </button>
214
+ </div>
215
+ {% endfor %}
216
+ {% endif %}
217
+ {% endwith %}
218
+ </div>
219
 
220
+ <!-- Onglets de navigation -->
221
  <ul class="nav nav-tabs" id="gestionTab" role="tablist">
222
+ <li class="nav-item" role="presentation">
223
+ <a class="nav-link active" id="matieres-tab" data-toggle="tab" href="#matieres" role="tab" aria-controls="matieres" aria-selected="true">
224
  <i class="fas fa-book"></i> Matières
225
  </a>
226
  </li>
227
+ <li class="nav-item" role="presentation">
228
+ <a class="nav-link" id="sous-categories-tab" data-toggle="tab" href="#sous-categories" role="tab" aria-controls="sous-categories" aria-selected="false">
229
  <i class="fas fa-list"></i> Sous-Catégories
230
  </a>
231
  </li>
232
+ <li class="nav-item" role="presentation">
233
+ <a class="nav-link" id="textes-tab" data-toggle="tab" href="#textes" role="tab" aria-controls="textes" aria-selected="false">
234
  <i class="fas fa-file-alt"></i> Textes
235
  </a>
236
  </li>
237
+ <li class="nav-item" role="presentation">
238
+ <a class="nav-link" id="ajouter-tab" data-toggle="tab" href="#ajouter" role="tab" aria-controls="ajouter" aria-selected="false">
239
  <i class="fas fa-plus-circle"></i> Ajouter
240
  </a>
241
  </li>
242
  </ul>
243
 
244
+ <!-- Contenu des onglets -->
245
  <div class="tab-content" id="gestionTabContent">
246
+
247
  <!-- Onglet Matières -->
248
+ <div class="tab-pane fade show active" id="matieres" role="tabpanel" aria-labelledby="matieres-tab">
249
  <div class="card">
250
  <div class="card-header">
251
  <i class="fas fa-book mr-2"></i>Liste des Matières
252
  </div>
253
  <ul class="list-group list-group-flush">
254
  {% for matiere in matieres %}
255
+ <li class="list-group-item" id="matiere-{{ matiere.id }}">
256
  <div class="d-flex justify-content-between align-items-center">
257
  <span class="display-mode">{{ matiere.nom }}</span>
258
+ <!-- Formulaire d'édition caché -->
259
+ <form method="post" class="editable flex-grow-1 mr-2">
260
+ <input type="hidden" name="action" value="edit_matiere_{{ matiere.id }}">
261
+ <div class="input-group">
262
+ <input type="text" name="edit_nom_matiere_{{ matiere.id }}" value="{{ matiere.nom }}" class="form-control" required>
263
+ <div class="input-group-append">
264
+ <button type="submit" class="btn btn-success btn-icon">
265
+ <i class="fas fa-check"></i> Enregistrer
266
+ </button>
267
+ <button type="button" class="btn btn-secondary btn-icon cancel-edit">
268
+ <i class="fas fa-times"></i> Annuler
269
+ </button>
270
+ </div>
271
+ </div>
272
+ </form>
273
+ <!-- Boutons d'action visibles -->
274
  <div class="action-buttons">
275
  <button class="btn btn-warning btn-sm btn-icon edit-button">
276
  <i class="fas fa-edit"></i> Modifier
277
  </button>
278
+ <form method="post" class="d-inline delete-form">
279
  <input type="hidden" name="action" value="delete_matiere_{{ matiere.id }}">
280
+ <button type="submit" class="btn btn-danger btn-sm btn-icon">
281
  <i class="fas fa-trash"></i> Supprimer
282
  </button>
283
  </form>
284
  </div>
285
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
  </li>
287
  {% else %}
288
  <li class="list-group-item text-center text-muted">Aucune matière trouvée.</li>
 
292
  </div>
293
 
294
  <!-- Onglet Sous-Catégories -->
295
+ <div class="tab-pane fade" id="sous-categories" role="tabpanel" aria-labelledby="sous-categories-tab">
296
  <div class="card">
297
  <div class="card-header">
298
  <i class="fas fa-list mr-2"></i>Liste des Sous-Catégories
299
  </div>
300
  <ul class="list-group list-group-flush">
301
  {% for sous_categorie in sous_categories %}
302
+ <li class="list-group-item" id="sous-categorie-{{ sous_categorie.id }}">
303
  <div class="d-flex justify-content-between align-items-center">
304
+ <span class="display-mode">
305
+ {{ sous_categorie.nom }}
306
+ <small class="text-muted"><i class="fas fa-book"></i>{{ sous_categorie.matiere.nom }}</small>
307
+ </span>
308
+ <!-- Formulaire d'édition caché -->
309
+ <form method="post" class="editable flex-grow-1 mr-2">
310
+ <input type="hidden" name="action" value="edit_sous_categorie_{{ sous_categorie.id }}">
311
+ <div class="form-row align-items-center">
312
+ <div class="col-md-6 mb-2 mb-md-0">
313
+ <input type="text" name="edit_nom_sous_categorie_{{ sous_categorie.id }}" value="{{ sous_categorie.nom }}" class="form-control" placeholder="Nom" required>
314
+ </div>
315
+ <div class="col-md-4 mb-2 mb-md-0">
316
+ <select name="edit_matiere_id_{{ sous_categorie.id }}" class="form-control" required>
317
+ {% for matiere in matieres %}
318
+ <option value="{{ matiere.id }}" {% if matiere.id == sous_categorie.matiere_id %}selected{% endif %}>
319
+ {{ matiere.nom }}
320
+ </option>
321
+ {% endfor %}
322
+ </select>
323
+ </div>
324
+ <div class="col-md-2">
325
+ <div class="btn-group" role="group">
326
+ <button type="submit" class="btn btn-success btn-icon">
327
+ <i class="fas fa-check"></i> <span class="d-none d-lg-inline">Enr.</span>
328
+ </button>
329
+ <button type="button" class="btn btn-secondary btn-icon cancel-edit">
330
+ <i class="fas fa-times"></i> <span class="d-none d-lg-inline">Ann.</span>
331
+ </button>
332
+ </div>
333
+ </div>
334
+ </div>
335
  </form>
336
+ <!-- Boutons d'action visibles -->
337
+ <div class="action-buttons">
338
+ <button class="btn btn-warning btn-sm btn-icon edit-button">
339
+ <i class="fas fa-edit"></i> Modifier
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
  </button>
341
+ <form method="post" class="d-inline delete-form">
342
+ <input type="hidden" name="action" value="delete_sous_categorie_{{ sous_categorie.id }}">
343
+ <button type="submit" class="btn btn-danger btn-sm btn-icon">
344
+ <i class="fas fa-trash"></i> Supprimer
345
  </button>
346
+ </form>
347
  </div>
348
+ </div>
 
349
  </li>
350
  {% else %}
351
  <li class="list-group-item text-center text-muted">Aucune sous-catégorie trouvée.</li>
 
355
  </div>
356
 
357
  <!-- Onglet Textes -->
358
+ <div class="tab-pane fade" id="textes" role="tabpanel" aria-labelledby="textes-tab">
359
  <div class="card">
360
  <div class="card-header">
361
  <i class="fas fa-file-alt mr-2"></i>Liste des Textes
362
  </div>
363
  <ul class="list-group list-group-flush">
364
  {% for texte in textes %}
365
+ <li class="list-group-item" id="texte-{{ texte.id }}">
366
+ <div class="d-flex justify-content-between align-items-start"> <!-- align-items-start pour contenu multiligne -->
367
+ <span class="display-mode">
368
+ <strong>{{ texte.titre }}</strong>
369
+ <small class="text-muted">
370
+ <i class="fas fa-list"></i>{{ texte.sous_categorie.nom }}
371
+ <i class="fas fa-book"></i>{{ texte.sous_categorie.matiere.nom }}
372
+ </small>
373
+ <!-- Optionnel: Aperçu du contenu -->
374
+ <!-- <p class="text-muted mt-1 mb-0 small">{{ texte.contenu | truncate(100) }}</p> -->
375
+ </span>
376
+ <!-- Formulaire d'édition caché -->
377
+ <form method="post" class="editable flex-grow-1 mr-2">
378
+ <input type="hidden" name="action" value="edit_texte_{{ texte.id }}">
379
+ <div class="form-group">
380
+ <label for="edit_titre_texte_{{ texte.id }}" class="sr-only">Titre</label>
381
+ <input type="text" id="edit_titre_texte_{{ texte.id }}" name="edit_titre_texte_{{ texte.id }}" value="{{ texte.titre }}" class="form-control mb-2" placeholder="Titre" required>
382
+ </div>
383
+ <div class="form-group">
384
+ <label for="edit_contenu_texte_{{ texte.id }}" class="sr-only">Contenu</label>
385
+ <textarea id="edit_contenu_texte_{{ texte.id }}" name="edit_contenu_texte_{{ texte.id }}" class="form-control mb-2" rows="4" placeholder="Contenu" required>{{ texte.contenu }}</textarea>
386
+ </div>
387
+ <div class="form-row align-items-center">
388
+ <div class="col-md-8 mb-2 mb-md-0">
389
+ <label for="edit_sous_categorie_id_{{ texte.id }}" class="sr-only">Sous-catégorie</label>
390
+ <select id="edit_sous_categorie_id_{{ texte.id }}" name="edit_sous_categorie_id_{{ texte.id }}" class="form-control" required>
391
+ {% for sous_categorie in sous_categories %}
392
+ <option value="{{ sous_categorie.id }}" {% if sous_categorie.id == texte.sous_categorie_id %}selected{% endif %}>
393
+ {{ sous_categorie.nom }} ({{ sous_categorie.matiere.nom }})
394
+ </option>
395
+ {% endfor %}
396
+ </select>
397
+ </div>
398
+ <div class="col-md-4">
399
+ <div class="btn-group" role="group">
400
+ <button type="submit" class="btn btn-success btn-icon">
401
+ <i class="fas fa-check"></i> <span class="d-none d-lg-inline">Enr.</span>
402
+ </button>
403
+ <button type="button" class="btn btn-secondary btn-icon cancel-edit">
404
+ <i class="fas fa-times"></i> <span class="d-none d-lg-inline">Ann.</span>
405
+ </button>
406
+ </div>
407
+ </div>
408
+ </div>
409
  </form>
410
+ <!-- Boutons d'action visibles -->
411
+ <div class="action-buttons">
412
+ <button class="btn btn-warning btn-sm btn-icon edit-button">
413
+ <i class="fas fa-edit"></i> Modifier
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
414
  </button>
415
+ <form method="post" class="d-inline delete-form">
416
+ <input type="hidden" name="action" value="delete_texte_{{ texte.id }}">
417
+ <button type="submit" class="btn btn-danger btn-sm btn-icon">
418
+ <i class="fas fa-trash"></i> Supprimer
419
  </button>
420
+ </form>
421
  </div>
422
+ </div>
 
423
  </li>
424
  {% else %}
425
  <li class="list-group-item text-center text-muted">Aucun texte trouvé.</li>
 
429
  </div>
430
 
431
  <!-- Onglet Ajouter -->
432
+ <div class="tab-pane fade" id="ajouter" role="tabpanel" aria-labelledby="ajouter-tab">
433
+ <div class="row">
434
+ <!-- Colonne pour Matière et Sous-catégorie -->
435
+ <div class="col-md-6">
436
+ <!-- Formulaire d'ajout d'une matière -->
437
+ <div class="card mb-4">
438
+ <div class="card-header">
439
+ <i class="fas fa-plus-circle mr-2"></i>Ajouter une Matière
 
 
 
 
440
  </div>
441
+ <div class="card-body">
442
+ <form method="post">
443
+ <input type="hidden" name="action" value="add_matiere">
444
+ <div class="form-group">
445
+ <label for="nom_matiere">Nom de la Matière</label>
446
+ <input type="text" id="nom_matiere" name="nom_matiere" class="form-control" required>
447
+ </div>
448
+ <button type="submit" class="btn btn-primary btn-icon">
449
+ <i class="fas fa-plus"></i> Ajouter Matière
450
+ </button>
451
+ </form>
452
+ </div>
453
+ </div>
454
 
455
+ <!-- Formulaire d'ajout d'une sous-catégorie -->
456
+ <div class="card">
457
+ <div class="card-header">
458
+ <i class="fas fa-plus-circle mr-2"></i>Ajouter une Sous-Catégorie
 
 
 
 
 
 
 
459
  </div>
460
+ <div class="card-body">
461
+ <form method="post">
462
+ <input type="hidden" name="action" value="add_sous_categorie">
463
+ <div class="form-group">
464
+ <label for="nom_sous_categorie">Nom de la Sous-Catégorie</label>
465
+ <input type="text" id="nom_sous_categorie" name="nom_sous_categorie" class="form-control" required>
466
+ </div>
467
+ <div class="form-group">
468
+ <label for="matiere_id">Matière associée</label>
469
+ <select id="matiere_id" name="matiere_id" class="form-control" required>
470
+ <option value="" disabled selected>Choisir une matière...</option>
471
+ {% for matiere in matieres %}
472
+ <option value="{{ matiere.id }}">{{ matiere.nom }}</option>
473
+ {% endfor %}
474
+ </select>
475
+ </div>
476
+ <button type="submit" class="btn btn-primary btn-icon">
477
+ <i class="fas fa-plus"></i> Ajouter Sous-Catégorie
478
+ </button>
479
+ </form>
480
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
481
  </div>
 
482
  </div>
483
+
484
+ <!-- Colonne pour Texte -->
485
+ <div class="col-md-6">
486
+ <!-- Formulaire d'ajout d'un texte avec module IA -->
487
+ <div class="card">
488
+ <div class="card-header">
489
+ <i class="fas fa-plus-circle mr-2"></i>Ajouter un Texte
490
+ </div>
491
+ <div class="card-body">
492
+ <ul class="nav nav-pills mb-3" id="textInputTabs" role="tablist">
493
+ <li class="nav-item">
494
+ <a class="nav-link active" id="manual-tab" data-toggle="pill" href="#manual-input" role="tab" aria-controls="manual-input" aria-selected="true">
495
+ <i class="fas fa-edit mr-1"></i> Manuel
496
+ </a>
497
+ </li>
498
+ <li class="nav-item">
499
+ <a class="nav-link" id="ia-tab" data-toggle="pill" href="#ia-input" role="tab" aria-controls="ia-input" aria-selected="false">
500
+ <i class="fas fa-robot mr-1"></i> Génération IA
501
+ </a>
502
+ </li>
503
+ </ul>
504
+
505
+ <div class="tab-content" id="textInputTabContent">
506
+ <!-- Onglet Saisie Manuelle -->
507
+ <div class="tab-pane fade show active" id="manual-input" role="tabpanel" aria-labelledby="manual-tab">
508
+ <form method="post" id="manual-add-text-form">
509
+ <input type="hidden" name="action" value="add_texte">
510
+ <div class="form-group">
511
+ <label for="titre_texte">Titre du Texte</label>
512
+ <input type="text" id="titre_texte" name="titre_texte" class="form-control" required>
513
+ </div>
514
+ <div class="form-group">
515
+ <label for="contenu_texte">Contenu du Texte</label>
516
+ <textarea id="contenu_texte" name="contenu_texte" class="form-control" rows="5" required></textarea>
517
+ </div>
518
+ <div class="form-group">
519
+ <label for="sous_categorie_id">Sous-Catégorie</label>
520
+ <select id="sous_categorie_id" name="sous_categorie_id" class="form-control" required>
521
+ <option value="" disabled selected>Choisir une sous-catégorie...</option>
522
+ {% for sous_categorie in sous_categories %}
523
+ <option value="{{ sous_categorie.id }}">{{ sous_categorie.nom }} ({{ sous_categorie.matiere.nom }})</option>
524
+ {% endfor %}
525
+ </select>
526
+ </div>
527
+ <button type="submit" class="btn btn-primary btn-icon">
528
+ <i class="fas fa-plus"></i> Ajouter Texte Manuel
529
+ </button>
530
+ </form>
531
+ </div>
532
+
533
+ <!-- Onglet Génération IA -->
534
+ <div class="tab-pane fade" id="ia-input" role="tabpanel" aria-labelledby="ia-tab">
535
+ <form id="ia-generation-form"> <!-- Pas de method="post" ici, géré par AJAX -->
536
+ <input type="hidden" name="action" value="generate_ia_content"> <!-- Gardé pour info, mais pas soumis classiquement -->
537
+ <div class="form-group">
538
+ <label for="ia_titre_texte">Titre du Texte (pour référence)</label>
539
+ <input type="text" id="ia_titre_texte" name="ia_titre_texte" class="form-control" required>
540
+ </div>
541
+ <div class="form-group">
542
+ <label for="youtube_url">URL de la vidéo YouTube</label>
543
+ <input type="url" id="youtube_url" name="youtube_url" class="form-control" placeholder="https://www.youtube.com/watch?v=..." required>
544
+ </div>
545
+ <div class="form-group">
546
+ <label for="ia_prompt">Instruction pour l'IA (Prompt)</label>
547
+ <textarea id="ia_prompt" name="ia_prompt" class="form-control" rows="3" placeholder="Ex: Faire un résumé détaillé de cette vidéo avec les points clés et des exemples." required></textarea>
548
+ </div>
549
+ <div class="form-group">
550
+ <label for="ia_model">Modèle Gemini</label>
551
+ <select id="ia_model" name="ia_model" class="form-control">
552
+ <option value="gemini-2.5-pro-exp-03-25">gemini-2.5-pro-exp-03-25</option>
553
+ <option value="gemini-2.0-flash">gemini-2.0-flash</option>
554
+ <!-- Ajouter d'autres modèles si disponibles/pertinents -->
555
+ </select>
556
+ </div>
557
+ <div class="form-group">
558
+ <label for="ia_sous_categorie_id">Sous-Catégorie (pour classement)</label>
559
+ <select id="ia_sous_categorie_id" name="ia_sous_categorie_id" class="form-control" required>
560
+ <option value="" disabled selected>Choisir une sous-catégorie...</option>
561
+ {% for sous_categorie in sous_categories %}
562
+ <option value="{{ sous_categorie.id }}">{{ sous_categorie.nom }} ({{ sous_categorie.matiere.nom }})</option>
563
+ {% endfor %}
564
+ </select>
565
+ </div>
566
+ <button type="submit" id="generate-content-btn" class="btn btn-info btn-icon">
567
+ <i class="fas fa-magic"></i> Générer le Contenu
568
+ </button>
569
+ <div id="ia-loading" class="mt-3 d-none">
570
+ <div class="spinner-border text-primary" role="status">
571
+ <span class="sr-only">Génération en cours...</span>
572
+ </div>
573
+ <span class="ml-2 align-middle">Analyse de la vidéo et génération en cours, veuillez patienter...</span>
574
+ </div>
575
+ <!-- Zone pour afficher les erreurs AJAX -->
576
+ <div id="ia-error-container" class="mt-3 alert alert-danger d-none" role="alert"></div>
577
+ <!-- Zone pour afficher le résultat -->
578
+ <div id="ia-result-container" class="mt-3 d-none">
579
+ <div class="form-group">
580
+ <label for="ia_generated_content"><strong>Contenu Généré</strong></label>
581
+ <textarea id="ia_generated_content" name="ia_generated_content" class="form-control" rows="10" readonly></textarea>
582
+ </div>
583
+ <button type="button" id="use-content-btn" class="btn btn-success btn-icon">
584
+ <i class="fas fa-check"></i> Utiliser ce Contenu
585
+ </button>
586
+ <button type="button" id="modify-content-btn" class="btn btn-warning btn-icon ml-2">
587
+ <i class="fas fa-edit"></i> Modifier avant Utilisation
588
+ </button>
589
+ </div>
590
+ </form>
591
+ <!-- Formulaire caché pour soumettre le texte généré/finalisé -->
592
+ <form method="post" id="submit-ia-content-form" class="d-none">
593
+ <input type="hidden" name="action" value="add_texte">
594
+ <input type="hidden" id="final_titre_texte" name="titre_texte">
595
+ <input type="hidden" id="final_contenu_texte" name="contenu_texte">
596
+ <input type="hidden" id="final_sous_categorie_id" name="sous_categorie_id">
597
+ </form>
598
+ </div>
599
+ </div>
600
+ </div>
601
  </div>
 
 
 
 
 
 
602
  </div>
603
+ </div>
604
+ </div><!-- Fin Onglet Ajouter -->
 
 
 
 
 
 
 
 
 
 
605
 
606
+ </div> <!-- Fin tab-content -->
607
+ </div> <!-- Fin container -->
608
 
609
  <!-- Scripts -->
610
+ <!-- jQuery with SRI -->
611
+ <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
612
+ <!-- Popper.js with SRI -->
613
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
614
+ <!-- Bootstrap JS with SRI -->
615
+ <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
616
+
617
  <script>
618
  $(document).ready(function() {
619
+
620
+ // --- Gestion Générale UI ---
621
+
622
+ // Initialiser les tooltips si vous en ajoutez
623
+ // $('[data-toggle="tooltip"]').tooltip();
624
+
625
+ // Faire disparaître les messages flash après un délai
626
+ $('#flash-message-container .alert').delay(5000).fadeOut(1000);
627
+
628
+ // --- Gestion Édition Inline ---
629
+
630
+ // Clic sur le bouton "Modifier"
631
  $(document).on('click', '.edit-button', function(e) {
632
  e.preventDefault();
633
+ const listItem = $(this).closest('.list-group-item');
634
+ // Cache tous les autres formulaires d'édition ouverts dans la même liste
635
+ listItem.siblings().find('.editable').slideUp();
636
+ listItem.siblings().find('.display-mode, .action-buttons').show();
637
+ // Affiche le formulaire d'édition pour cet item
638
  listItem.find('.editable').slideDown();
639
+ listItem.find('.display-mode, .action-buttons').hide();
640
+ // Focus sur le premier input du formulaire éditable
641
+ listItem.find('.editable').find('input[type="text"], textarea').first().focus();
642
  });
643
 
644
+ // Clic sur le bouton "Annuler" dans un formulaire d'édition
645
  $(document).on('click', '.cancel-edit', function(e) {
646
  e.preventDefault();
647
+ const listItem = $(this).closest('.list-group-item');
648
  listItem.find('.editable').slideUp();
649
+ listItem.find('.display-mode, .action-buttons').show();
650
+ // Optionnel: Réinitialiser les valeurs du formulaire aux valeurs d'origine si nécessaire
651
+ // (nécessiterait de stocker les valeurs initiales ou de ne pas soumettre le formulaire)
652
  });
653
 
654
+ // --- Gestion Suppression ---
 
655
 
656
+ // Intercepter la soumission des formulaires de suppression pour confirmation
657
+ $(document).on('submit', 'form.delete-form', function(e) {
658
+ const actionInput = $(this).find('input[name="action"]');
659
+ // Vérifier si c'est bien une action de suppression
660
+ if (actionInput.length > 0 && actionInput.val().startsWith('delete_')) {
661
+ // Utiliser une boîte de dialogue de confirmation
662
+ if (!confirm('Êtes-vous sûr de vouloir supprimer cet élément ? Cette action est irréversible.')) {
663
+ e.preventDefault(); // Annuler la soumission si l'utilisateur clique sur "Annuler"
664
  }
665
+ // Si l'utilisateur confirme, le formulaire est soumis normalement
666
  }
667
  });
668
+
669
+
670
+ // --- Gestion Génération IA ---
671
+
672
+ $('#ia-generation-form').on('submit', function(e) {
673
+ e.preventDefault(); // Empêche la soumission classique du formulaire
674
+
675
+ const generateBtn = $('#generate-content-btn');
676
+ const loadingIndicator = $('#ia-loading');
677
+ const resultContainer = $('#ia-result-container');
678
+ const errorContainer = $('#ia-error-container');
679
+ const generatedContentTextarea = $('#ia_generated_content');
680
+
681
+ const youtubeUrl = $('#youtube_url').val().trim();
682
+ const prompt = $('#ia_prompt').val().trim();
683
+ const model = $('#ia_model').val();
684
+ const title = $('#ia_titre_texte').val().trim();
685
+ const category = $('#ia_sous_categorie_id').val();
686
+
687
+ // Validation simple côté client
688
+ if (!youtubeUrl || !prompt || !title || !category) {
689
+ errorContainer.text('Veuillez remplir tous les champs requis pour la génération IA.').removeClass('d-none');
690
+ return;
691
+ }
692
+ // Validation basique de l'URL YouTube
693
+ const youtubeRegex = /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+$/;
694
+ if (!youtubeRegex.test(youtubeUrl)) {
695
+ errorContainer.text('Veuillez entrer une URL YouTube valide.').removeClass('d-none');
696
+ return;
697
+ }
698
+
699
+
700
+ // Réinitialiser l'état UI
701
+ generateBtn.prop('disabled', true).find('i').removeClass('fa-magic').addClass('fa-spinner fa-spin');
702
+ loadingIndicator.removeClass('d-none');
703
+ resultContainer.addClass('d-none');
704
+ errorContainer.addClass('d-none').text('');
705
+ generatedContentTextarea.val('');
706
+
707
+ // Appel AJAX vers le backend Flask
708
+ $.ajax({
709
+ url: '/generate-content', // L'URL de votre route Flask pour la génération
710
+ type: 'POST',
711
+ contentType: 'application/json', // Important pour envoyer du JSON
712
+ data: JSON.stringify({ // Convertir les données JS en chaîne JSON
713
+ youtube_url: youtubeUrl,
714
+ prompt: prompt,
715
+ model: model
716
+ // Note: titre et catégorie ne sont pas envoyés pour génération, mais utilisés après
717
+ }),
718
+ success: function(response) {
719
+ if (response.success && response.text) {
720
+ generatedContentTextarea.val(response.text.trim()); // Afficher le texte reçu
721
+ resultContainer.removeClass('d-none'); // Afficher la zone de résultat
722
+ } else {
723
+ // Gérer les erreurs renvoyées par le backend (même si status 200)
724
+ const errorMessage = response.error || 'Une erreur inconnue est survenue lors de la génération.';
725
+ errorContainer.text('Erreur : ' + errorMessage).removeClass('d-none');
726
+ }
727
+ },
728
+ error: function(xhr, status, error) {
729
+ // Gérer les erreurs de communication réseau ou serveur (status != 2xx)
730
+ let errorMessage = 'Erreur lors de la communication avec le serveur. ';
731
+ if (xhr.responseJSON && xhr.responseJSON.error) {
732
+ errorMessage += xhr.responseJSON.error;
733
+ } else if (xhr.responseText) {
734
+ // Essayer d'afficher une partie de la réponse texte si JSON échoue
735
+ errorMessage += `(${xhr.status}: ${error}). Réponse: ${xhr.responseText.substring(0, 100)}...`;
736
+ } else {
737
+ errorMessage += `(${xhr.status}: ${error})`;
738
+ }
739
+ errorContainer.text(errorMessage).removeClass('d-none');
740
+ },
741
+ complete: function() {
742
+ // Quoi qu'il arrive (succès ou erreur), réactiver le bouton et cacher le spinner
743
+ generateBtn.prop('disabled', false).find('i').removeClass('fa-spinner fa-spin').addClass('fa-magic');
744
+ loadingIndicator.addClass('d-none');
745
+ }
746
+ });
747
+ });
748
+
749
+ // Bouton "Utiliser ce Contenu" (après génération IA)
750
+ $('#use-content-btn').on('click', function() {
751
+ const titre = $('#ia_titre_texte').val().trim();
752
+ const contenu = $('#ia_generated_content').val().trim();
753
+ const sousCategorieId = $('#ia_sous_categorie_id').val();
754
+
755
+ if (!titre || !contenu || !sousCategorieId) {
756
+ alert("Impossible d'utiliser le contenu : des informations (titre, contenu généré ou catégorie) sont manquantes.");
757
+ return;
758
  }
759
+
760
+ // Remplir le formulaire caché et le soumettre pour ajout
761
+ $('#final_titre_texte').val(titre);
762
+ $('#final_contenu_texte').val(contenu);
763
+ $('#final_sous_categorie_id').val(sousCategorieId);
764
+ $('#submit-ia-content-form').submit();
765
+ });
766
+
767
+ // Bouton "Modifier avant Utilisation" (après génération IA)
768
+ $('#modify-content-btn').on('click', function() {
769
+ const titre = $('#ia_titre_texte').val().trim();
770
+ const contenu = $('#ia_generated_content').val().trim();
771
+ const sousCategorieId = $('#ia_sous_categorie_id').val();
772
+
773
+ // Pré-remplir les champs du formulaire manuel
774
+ $('#titre_texte').val(titre);
775
+ $('#contenu_texte').val(contenu);
776
+ $('#sous_categorie_id').val(sousCategorieId);
777
+
778
+ // Basculer vers l'onglet de saisie manuelle
779
+ $('#manual-tab').tab('show'); // Utiliser Bootstrap pour changer d'onglet
780
+
781
+ // Optionnel: Faire défiler la page jusqu'au formulaire manuel
782
+ $('html, body').animate({
783
+ scrollTop: $("#manual-add-text-form").offset().top - 20 // -20 pour un peu d'espace au dessus
784
+ }, 500);
785
+
786
+ // Cacher la zone de résultat IA pour éviter la confusion
787
+ $('#ia-result-container').addClass('d-none');
788
+ });
789
+
790
+ }); // Fin $(document).ready
 
 
 
 
 
791
  </script>
792
  </body>
793
  </html>