6 changed files with 138 additions and 196 deletions
@ -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 = "<b><u><i>" + get_eleve_name(completion.choices[0].message.content, liste_eleves) + "</i></u></b>\n" |
|
||||||
resultat += replace_eleve_ids_with_names(completion.choices[0].message.content, liste_eleves) |
|
||||||
responses.append(resultat) |
|
||||||
|
|
||||||
return responses |
|
||||||
@ -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'); |
|
||||||
} |
|
||||||
Loading…
Reference in new issue