From 0c9b466d42b4318dd476f79dbdd924e5532c22fe Mon Sep 17 00:00:00 2001 From: scayac Date: Mon, 16 Jun 2025 22:38:40 +0200 Subject: [PATCH] Modif CSS PDF --- README.md | 1 + docker-compose.yml | 0 main/openaiApprecioations copy.py | 129 --------------------- main/templates/export_pdf.js | 38 ------ main/templates/generation.html | 90 +++++++++++++- main/templates/resultat_appreciations.html | 76 ++++++++---- 6 files changed, 138 insertions(+), 196 deletions(-) create mode 100644 docker-compose.yml delete mode 100644 main/openaiApprecioations copy.py delete mode 100644 main/templates/export_pdf.js diff --git a/README.md b/README.md index c0dd61c..7ec43f9 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ IAProf 5. Appliquez les migrations : ``` + python manage.py makemigrations main python manage.py migrate ``` diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e69de29 diff --git a/main/openaiApprecioations copy.py b/main/openaiApprecioations copy.py deleted file mode 100644 index 2d4ab06..0000000 --- a/main/openaiApprecioations copy.py +++ /dev/null @@ -1,129 +0,0 @@ -from openai import OpenAI -from PyPDF2 import PdfReader -from django.conf import settings - -liste_eleves = {} -client = OpenAI(api_key=settings.OPENAI_API_KEY) - -def split_by_eleve(text): - """ - Découpe le texte en une liste de chaînes, chaque élément commençant par 'ELEVE'. - """ - import re - # On split sur chaque occurrence de 'ELEVE' suivie d'un ou plusieurs chiffres - parts = re.split(r'(ELEVE\d+)', text) - result = [] - for i in range(1, len(parts), 2): - # parts[i] est 'ELEVEid', parts[i+1] est le texte associé - bloc = parts[i] + parts[i+1] if i+1 < len(parts) else parts[i] - result.append(bloc.strip()) - return result - -def anonymiserPdf(file, eleves): - eleve_id = 1 - pages_content = "" - - for page in file.pages: - lines = page.extract_text().split('\n') - curent_page = [] - write = False - eleve_found = False - - for i, line in enumerate(lines): - # Attendre la ligne qui se termine par " Trimestre" - if not write: - if line.strip().endswith("Trimestre"): - write = True - continue - - # Enregistrer la ligne suivante (nom de l'élève) - if write and not eleve_found: - eleve_nom = line.strip() - if eleve_nom not in eleves: - eleves[eleve_nom] = f"ELEVE{eleve_id}" - eleve_id += 1 - curent_page.append(eleves[eleve_nom] + "\n") - eleve_found = True - continue - - # Attendre la ligne qui commence par "Appréciations" - if eleve_found: - if line.strip().startswith("Appréciations"): - # Commencer à écrire les lignes suivantes - for l in lines[i+1:]: - if l.startswith("M.") or l.startswith("Mme"): - continue - curent_page.append(l + "\n") - break # Fin du traitement de cette page - - pages_content += "".join(curent_page) - return pages_content - -def get_eleve_name(text, eleves): - """ - Extrait le nom de l'élève à partir du texte. - """ - for line in text.split('\n'): - line = line.strip() - if line in eleves: - return eleves[line] - return None - -def replace_eleve_ids_with_names(text, eleves): - # Inverse the eleves dict to map ELEVEid -> nom prénom - id_to_name = {v: k for k, v in eleves.items()} - # Trier les IDs par longueur décroissante pour éviter les remplacements partiels - for eleve_id in sorted(id_to_name.keys(), key=len, reverse=True): - nom = id_to_name[eleve_id] - if eleve_id in text: - text = text.replace(eleve_id, nom) - return text - -def generatationAppreciations(appreciations_path, modele_path=None): - - if (modele_path): - modele = PdfReader(modele_path) - modele_anonyme = anonymiserPdf(modele, liste_eleves) - - appreciations = PdfReader(appreciations_path) - appreciation_anonyme = anonymiserPdf(appreciations, liste_eleves) - tableau_appreciations = split_by_eleve(appreciation_anonyme) - - responses = [] - #debug - tableau_appreciations = tableau_appreciations[:3] - for eleve in tableau_appreciations: - if modele_path: - # Si un modèle est fourni, on utilise le modèle pour chaque élève - data = [ - { - "role": "developer", - "content": "Tu dois générer des appréciations générales de bulletins avec le style de l'exemple suivant (500 caractères max)" - },{ - "role": "assistant", - "content": modele_anonyme - }, - { - "role": "user", - "content": eleve - }] - else: - data = [ - { - "role": "developer", - "content": "Tu dois générer des appréciations générales de bulletins (500 caractères max)" - }, - { - "role": "user", - "content": eleve - }] - completion = client.chat.completions.create( - model="gpt-4.1-mini", - messages=data, - temperature=1, - top_p=1) - resultat = "" + get_eleve_name(completion.choices[0].message.content, liste_eleves) + "\n" - resultat += replace_eleve_ids_with_names(completion.choices[0].message.content, liste_eleves) - responses.append(resultat) - - return responses diff --git a/main/templates/export_pdf.js b/main/templates/export_pdf.js deleted file mode 100644 index 1a31bc9..0000000 --- a/main/templates/export_pdf.js +++ /dev/null @@ -1,38 +0,0 @@ -// CDN jsPDF + autoTable pour export PDF -document.addEventListener('DOMContentLoaded', function() { - if (!window.jspdfLoaded) { - const script1 = document.createElement('script'); - script1.src = 'https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js'; - script1.onload = function() { - const script2 = document.createElement('script'); - script2.src = 'https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.8.2/jspdf.plugin.autotable.min.js'; - script2.onload = function() { window.jspdfLoaded = true; }; - document.body.appendChild(script2); - }; - document.body.appendChild(script1); - } -}); - -function exportTableToPDF() { - if (!window.jspdfLoaded) { - alert('Les librairies PDF ne sont pas encore chargées. Veuillez réessayer dans quelques secondes.'); - return; - } - const { jsPDF } = window.jspdf; - const doc = new jsPDF(); - doc.text('Tableau des appréciations', 14, 14); - const table = document.getElementById('appreciations-table'); - const rows = Array.from(table.querySelectorAll('tbody tr')) - .map(tr => [ - tr.querySelector('.eleve')?.textContent.trim() || '', - tr.querySelector('.appreciation')?.textContent.trim() || '' - ]); - doc.autoTable({ - head: [['Élève', 'Appréciation']], - body: rows, - startY: 20, - styles: { fontSize: 10, cellWidth: 'wrap' }, - headStyles: { fillColor: [55, 90, 127] } - }); - doc.save('appreciations.pdf'); -} diff --git a/main/templates/generation.html b/main/templates/generation.html index 43a20ce..3c977b4 100644 --- a/main/templates/generation.html +++ b/main/templates/generation.html @@ -60,11 +60,77 @@ [class*="bg-"] { background-color: inherit !important; } - /* Forcer le texte noir sur fond blanc pour le modal */ - #processingModal .modal-content, #processingModal .modal-header, #processingModal .modal-body, #processingModal p { + #processingModal .modal-content, #processingModal .modal-header, #processingModal .modal-body, #processingModal p, #processingModal .modal-body * { background-color: #fff !important; color: #212529 !important; } + @media (prefers-color-scheme: dark) { + #processingModal .modal-content, #processingModal .modal-header, #processingModal .modal-body, #processingModal p, #processingModal .modal-body * { + background-color: #fff !important; + color: #212529 !important; + } + } + #btn-aide { + background-color: #ffe082 !important; + color: #23272b !important; + border: 1px solid #444c56 !important; + font-weight: 600; + } + @media (prefers-color-scheme: dark) { + #btn-aide { + background-color: #ffe082 !important; + color: #23272b !important; + border: 1px solid #444c56 !important; + font-weight: 600; + } + } + } + #aideModal .modal-content, #aideModal .modal-header, #aideModal .modal-body, #aideModal p, #aideModal .modal-body * { + background-color: #fff !important; + color: #212529 !important; + } + @media (prefers-color-scheme: dark) { + #aideModal .modal-content, #aideModal .modal-header, #aideModal .modal-body, #aideModal p, #aideModal .modal-body * { + background-color: #fff !important; + color: #212529 !important; + } + } + html, body { + height: 100%; + margin: 0; + padding: 0; + overflow: hidden; + } + body { + min-height: 100vh; + overflow: hidden; + } + #layoutSidenav { + min-height: 0; + height: 100%; + overflow: hidden; + } + #layoutSidenav_content { + min-height: 0; + height: 100%; + overflow: hidden; + } + main { + min-height: 0; + height: 100%; + overflow: hidden; + } + .container-fluid { + min-height: 0; + overflow: hidden; + } + .card.shadow.mb-4 { + min-height: 0; + overflow: hidden; + } + .card-body { + min-height: 0; + overflow: hidden; } @@ -83,8 +149,25 @@
-
+

Choix du fichier de bulletins à traiter :

+ +
+
{% if success %} @@ -132,5 +215,4 @@ }); - \ No newline at end of file diff --git a/main/templates/resultat_appreciations.html b/main/templates/resultat_appreciations.html index 26860e9..633c102 100644 --- a/main/templates/resultat_appreciations.html +++ b/main/templates/resultat_appreciations.html @@ -70,7 +70,7 @@ body, .bg-light { border: 1px solid #444c56 !important; } } - +
- +
@@ -235,28 +284,5 @@ document.addEventListener('DOMContentLoaded', function() {
- - -