New file : config.py (for models)
This commit is contained in:
+15
-6
@@ -1,7 +1,7 @@
|
|||||||
#+title: Script
|
#+title: Script
|
||||||
#+author: Sébastien Miquel
|
#+author: Sébastien Miquel
|
||||||
#+date: 14-03-2026
|
#+date: 14-03-2026
|
||||||
# Time-stamp: <09-07-26 15:54>
|
# Time-stamp: <07-08-26 18:06>
|
||||||
#+OPTIONS:
|
#+OPTIONS:
|
||||||
|
|
||||||
* Méta
|
* Méta
|
||||||
@@ -67,13 +67,21 @@ Puis ajouter =GEMINI_API_KEY= à l'environnement avec :
|
|||||||
export GEMINI_API_KEY=…
|
export GEMINI_API_KEY=…
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
ou éventuellement, la renseigner directement dans le fichier
|
||||||
|
`config.py`.
|
||||||
|
|
||||||
|
** Configuration
|
||||||
|
|
||||||
|
Copier `default_config.py` en `config.py`. Éventuellement le modifier.
|
||||||
|
|
||||||
** Correction d'un paquet de copies
|
** Correction d'un paquet de copies
|
||||||
|
|
||||||
1. Créer un fichier =names= dans le dossier courant, avec les
|
1. Créer un fichier =names= dans le dossier courant, avec les
|
||||||
noms/prénoms des élèves, un par ligne
|
noms/prénoms des élèves, un par ligne
|
||||||
2. Créer un dossier correspondant à l'évaluation, comme =Interro=
|
2. Créer un dossier correspondant à l'évaluation (=Interro= dans la
|
||||||
|
suite)
|
||||||
3. Mettre l'énoncé, au format pdf, et l'énoncé et le corrigé au
|
3. Mettre l'énoncé, au format pdf, et l'énoncé et le corrigé au
|
||||||
format .tex dans le dossier.
|
format .tex dans le dossier.
|
||||||
4. Mettre les fichiers pdfs scannés dans =Interro=.
|
4. Mettre les fichiers pdfs scannés dans =Interro=.
|
||||||
5. Dans le dossier =Interro= créer un fichier =labels= avec les labels
|
5. Dans le dossier =Interro= créer un fichier =labels= avec les labels
|
||||||
des questions, comme =Ex 1 : 1)a)=, un par ligne.
|
des questions, comme =Ex 1 : 1)a)=, un par ligne.
|
||||||
@@ -107,9 +115,10 @@ export GEMINI_API_KEY=…
|
|||||||
|
|
||||||
** Prétraitement des copies
|
** Prétraitement des copies
|
||||||
|
|
||||||
1. =./rotate_all.sh Interro=
|
1. =./rotate_all.sh Interro= (facultatif)
|
||||||
(facultatif)
|
|
||||||
Retourne toutes les pdf de 180°
|
Retourne tous les pdf de 180°, si la photocopie a été faite à
|
||||||
|
l'envers.
|
||||||
2. =./rename_to_copie.sh Interro=
|
2. =./rename_to_copie.sh Interro=
|
||||||
change le nom des copies en =Copie{id}.pdf=
|
change le nom des copies en =Copie{id}.pdf=
|
||||||
3. =python page_splitter.py Interro=
|
3. =python page_splitter.py Interro=
|
||||||
|
|||||||
+5
-3
@@ -78,9 +78,11 @@ if PROXY_URL:
|
|||||||
os.environ["http_proxy"] = PROXY_URL
|
os.environ["http_proxy"] = PROXY_URL
|
||||||
os.environ["https_proxy"] = PROXY_URL
|
os.environ["https_proxy"] = PROXY_URL
|
||||||
|
|
||||||
MODEL_ID_pro = "gemini-3.1-pro-preview"
|
import config
|
||||||
MODEL_ID_flash = "gemini-3-flash-preview"
|
|
||||||
api_key = os.environ["GEMINI_API_KEY"]
|
MODEL_ID_pro = config.MODEL_PRO_ID
|
||||||
|
MODEL_ID_flash = config.MODEL_FLASH_ID
|
||||||
|
api_key = config.API_KEY
|
||||||
|
|
||||||
# --- Thread-safe Logging ---
|
# --- Thread-safe Logging ---
|
||||||
log_lock = threading.Lock()
|
log_lock = threading.Lock()
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
API_KEY = os.environ.get("GEMINI_API_KEY")
|
||||||
|
|
||||||
|
# Modèle pour des choses très légères
|
||||||
|
MODEL_LITE_ID = "gemini-3.5-flash-lite"
|
||||||
|
|
||||||
|
# Modèle pour des choses normales
|
||||||
|
MODEL_FLASH_ID = "gemini-3.6-flash"
|
||||||
|
|
||||||
|
# Modèle pour des choses dures
|
||||||
|
MODEL_PRO_ID = "gemini-3.6-flash"
|
||||||
|
# MODEL_PRO_ID = "gemini-3.1-pro-preview"
|
||||||
|
|
||||||
|
PAGE_SPLITTER_KB = {
|
||||||
|
"move_left": "<Left>",
|
||||||
|
"move_right": "<Right>",
|
||||||
|
"confirm_next": "<Return>",
|
||||||
|
"rotate_page": "r",
|
||||||
|
"rotate_all_pages": "R",
|
||||||
|
"rotate_all_files": ",",
|
||||||
|
"keep_left": "q",
|
||||||
|
"keep_right": "d",
|
||||||
|
"keep_as_is": "f",
|
||||||
|
"next_page": "s",
|
||||||
|
"discard_page": "z",
|
||||||
|
"send_end": "a", # Send this page to the end
|
||||||
|
"restart_file": "T",
|
||||||
|
"arranger": "A", # Call `pdf arranger` software, if available
|
||||||
|
"prev_file": "P",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PLOTTING_KB = {
|
||||||
|
"OK": "<Return>",
|
||||||
|
"previous": "p",
|
||||||
|
"edit": "e",
|
||||||
|
"open pdf": "o",
|
||||||
|
"open original pdf": "O",
|
||||||
|
"open eval": "i",
|
||||||
|
}
|
||||||
@@ -19,9 +19,10 @@ def get_lcp(s1: str, s2: str) -> str:
|
|||||||
return s1[:i]
|
return s1[:i]
|
||||||
|
|
||||||
|
|
||||||
# MODEL_ID = "gemini-3-flash-preview"
|
import config
|
||||||
MODEL_ID = "gemini-3.1-flash-lite"
|
|
||||||
api_key = os.environ.get("GEMINI_API_KEY")
|
MODEL_ID = config.MODEL_LITE_ID
|
||||||
|
api_key = config.API_KEY
|
||||||
|
|
||||||
# --- Modèles pour la Requête 1 ---
|
# --- Modèles pour la Requête 1 ---
|
||||||
class QuestionOnlyItem(BaseModel):
|
class QuestionOnlyItem(BaseModel):
|
||||||
|
|||||||
@@ -12,9 +12,10 @@ import argparse
|
|||||||
import re
|
import re
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
import config
|
||||||
|
|
||||||
MODEL_ID = "gemini-3-flash-preview"
|
MODEL_ID = config.MODEL_FLASH_ID
|
||||||
api_key = os.environ["GEMINI_API_KEY"]
|
api_key = config.API_KEY
|
||||||
|
|
||||||
my_prompt = """I'm giving you an image of the left columns of a written exam.
|
my_prompt = """I'm giving you an image of the left columns of a written exam.
|
||||||
Students answer several exercises, which can have several questions.
|
Students answer several exercises, which can have several questions.
|
||||||
|
|||||||
+50
-22
@@ -10,6 +10,9 @@ import shutil
|
|||||||
import subprocess
|
import subprocess
|
||||||
from pypdf import PdfReader, PdfWriter
|
from pypdf import PdfReader, PdfWriter
|
||||||
|
|
||||||
|
from config import PAGE_SPLITTER_KB
|
||||||
|
|
||||||
|
|
||||||
# --- Constants ---
|
# --- Constants ---
|
||||||
# Conversion factor: 1 cm to points (1 inch = 2.54 cm, 72 points = 1 inch)
|
# Conversion factor: 1 cm to points (1 inch = 2.54 cm, 72 points = 1 inch)
|
||||||
CM_TO_POINTS = (1 / 2.54) * 72
|
CM_TO_POINTS = (1 / 2.54) * 72
|
||||||
@@ -98,18 +101,21 @@ class PDFPreviewer:
|
|||||||
# Set a reasonable initial size for the window
|
# Set a reasonable initial size for the window
|
||||||
self.master.geometry("800x1000")
|
self.master.geometry("800x1000")
|
||||||
|
|
||||||
|
def fmt(action):
|
||||||
|
k = PAGE_SPLITTER_KB.get(action, "")
|
||||||
|
return k
|
||||||
|
|
||||||
|
# Dynamic instructions text
|
||||||
instructions = (
|
instructions = (
|
||||||
"← / → : Move line 1cm left/right\n"
|
f"{fmt('move_left')} / {fmt('move_right')} : Move line 1cm left/right\n"
|
||||||
"'c': Rotate page 180°, 'C' : rotate all pages, ',' : rotate all files\n"
|
f"'{fmt('rotate_page')}': Rotate page 180°, '{fmt('rotate_all_pages')}' : rotate all pages, '{fmt('rotate_all_files')}' : rotate all files\n"
|
||||||
"t s r n m: keep left, next page, keep none, keep right, keep as is\n"
|
f"{fmt('keep_left')} {fmt('next_page')} {fmt('discard_page')} {fmt('keep_right')} {fmt('keep_as_is')}: keep left, next page, keep none, keep right, keep as is\n"
|
||||||
"z: send this page to the end, 'A':pdf arranger 'R':restart file, 'P':back to previous file\n"
|
f"{fmt('send_end')}: send page to end, '{fmt('arranger')}': pdf arranger, '{fmt('restart_file')}': restart file, '{fmt('prev_file')}': previous file\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.info_label = tk.Label(master, text=instructions, justify=tk.LEFT)
|
self.info_label = tk.Label(master, text=instructions, justify=tk.LEFT)
|
||||||
self.info_label.pack(pady=5, side=tk.TOP)
|
self.info_label.pack(pady=5, side=tk.TOP)
|
||||||
|
|
||||||
# self.restart_btn = tk.Button(master, text="Restart File (R)", command=self.restart_current_file)
|
|
||||||
# self.restart_btn.pack(pady=2, side=tk.TOP)
|
|
||||||
|
|
||||||
self.page_label = tk.Label(master, text="", font=("Helvetica", 12))
|
self.page_label = tk.Label(master, text="", font=("Helvetica", 12))
|
||||||
self.page_label.pack(pady=5, side=tk.TOP)
|
self.page_label.pack(pady=5, side=tk.TOP)
|
||||||
|
|
||||||
@@ -118,21 +124,43 @@ class PDFPreviewer:
|
|||||||
self.canvas.pack(fill="both", expand=True)
|
self.canvas.pack(fill="both", expand=True)
|
||||||
|
|
||||||
# --- Bindings ---
|
# --- Bindings ---
|
||||||
self.master.bind("<Left>", self.move_line_left)
|
action_map = {
|
||||||
self.master.bind("<Right>", self.move_line_right)
|
"move_left": self.move_line_left,
|
||||||
self.master.bind("<Return>", self.confirm_and_next_page)
|
"move_right": self.move_line_right,
|
||||||
self.master.bind("c", self.rotate_page)
|
"confirm_next": self.confirm_and_next_page,
|
||||||
self.master.bind("C", self.rotate_all_pages)
|
"rotate_page": self.rotate_page,
|
||||||
self.master.bind(",", self.rotate_all_files)
|
"rotate_all_pages": self.rotate_all_pages,
|
||||||
self.master.bind("t", self.keep_left)
|
"rotate_all_files": self.rotate_all_files,
|
||||||
self.master.bind("n", self.keep_right)
|
"keep_left": self.keep_left,
|
||||||
self.master.bind("m", self.keep_as_is)
|
"keep_right": self.keep_right,
|
||||||
self.master.bind("s", self.confirm_and_next_page)
|
"keep_as_is": self.keep_as_is,
|
||||||
self.master.bind("r", self.discard_page)
|
"next_page": self.confirm_and_next_page,
|
||||||
self.master.bind("z", self.send_page_end)
|
"discard_page": self.discard_page,
|
||||||
self.master.bind("R", self.restart_current_file)
|
"send_end": self.send_page_end,
|
||||||
self.master.bind("A", self.start_arranger)
|
"restart_file": self.restart_current_file,
|
||||||
self.master.bind("P", self.go_to_previous_file)
|
"arranger": self.start_arranger,
|
||||||
|
"prev_file": self.go_to_previous_file,
|
||||||
|
}
|
||||||
|
|
||||||
|
for action, key in PAGE_SPLITTER_KB.items():
|
||||||
|
if action in action_map:
|
||||||
|
self.master.bind(key, action_map[action])
|
||||||
|
|
||||||
|
# self.master.bind("<Left>", self.move_line_left)
|
||||||
|
# self.master.bind("<Right>", self.move_line_right)
|
||||||
|
# self.master.bind("<Return>", self.confirm_and_next_page)
|
||||||
|
# self.master.bind("c", self.rotate_page)
|
||||||
|
# self.master.bind("C", self.rotate_all_pages)
|
||||||
|
# self.master.bind(",", self.rotate_all_files)
|
||||||
|
# self.master.bind("t", self.keep_left)
|
||||||
|
# self.master.bind("n", self.keep_right)
|
||||||
|
# self.master.bind("m", self.keep_as_is)
|
||||||
|
# self.master.bind("s", self.confirm_and_next_page)
|
||||||
|
# self.master.bind("r", self.discard_page)
|
||||||
|
# self.master.bind("z", self.send_page_end)
|
||||||
|
# self.master.bind("R", self.restart_current_file)
|
||||||
|
# self.master.bind("A", self.start_arranger)
|
||||||
|
# self.master.bind("P", self.go_to_previous_file)
|
||||||
|
|
||||||
|
|
||||||
# Bind the resize event on the canvas
|
# Bind the resize event on the canvas
|
||||||
|
|||||||
+8
-7
@@ -193,14 +193,15 @@ class ImageViewer:
|
|||||||
self.forward_stack = []
|
self.forward_stack = []
|
||||||
self.current_pil_image = None
|
self.current_pil_image = None
|
||||||
|
|
||||||
|
from config import PLOTTING_KB
|
||||||
|
|
||||||
# Bindings
|
# Bindings
|
||||||
self.root.bind('<Return>', self.on_enter)
|
self.root.bind(PLOTTING_KB["OK"], self.on_enter)
|
||||||
self.root.bind('p', self.on_previous)
|
self.root.bind(PLOTTING_KB["previous"], self.on_previous)
|
||||||
self.root.bind('e', self.on_edit)
|
self.root.bind(PLOTTING_KB["edit"], self.on_edit)
|
||||||
self.root.bind('o', self.on_open_pdf)
|
self.root.bind(PLOTTING_KB["open pdf"], self.on_open_pdf)
|
||||||
self.root.bind('i', self.on_open_interro)
|
self.root.bind(PLOTTING_KB["open originial pdf"], self.on_open_ori_pdf)
|
||||||
self.root.bind('O', self.on_open_ori_pdf)
|
self.root.bind(PLOTTING_KB["open eval"], self.on_open_interro)
|
||||||
self.root.bind('<Escape>', lambda e: self.root.quit())
|
self.root.bind('<Escape>', lambda e: self.root.quit())
|
||||||
self.label.bind('<Button-1>', self.on_click)
|
self.label.bind('<Button-1>', self.on_click)
|
||||||
|
|
||||||
@@ -279,7 +280,7 @@ class ImageViewer:
|
|||||||
|
|
||||||
if metadata.get("error"):
|
if metadata.get("error"):
|
||||||
msg = f"Error generating boxes for {json_path.name}:\n\n{metadata['error']}\n\nPlease press 'e' to fix the JSON file, then press Enter to retry."
|
msg = f"Error generating boxes for {json_path.name}:\n\n{metadata['error']}\n\nPlease press 'e' to fix the JSON file, then press Enter to retry."
|
||||||
messagebox.showerror("Processing Error", msg)
|
messagebox.showerror("Processing Error", msg)
|
||||||
|
|
||||||
def on_enter(self, event):
|
def on_enter(self, event):
|
||||||
if self.is_viewing:
|
if self.is_viewing:
|
||||||
|
|||||||
Reference in New Issue
Block a user