small fixes

This commit is contained in:
2026-08-08 16:47:09 +02:00
parent f345f8bb4f
commit c535febbc4
6 changed files with 54 additions and 47 deletions
+8 -6
View File
@@ -1,7 +1,7 @@
#+title: Script
#+author: Sébastien Miquel
#+date: 14-03-2026
# Time-stamp: <08-08-26 13:18>
# Time-stamp: <08-08-26 16:44>
#+OPTIONS:
* Méta
@@ -149,6 +149,8 @@ Mettre les copies scannées au format pdf dans =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=
** Labelisation et regroupement
@@ -174,11 +176,11 @@ Set proxy with ~export HTTPS_PROXY="http://10.0.0.1:3128"~
=python plotting.py Interro/Copies/Copie01.pdf=
It also generates les =Copie01.json=, à partir des =Copie01_01.json=
1. 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.
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.
3. =python splitting_int.py Interro=
Découpe les copies suivant les exercices
+2
View File
@@ -1,6 +1,7 @@
import sys
import os
import json
import utils
import shutil
import argparse
import concurrent.futures
@@ -124,6 +125,7 @@ def main():
with open(label_groups, 'w') as f:
for items in groups.values():
f.write(",".join(items) + "\n")
utils.edit_file_and_enter(label_groups)
with open(label_groups, "r") as f:
lines = [line.strip() for line in f if line.strip()]
+18 -23
View File
@@ -3,6 +3,7 @@ from functools import lru_cache
import os
import time
import json # Added for schema output
import argparse
import tkinter as tk
from threading import Thread
from queue import Queue, Empty
@@ -14,10 +15,13 @@ DELIMITER_WIDTH = 5
DELIMITER_COLOR = (0, 0, 0)
OUTPUT_SIZE = (1800, 1000)
if len(sys.argv) < 2:
sys.exit("Usage: python script.py <directory_path_or_file_path>")
parser = argparse.ArgumentParser(description="PDF Cropper")
parser.add_argument("path", help="Directory path or PDF file path")
parser.add_argument("--fullpage", action="store_true", help="Process all files in full page mode (1 page per output file)")
args = parser.parse_args()
path_arg = sys.argv[1]
path_arg = args.path
fullpage_mode = args.fullpage
files = []
INPUT_DIR = ""
COPIES_DIR = ""
@@ -121,7 +125,6 @@ def process_single_pdf(filename, shift_offset=0, max_per_file=5):
Converts PDF to stitched images.
Returns a tuple: (preview_image_resized, list_of_split_images, schema_dict)
"""
# pdf_path = os.path.join(INPUT_DIR, filename)
try:
pages = get_pdf_pages(filename)
cropped_images = []
@@ -164,7 +167,6 @@ def process_single_pdf(filename, shift_offset=0, max_per_file=5):
# 3. Generate Preview (All stitched together, Resized)
full_stitch = stitch_images(cropped_images)
# preview_resized = full_stitch.resize(OUTPUT_SIZE, Image.LANCZOS)
preview_resized = full_stitch.resize(OUTPUT_SIZE, Image.BILINEAR)
schema = {
@@ -190,21 +192,15 @@ def save_results(result_tuple, filename):
# --- Cleanup: Delete existing files for this PDF ---
for f in os.listdir(OUTPUT_DIR):
file_path = os.path.join(OUTPUT_DIR, f)
# 1. Delete schema file
if f == f"{base_name}_schema.json":
os.remove(file_path)
# 2. Delete image files (pattern: basename_01.jpg, etc.)
elif f.startswith(f"{base_name}_") and f.endswith(".jpg"):
# Check if the suffix is strictly numeric (e.g. "01") to avoid
# deleting unrelated files like "file_v2_01.jpg" when processing "file.pdf"
suffix = f[len(base_name)+1:-4]
if suffix.isdigit():
os.remove(file_path)
# ---------------------------------------------------
# Save Images
for i, img in enumerate(splits):
# Suffix _01, _02, etc.
suffix = f"_{i+1:02d}"
output_filename = f"{base_name}{suffix}.jpg"
output_path = os.path.join(OUTPUT_DIR, output_filename)
@@ -217,14 +213,17 @@ def save_results(result_tuple, filename):
with open(json_path, 'w') as f:
json.dump(schema, f, indent=4)
print(f"Saved schema: {json_filename}")
# --- GUI Application ---
class ImageReviewer:
def __init__(self, file_list):
def __init__(self, file_list, default_max_per_file=5):
self.files = file_list
self.index = 0
self.current_shift = 0
self.current_max_per_file = 5
self.default_max_per_file = default_max_per_file
self.current_max_per_file = default_max_per_file
self.current_preview = None # Only stores the resized preview for GUI
self.is_processing = False
@@ -247,8 +246,7 @@ class ImageReviewer:
self.root.bind('n', lambda e: self.on_shift(50))
self.root.bind('N', lambda e: self.on_shift(100))
self.root.bind('t', lambda e: self.on_shift(-50))
self.root.bind('1', lambda e: self.on_set_max_pages(1)) # New Binding
self.root.bind('1', lambda e: self.on_set_max_pages(1))
# Start background pre-fetcher
self.bg_thread = Thread(target=self.prefetch_worker, daemon=True)
@@ -266,7 +264,6 @@ class ImageReviewer:
return
self.current_max_per_file = count
print(f"Setting max pages per file: {count}")
# Trigger reprocessing with current settings
self.trigger_processing(self.files[self.index], self.current_shift)
def prefetch_worker(self):
@@ -276,7 +273,7 @@ class ImageReviewer:
target = self.index + 1
if target < len(self.files) and target != idx_to_process:
fname = self.files[target]
get_pdf_pages(fname) # Just calling it warms the lru_cache
get_pdf_pages(fname)
idx_to_process = target
time.sleep(0.05)
@@ -290,7 +287,6 @@ class ImageReviewer:
self.is_processing = False
self.current_shift = 0
# Always trigger processing. If prefetched, get_pdf_pages returns instantly.
self.trigger_processing(filename, self.current_shift)
def trigger_processing(self, filename, shift):
@@ -317,7 +313,6 @@ class ImageReviewer:
self.load_current_image(use_prefetch=True)
self.is_processing = False
except Empty:
# Check again in 100ms
self.root.after(100, lambda: self.check_manual_queue(filename))
def handle_processing_result(self, result, filename):
@@ -325,7 +320,6 @@ class ImageReviewer:
preview, splits, schema = result
self.current_preview = preview
# Save in a background thread so the GUI updates instantly
Thread(target=save_results, args=(result, filename), daemon=True).start()
self.update_display(filename, schema)
@@ -350,7 +344,7 @@ class ImageReviewer:
def on_shift(self, amount):
if self.is_processing:
return # Ignore keys while processing
return
self.current_shift += amount
print(f"Applying shift: {self.current_shift}")
self.trigger_processing(self.files[self.index], self.current_shift)
@@ -360,12 +354,13 @@ class ImageReviewer:
return
self.index += 1
self.current_shift = 0
self.current_max_per_file = 5 # Reset to default
self.current_max_per_file = self.default_max_per_file
self.load_current_image(use_prefetch=True)
# --- Entry Point ---
if __name__ == "__main__":
if not files:
print("No PDF files found.")
else:
app = ImageReviewer(files)
app = ImageReviewer(files, default_max_per_file=1 if fullpage_mode else 5)
+7 -18
View File
@@ -1,6 +1,6 @@
import shlex
import re
import os
import utils
import subprocess
import sys
import argparse
@@ -119,7 +119,7 @@ PROMPT_3 = """I am providing:
2. The source code of the exam questions (`enonce` file).
Your task:
Extract important information necessary to understand the questions (e.g., definitions of objects, global notations, hypotheses, context) that are NOT part of the question texts themselves. Often, this information can be in a previous \\item that is not itself a question, but contains the question items.
Extract important information necessary to understand the questions (e.g., definitions of objects, global notations, hypotheses, context) that are NOT part of the question texts themselves. Often, this information can be in a previous \\item that is not itself a question, but contains the question items.
For example, given LaTeX code like
@@ -148,7 +148,9 @@ def process_exam(folder_path: str, restart: bool = False):
folder = Path(folder_path)
cache_dir = folder / "Cache"
tmp_dir = folder / "Tmp"
cache_dir.mkdir(exist_ok=True)
tmp_dir.mkdir(exist_ok=True)
cache_q_file = cache_dir / "gemini_questions.json"
cache_s_file = cache_dir / "gemini_solutions.json"
@@ -341,8 +343,8 @@ def process_exam(folder_path: str, restart: bool = False):
# ==========================================
# INITIAL GROUPING COMPUTATION
# ==========================================
items_file = folder / "exam_items.txt"
full_items_file = folder / "exam_items_full.txt"
items_file = tmp_dir / "exam_items.txt"
full_items_file = tmp_dir / "exam_items_full.txt"
trunc_map = {}
# --- INITIAL GROUPING COMPUTATION ---
@@ -469,20 +471,7 @@ def process_exam(folder_path: str, restart: bool = False):
# --- OPEN EDITOR AND PARSE ---
while True:
print("Opening items file for editing...")
editor = os.environ.get("EDITOR")
try:
if editor:
subprocess.run(shlex.split(editor) + [str(items_file)])
else:
if sys.platform.startswith("linux"):
subprocess.run(["xdg-open", str(items_file)])
elif sys.platform == "darwin":
subprocess.run(["open", str(items_file)])
else:
os.startfile(str(items_file))
input("Press ENTER here once you have saved and closed the text file...")
except Exception as e:
print(f"Error running editor: {e}")
utils.edit_file_and_enter(items_file)
print(f"Parsing edited items from {items_file.name}...")
with open(items_file, "r", encoding="utf-8") as f:
+1
View File
@@ -180,6 +180,7 @@ def generate_request(file, labels, names, context_labels, wrong_labels):
parser = argparse.ArgumentParser(description="Process a directory or specific files using Gemini.")
parser.add_argument("input_paths", nargs='+', help="The input directory or specific files")
parser.add_argument("--overwrite", action="store_true", help="Regenerate output even if it exists")
args = parser.parse_args()
# input_arg = Path(args.input_path)
+18
View File
@@ -23,6 +23,24 @@ def enonce_total(base_dir):
return "".join(output)
import os
import shlex
def edit_file_and_enter(file):
editor = os.environ.get("EDITOR")
try:
if editor:
subprocess.run(shlex.split(editor) + [str(file)])
else:
if sys.platform.startswith("linux"):
subprocess.run(["xdg-open", str(file)])
elif sys.platform == "darwin":
subprocess.run(["open", str(file)])
else:
os.startfile(str(file))
input("Press ENTER here once you have saved and closed the text file...")
except Exception as e:
print(f"Error running editor: {e}")
def pdf_image_of_enonce(root_dir, label):
pdf_path = os.path.join(root_dir, "Text2", f"{label}.pdf")