|
|
|
|
@ -94,7 +94,7 @@ body, .bg-light {
@@ -94,7 +94,7 @@ body, .bg-light {
|
|
|
|
|
<div> |
|
|
|
|
<label for="modele-select" class="form-label">Choisir un modèle</label> |
|
|
|
|
<select id="modele-select" class="form-select"> |
|
|
|
|
{% for modele in modeles %} |
|
|
|
|
{% for modele in modeles|dictsortreversed:'id' %} |
|
|
|
|
<option value="{{ modele.code }}" {% if modele.code == 'gpt-4.1-mini' %}selected{% endif %}>{{ modele.nom }}</option> |
|
|
|
|
{% endfor %} |
|
|
|
|
{% if not modeles or not modeles|dictsort:'code'|length %} |
|
|
|
|
@ -116,21 +116,23 @@ body, .bg-light {
@@ -116,21 +116,23 @@ body, .bg-light {
|
|
|
|
|
<table class="table table-bordered" id="appreciations-table"> |
|
|
|
|
<thead> |
|
|
|
|
<tr> |
|
|
|
|
<th>Élève</th> |
|
|
|
|
<th style="width:1%; white-space:nowrap;">Élève</th> |
|
|
|
|
<th>Appréciation</th> |
|
|
|
|
<th style="width:1%; white-space:nowrap; text-align:center;">Action</th> |
|
|
|
|
</tr> |
|
|
|
|
</thead> |
|
|
|
|
<tbody> |
|
|
|
|
{% if appreciations_json and appreciations_json|length > 0 %} |
|
|
|
|
{% for appreciation in appreciations_json %} |
|
|
|
|
<tr> |
|
|
|
|
<td class="eleve">{{ appreciation.eleve }}</td> |
|
|
|
|
<td class="eleve" style="width:1%; white-space:nowrap;">{{ appreciation.eleve }}</td> |
|
|
|
|
<td class="appreciation"></td> |
|
|
|
|
<td style="width:1%; text-align:center;"><button class="btn btn-outline-primary btn-sm action-generate" type="button">Générer</button></td> |
|
|
|
|
</tr> |
|
|
|
|
{% endfor %} |
|
|
|
|
{% else %} |
|
|
|
|
<tr> |
|
|
|
|
<td colspan="2"><div class="alert alert-warning mb-0">Aucune appréciation générée.</div></td> |
|
|
|
|
<td colspan="3"><div class="alert alert-warning mb-0">Aucune appréciation générée.</div></td> |
|
|
|
|
</tr> |
|
|
|
|
{% endif %} |
|
|
|
|
</tbody> |
|
|
|
|
@ -139,6 +141,21 @@ body, .bg-light {
@@ -139,6 +141,21 @@ body, .bg-light {
|
|
|
|
|
let stopGeneration = false; |
|
|
|
|
let enCours = false; |
|
|
|
|
|
|
|
|
|
function updateActionButtons() { |
|
|
|
|
const rows = document.querySelectorAll('#appreciations-table tbody tr'); |
|
|
|
|
rows.forEach(row => { |
|
|
|
|
const appreciationCell = row.querySelector('.appreciation'); |
|
|
|
|
const btn = row.querySelector('.action-generate'); |
|
|
|
|
if (!btn) return; |
|
|
|
|
if (appreciationCell.textContent.trim()) { |
|
|
|
|
btn.textContent = 'Régénérer'; |
|
|
|
|
} else { |
|
|
|
|
btn.textContent = 'Générer'; |
|
|
|
|
} |
|
|
|
|
btn.disabled = enCours; |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function getRowsSansAppreciation() { |
|
|
|
|
return Array.from(document.querySelectorAll('#appreciations-table tbody tr')).filter(row => !row.querySelector('.appreciation').textContent.trim()); |
|
|
|
|
} |
|
|
|
|
@ -165,13 +182,16 @@ document.addEventListener('DOMContentLoaded', function() {
@@ -165,13 +182,16 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
|
|
|
|
|
function traiterLignes() { |
|
|
|
|
rows = getRowsSansAppreciation(); |
|
|
|
|
updateActionButtons(); |
|
|
|
|
if (rows.length === 0 || stopGeneration) { |
|
|
|
|
enCours = false; |
|
|
|
|
updateActionButtons(); |
|
|
|
|
if (stopGeneration) setButtonState('continuer'); |
|
|
|
|
else setButtonState('lancer'); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
enCours = true; |
|
|
|
|
updateActionButtons(); |
|
|
|
|
setButtonState('arreter'); |
|
|
|
|
const row = rows[0]; |
|
|
|
|
const eleve = row.querySelector('.eleve').textContent; |
|
|
|
|
@ -188,6 +208,7 @@ document.addEventListener('DOMContentLoaded', function() {
@@ -188,6 +208,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
.then(response => response.json()) |
|
|
|
|
.then(data => { |
|
|
|
|
appreciationCell.textContent = data.appreciation; |
|
|
|
|
updateActionButtons(); |
|
|
|
|
if (typeof data.credit !== 'undefined') { |
|
|
|
|
creditRestant.textContent = 'Crédits restants : ' + data.credit; |
|
|
|
|
} |
|
|
|
|
@ -203,6 +224,7 @@ document.addEventListener('DOMContentLoaded', function() {
@@ -203,6 +224,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
}) |
|
|
|
|
.catch(() => { |
|
|
|
|
appreciationCell.textContent = 'Erreur lors de la génération'; |
|
|
|
|
updateActionButtons(); |
|
|
|
|
traiterLignes(); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
@ -225,7 +247,43 @@ document.addEventListener('DOMContentLoaded', function() {
@@ -225,7 +247,43 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// Action individuelle sur bouton Générer/Régénérer |
|
|
|
|
document.querySelectorAll('.action-generate').forEach(btn => { |
|
|
|
|
btn.addEventListener('click', function() { |
|
|
|
|
if (enCours) return; |
|
|
|
|
const row = btn.closest('tr'); |
|
|
|
|
const eleve = row.querySelector('.eleve').textContent; |
|
|
|
|
const appreciationCell = row.querySelector('.appreciation'); |
|
|
|
|
appreciationCell.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Génération...'; |
|
|
|
|
btn.disabled = true; |
|
|
|
|
fetch("{% url 'generer_appreciation_ajax' %}", { |
|
|
|
|
method: 'POST', |
|
|
|
|
headers: { |
|
|
|
|
'Content-Type': 'application/json', |
|
|
|
|
'X-CSRFToken': '{{ csrf_token }}' |
|
|
|
|
}, |
|
|
|
|
body: JSON.stringify({eleve: eleve, modele: selectModele.value}) |
|
|
|
|
}) |
|
|
|
|
.then(response => response.json()) |
|
|
|
|
.then(data => { |
|
|
|
|
appreciationCell.textContent = data.appreciation; |
|
|
|
|
updateActionButtons(); |
|
|
|
|
if (typeof data.credit !== 'undefined') { |
|
|
|
|
creditRestant.textContent = 'Crédits restants : ' + data.credit; |
|
|
|
|
} |
|
|
|
|
if (data.credit === 0) { |
|
|
|
|
creditAlert.classList.remove('d-none'); |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
.catch(() => { |
|
|
|
|
appreciationCell.textContent = 'Erreur lors de la génération'; |
|
|
|
|
updateActionButtons(); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
setButtonState('lancer'); |
|
|
|
|
updateActionButtons(); |
|
|
|
|
}); |
|
|
|
|
</script> |
|
|
|
|
<script> |
|
|
|
|
|