From a80187ba806eea5bfe46f1dcdde58111f46fa7f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Miquel?= Date: Sat, 6 Jun 2026 10:10:53 +0200 Subject: [PATCH] support for `--update-score' after manual update of score.json --- Readme.org | 9 +++++--- reading_annotations.py | 38 +++++++++++++++++++++++++++------- reading_grouped_annotations.py | 24 +++++++++++++++++++-- 3 files changed, 58 insertions(+), 13 deletions(-) diff --git a/Readme.org b/Readme.org index 5f7731e..8bd144a 100644 --- a/Readme.org +++ b/Readme.org @@ -1,7 +1,7 @@ #+title: Script #+author: Sébastien Miquel #+date: 14-03-2026 -# Time-stamp: <02-06-26 09:26> +# Time-stamp: <06-06-26 10:10> #+OPTIONS: * Méta @@ -235,7 +235,7 @@ sous le nom =Concat_annotated.pdf=. OU 2. =python reading_grouped_annotations.py Interro= - Idem, mais pour =BGnot=. + Idem, mais pour =BGnot=. 3. =python giving_names.py Interro BGnot= @@ -245,7 +245,10 @@ OU 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. 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) diff --git a/reading_annotations.py b/reading_annotations.py index a639b09..5b9a20f 100644 --- a/reading_annotations.py +++ b/reading_annotations.py @@ -161,7 +161,8 @@ def has_significant_notes(note_img, threshold=20): # print(f"Debug : visible pixels is {visible_pixels}") return visible_pixels > threshold -def apply_actions_and_regenerate(root_dir, data, student_id, actions, notes_layer, all_labels): +def apply_actions_and_regenerate(root_dir, data, student_id, actions, notes_layer, + all_labels, update_score=False): """ Modifies data based on actions, reads bnote.json, cuts notes, regenerates all label images for consistency, saves dirty ones, @@ -230,6 +231,23 @@ def apply_actions_and_regenerate(root_dir, data, student_id, actions, notes_laye print(f" > Deleted rect in {label}") dirty_labels.add(label) + # --- 1.5 Override with existing score.json if requested --- + if update_score and os.path.exists(score_path): + try: + with open(score_path, "r") as f: + existing_scores = json.load(f) + for label, existing_score in existing_scores.items(): + if label in labels_data: + current_score = str(labels_data[label]['result'].get('score', 0)) + # If manually modified, override the result and mark dirty + if current_score != str(existing_score): + labels_data[label]['result']['score'] = existing_score + dirty_labels.add(label) + print(f" > Overrode score for {label} to {existing_score} from existing score.json") + except json.JSONDecodeError: + print(f" > Warning: Could not read existing {score_path}") + + # --- 2. Process Images (Cut notes, Regenerate, Concatenate) --- concat_list = [] concat_list_F = [] @@ -256,7 +274,7 @@ def apply_actions_and_regenerate(root_dir, data, student_id, actions, notes_laye # B. Regenerate Label Image # We always regenerate to ensure Concat.jpg is consistent with any modifications # pdf_path = Path(root_dir) / "Copies" / f"Copie{student_id}" / f"{label}.pdf" - pdf_path = content.get('pdf_path') # Contient le suffixe _new si nécessaire + pdf_path = content.get('pdf_path') # Contient le suffixe _new si nécessaire if not os.path.exists(pdf_path): continue (base_img, _, _) = annotating.make_base_image(pdf_path) @@ -332,11 +350,13 @@ def apply_actions_and_regenerate(root_dir, data, student_id, actions, notes_laye from utils import read_all_labels if __name__ == "__main__": - if len(sys.argv) < 2: - print("Usage: python reading_annotations.py ") - sys.exit(1) + import argparse + parser = argparse.ArgumentParser(description="Read annotations and compile PDFs") + parser.add_argument("input_path", help="Directory path") + parser.add_argument("--update-score", action="store_true", help="Override scores with values from existing score.json") + args = parser.parse_args() - root_dir = sys.argv[1] + root_dir = args.input_path try: all_labels = read_all_labels(Path(root_dir)) @@ -352,7 +372,9 @@ if __name__ == "__main__": if os.path.exists(bnot_dir): print(f"Processing annotations for: {student_id}") actions, notes = detect_checks_and_notes(bnot_dir) - if actions or notes: - apply_actions_and_regenerate(root_dir, original_data, student_id, actions, notes, all_labels) + if actions or notes or args.update_score: + apply_actions_and_regenerate(root_dir, original_data, student_id, + actions, notes, all_labels, + update_score=args.update_score) else: print(" No changes detected or missing files.") diff --git a/reading_grouped_annotations.py b/reading_grouped_annotations.py index 030bceb..64b354d 100644 --- a/reading_grouped_annotations.py +++ b/reading_grouped_annotations.py @@ -91,7 +91,8 @@ def save_paginated_pdf(image_groups, output_path): pages[0].save(output_path, "PDF", resolution=100.0, save_all=True, append_images=pages[1:]) def apply_actions_and_regenerate_grouped(root_dir, data, student_id, - actions, label_notes, all_labels): + actions, label_notes, all_labels, + update_score=False): """ Modifies data based on actions, pastes label-specific note crops, regenerates label images for consistency, saves dirty ones, @@ -155,6 +156,23 @@ def apply_actions_and_regenerate_grouped(root_dir, data, student_id, logs.append(f" > Deleted rect in {label}") dirty_labels.add(label) + # --- 1.5 Override with existing score.json if requested --- + if update_score and os.path.exists(score_path): + try: + with open(score_path, "r") as f: + existing_scores = json.load(f) + for label, existing_score in existing_scores.items(): + if label in labels_data: + current_score = str(labels_data[label]['result'].get('score', 0)) + # If manually modified, override the result and mark dirty + if current_score != str(existing_score): + labels_data[label]['result']['score'] = existing_score + dirty_labels.add(label) + logs.append(f" > Overrode score for {label} to {existing_score} from existing score.json") + except json.JSONDecodeError: + logs.append(f" > Warning: Could not read existing {score_path}") + + # --- 2. Process Images (Regenerate & Concatenate) --- concat_list = [] concat_list_F = [] @@ -258,6 +276,7 @@ if __name__ == "__main__": parser = argparse.ArgumentParser(description="Read grouped annotations and compile PDFs") parser.add_argument("input_path", help="Directory path") parser.add_argument("--refaire", action="store_true", help="Merge refaire annotations from Bnot") + parser.add_argument("--update-score", action="store_true", help="Override scores with values from existing score.json") args = parser.parse_args() root_dir = sys.argv[1] @@ -396,7 +415,8 @@ if __name__ == "__main__": sid, actions_by_student[sid], notes_by_student[sid], - all_labels + all_labels, + update_score=args.update_score ) # --- 2. Process each student concurrently using 4 threads ---