#+title:  Script
#+author: Sébastien Miquel
#+date:   14-03-2026
# Time-stamp: <01-05-26 22:19>
#+OPTIONS:

* 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`).


* 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.

* Prétraitement

 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/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/Copie01.pdf`
 5. `python enonce_info.py Interro` (gestion perso)

* Labelisation et regroupement

Set proxy with `export HTTPS_PROXY="http://192.168.241.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.

    Pour modifier une seule copie :
    `python plotting.py Interro/Copie01.pdf`

    It also generates les `Copie01.json`, à partir des `Copie01_01.json`
 3. 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.
 4. `python splitting_int.py Interro`

    Découpe les copies suivant les exercices
 5. `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/Ex\ 2/Group_1.jpg` OU
    `python correction.py Interro --overwrite`

    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`
    + `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`.

* 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 manuelle

 1. `python from_tablette.py Interro` (gestion perso)

      _Before_ : delete `~/SyncCopies/Annotées`, copy 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.

    On peut faire des changements manuels aux `score.json` ici.
 4. (gestion perso)
    + `gestion_classe ne` pour créer l'interro puis
    + `gestion_classe we` (set barème here)
    + `python update_ods.py Interro`
    + `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`.

* 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`

* Install

#+BEGIN_SRC bash
pip install highlight-text --break-system-packages
#+END_SRC
