Splitting of Readme.org
This commit is contained in:
@@ -0,0 +1,124 @@
|
|||||||
|
#+title: Architecture et conventions de développement
|
||||||
|
#+author: Sébastien Miquel
|
||||||
|
#+date: 22-08-2026
|
||||||
|
#+OPTIONS:
|
||||||
|
|
||||||
|
Ce document décrit les invariants techniques du projet. Il s'adresse
|
||||||
|
aux développeurs et aux agents logiciels qui modifient le dépôt.
|
||||||
|
|
||||||
|
- [[file:Readme.org][Guide de démarrage]]
|
||||||
|
- [[file:Script.org][Référence des étapes et des scripts]]
|
||||||
|
|
||||||
|
* API commune pour les scripts
|
||||||
|
|
||||||
|
Le paquet =copienator= centralise les chemins d'une évaluation et les
|
||||||
|
écritures JSON sûres. Un script ne devrait donc plus reconstruire les
|
||||||
|
chemins partagés à la main :
|
||||||
|
|
||||||
|
#+BEGIN_SRC python
|
||||||
|
from copienator import EvaluationWorkspace, atomic_write_json
|
||||||
|
|
||||||
|
workspace = EvaluationWorkspace("Interro")
|
||||||
|
atomic_write_json(workspace.correction_file, corrections)
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
=EvaluationWorkspace.discover(path)= retrouve également la racine d'une
|
||||||
|
évaluation à partir d'un fichier ou d'un sous-dossier. Sa construction
|
||||||
|
ne crée aucun fichier. La création explicite de
|
||||||
|
=.copienator/logs/= et =.copienator/runs/= se fait avec
|
||||||
|
=workspace.ensure_control_directories()=. Le chemin
|
||||||
|
=.copienator/state.sqlite3= est réservé à une future couche d'état
|
||||||
|
transactionnelle.
|
||||||
|
|
||||||
|
=atomic_write_json= écrit d'abord dans un fichier temporaire situé dans
|
||||||
|
le même dossier, synchronise son contenu, puis remplace la destination.
|
||||||
|
Une interruption ne laisse donc pas un JSON partiellement écrit. Pour
|
||||||
|
une modification concurrente de type lire-modifier-écrire, utiliser
|
||||||
|
=atomic_update_json= : cet utilitaire protège l'opération complète avec
|
||||||
|
un verrou inter-processus Linux/Windows.
|
||||||
|
|
||||||
|
* Convention des scripts standardisés
|
||||||
|
|
||||||
|
Les scripts standardisés exposent =build_parser()=, =run(...)= et
|
||||||
|
=main(argv=None)=. Leur import ne lance aucun traitement. Ils acceptent
|
||||||
|
le dossier d'évaluation comme premier argument positionnel, utilisent
|
||||||
|
=EvaluationWorkspace= pour les chemins partagés et peuvent afficher la
|
||||||
|
trace complète d'une erreur avec =--verbose=.
|
||||||
|
|
||||||
|
Les codes de sortie communs sont :
|
||||||
|
|
||||||
|
| Code | Signification |
|
||||||
|
|------+---------------|
|
||||||
|
| 0 | réussite |
|
||||||
|
| 1 | erreur de traitement |
|
||||||
|
| 2 | arguments invalides |
|
||||||
|
| 3 | évaluation ou prérequis invalides |
|
||||||
|
| 4 | traitement partiel, avec avertissements |
|
||||||
|
| 130 | interruption par l'utilisateur |
|
||||||
|
|
||||||
|
Le GUI distingue notamment un traitement partiel d'un échec. Les
|
||||||
|
scripts migrés vers cette convention sont actuellement :
|
||||||
|
|
||||||
|
- =copies_tools.py=, =grouping.py= et =verify_groups.py= ;
|
||||||
|
- =post-correction.py= et =resolve_manual.py= ;
|
||||||
|
- =page_splitter.py=, =cutleft.py=, =plotting.py= et
|
||||||
|
=splitting_int.py= ;
|
||||||
|
- =gemini_for_labels.py= ;
|
||||||
|
- =gemini_for_enonce.py= et =enonce_info.py= ;
|
||||||
|
- =correction.py=, =submit_batches.py=, =batch_status.py= et
|
||||||
|
=fetch_batched_results.py= ;
|
||||||
|
- =annotating.py=, =annotating_with_checks.py= et
|
||||||
|
=annotating_by_label.py= ;
|
||||||
|
- =reading_annotations.py= et =reading_grouped_annotations.py= ;
|
||||||
|
- =export.py=, =import.py= et =giving_names.py=.
|
||||||
|
|
||||||
|
* Organisation du code
|
||||||
|
|
||||||
|
- Le paquet =copienator= contient les abstractions partagées par les
|
||||||
|
scripts, notamment =EvaluationWorkspace= et les écritures atomiques.
|
||||||
|
- Le paquet =copienator_gui= contient la définition du workflow, l'état
|
||||||
|
persistant, le lanceur de processus et l'application Tk.
|
||||||
|
- Les scripts situés à la racine restent des points d'entrée autonomes.
|
||||||
|
Leur import ne doit pas déclencher de traitement.
|
||||||
|
|
||||||
|
* État et exécution du GUI
|
||||||
|
|
||||||
|
L'état d'une évaluation est conservé dans =.copienator-gui.json=. Les
|
||||||
|
valeurs des arguments, le dernier mode exécuté, les statuts et un
|
||||||
|
historique borné y sont enregistrés atomiquement. Les sorties des
|
||||||
|
processus sont conservées dans =.copienator/logs/=. Le GUI lance les
|
||||||
|
scripts dans des processus séparés afin de pouvoir afficher leur sortie,
|
||||||
|
leur transmettre une saisie et les interrompre.
|
||||||
|
|
||||||
|
Les retours en arrière ne suppriment pas les artefacts. Ils marquent les
|
||||||
|
étapes suivantes comme étant à revalider. Les automatismes de première
|
||||||
|
visite sont également persistés et ne doivent pas être rejoués lors d'un
|
||||||
|
retour en arrière.
|
||||||
|
|
||||||
|
* Invariants à préserver
|
||||||
|
|
||||||
|
- Utiliser =EvaluationWorkspace= pour les chemins partagés d'une
|
||||||
|
évaluation au lieu de reconstruire ces chemins dans chaque script.
|
||||||
|
- Publier les JSON et les ensembles de fichiers importants de façon
|
||||||
|
atomique. Une interruption ou un résultat partiel doit conserver la
|
||||||
|
dernière sortie complète lorsqu'elle existe.
|
||||||
|
- Conserver la convention =build_parser()=, =run(...)= et
|
||||||
|
=main(argv=None)= pour les scripts standardisés.
|
||||||
|
- Ne lancer aucun traitement lors de l'import d'un module.
|
||||||
|
- Retourner les codes de sortie communs afin que le GUI distingue une
|
||||||
|
réussite, un résultat partiel, un échec et une interruption.
|
||||||
|
- Préserver les modifications manuelles et les fichiers déjà présents,
|
||||||
|
sauf lorsqu'une option explicite comme =--overwrite= ou =--reset=
|
||||||
|
autorise leur remplacement.
|
||||||
|
- Les labels deviennent des noms de fichiers. Ils doivent donc respecter
|
||||||
|
les contraintes de la plateforme, notamment l'interdiction de =:= sous
|
||||||
|
Windows.
|
||||||
|
|
||||||
|
* Règle de classement de la documentation
|
||||||
|
|
||||||
|
- Une information nécessaire pour installer ou démarrer l'application
|
||||||
|
appartient à [[file:Readme.org][Readme.org]].
|
||||||
|
- Une commande, un argument ou une étape du workflow appartient à
|
||||||
|
[[file:Script.org][Script.org]].
|
||||||
|
- Une convention interne, un invariant ou une décision d'architecture
|
||||||
|
appartient au présent document.
|
||||||
+7
-406
@@ -1,10 +1,10 @@
|
|||||||
#+title: Script
|
#+title: Copienator
|
||||||
#+author: Sébastien Miquel
|
#+author: Sébastien Miquel
|
||||||
#+date: 14-03-2026
|
#+date: 14-03-2026
|
||||||
# Time-stamp: <22-08-26 12:22>
|
# Time-stamp: <22-08-26 12:22>
|
||||||
#+OPTIONS:
|
#+OPTIONS:
|
||||||
|
|
||||||
* Méta
|
* Présentation
|
||||||
** Quézaco
|
** Quézaco
|
||||||
|
|
||||||
Ce dépôt contient un certain nombre de script Python que j'utilise
|
Ce dépôt contient un certain nombre de script Python que j'utilise
|
||||||
@@ -108,408 +108,9 @@ Les chemins des étapes personnelles peuvent être adaptés avec
|
|||||||
=CURRENT_SCORE_ODS_PATH=, =FINAL_SCORE_ODS_PATH=,
|
=CURRENT_SCORE_ODS_PATH=, =FINAL_SCORE_ODS_PATH=,
|
||||||
=FINAL_SCORE_OUTPUT_DIR= et =FINAL_SCORE_FONT_PATH= dans =config.py=.
|
=FINAL_SCORE_OUTPUT_DIR= et =FINAL_SCORE_FONT_PATH= dans =config.py=.
|
||||||
|
|
||||||
*** API commune pour les scripts
|
* Documentation complémentaire
|
||||||
|
|
||||||
Le paquet =copienator= centralise les chemins d'une évaluation et les
|
- [[file:Script.org][Référence des étapes et des scripts]] : commandes, arguments,
|
||||||
écritures JSON sûres. Un script ne devrait donc plus reconstruire les
|
prérequis, fichiers produits et parcours alternatifs.
|
||||||
chemins partagés à la main :
|
- [[file:Architecture.org][Architecture et conventions de développement]] : API commune,
|
||||||
|
état partagé, écritures sûres et règles de maintenance.
|
||||||
#+BEGIN_SRC python
|
|
||||||
from copienator import EvaluationWorkspace, atomic_write_json
|
|
||||||
|
|
||||||
workspace = EvaluationWorkspace("Interro")
|
|
||||||
atomic_write_json(workspace.correction_file, corrections)
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
=EvaluationWorkspace.discover(path)= retrouve également la racine d'une
|
|
||||||
évaluation à partir d'un fichier ou d'un sous-dossier. Sa construction
|
|
||||||
ne crée aucun fichier. La création explicite de
|
|
||||||
=.copienator/logs/= et =.copienator/runs/= se fait avec
|
|
||||||
=workspace.ensure_control_directories()=. Le chemin
|
|
||||||
=.copienator/state.sqlite3= est réservé à une future couche d'état
|
|
||||||
transactionnelle.
|
|
||||||
|
|
||||||
=atomic_write_json= écrit d'abord dans un fichier temporaire situé dans
|
|
||||||
le même dossier, synchronise son contenu, puis remplace la destination.
|
|
||||||
Une interruption ne laisse donc pas un JSON partiellement écrit. Pour
|
|
||||||
une modification concurrente de type lire-modifier-écrire, utiliser
|
|
||||||
=atomic_update_json= : cet utilitaire protège l'opération complète avec
|
|
||||||
un verrou inter-processus Linux/Windows.
|
|
||||||
|
|
||||||
*** Convention des scripts standardisés
|
|
||||||
|
|
||||||
Les scripts standardisés exposent =build_parser()=, =run(...)= et
|
|
||||||
=main(argv=None)=. Leur import ne lance aucun traitement. Ils acceptent
|
|
||||||
le dossier d'évaluation comme premier argument positionnel, utilisent
|
|
||||||
=EvaluationWorkspace= pour les chemins partagés et peuvent afficher la
|
|
||||||
trace complète d'une erreur avec =--verbose=.
|
|
||||||
|
|
||||||
Les codes de sortie communs sont :
|
|
||||||
|
|
||||||
| Code | Signification |
|
|
||||||
|------+---------------|
|
|
||||||
| 0 | réussite |
|
|
||||||
| 1 | erreur de traitement |
|
|
||||||
| 2 | arguments invalides |
|
|
||||||
| 3 | évaluation ou prérequis invalides |
|
|
||||||
| 4 | traitement partiel, avec avertissements |
|
|
||||||
| 130 | interruption par l'utilisateur |
|
|
||||||
|
|
||||||
Le GUI distingue notamment un traitement partiel d'un échec. Les
|
|
||||||
scripts migrés vers cette convention sont actuellement :
|
|
||||||
|
|
||||||
- =copies_tools.py=, =grouping.py= et =verify_groups.py= ;
|
|
||||||
- =post-correction.py= et =resolve_manual.py= ;
|
|
||||||
- =page_splitter.py=, =cutleft.py=, =plotting.py= et
|
|
||||||
=splitting_int.py= ;
|
|
||||||
- =gemini_for_labels.py= ;
|
|
||||||
- =gemini_for_enonce.py= et =enonce_info.py= ;
|
|
||||||
- =correction.py=, =submit_batches.py=, =batch_status.py= et
|
|
||||||
=fetch_batched_results.py= ;
|
|
||||||
- =annotating.py=, =annotating_with_checks.py= et
|
|
||||||
=annotating_by_label.py= ;
|
|
||||||
- =reading_annotations.py= et =reading_grouped_annotations.py= ;
|
|
||||||
- =export.py=, =import.py= et =giving_names.py=.
|
|
||||||
|
|
||||||
* Étapes et Script
|
|
||||||
|
|
||||||
Utiliser `python gui.py` ou `python gui.py 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 gemini_for_enonce.py Interro` or
|
|
||||||
`python gemini_for_enonce.py 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 enonce_info.py 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
|
|
||||||
=gemini_for_enonce.py= et le fichier =labels= sont publiés
|
|
||||||
atomiquement.
|
|
||||||
|
|
||||||
** Prétraitement des copies
|
|
||||||
|
|
||||||
Mettre les copies scannées au format pdf dans =Interro=.
|
|
||||||
|
|
||||||
1. =python copies_tools.py rotate Interro= (facultatif)
|
|
||||||
|
|
||||||
Retourne tous les pdf de 180°, si la photocopie a été faite à
|
|
||||||
l'envers.
|
|
||||||
2. =python copies_tools.py rename 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.
|
|
||||||
|
|
||||||
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 page_splitter.py 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 cutleft.py Interro=
|
|
||||||
|
|
||||||
Découpe la partie gauche des copies, là où il devrait y avoir les
|
|
||||||
labels des exercices/questions.
|
|
||||||
|
|
||||||
=python cutleft.py Interro --fullpage= to use the full page always.
|
|
||||||
|
|
||||||
Rerun on a single file with =python cutleft.py 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 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.
|
|
||||||
|
|
||||||
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 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=
|
|
||||||
|
|
||||||
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 cutleft.py Interro/Copie{id}=
|
|
||||||
- Rerun =python gemini_for_labels.py Interro/Copie{id}=
|
|
||||||
3. =python splitting_int.py 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 grouping.py Interro=
|
|
||||||
|
|
||||||
Regroupe les mêmes questions de différentes copies en groupes de
|
|
||||||
tailles raisonnables.
|
|
||||||
5. Facultatif : =python verify_groups.py 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 =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=
|
|
||||||
|
|
||||||
Fais les requêtes de correction à Gemini.
|
|
||||||
|
|
||||||
=correction.py= 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 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=
|
|
||||||
|
|
||||||
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. =submit_batches.py= 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. =batch_status.py --download JOB --output
|
|
||||||
resultat.jsonl= permet aussi de télécharger atomiquement le résultat
|
|
||||||
d'un job particulier.
|
|
||||||
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.
|
|
||||||
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 resolve_manual.py Interro`
|
|
||||||
5. Call `python correction.py Interro --refaire`.
|
|
||||||
|
|
||||||
|
|
||||||
** 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=.
|
|
||||||
OU
|
|
||||||
2. =python annotating_with_checks.py 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 annotating_with_checks.py Interro/Copies/Copie01.pdf=.
|
|
||||||
Le mode =--refaire= exige un fichier =refaire.json= et écrit dans
|
|
||||||
=BRnot=.
|
|
||||||
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 export.py 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 import.py 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 reading_annotations.py 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 reading_grouped_annotations.py Interro=
|
|
||||||
|
|
||||||
Idem, mais pour =BGnot=. Les tâches parallèles remontent leurs
|
|
||||||
erreurs au processus principal au lieu de les ignorer.
|
|
||||||
|
|
||||||
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. Éventuellement, faire des modifications manuelles aux =score.json=.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
* Autres
|
|
||||||
** 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
|
|
||||||
: [["Copie02", []],
|
|
||||||
: ["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=
|
|
||||||
6. =python export.py --refaire Interro24=
|
|
||||||
6. =python import.py --refaire Interro24=
|
|
||||||
7. =python reading_grouped_annotations.py --refaire Interro24=
|
|
||||||
|
|
||||||
Avec =--refaire=, =refaire.json= et le dossier =BRnot= sont des
|
|
||||||
prérequis obligatoires ; leur absence produit le code de sortie 3.
|
|
||||||
|
|
||||||
** Exemple de replotting, refaire d'une copie
|
|
||||||
|
|
||||||
1. replot it.
|
|
||||||
2. `python splitting_int.py DS09VA/Copies/Copie25.pdf`
|
|
||||||
this will get rid of old/new.
|
|
||||||
!! Attention, et si ça dégage un new : bad bad bad.
|
|
||||||
3. Make `refaire.json`, avec la copie, et les labels à refaire.
|
|
||||||
4. `python correction.py DS09VA --refaire`
|
|
||||||
5. `python annotating_with_checks.py DS09VA --refaire`
|
|
||||||
6. `python import.py Interro24 --refaire`
|
|
||||||
|
|||||||
+354
@@ -0,0 +1,354 @@
|
|||||||
|
#+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 et Script
|
||||||
|
|
||||||
|
Utiliser `python gui.py` ou `python gui.py 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 gemini_for_enonce.py Interro` or
|
||||||
|
`python gemini_for_enonce.py 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 enonce_info.py 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
|
||||||
|
=gemini_for_enonce.py= et le fichier =labels= sont publiés
|
||||||
|
atomiquement.
|
||||||
|
|
||||||
|
** Prétraitement des copies
|
||||||
|
|
||||||
|
Mettre les copies scannées au format pdf dans =Interro=.
|
||||||
|
|
||||||
|
1. =python copies_tools.py rotate Interro= (facultatif)
|
||||||
|
|
||||||
|
Retourne tous les pdf de 180°, si la photocopie a été faite à
|
||||||
|
l'envers.
|
||||||
|
2. =python copies_tools.py rename 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.
|
||||||
|
|
||||||
|
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 page_splitter.py 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 cutleft.py Interro=
|
||||||
|
|
||||||
|
Découpe la partie gauche des copies, là où il devrait y avoir les
|
||||||
|
labels des exercices/questions.
|
||||||
|
|
||||||
|
=python cutleft.py Interro --fullpage= to use the full page always.
|
||||||
|
|
||||||
|
Rerun on a single file with =python cutleft.py 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 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.
|
||||||
|
|
||||||
|
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 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=
|
||||||
|
|
||||||
|
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 cutleft.py Interro/Copie{id}=
|
||||||
|
- Rerun =python gemini_for_labels.py Interro/Copie{id}=
|
||||||
|
3. =python splitting_int.py 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 grouping.py Interro=
|
||||||
|
|
||||||
|
Regroupe les mêmes questions de différentes copies en groupes de
|
||||||
|
tailles raisonnables.
|
||||||
|
5. Facultatif : =python verify_groups.py 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 =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=
|
||||||
|
|
||||||
|
Fais les requêtes de correction à Gemini.
|
||||||
|
|
||||||
|
=correction.py= 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 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=
|
||||||
|
|
||||||
|
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. =submit_batches.py= 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. =batch_status.py --download JOB --output
|
||||||
|
resultat.jsonl= permet aussi de télécharger atomiquement le résultat
|
||||||
|
d'un job particulier.
|
||||||
|
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.
|
||||||
|
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 resolve_manual.py Interro`
|
||||||
|
5. Call `python correction.py Interro --refaire`.
|
||||||
|
|
||||||
|
|
||||||
|
** 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=.
|
||||||
|
OU
|
||||||
|
2. =python annotating_with_checks.py 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 annotating_with_checks.py Interro/Copies/Copie01.pdf=.
|
||||||
|
Le mode =--refaire= exige un fichier =refaire.json= et écrit dans
|
||||||
|
=BRnot=.
|
||||||
|
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 export.py 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 import.py 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 reading_annotations.py 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 reading_grouped_annotations.py Interro=
|
||||||
|
|
||||||
|
Idem, mais pour =BGnot=. Les tâches parallèles remontent leurs
|
||||||
|
erreurs au processus principal au lieu de les ignorer.
|
||||||
|
|
||||||
|
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. Éventuellement, faire des modifications manuelles aux =score.json=.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
* Autres
|
||||||
|
** 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
|
||||||
|
: [["Copie02", []],
|
||||||
|
: ["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=
|
||||||
|
6. =python export.py --refaire Interro24=
|
||||||
|
6. =python import.py --refaire Interro24=
|
||||||
|
7. =python reading_grouped_annotations.py --refaire Interro24=
|
||||||
|
|
||||||
|
Avec =--refaire=, =refaire.json= et le dossier =BRnot= sont des
|
||||||
|
prérequis obligatoires ; leur absence produit le code de sortie 3.
|
||||||
|
|
||||||
|
** Exemple de replotting, refaire d'une copie
|
||||||
|
|
||||||
|
1. replot it.
|
||||||
|
2. `python splitting_int.py DS09VA/Copies/Copie25.pdf`
|
||||||
|
this will get rid of old/new.
|
||||||
|
!! Attention, et si ça dégage un new : bad bad bad.
|
||||||
|
3. Make `refaire.json`, avec la copie, et les labels à refaire.
|
||||||
|
4. `python correction.py DS09VA --refaire`
|
||||||
|
5. `python annotating_with_checks.py DS09VA --refaire`
|
||||||
|
6. `python import.py Interro24 --refaire`
|
||||||
|
|
||||||
Reference in New Issue
Block a user