From 26d02b098774ff43f080b2bee05323d83dcd45a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Miquel?= Date: Fri, 8 May 2026 15:36:18 +0200 Subject: [PATCH] Divers : Interro 27 --- Readme.org | 9 +++++++-- correction.py | 4 +++- enonce_info.py | 14 +++++++++---- gemini_for_labels.py | 2 +- liste_francais.txt | 4 ++++ plotting.py | 47 ++++++++++++++++++++++++++++++++++++++------ utils.py | 5 ++++- 7 files changed, 70 insertions(+), 15 deletions(-) diff --git a/Readme.org b/Readme.org index 8c984cd..4fd571f 100644 --- a/Readme.org +++ b/Readme.org @@ -1,7 +1,7 @@ #+title: Script #+author: Sébastien Miquel #+date: 14-03-2026 -# Time-stamp: <02-05-26 13:44> +# Time-stamp: <07-05-26 11:33> #+OPTIONS: * Quézaco @@ -205,7 +205,8 @@ OU 1. =python from_tablette.py Interro= (gestion perso) - _Before_ : delete =~/SyncCopies/Annotées=, copy from the tablette to here. + _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, @@ -242,9 +243,13 @@ OU 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 !! diff --git a/correction.py b/correction.py index 620fb58..234e01b 100644 --- a/correction.py +++ b/correction.py @@ -649,7 +649,7 @@ def process_single_task(task_tuple, precomputed_response=None): for p in json_data: pid = p["id"] res = p["result"] - + # Inject additional error if present if injected_error: if res["error"]: @@ -720,6 +720,8 @@ def process_single_task(task_tuple, precomputed_response=None): tprint(f"Error decoding JSON for {file_path}", file=sys.stderr) except Exception as e: error_msg = f"Exception processing {file_path}: {e}" + import traceback + traceback.print_exc() # <--- Add this line to see the real crash print(error_msg, file=sys.stderr) with io_lock: errors_summary.append((error_msg, file_path)) diff --git a/enonce_info.py b/enonce_info.py index a2fdf61..07ad7c9 100644 --- a/enonce_info.py +++ b/enonce_info.py @@ -55,7 +55,10 @@ def compile_to_pdf(text, output_pdf_path): # 21 cm + 3.8 (dimension de la marge def fetch_and_save_sub_text(ex_id, indices, label, text_path): """Fetches text for a specific sub-question and saves it to Text/{label}.tex""" qinds = ",".join(map(str, indices)) - url = f"http://localhost:8080/exercices/exo_q_text/{ex_id}/{qinds}" + if qinds: + url = f"http://localhost:8080/exercices/exo_q_text/{ex_id}/{qinds}" + else: + url = f"http://localhost:8080/exercices/exo_q_text/{ex_id}" try: with urllib.request.urlopen(url) as response: content = response.read().decode('utf-8') @@ -71,7 +74,10 @@ def fetch_and_save_sub_text(ex_id, indices, label, text_path): def fetch_and_save_sub_sol(ex_id, indices, label, sol_path): """Fetches text for a specific sub-question and saves it to Text/{label}.tex""" qinds = ",".join(map(str, indices)) - url = f"http://localhost:8080/exercices/exo_q_sol/{ex_id}/{qinds}" + if qinds: + url = f"http://localhost:8080/exercices/exo_q_sol/{ex_id}/{qinds}" + else: + url = f"http://localhost:8080/exercices/exo_q_sol/{ex_id}" try: with urllib.request.urlopen(url) as response: content = response.read().decode('utf-8') @@ -168,11 +174,11 @@ def process_directory(directory): if not tex_files: print(f"No .tex file found in {directory}. Looking in /Staging/Interro/") int_name = directory[:-1] if directory.endswith("/") else directory - tex_path = os.path.join(os.path.expanduser("~"), "Prépa/Staging/Interro/", int_name, ".tex") + tex_path = os.path.join(os.path.expanduser("~"), "Prépa/Staging/Interro", f"{int_name}.tex") if os.path.exists(tex_path): tex_file = tex_path else: - print("Not found.") + print("Not found in ", tex_path) return else: tex_file = tex_files[0] diff --git a/gemini_for_labels.py b/gemini_for_labels.py index 7299492..7b596cd 100644 --- a/gemini_for_labels.py +++ b/gemini_for_labels.py @@ -314,7 +314,7 @@ def process_copy_group(group_key, files): # Run ThreadPool on GROUPS (Copies), not individual files # Each thread handles one student's full exam copy sequentially -with ThreadPoolExecutor(max_workers=12) as executor: +with ThreadPoolExecutor(max_workers=16) as executor: # Convert dict items to arguments for map # executor.map expects a function and an iterable. # We use a lambda or separate function to unpack the tuple if needed, diff --git a/liste_francais.txt b/liste_francais.txt index cbdd256..df6faca 100644 --- a/liste_francais.txt +++ b/liste_francais.txt @@ -4358,6 +4358,8 @@ conjoncture conjugaison conjugal conjuguer +conjugué +conjugués conjuration conjuré conjurer @@ -6097,6 +6099,7 @@ détenus détérioration détériorer déterminant +déterminants déterminante détermination détermine @@ -10279,6 +10282,7 @@ inacceptable inacceptables inaccessible inaccoutumé +inachevé inactif inaction inadmissible diff --git a/plotting.py b/plotting.py index ab7b203..0ee4fd7 100644 --- a/plotting.py +++ b/plotting.py @@ -9,7 +9,7 @@ from tkinter import messagebox from pathlib import Path from PIL import Image, ImageDraw, ImageFont, ImageTk -print("o to open pdf, O original pdf, e to emacs part, i to interro, click for coordinates") +print("o to open pdf, O original pdf, e to emacs part, p to go back, i to interro, click for coordinates") # --- Configuration & Globals --- padding = 60 @@ -80,7 +80,7 @@ def prepare_image(image_path: str, bounding_boxes, all_labels, nb_pages, last_la if current_index < last_label_index or (last_label_index == -1 and current_index != 0): color = "red" elif current_index > last_label_index + 1: - color = "yellow" + color = "orange" last_label_index = current_index draw.rectangle(((abs_x_min, abs_y_min), (abs_x_max, abs_y_max)), outline=color, width=4) @@ -172,8 +172,15 @@ class ImageViewer: self.active_copie_name = None self.accumulated_results = None # Dict with "name" and "list" + # To go back + self.history = [] + self.forward_stack = [] + self.current_pil_image = None + + # Bindings self.root.bind('', self.on_enter) + self.root.bind('p', self.on_previous) self.root.bind('e', self.on_edit) self.root.bind('o', self.on_open_pdf) self.root.bind('i', self.on_open_interro) @@ -186,7 +193,11 @@ class ImageViewer: def poll_queue(self): if not self.is_viewing: try: - pil_image, json_path, metadata = image_queue.get_nowait() + # pil_image, json_path, metadata = image_queue.get_nowait() + if self.forward_stack: + pil_image, json_path, metadata = self.forward_stack.pop() + else: + pil_image, json_path, metadata = image_queue.get_nowait() # Handle End of Stream if pil_image is None: @@ -201,6 +212,7 @@ class ImageViewer: # Start new batch self.active_copie_name = metadata["copie"] self.accumulated_results = {"name": metadata["name"], "list": []} + self.history.clear() self.display_image(pil_image, json_path, metadata) except queue.Empty: @@ -216,7 +228,24 @@ class ImageViewer: json.dump(self.accumulated_results, f) self.accumulated_results = None + + def on_previous(self, event): + if self.is_viewing and self.history: + print("Going back to previous image...") + prev_pil, prev_json, prev_meta, num_added = self.history.pop() + + # Undo the accumulation to prevent duplicates when we hit Enter again + if self.accumulated_results and num_added > 0: + self.accumulated_results["list"] = self.accumulated_results["list"][:-num_added] + + # Push current image to the forward stack so we don't lose it + self.forward_stack.append((self.current_pil_image, + self.current_json_path, self.current_meta)) + + # Display the previous image immediately + self.display_image(prev_pil, prev_json, prev_meta) def display_image(self, pil_image, json_path, metadata): + self.current_pil_image = pil_image # ADD THIS LINE self.orig_size = pil_image.size self.scale_factor = 1.0 screen_h = self.root.winfo_screenheight() - 100 @@ -235,6 +264,7 @@ class ImageViewer: def on_enter(self, event): if self.is_viewing: print(f"Committing data for {self.current_json_path.name}...") + num_added = 0 # ADD THIS LINE try: with open(self.current_json_path, 'r') as f: @@ -247,6 +277,8 @@ class ImageViewer: self.current_meta["schema"] ) + num_added = len(converted_items) + # Add to accumulator if self.accumulated_results: self.accumulated_results["list"].extend(converted_items) @@ -261,6 +293,9 @@ class ImageViewer: messagebox.showerror("JSON Error", msg) return # Abort advancement + self.history.append((self.current_pil_image, self.current_json_path, + self.current_meta, num_added)) + # Advance UI self.is_viewing = False self.label.config(image="", text="Loading next...") @@ -272,13 +307,13 @@ class ImageViewer: print(f"Opening {pdf_path}") subprocess.Popen(['xdg-open', str(pdf_path.absolute())]) - def on_open_ori_pdf(self, event): + def on_open_interro(self, event): if self.is_viewing and self.current_json_path: - pdf_path = "/home/sebastien/Staging/Interro/" + str(base_dir) + "pdf" + pdf_path = "/home/sebastien/Prépa/Staging/Interro/" + str(base_dir) + ".pdf" print(f"Opening {pdf_path}") subprocess.Popen(['xdg-open', pdf_path]) - def on_open_interro(self, event): + def on_open_ori_pdf(self, event): if self.is_viewing and self.current_json_path: new_filename = self.current_json_path.stem.split('_')[0] + ".pdf" pdf_path = self.current_json_path.parent / "Copies Originales" / new_filename diff --git a/utils.py b/utils.py index 2b129ee..2bb7c73 100644 --- a/utils.py +++ b/utils.py @@ -14,7 +14,10 @@ def enonce_total(base_dir): if not text_dir.is_dir(): return "" - files = [f for f in text_dir.iterdir() if f.is_file()] + # Exclude .tex and .pdf files + files = [f for f in text_dir.iterdir() + if f.is_file() and f.suffix.lower() not in ('.tex', '.pdf')] + files.sort(key=lambda f: natural_key(f.name)) output = []