small fixes
This commit is contained in:
+8
-6
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user