449 lines
21 KiB
Org Mode
449 lines
21 KiB
Org Mode
#+title: Référence des étapes et des scripts
|
|
#+author: Sébastien Miquel
|
|
#+date: 22-08-2026
|
|
#+OPTIONS:
|
|
|
|
Ce document décrit le workflow détaillé, les commandes disponibles et
|
|
les parcours alternatifs.
|
|
|
|
- [[file:Readme.org][Guide de démarrage]]
|
|
- [[file:Architecture.org][Architecture et conventions de développement]]
|
|
|
|
* Étapes
|
|
|
|
Utiliser `python -m copienator gui` ou `python -m copienator gui Interro` pour lancer un GUI
|
|
qui suit automatiquement les étapes décrites ci-dessous.
|
|
|
|
** Prétraitement de l'énoncé
|
|
|
|
Dans le dossier de l'évaluation, mettre les fichiers suivants de l'évaluation :
|
|
|
|
`enonce.pdf`, `enonce.tex`, `correction.tex`.
|
|
|
|
- `python -m copienator statement Interro` or
|
|
`python -m copienator statement Interro --restart`
|
|
|
|
À partir des trois fichiers précédents, se charge de détecter les
|
|
labels des questions et leur contenu.
|
|
|
|
Les questions vont également être regroupées. Par la suite, quand
|
|
des requêtes de corrections seront effectuées sur une question,
|
|
seulement les énoncés des questions du groupe seront envoyés (et le
|
|
corrigé de la question). Il faut donc que chaque groupe contienne
|
|
si possible le contexte nécessaire pour comprendre la question.
|
|
|
|
Une fenêtre s'ouvre pour permettre d'éditer le résultat. Ne pas
|
|
hésiter à faire des groupes plus gros que les groupes par défaut.
|
|
|
|
Après relecture le script génère :
|
|
|
|
+ un fichier `labels` avec les labels des questions
|
|
+ Un dossier `Text` avec le contenu textuel des questions,
|
|
regroupées.
|
|
+ Un dossier `Sol` avec le contenu textuel du corrigé, question par
|
|
question.
|
|
+ Un dossier `Text2`, qui compile un fichier `.tex` pour chaque
|
|
question (utilisé pour compiler un rendu pdf du corrigé pour
|
|
chaque question)
|
|
+ Un dossier `Sol2`, qui compile un fichier `.tex` pour chaque
|
|
correction de chaque question.
|
|
+ Un dossier `Persp` avec des instruction de barème pour chaque
|
|
question.
|
|
|
|
Éventuellement : vérifier et modifier les barèmes dans `Persp`.
|
|
|
|
- Alternative personnelle : `python -m copienator statement-personal Interro`
|
|
|
|
Ces deux commandes suivent la convention des scripts standardisés.
|
|
Leur import ne lance aucun traitement et les erreurs partielles sont
|
|
distinguées des échecs. Les réponses d'extraction mises en cache par
|
|
=copienator statement= et le fichier =labels= sont publiés
|
|
atomiquement.
|
|
|
|
** Prétraitement des copies
|
|
|
|
Mettre les copies scannées au format pdf dans =Interro=.
|
|
|
|
1. =python -m copienator copies rotate Interro= (facultatif)
|
|
|
|
Retourne tous les pdf de 180°, si la photocopie a été faite à
|
|
l'envers.
|
|
2. =python -m copienator copies rename Interro=
|
|
change le nom des copies en =Copie{id}.pdf=
|
|
3. =python -m copienator page-split Interro=
|
|
|
|
Découpe des copies A3 en pages A4, en retirant les pages vides.
|
|
|
|
Pour chaque page double il est possible
|
|
+ de garder les deux pages
|
|
+ de ne garder qu'une des deux pages.
|
|
+ de jeter les deux pages
|
|
+ de déplacer la délimitation à droite/gauche
|
|
|
|
Fix issues with =python -m copienator page-split Interro14/Copies/Copie01.pdf=
|
|
|
|
Le PDF transformé est construit dans un dossier temporaire. La
|
|
copie produite et la sauvegarde dans =Copies Originales= sont
|
|
ensuite installées avec rollback : une erreur conserve les deux
|
|
versions précédentes. Une relance ciblée lit directement la
|
|
sauvegarde originale sans la déplacer au préalable.
|
|
4. =python -m copienator crop-labels Interro=
|
|
|
|
Découpe la partie gauche des copies, là où il devrait y avoir les
|
|
labels des exercices/questions.
|
|
|
|
=python -m copienator crop-labels Interro --fullpage= to use the full page always.
|
|
|
|
Rerun on a single file with =python -m copienator crop-labels Interro/Copies/Copie01.pdf=
|
|
|
|
Les images et le fichier =_schema.json= d'une copie sont remplacés
|
|
ensemble. Fermer l'outil juste après la dernière validation ne peut
|
|
donc plus interrompre un thread de sauvegarde en arrière-plan.
|
|
|
|
** Labelisation et regroupement
|
|
|
|
Optional : Set proxy with ~export HTTPS_PROXY="http://10.0.0.1:3128"~
|
|
|
|
1. =python -m copienator labels 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.
|
|
|
|
Une copie PDF ou une image précise de =Cutleft= peut également être
|
|
ciblée. Plusieurs cibles de la même évaluation sont acceptées. Les
|
|
parties d'une copie restent traitées séquentiellement afin de
|
|
conserver les labels précédents comme contexte, tandis que les
|
|
copies différentes sont traitées en parallèle. Chaque réponse JSON
|
|
validée est écrite atomiquement. Une cible sans image correspondante
|
|
produit le code de sortie 4.
|
|
2. =python -m copienator review-labels Interro=
|
|
|
|
Permet de vérifier visuellement les labels trouvés.
|
|
+ Sous Linux et macOS, 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
|
|
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 -m copienator review-labels Interro/Copies/Copie01.pdf=
|
|
|
|
Les coordonnées agrégées sont écrites atomiquement dans le JSON de
|
|
la copie. Fermer la fenêtre avant la fin d'une copie ne remplace pas
|
|
son JSON par un résultat incomplet.
|
|
|
|
It also generates les =Copie01.json=, à partir des =Copie01_01.json=
|
|
En cas de soucis, (par exemple les pages ne sont pas dans le bon ordre)
|
|
- Réordonner les pages du fichier pdf
|
|
- Rerun =python -m copienator crop-labels Interro/Copie{id}=
|
|
- Rerun =python -m copienator labels Interro/Copie{id}=
|
|
3. =python -m copienator split-answers Interro=
|
|
|
|
Découpe les copies suivant les exercices
|
|
Peut-être appelé avec une seule copie.
|
|
|
|
Les réponses d'une copie sont préparées dans un dossier temporaire,
|
|
puis remplacent ensemble le dossier précédent. En cas d'erreur,
|
|
l'ancienne version est conservée. Les réponses devenues obsolètes
|
|
restent archivées dans le sous-dossier =Missing=.
|
|
4. =python -m copienator group-answers Interro=
|
|
|
|
Regroupe les mêmes questions de différentes copies en groupes de
|
|
tailles raisonnables.
|
|
5. Facultatif : =python -m copienator verify-groups Interro=
|
|
|
|
Vérifie que chaque réponse PDF apparaît bien dans les métadonnées
|
|
des groupes. La commande renvoie un code non nul si une réponse est
|
|
absente ou si la vérification est incomplète.
|
|
|
|
** Correction et annotation
|
|
|
|
Optional : 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 =copienator statement-personal=
|
|
2. =python -m copienator correct Interro --limit 240= OU
|
|
=python -m copienator correct Interro/Par\ label/Ex\ 2/Group_1.jpg= OU
|
|
=python -m copienator correct Interro --overwrite=
|
|
|
|
Fais les requêtes de correction à Gemini.
|
|
|
|
=copienator correct= peut être relancé sans supprimer son état. Les
|
|
fichiers =correction.json= et =correction_progress.json= sont mis à
|
|
jour atomiquement. Avec =--overwrite=, leur version précédente reste
|
|
en place jusqu'à la première écriture réussie de la nouvelle
|
|
exécution. =--reset= est la seule option qui supprime explicitement
|
|
cet état et restaure les fichiers =*_old.pdf=.
|
|
|
|
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.
|
|
|
|
Pour diminuer le coût, il est possible de batch les requêtes, qui
|
|
seront alors traitées sous au plus 24h.
|
|
+ =python -m copienator correct Interro --batch=
|
|
+ OU =python -m copienator correct Interro --batch-from 'Ex 4'=
|
|
+ =python -m copienator batch-submit Interro=
|
|
+ =python -m copienator batch-status=
|
|
+ =python -m copienator batch-fetch Interro=
|
|
+ =python -m copienator correct Interro --deal-with-batched=
|
|
|
|
Les quatre commandes de ce flux suivent la convention des scripts
|
|
standardisés. Les fichiers de requêtes et le résultat JSONL combiné
|
|
sont publiés atomiquement : une interruption ne laisse pas de fichier
|
|
final partiellement écrit. =copienator batch-submit= conserve aussi les
|
|
identifiants distants dans =batch_jobs.json= ; la récupération les
|
|
utilise en priorité et garde la recherche par nom pour les anciens
|
|
batchs. =python -m copienator batch-status --download JOB --output
|
|
resultat.jsonl= permet aussi de télécharger atomiquement le résultat
|
|
d'un job particulier.
|
|
3. =python -m copienator post-correction Interro=
|
|
|
|
- Essaye de corriger des erreurs d'encodage/d'accents dans
|
|
=correction.json=.
|
|
- aussi échappe les `_` en dehors du mode math, pour LaTeX.
|
|
4. Résolution manuel de conflits, s'il y en a.
|
|
|
|
Edit `manual_resolutions.txt`. Use :
|
|
+ `->` or `x>` : Here set a pipe `|` before or after the new_label name
|
|
+ `-x` : replace the goal
|
|
+ `ss` : do nothing
|
|
+ `sx` : stay, and remove goal.
|
|
+ `xx` : move to goal.
|
|
+ `xs` : remove old, keep goal.
|
|
|
|
Then call `python -m copienator resolve-manual Interro`
|
|
5. Call `python -m copienator correct Interro --refaire`.
|
|
|
|
|
|
** Génération des copies annotées
|
|
|
|
1. =python -m copienator annotate-simple Interro= (facultatif)
|
|
|
|
Ajoute les annotations Gemini aux copies, enregistrées dans le dossier =Anot=.
|
|
On peut passer l'argument =--overwrite=.
|
|
OU
|
|
2. =python -m copienator annotate-checks Interro=
|
|
|
|
Ajoute les annotations Gemini, et des checkboxes à cocher.
|
|
Enregistrées dans le dossier =Bnot=,
|
|
=--overwrite=
|
|
|
|
Une seule copie peut être ciblée avec, par exemple,
|
|
=python -m copienator annotate-checks Interro/Copies/Copie01.pdf=.
|
|
Le mode =--refaire= exige un fichier =refaire.json= et écrit dans
|
|
=BRnot=.
|
|
OU
|
|
2. =python -m copienator annotate-grouped 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 -m copienator export Interro BGnot= (gestion perso)
|
|
Cela déplace les groupes dans le dossier configuré par =EXPORT_DIR=
|
|
(par défaut =Export=).
|
|
|
|
Le second argument peut être =BGnot=, =Bnot= ou =Anot= et reste
|
|
facultatif (=BGnot= par défaut). =Anot= exporte =Concat.jpg= ; les
|
|
deux autres modes exportent =Concat.pdf=. Dans le GUI, seuls les
|
|
dossiers présents sont proposés et le mode de la dernière génération
|
|
d'annotations est présélectionné.
|
|
|
|
Il faut ensuite annoter les fichiers dans `EXPORT_DIR` avec une
|
|
tablette graphique.
|
|
|
|
** Lecture de la correction manuscrite
|
|
|
|
_Before_ : vider le dossier configuré par =IMPORT_DIR= (par défaut
|
|
=Import=), puis y copier ou synchroniser les fichiers depuis la tablette.
|
|
|
|
1. =python -m copienator import Interro BGnot=
|
|
|
|
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=.
|
|
|
|
Comme pour l'export, le second argument accepte =BGnot=, =Bnot= ou
|
|
=Anot=. Le GUI présélectionne le dossier utilisé lors du dernier
|
|
export. Pour =Anot=, l'image est importée sous le nom
|
|
=Concat_annotated.jpg=.
|
|
|
|
2. =python -m copienator read-annotations Interro=
|
|
|
|
Lit les =Concat_annotated= dans =Bnot=, regénère les copies avec
|
|
les modifications. Les fichiers générés (=score.json=,
|
|
=Concat.jpg=, etc.) sont préparés séparément puis installés
|
|
ensemble. Les entrées du dossier =Bnot= restent en place et une
|
|
erreur de génération conserve les anciennes sorties.
|
|
OU
|
|
2. =python -m copienator read-grouped Interro=
|
|
|
|
Idem, mais pour =BGnot=. Les tâches parallèles remontent leurs
|
|
erreurs au processus principal au lieu de les ignorer.
|
|
|
|
3. =python -m copienator giving-names 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. Éventuellement, faire des modifications manuelles aux =score.json=.
|
|
|
|
Puis
|
|
- `python -m copienator read-annotations --update-score Interro`
|
|
- `python -m copienator read-grouped --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 -m copienator update-ods Interro=
|
|
ou =python -m copienator update-ods Interro --sum= (en l'absence de barème)
|
|
+ =gestion_classe re=
|
|
+ =gestion_classe wsent=
|
|
+ =python -m copienator add-final-score 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.
|
|
|
|
** Archivage et nettoyage
|
|
|
|
Une fois l'évaluation terminée, =python -m copienator clean Interro=
|
|
supprime les fichiers intermédiaires et régénérables. La commande ne
|
|
conserve que :
|
|
|
|
+ les PDF =Copies/*.pdf= produits après le découpage des pages ;
|
|
+ les sources et sorties textuelles du prétraitement de l'énoncé :
|
|
=enonce.tex=, =correction.tex=, =labels=, =label_groups=, =Text=,
|
|
=Sol=, =Persp=, les fichiers TeX de =Text2= et =Sol2=, =Cache= et
|
|
=Tmp= ;
|
|
+ le résultat final =correction.json= ;
|
|
+ les journaux de =.copienator/logs= et les journaux placés à la
|
|
racine, comme =correction_log= ;
|
|
+ les images et fichiers =score.json= présents dans =A Rendre=.
|
|
|
|
Les liens symboliques conservés dans =A Rendre= sont remplacés par de
|
|
véritables fichiers avant la suppression de leurs cibles. La commande
|
|
refuse de démarrer si les copies traitées, =correction.json= ou une
|
|
image/un score d'élève sont absents. Elle affiche d'abord un résumé et
|
|
demande de saisir le nom de l'évaluation pour confirmer.
|
|
|
|
Dans le GUI, cette commande apparaît comme dernière étape facultative
|
|
dans la section =Archivage=. Un avertissement rappelle que la
|
|
progression du GUI et les données binaires permettant de reprendre les
|
|
étapes seront définitivement perdues.
|
|
|
|
Utiliser =python -m copienator clean Interro --dry-run= pour afficher
|
|
le plan sans rien supprimer, et =--yes= pour omettre la confirmation
|
|
interactive.
|
|
|
|
* Autres
|
|
** Recorrection d'une copie ou de quelques questions
|
|
|
|
Dans le GUI, ouvrir la section =Refaire des copies (facultatif)=,
|
|
repliée par défaut. Ajouter les copies et leurs questions depuis les
|
|
listes déroulantes, ou choisir =Toute la copie=, puis enregistrer la
|
|
sélection. Le dossier du passage principal est présélectionné d'après
|
|
le dernier mode utilisé et les dossiers présents ; vérifier ce choix.
|
|
Pour reprendre une même question dans toute la classe, choisir
|
|
=Toutes les copies=, sélectionner la question, puis =+ Ajouter=.
|
|
Seules les copies ayant un PDF de réponse pour cette question (normal
|
|
ou =_new=) sont ajoutées ; le nombre de copies sans réponse est affiché.
|
|
Une copie déjà sélectionnée entièrement reste sélectionnée entièrement.
|
|
|
|
Les boutons =Corrigés (Sol)= et =Consignes de notation (Persp)= ouvrent
|
|
les dossiers des textes utilisés par la correction. Modifier et enregistrer
|
|
les fichiers des questions concernées avant de relancer =Refaire la correction=.
|
|
Ces boutons sont aussi disponibles dans le parcours principal.
|
|
|
|
Le choix =PDF à vérifier= propose =Automatique=, =Par question (groupé)=
|
|
ou =Par copie=. En automatique, une question présente dans plusieurs
|
|
copies déclenche le regroupement ; sinon les PDF sont produits par copie.
|
|
Les groupes sont limités en hauteur : une question pour toute la classe
|
|
peut donc produire quelques PDF plutôt qu'un fichier par élève.
|
|
Le GUI écrit =refaire.json= et guide ensuite le parcours ci-dessous.
|
|
La vérification du découpage, le redécoupage et la recorrection peuvent
|
|
être ignorés. Pour plusieurs copies, les vérifications et découpages
|
|
s'exécutent successivement ; un échec ou une interruption arrête la suite.
|
|
Ce parcours a sa propre progression : les boutons de navigation du
|
|
passage principal ne l'ouvrent pas automatiquement. Après la fusion,
|
|
les étapes de restitution déjà terminées sont marquées à revalider.
|
|
|
|
Ce flux fonctionne après =annotate-grouped= (=BGnot=),
|
|
=annotate-checks= (=Bnot=) ou =annotate-simple= (=Anot=).
|
|
Terminer d'abord la lecture des annotations du passage principal
|
|
(=read-grouped= ou =read-annotations= pour les modes à cases).
|
|
Conserver les dossiers d'annotation et leurs fichiers de référence.
|
|
|
|
1. Si nécessaire, reprendre le découpage :
|
|
+ =python -m copienator review-labels Interro/Copies/Copie01.pdf=
|
|
+ =python -m copienator split-answers Interro/Copies/Copie01.pdf=
|
|
Vérifier les réponses découpées avant de relancer la correction,
|
|
notamment les fichiers =_new= et =_old= issus de résolutions manuelles.
|
|
2. Créer =Interro/refaire.json= :
|
|
: [["Copie02", []],
|
|
: ["Copie01", ["Ex 1 : 1)"]]]
|
|
Une liste vide sélectionne toute la copie ; sinon donner les labels
|
|
exacts des questions (pas seulement le nom de l'exercice).
|
|
3. =python -m copienator correct Interro --refaire=
|
|
Crée des groupes individuels et remplace les corrections sélectionnées.
|
|
Les anciennes corrections sont conservées dans =overwritten_correction.json=.
|
|
Cette étape peut être omise si les corrections sont modifiées à la main.
|
|
4. Générer les PDF de vérification, selon la présentation souhaitée :
|
|
+ Par question : =python -m copienator annotate-grouped Interro --refaire --overwrite=
|
|
+ Par copie : =python -m copienator annotate-checks Interro --refaire --overwrite=
|
|
Les deux commandes produisent uniquement les réponses sélectionnées
|
|
dans =BRnot=, avec des cases à cocher, quel que soit le mode du passage
|
|
principal. Le mode groupé garde les identifiants des élèves et regroupe
|
|
les réponses par label sans demander de modifier =label_groups=.
|
|
Cela ne nécessite pas d'avoir généré =Bnot= ou =BGnot= auparavant.
|
|
Attention : =--overwrite= remplace tout le précédent passage dans
|
|
=BRnot=, y compris ses annotations manuscrites. Une génération incomplète
|
|
conserve l'ancien =BRnot=. Sans =--overwrite=, un =BRnot= existant est refusé.
|
|
5. Vider les dossiers personnels d'export/import des anciens fichiers,
|
|
puis =python -m copienator export Interro --refaire=.
|
|
Annoter les PDF sur la tablette, puis placer les PDF retournés dans
|
|
=IMPORT_DIR= en conservant leur nom exporté (nom de groupe ou =Copie01.pdf=).
|
|
Même sans modification manuscrite, retourner le PDF pour valider ce passage.
|
|
6. =python -m copienator import Interro --refaire=
|
|
7. Fusionner dans le dossier du passage principal :
|
|
+ Groupé : =python -m copienator read-grouped Interro --refaire=
|
|
+ Cases : =python -m copienator read-grouped Interro --refaire --annotation-dir Bnot=
|
|
+ Simple : =python -m copienator read-grouped Interro --refaire --annotation-dir Anot=
|
|
|
|
Le lecteur reconnaît les retours par question comme les retours par
|
|
copie grâce aux métadonnées et réattribue les cases et notes à chaque
|
|
élève. Un groupe manquant laisse intactes les copies qui en dépendent.
|
|
Il reconstruit la copie complète, conserve les réponses non
|
|
sélectionnées et leurs scores, et remplace les réponses sélectionnées
|
|
par celles de =BRnot=. Dans la compilation filtrée, les images déjà
|
|
enregistrées des questions non sélectionnées sont conservées par
|
|
prudence, même si leur score est parfait, pour ne pas perdre de notes.
|
|
Les anciennes cases et notes manuscrites des
|
|
questions refaites sont remplacées. Les autres copies restent intactes.
|
|
En mode simple, une image =Concat_annotated.jpg= ou =.jpeg= importée
|
|
doit conserver les dimensions de l'image exportée ; les parties non
|
|
sélectionnées sont conservées. Le fichier =refaire_simple_layout.json=
|
|
mémorise le découpage de cette image pour les passages suivants.
|
|
|
|
Les sorties finales (=Concat.jpg=, images par question, =score.json=
|
|
et compilation filtrée) sont mises à jour dans =BGnot=, =Bnot= ou
|
|
=Anot= ; les PDF et références du passage principal restent ceux de
|
|
ce passage. Pour une nouvelle retouche, reprendre ce flux =--refaire=,
|
|
sans relire ensuite les anciennes annotations avec le lecteur normal.
|
|
Relancer ensuite les étapes habituelles de calcul des notes et de diffusion.
|
|
|
|
=refaire.json=, =BRnot= et le dossier du passage principal sont
|
|
obligatoires (code de sortie 3 s'ils manquent). Une copie dont les
|
|
fichiers de retour sont incomplets est laissée intacte (code 4).
|
|
Ne pas ajouter =--update-score= sauf pour imposer volontairement les
|
|
anciens scores, y compris ceux des questions refaites.
|