This commit is contained in:
2026-06-06 22:09:00 +02:00
parent a80187ba80
commit 27c0dae20e
9 changed files with 315 additions and 69 deletions
+90 -23
View File
@@ -1,4 +1,6 @@
import shlex
import os
import subprocess
import sys
import argparse
from pathlib import Path
@@ -7,7 +9,9 @@ from typing import List
from google import genai
from google.genai import types
MODEL_ID = "gemini-3-flash-preview"
# Bug : l'output est limité à 8k token…
# MODEL_ID = "gemini-3-flash-preview"
MODEL_ID = "gemini-3.1-flash-lite"
api_key = os.environ.get("GEMINI_API_KEY")
class QuestionItem(BaseModel):
@@ -84,14 +88,25 @@ def process_exam(folder_path: str):
response_json_schema=ExamExtraction.model_json_schema(),
)
print("Sending request to Gemini...")
response = client.models.generate_content(
model=MODEL_ID,
contents=contents,
config=config
)
cache_file = folder / "gemini_response.json"
extracted_data = ExamExtraction.model_validate_json(response.text)
if cache_file.is_file():
print("Loading cached response from gemini_response.json...")
response_text = cache_file.read_text(encoding="utf-8")
else:
print("Sending request to Gemini...")
response = client.models.generate_content(
model=MODEL_ID,
contents=contents,
config=config
)
response_text = response.text
print("Saving response to cache...")
cache_file.write_text(response_text, encoding="utf-8")
# Validate from the text variable (cached or fresh)
extracted_data = ExamExtraction.model_validate_json(response_text)
# 2. Setup output directories
text_dir = folder / "Text"
@@ -101,28 +116,80 @@ def process_exam(folder_path: str):
labels_file = folder / "labels"
print("Writing files...")
# Step 1: Write initial labels
print("Writing initial labels file...")
with open(labels_file, "w", encoding="utf-8") as flabels:
for q in extracted_data.questions:
# Sanitize label for filesystem (prevent directory traversal if label contains '/')
safe_label = q.label.replace("/", "_")
flabels.write(f"{q.label}\n")
flabels.write(f"{safe_label}\n")
# Step 2: Open labels file for user editing
print("Opening labels file for editing...")
editor = os.environ.get("EDITOR")
try:
if editor:
subprocess.run(shlex.split(editor) + [str(labels_file)])
else:
# Fallbacks if $EDITOR is not set
if sys.platform.startswith("linux"):
subprocess.Popen(["xdg-open", str(labels_file)])
elif sys.platform == "darwin":
subprocess.Popen(["open", str(labels_file)])
else:
os.startfile(str(labels_file))
# Fix double-escaped newlines
q_content = q.question_content.replace("\\n", "\n")
s_content = q.solution_content.replace("\\n", "\n")
# xdg-open/open usually do not block, so we wait for user confirmation
input("Press ENTER here once you have saved and closed the labels file...")
except Exception:
print("Error running editor, using labels as given.")
# Write Text/label
with open(text_dir / safe_label, "w", encoding="utf-8") as f:
f.write(f"{q.label}\n{q.question_content}")
# Step 3 & 4: Read the edited file back and create a mapping
with open(labels_file, "r", encoding="utf-8") as flabels:
edited_lines = [line.strip() for line in flabels if line.strip()]
# Write Sol/label
with open(sol_dir / safe_label, "w", encoding="utf-8") as f:
f.write(f"{q.label}\n{q.solution_content}")
mapping = []
final_labels = []
orig_idx = 0
print(f"Success! Processed {len(extracted_data.questions)} questions.")
for line in edited_lines:
if line.startswith("+"):
new_label = line[1:].lstrip()
final_labels.append(new_label)
# New label, no source content
mapping.append((new_label, None))
else:
new_label = line
final_labels.append(new_label)
# Map to initial order, advancing index only for non-'+' items
q_item = extracted_data.questions[orig_idx] if orig_idx < len(extracted_data.questions) else None
mapping.append((new_label, q_item))
orig_idx += 1
# Rewrite the labels file cleanly (removing '+' prefixes)
with open(labels_file, "w", encoding="utf-8") as flabels:
for lbl in final_labels:
flabels.write(f"{lbl}\n")
# Step 5: Write the final question and solution files
print("Writing question and solution files...")
for new_label, q_item in mapping:
safe_label = new_label.replace("/", "_")
if q_item:
q_content = q_item.question_content.replace("\\n", "\n")
s_content = q_item.solution_content.replace("\\n", "\n")
else:
q_content = ""
s_content = ""
# Write Text/label
with open(text_dir / safe_label, "w", encoding="utf-8") as f:
f.write(f"{new_label}\n{q_content}")
# Write Sol/label
with open(sol_dir / safe_label, "w", encoding="utf-8") as f:
f.write(f"{new_label}\n{s_content}")
print(f"Success! Processed {len(mapping)} labels.")
if __name__ == "__main__":
if not api_key: