Enonce info : generate pdf per question/solution

master
Sébastien Miquel 2026-04-24 08:22:42 +02:00
parent dd0d757fc9
commit 95e944f983
2 changed files with 102 additions and 17 deletions

View File

@ -4,6 +4,83 @@ import glob
import json import json
import urllib.request import urllib.request
import re import re
import subprocess
import tempfile
import shutil
def compile_to_pdf(text, output_pdf_path):
"""Wraps text in a standalone template and compiles it to PDF."""
latex_template = f"""\\documentclass[varwidth=21cm,margin=0.2cm]{{standalone}}
\\usepackage[utf8]{{inputenc}}
\\usepackage[T1]{{fontenc}}
\\usepackage{{lmodern}}
\\usepackage{{amsmath, amssymb}}
\\usepackage{{commands}}
\\usepackage{{enumitem}}
\\begin{{document}}
{text}
\\end{{document}}
"""
with tempfile.TemporaryDirectory() as temp_dir:
tex_filename = 'text.tex'
pdf_filename = 'text.pdf'
tex_path = os.path.join(temp_dir, tex_filename)
with open(tex_path, 'w', encoding='utf-8') as f:
f.write(latex_template)
# Set TEXINPUTS so pdflatex can find commands.sty if it's in the current dir
# env = os.environ.copy()
# current_dir = os.getcwd()
# env['TEXINPUTS'] = f".:{current_dir}:"
try:
subprocess.run(
['pdflatex', '-interaction=nonstopmode', tex_filename],
cwd=temp_dir,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
check=False
)
generated_pdf = os.path.join(temp_dir, pdf_filename)
if os.path.exists(generated_pdf):
shutil.move(generated_pdf, output_pdf_path)
except Exception as e:
print(f"Compilation error for {output_pdf_path}: {e}")
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}"
try:
with urllib.request.urlopen(url) as response:
content = response.read().decode('utf-8')
content = replace_dots(content.strip("\n"))
with open(os.path.join(text_path, f"{label}.tex"), 'w', encoding='utf-8') as f:
f.write(content)
# Compile PDF
pdf_file = os.path.join(text_path, f"{label}.pdf")
compile_to_pdf(content, pdf_file)
except Exception as e:
print(f"Error fetching sub-text from {url}: {e}")
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}"
try:
with urllib.request.urlopen(url) as response:
content = response.read().decode('utf-8')
content = replace_dots(content.strip("\n"))
with open(os.path.join(sol_path, f"{label}.tex"), 'w', encoding='utf-8') as f:
f.write(content)
# Compile PDF
pdf_file = os.path.join(sol_path, f"{label}.pdf")
compile_to_pdf(content, pdf_file)
except Exception as e:
print(f"Error fetching sub-text from {url}: {e}")
ROMANS_CAP = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"] ROMANS_CAP = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"]
ROMANS_LOW = ["", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x"] ROMANS_LOW = ["", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x"]
@ -55,6 +132,7 @@ def save_split_content(text, path, base_fname, problem):
with open(os.path.join(path, base_fname), 'w', encoding='utf-8') as f: with open(os.path.join(path, base_fname), 'w', encoding='utf-8') as f:
f.write(text) f.write(text)
pattern = re.compile(r"(?m)^([ \t]+)([a-zA-Z0-9]+)\)") pattern = re.compile(r"(?m)^([ \t]+)([a-zA-Z0-9]+)\)")
all_matches = list(pattern.finditer(text)) all_matches = list(pattern.finditer(text))
@ -80,6 +158,7 @@ def save_split_content(text, path, base_fname, problem):
with open(os.path.join(path, sub_fname), 'w', encoding='utf-8') as f: with open(os.path.join(path, sub_fname), 'w', encoding='utf-8') as f:
f.write(chunk) f.write(chunk)
def process_directory(directory): def process_directory(directory):
# Find the first .tex file in the directory # Find the first .tex file in the directory
tex_files = glob.glob(os.path.join(directory, "*.tex")) tex_files = glob.glob(os.path.join(directory, "*.tex"))
@ -124,24 +203,10 @@ def process_directory(directory):
# Check if text until next SHEETINFO block contains \Roman # Check if text until next SHEETINFO block contains \Roman
problem = r"\Roman" in block_content problem = r"\Roman" in block_content
if not json_str: if not json_str: continue
continue
try: try:
data = json.loads(json_str) data = json.loads(json_str)
# 2. Handle Labels
indexes = data.get('indexes', [])
if not indexes:
f_labels.write(f"Ex {current_ex_num}\n")
else:
for item in indexes:
suffix = format_indices(item['indices'], problem)
if suffix != "":
f_labels.write(f"Ex {current_ex_num} : {suffix}\n")
else:
f_labels.write(f"Ex {current_ex_num}\n")
# Construct 'ids' parameter # Construct 'ids' parameter
ex_id = str(data['id']) ex_id = str(data['id'])
selection = data.get('select') selection = data.get('select')
@ -152,10 +217,27 @@ def process_directory(directory):
else: else:
ids = ex_id ids = ex_id
# 2. Handle Labels
indexes = data.get('indexes', [])
if not indexes:
label = f"Ex {current_ex_num}"
f_labels.write(f"{label}\n")
fetch_and_save_sub_text(ids, [], label, paths['Text'])
fetch_and_save_sub_sol(ids, [], label, paths['Sol'])
else:
for item in indexes:
suffix = format_indices(item['indices'], problem)
label = f"Ex {current_ex_num}" + (f" : {suffix}" if suffix else "")
f_labels.write(f"{label}\n")
fetch_and_save_sub_text(ids, item['indices'], label, paths['Text'])
fetch_and_save_sub_sol(ids, item['indices'], label, paths['Sol'])
# Construct URL (append pb=true if \Roman matched) # Construct URL (append pb=true if \Roman matched)
url = f"http://localhost:8080/exercices/emacs/{ids}?pretty=true&all=true&persp=true" url = f"http://localhost:8080/exercices/emacs/{ids}?pretty=true&all=true&persp=true"
if problem: # if problem:
url += "&pb=true" # url += "&pb=true"
# Perform GET request # Perform GET request
with urllib.request.urlopen(url) as response: with urllib.request.urlopen(url) as response:

View File

@ -1387,6 +1387,7 @@ ardu
are are
arène arène
arête arête
arêtes
argent argent
argenterie argenterie
argile argile
@ -19270,6 +19271,7 @@ suppléer
supplément supplément
supplémentaire supplémentaire
supplémentaires supplémentaires
supplémentarité
suppliant suppliant
supplication supplication
supplice supplice
@ -19778,6 +19780,7 @@ théoriciens
théorie théorie
théories théories
théorique théorique
théorème
théoriquement théoriquement
théoriques théoriques
thérapeutique thérapeutique