diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f1b13c3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*~ +*.xlsx +__pycache__/ diff --git a/Dockerfile~ b/Dockerfile~ deleted file mode 100644 index d427097..0000000 --- a/Dockerfile~ +++ /dev/null @@ -1,21 +0,0 @@ -# On part d'une version légère de Python -FROM python:3.9-slim - -# On se met dans un dossier de travail -WORKDIR /app - -# On installe les dépendances système (nécessaire parfois pour pdfplumber/images) -RUN apt-get update && apt-get install -y libgl1-mesa-glx && rm -rf /var/lib/apt/lists/* - -# On copie les requirements et on installe -COPY requirements.txt . -RUN pip install --no-cache-dir -r requirements.txt - -# On copie le code -COPY webapp.py . - -# On expose le port 5000 -EXPOSE 5000 - -# La commande de démarrage -CMD ["python", "webapp.py"] \ No newline at end of file diff --git a/webapp.py~ b/webapp.py~ deleted file mode 100644 index 0d36071..0000000 --- a/webapp.py~ +++ /dev/null @@ -1,277 +0,0 @@ -import os -import io -import pandas as pd -import pdfplumber -from flask import Flask, request, render_template_string, Response, send_from_directory - -app = Flask(__name__) - -# Dossier temporaire pour stocker le fichier généré à l'intérieur du conteneur -TEMP_DIR = "/app/downloads" -if not os.path.exists(TEMP_DIR): - os.makedirs(TEMP_DIR) - -# --- DESIGN HTML & JAVASCRIPT --- -# Ce bloc est envoyé en premier au navigateur pour préparer l'interface de log -HTML_LAYOUT = """ - - - - - - Extracteur PDF - Progression en direct - - - -
-

Analyse du catalogue en cours...

-

Chaque page du fichier est analysée pour extraire les fiches de formation.

- -
- -
- > Initialisation du moteur d'extraction...
-
- - -
- - -""" - -# --- PAGE D'ACCUEIL --- -@app.route("/") -def home(): - return render_template_string(""" - - - - - - Extracteur de formations - - - -
-
📄
-

Extracteur PDF

-

Sélectionnez le catalogue de formations (PDF) pour extraire les données vers Excel.

- -
-
- - -
- - -
-
- - - - - """) - -# --- MOTEUR D'EXTRACTION --- -@app.route("/process", methods=["POST"]) -def process(): - file = request.files['pdf_file'] - if not file: return "Fichier manquant" - - file_content = file.read() # On garde le fichier en mémoire vive - - def generate(): - yield HTML_LAYOUT # Envoie l'interface au navigateur - - all_formations = [] - COLONNES_ADMISES = ["Référence", "Durée", "Type", "Publics éligibles", "Niveau", "Sessions", "Tarifs"] - - try: - with pdfplumber.open(io.BytesIO(file_content)) as pdf: - total_pages = len(pdf.pages) - yield f"" - - for i, page in enumerate(pdf.pages): - page_num = i + 1 - percent = int((page_num / total_pages) * 100) - - try: - # Zone de détection (haut de page) - check_zone = page.crop((page.width * 0.5, 0, page.width, 400)) - text = check_zone.extract_text() or "" - - if "Référence" in text: - # --- EXTRACTION DE LA FICHE --- - header = page.crop((0, 0, page.width, 100)) - titre_brut = header.extract_text().split('\n')[0].strip() - # Sécurisation du titre pour JS (on enlève les quotes) - titre_clean = titre_brut.replace("'", "").replace('"', '').strip()[:60] - - data = {'Titre': titre_brut, 'Page_Source': page_num} - - # Extraction du tableau à droite - right_side = page.crop((page.width * 0.6, 180, page.width, 600)) - table = right_side.extract_table() - if table: - for row in table: - if len(row) >= 2 and row[0]: - cle = row[0].replace('\n', ' ').strip() - for col in COLONNES_ADMISES: - if col.lower() in cle.lower(): - data[col] = row[1].replace('\n', ' ').strip() - break - - all_formations.append(data) - yield f"" - - else: - # --- PAGE IGNORÉE --- - yield f"" - - except Exception as page_err: - yield f"" - - # --- FIN DE BOUCLE : SAUVEGARDE EXCEL --- - yield f"" - - if all_formations: - df = pd.DataFrame(all_formations) - output_path = os.path.join(TEMP_DIR, "resultat.xlsx") - # On utilise xlsxwriter pour la stabilité - df.to_excel(output_path, index=False, engine='xlsxwriter') - yield f"" - yield "" - else: - yield f"" - - except Exception as global_err: - yield f"" - - yield "" - - return Response(generate(), mimetype='text/html') - -# --- TÉLÉCHARGEMENT --- -@app.route("/download") -def download(): - return send_from_directory(TEMP_DIR, "resultat.xlsx", as_attachment=True) - -if __name__ == "__main__": - # Écoute sur 0.0.0.0 pour Docker - app.run(host='0.0.0.0', port=5000, debug=False)