diff --git a/app/gen_op.py b/app/gen_op.py new file mode 100755 index 0000000..2045833 --- /dev/null +++ b/app/gen_op.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +import random +import io +from fpdf import FPDF + +def generer_nombre(): + """Génère un nombre naturel entre 1 et 9""" + return random.randint(1, 9) + +def evaluer_expression(expr): + """Évalue une expression mathématique en remplaçant × par *""" + try: + # Remplacer × par * pour l'évaluation + expr_eval = expr.replace('×', '*') + return eval(expr_eval) + except: + return -1 # En cas d'erreur, considérer comme négatif + +def generer_expression(): + """Génère une expression aléatoire respectant les contraintes""" + # On choisit aléatoirement un type d'expression (avec ou sans parenthèses) + # On vérifie que le résultat est positif + expressions_positives = [ + lambda: f"({generer_nombre()} + {generer_nombre()}) × {generer_nombre()} - {generer_nombre()}", + lambda: f"{generer_nombre()} + {generer_nombre()} × {generer_nombre()} - {generer_nombre()}", + lambda: f"({generer_nombre()} + {generer_nombre()}) × ({generer_nombre()} + {generer_nombre()})", + lambda: f"{generer_nombre()} + {generer_nombre()} × {generer_nombre()} - {generer_nombre()} + {generer_nombre()}", + lambda: f"({generer_nombre()} + {generer_nombre()}) × {generer_nombre()} - {generer_nombre()} + {generer_nombre()}", + lambda: f"{generer_nombre()} × {generer_nombre()} + {generer_nombre()} - {generer_nombre()} × {generer_nombre()}", + lambda: f"({generer_nombre()} + {generer_nombre()}) + {generer_nombre()} × {generer_nombre()} - {generer_nombre()}", + lambda: f"{generer_nombre()} + {generer_nombre()} × ({generer_nombre()} + {generer_nombre()}) - {generer_nombre()}", + lambda: f"({generer_nombre()} + {generer_nombre()}) + {generer_nombre()} × {generer_nombre()} - {generer_nombre()}", + lambda: f"{generer_nombre()} × ({generer_nombre()} + {generer_nombre()}) + {generer_nombre()} - {generer_nombre()}", + lambda: f"{generer_nombre()} + {generer_nombre()} × {generer_nombre()} - {generer_nombre()} × {generer_nombre()} + {generer_nombre()}", + lambda: f"({generer_nombre()} + {generer_nombre()}) × {generer_nombre()} - {generer_nombre()} + {generer_nombre()} - {generer_nombre()}", + ] + + # Essayer jusqu'à ce qu'on obtienne une expression avec résultat positif + while True: + choix = random.choice(expressions_positives) + expr = choix() + resultat = evaluer_expression(expr) + if resultat >= 0: + return expr + +def generer_feuille_exercices(n_exercices=20): + """Génère une feuille d'exercices en format 2 colonnes""" + expressions = [generer_expression() for _ in range(n_exercices)] + + # Format 2 colonnes : on affiche par paires + output = "" + for i in range(0, n_exercices, 2): + expr1 = f"{i+1}. {expressions[i]}" + expr2 = f"{i+2}. {expressions[i+1]}" if i+1 < len(expressions) else "" + # Alignement pour deux colonnes + output += f"{expr1:<36} {expr2}\n" + " " * 36 + " \n" * 3 + return output + +def generer_pdf_exercices_en_memoire(n_exercices=20): + """Génère une feuille d'exercices au format PDF en mémoire""" + pdf = FPDF() + pdf.add_page() + pdf.set_font("Helvetica", size=12) + + # Titre + pdf.cell(200, 10, text="Feuille d'exercices d'opérations", new_x="LMARGIN", new_y="NEXT", align='C') + pdf.ln(10) + + # Contenu en 2 colonnes + expressions = [generer_expression() for _ in range(n_exercices)] + + for i in range(0, n_exercices, 2): + # Colonne 1 + expr1 = f"{i+1}. {expressions[i]}" + pdf.cell(90, 10, text=expr1, border=0, align='L') + + # Colonne 2 + if i+1 < len(expressions): + expr2 = f"{i+2}. {expressions[i+1]}" + pdf.cell(90, 10, text=expr2, border=0, align='L') + pdf.ln(10) + + # Espacement supplémentaire - ajout de deux lignes vides supplémentaires + pdf.ln(15) + + # Retourner les données PDF en mémoire + return pdf.output() + +def generer_pdf_exercices(n_exercices=20, output_file="exercices.pdf"): + """Génère une feuille d'exercices au format PDF""" + pdf_data = generer_pdf_exercices_en_memoire(n_exercices) + + # Sauvegarde du PDF + with open(output_file, "wb") as f: + f.write(pdf_data) + return output_file diff --git a/app/main.py b/app/main.py index 9a4a5d3..23564c0 100644 --- a/app/main.py +++ b/app/main.py @@ -6,6 +6,7 @@ import io import boto3 import zipfile import tempfile +import importlib.util from botocore.exceptions import ClientError from typing import List from fastapi import FastAPI, Request, Form @@ -16,6 +17,9 @@ from fpdf import FPDF import logging +# Import the functions from gen_op.py +from app.gen_op import generer_pdf_exercices_en_memoire + # Custom filter to exclude health check logs class HealthCheckFilter(logging.Filter): def filter(self, record: logging.LogRecord) -> bool: @@ -163,6 +167,9 @@ class ExerciseRequest(BaseModel): max_table: int num_exercises: int = 15 +class OperationExerciseRequest(BaseModel): + num_exercises: int = 20 + def generate_exercises( min_table: int, max_table: int, num_exercises: int = 15 @@ -305,6 +312,26 @@ def create_math_exercises_pdf( return pdf_filename +def create_operation_exercises_pdf(num_exercises: int = 20) -> str: + """Crée un fichier PDF avec des exercices d'opérations et l'upload sur S3""" + import datetime + + # Add timestamp to filename + timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") + pdf_filename = f"exercices_operations_{num_exercises}_exercices_{timestamp}.pdf" + + # Generate PDF in memory using gen-op functions + pdf_data = generer_pdf_exercices_en_memoire(num_exercises) + + # Upload to S3 + upload_success = upload_to_s3(pdf_data, S3_BUCKET_NAME, pdf_filename, "application/pdf") + + if not upload_success: + raise Exception("Failed to upload PDF to S3") + + return pdf_filename + + @app.get("/", response_class=HTMLResponse) async def read_root(request: Request): return templates.TemplateResponse("index.html", {"request": request}) @@ -333,6 +360,21 @@ async def generate_exercises_endpoint(request: ExerciseRequest): return {"error": f"Erreur lors de la création du PDF: {str(e)}"} +@app.post("/generate-operations") +async def generate_operation_exercises_endpoint(request: OperationExerciseRequest): + try: + if request.num_exercises < 1: + return {"error": "Le nombre d'exercices doit être supérieur à 0"} + + pdf_filename = create_operation_exercises_pdf(request.num_exercises) + + # Return redirect to automatically download the file + return RedirectResponse(url=f"/download/{pdf_filename}", status_code=303) + + except Exception as e: + return {"error": f"Erreur lors de la création du PDF: {str(e)}"} + + @app.get("/download/{filename}") async def download_pdf(filename: str): # Download file from S3 diff --git a/app/templates/index.html b/app/templates/index.html index c4136bf..0e7c146 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -33,14 +33,15 @@
Créez des exercices de multiplication et division personnalisés en PDF
+Créez des exercices de multiplication, division et opérations complexes personnalisés en PDF
Les exercices sont présentés en trois colonnes pour économiser du papier.
+Les exercices de multiplication/division sont présentés en trois colonnes, les opérations complexes en deux colonnes.
+Générez des exercices avec des expressions mathématiques complexes incluant parenthèses, additions, soustractions et multiplications.
+Tous les fichiers générés sont automatiquement stockés dans le cloud et peuvent être téléchargés ultérieurement.
Le téléchargement devrait commencer automatiquement.
+