298 lines
11 KiB
Org Mode
298 lines
11 KiB
Org Mode
#+title: Script
|
|
#+author: Sébastien Miquel
|
|
#+date: 14-03-2026
|
|
# Time-stamp: <06-06-26 16:23>
|
|
#+OPTIONS:
|
|
|
|
* Méta
|
|
** Quézaco
|
|
|
|
Ce dépôt contient un certain nombre de script Python que j'utilise
|
|
pour faire corriger des copies par Gemini.
|
|
|
|
1. Les copies sont découpées suivant les labels des questions.
|
|
2. Des requêtes de correction sont faites à Gemini, qui met une note
|
|
entre 0 et 4 à la question, ajoute des commentaires, et encadre
|
|
certaines parties de la réponse.
|
|
3. Une version pdf annotée de la copie est générée, faite pour être
|
|
éditée sur tablette tactile. Le correcteur humain peut modifier la
|
|
note, supprimer des commentaires de l'IA, ou ajouter des remarques
|
|
manuscrites.
|
|
4. Ces annotations manuscrites sont lues et recompilées en une
|
|
version de la copie pour l'élève.
|
|
|
|
** Disclaimer
|
|
|
|
J'utilise régulièrement cet outil et j'en suis satisfait, mais j'ai
|
|
fait peu d'efforts pour le rendre universel et simple à l'emploi.
|
|
Plusieurs parties de mon workflow sont spécifiques à mes
|
|
représentations internes des sujets d'examens et/ou à mon environment.
|
|
|
|
L'utilisation de ce système nécessite une familiarité avec python et
|
|
la ligne de commande unix ; cette familiarité n'est probablement pas
|
|
suffisante en l'état, mais en théorie il devrait être possible de le
|
|
faire tourner sur le dossier =Example= qui contient une copie
|
|
initiale, les fichiers correspondant au sujet de l'interro, et des
|
|
examples du rendu final (dans le sous dossier =BGnot=).
|
|
|
|
Cette situation s'améliorera peut-être, mais faciliter l'utilisation
|
|
de ce système n'est pas une priorité.
|
|
|
|
** Requirements
|
|
|
|
*** Python
|
|
|
|
Libraries :
|
|
|
|
#+BEGIN_SRC bash
|
|
pip install numpy pandas matplotlib pillow pydantic pypdf pdf2image reportlab img2pdf pymupdf ftfy ezodf google
|
|
#+END_SRC
|
|
|
|
*** Poppler (for pdf2image)
|
|
|
|
+ Linux : install poppler-utils
|
|
+ Windows : Download from: https://github.com/oschwartz10612/poppler-windows
|
|
and add it to your PATH
|
|
|
|
*** Accès à Gemini
|
|
|
|
Il faut créer une clef API pour Gemini (pas facile).
|
|
|
|
NB : Lors de la création, google offre (offrait ?) 300€ d'utilisation,
|
|
mais seulement pendant les trois mois à venir.
|
|
|
|
Puis ajouter =GEMINI_API_KEY= à l'environnement avec :
|
|
|
|
#+BEGIN_SRC bash
|
|
export GEMINI_API_KEY=…
|
|
#+END_SRC
|
|
|
|
** Correction d'un paquet de copies
|
|
|
|
1. Créer un fichier =names= dans le dossier courant, avec les
|
|
noms/prénoms des élèves, un par ligne
|
|
2. Créer un dossier correspondant à l'évaluation, comme =Interro=
|
|
3. Mettre les fichiers pdfs scannés dans =Interro=.
|
|
4. Dans le dossier =Interro= créer un fichier =labels= avec les labels
|
|
des questions, comme =Ex 1 : 1)a)=, un par ligne.
|
|
5. Il faudra créer des dossiers =Text=, =Sol= et =Persp=, et dans ces
|
|
dossiers créer, pour chaque label (ou groupe de labels : par
|
|
exemple un seul fichier =Ex 1= peut être utilisé pour toutes les
|
|
questions de l'exercice 1) un fichier texte qui contient
|
|
respectivement l'énoncé, un corrigé, et des indications de comment
|
|
corriger (Gemini met une note sur 4, on peut demander 2 points
|
|
pour tel truc, etc)
|
|
6. Suivre les étapes plus bas.
|
|
|
|
* Étapes et Script
|
|
** Prétraitement de l'énoncé
|
|
|
|
- Dans le dossier de l'évaluation, mettre : + `enonce.pdf`
|
|
+ `enonce.tex` + `correction.tex`.
|
|
- `python gemini_for_enonce.py Interro`
|
|
Se charge de créer des dossiers `Text` et `Sol` avec
|
|
+ Le fichier `Text` contient
|
|
|
|
** Prétraitement des copies
|
|
|
|
1. =./rotate_all.sh Interro=
|
|
(facultatif)
|
|
Retourne toutes les pdf de 180°
|
|
2. =./rename_to_copie.sh Interro=
|
|
change le nom des copies en =Copie{id}.pdf=
|
|
3. =python page_splitter.py Interro=
|
|
|
|
Découpe des copies A3 en pages A4, en retirant les pages vides. + s pour garder les deux pages
|
|
+ t/n pour garder celle de gauche/de droite + r pour jeter les deux pages
|
|
|
|
Les key bindings ne sont pas adaptés à un clavier azerty… À changer…
|
|
|
|
Fix issues with =python page_splitter.py Interro14/Copies/Copie01.pdf=
|
|
4. =python cutleft.py Interro=
|
|
|
|
Découpe la partie gauche des copies, là où il devrait y avoir les
|
|
labels des exercices/questions.
|
|
|
|
Rerun on a single file with =python cutleft.py Interro/Copies/Copie01.pdf=
|
|
|
|
** Génération d'information sur l'énoncé
|
|
|
|
1. =python enonce_info.py Interro= (gestion perso)
|
|
OU
|
|
2. =python gemini_for_enonce.py Interro=
|
|
+ Nécessite =enonce.tex/org= et `correction.tex/org`
|
|
|
|
** Labelisation et regroupement
|
|
|
|
Set proxy with ~export HTTPS_PROXY="http://10.0.0.1:3128"~
|
|
|
|
1. =python gemini_for_labels.py Interro=, avec éventuellement =--overwrite=
|
|
|
|
Fait des requêtes à Gemini pour identifier les labels des
|
|
questions dans images générées à partir des parties gauches des copies.
|
|
2. =python plotting.py Interro=
|
|
|
|
Permet de vérifier visuellement les labels trouvés. + Sous linux, on peut faire =e= pour ouvrir le fichier .json et
|
|
l'éditer a la main.
|
|
+ Quand un label est manquant, il est possible de cliquer sur
|
|
l'image, ce qui copie les coordonnées dans le presse papier
|
|
(sous linux…), puis on peut l'ajouter à la main. + Utilisation de `_`, `|…` et `…|` :
|
|
+ `|…` n'est pas arrêté verticalement par son type opposé. + `…|` est stoppé horizontalement par le `|…` le plus proche.
|
|
Pour modifier une seule copie :
|
|
=python plotting.py Interro/Copies/Copie01.pdf=
|
|
|
|
It also generates les =Copie01.json=, à partir des =Copie01_01.json=
|
|
1. En cas de soucis, (par exemple les pages ne sont pas dans le bon ordre)
|
|
- Réordonner les pages du fichier pdf
|
|
- Rerun =python cutleft.py Interro/Copie{id}=
|
|
- Rerun =python gemini_dir_batching.py Interro/Copie{id}= ?? À
|
|
vérifier, pas sûr que ça marche.
|
|
3. =python splitting_int.py Interro=
|
|
|
|
Découpe les copies suivant les exercices
|
|
Peut-être appelé avec une seule copie.
|
|
4. =python grouping.py Interro=
|
|
|
|
Regroupe les mêmes questions de différentes copies en groupes de
|
|
tailles raisonnables.
|
|
|
|
** Correction et annotation
|
|
|
|
Set proxy with ~export HTTPS_PROXY="http://10.0.0.1:3128"~
|
|
|
|
1. Il faut créer des persp, pour indication de comment corriger, et
|
|
relancer =enonce_info.py=
|
|
2. =python correction.py Interro --limit 240= OU
|
|
=python correction.py Interro/Par\ label/Ex\ 2/Group_1.jpg= OU
|
|
=python correction.py Interro --overwrite=
|
|
=python correction.py Interro --pro-by-label= (needs `labels_for_pro`)
|
|
|
|
Fais les requêtes de correction à Gemini.
|
|
|
|
L'argument =limit= limite le nombre de requêtes à Gemini Pro
|
|
(chères), pour une version low cost, passer =--limit 0=, toutes
|
|
les requêtes seront sur Gemini Flash.
|
|
|
|
Will it resume ? It seems so. Best to wait a bit.
|
|
|
|
Pour diminuer le coût, il est possible de batch les requêtes, qui
|
|
seront alors traitées sous au plus 24h.
|
|
+ =python correction.py Interro --batch= + OU =python correction.py Interro --batch-from 'Ex 4'=
|
|
+ =python submit_batches.py Interro= + =python batch_status.py=
|
|
+ =python fetch_batched_results.py Interro= + =python correction.py Interro --deal-with-batched=
|
|
3. =python post-correction.py Interro=
|
|
|
|
- Essaye de corriger des erreurs d'encodage/d'accents dans
|
|
=correction.json=.
|
|
- aussi échappe les `_` en dehors du mode math, pour LaTeX.
|
|
|
|
** Génération des copies annotées
|
|
|
|
1. =python annotating.py Interro= (facultatif)
|
|
|
|
Ajoute les annotations Gemini aux copies, enregistrées dans le dossier =Anot=.
|
|
On peut passer l'argument =--overwrite=.
|
|
|
|
2. =python annotating_with_checks.py Interro=
|
|
|
|
Ajoute les annotations Gemini, et des checkboxes à cocher.
|
|
Enregistrées dans le dossier =Bnot=,
|
|
=--overwrite=
|
|
OU
|
|
2. =python annotating_by_label.py Interro= dans =BGnot=
|
|
|
|
Ajoute les annotations Gemini, et des checkboxes, et regroupe les
|
|
réponses par question.
|
|
Enregistrées dans =BGnot=
|
|
|
|
_Needs_ : label_groups file (made automatically by this function),
|
|
qui dit quelles questions regrouper.
|
|
|
|
|
|
3. =python to_tablette.py Interro= (gestion perso)
|
|
Cela déplace les groupes dans =SyncCopies/À Annoter=.
|
|
- Les mettre dans le dossier racine de la tablette, et renommer en =aaa=.
|
|
- Vider =Syncthing/Annotées= sur la tablette et localement.
|
|
À automatiser, aussi c'est lent…
|
|
|
|
** Lecture de la correction manuscrite
|
|
|
|
1. =python from_tablette.py Interro= (gestion perso)
|
|
|
|
_Before_ : delete =~/SyncCopies/Annotées=, copy or sync from the
|
|
tablette to here.
|
|
|
|
Une fois les corrections manuelles appliquées aux fichiers
|
|
=Concat.pdf=, il faut enregistrer le fichier annoté au même endroit,
|
|
sous le nom =Concat_annotated.pdf=.
|
|
|
|
(À faire : universaliser =to_tablette.py= et =from_tablette.py=)
|
|
|
|
2. =python reading_annotations.py Interro=
|
|
|
|
Lit les =Concat_annotated= dans =Bnot=, regénère les copies avec
|
|
les modifications.
|
|
OU
|
|
2. =python reading_grouped_annotations.py Interro=
|
|
|
|
Idem, mais pour =BGnot=.
|
|
|
|
3. =python giving_names.py Interro BGnot=
|
|
|
|
Crée un dossier =A Rendre= avec des liens symboliques vers
|
|
+ La copie à rendre + un fichier =score.json= qui contient les notes par question
|
|
|
|
Si un nom est =Unknown= : renommer à la main le dossier et le fichier dedans.
|
|
|
|
4. On peut faire des changements manuels aux =score.json= ici, puis
|
|
- `python reading_annotations.py --update-score Interro`
|
|
- `python reading_grouped_annotations.py --update-score Interro`
|
|
pour mettre à jour les scores dans les images.
|
|
4. (gestion perso)
|
|
+ =gestion_classe ne= pour créer l'interro puis + =gestion_classe we= (set barème here)
|
|
+ =python update_ods.py Interro=
|
|
ou =python update_ods.py Interro --sum= (en l'absence de barème) + =gestion_classe re=
|
|
+ =gestion_classe wsent= + =python add_final_score.py Interro21=
|
|
(this makes files in =Server/copies=)
|
|
5. (gestion perso)
|
|
+ Deploy =miqmacs-copies-assets=, and + update the copies from =miqmacs.fr/admin=.
|
|
6. (gestion perso) Impression d'une copie. Via Evince » print to pdf.
|
|
|
|
** Recorrection d'une seule copie (peu testé)
|
|
|
|
!! Attention, refaire ne marchera pas si tu fais une annotation non
|
|
groupée into refaire !!
|
|
|
|
1. Redécoupage
|
|
+ =python plotting.py InterroTest/Copie01.pdf=
|
|
+ =python splitting_int.py InterroTest/Copie20.pdf=
|
|
2. Créer =refaire.json=, avec un contenu comme
|
|
: [["Copie01", []],
|
|
: ["Copie01", ["Ex 1 : 1)"]]]
|
|
3. Appeler =correction= avec --refaire. Il doit créer des groupes
|
|
individuels, faire des requêtes, et remplacer les corrections
|
|
précédentes (à sauver ailleurs).
|
|
|
|
Ou non, si tu veux le faire à la main.
|
|
4. ?? Si je fais refaire, avant d'avoir créer les annotating with
|
|
checks, que se passe-t-il ???
|
|
5. Appeler =annotating_with_checks.py --refaire --overwrite= avec --refaire.
|
|
6. =python to_tablette.py --refaire Interro24=
|
|
6. =python from_tablette.py --refaire Interro24=
|
|
7. =python reading_grouped_annotations.py --refaire Interro24=
|