Spaces:
Build error
Build error
| import os | |
| import gradio as gr | |
| import google.generativeai as genai | |
| from pdf2image import convert_from_path | |
| import json | |
| # --- 1. CONFIGURATION --- | |
| # Récupération de la clé API depuis les secrets de Hugging Face | |
| api_key = os.environ.get("GOOGLE_API_KEY") | |
| if not api_key: | |
| raise ValueError("La clé API 'GOOGLE_API_KEY' n'est pas définie dans les Secrets du Space.") | |
| genai.configure(api_key=api_key) | |
| # On utilise le modèle Flash, très rapide et excellent pour la lecture de documents | |
| model = genai.GenerativeModel('gemini-1.5-flash') | |
| # --- 2. FONCTIONS DU BACKEND --- | |
| def analyze_pdf_content(pdf_file): | |
| """ | |
| Étape 1 : Convertit le PDF en images et demande à Gemini d'extraire TOUTES les données. | |
| """ | |
| if pdf_file is None: | |
| return None, "Veuillez d'abord uploader un fichier PDF." | |
| try: | |
| # Conversion du PDF en liste d'images (une par page) | |
| # Sur Hugging Face, poppler est installé via packages.txt | |
| pages = convert_from_path(pdf_file) | |
| # Le prompt demande une extraction structurée JSON | |
| prompt = """ | |
| Tu es un assistant administratif expert. Analyse ce document (qui est probablement un registre de commerce RCCM ou similaire). | |
| Tâche : | |
| 1. Lis TOUTES les pages fournies sous forme d'images. | |
| 2. Extrais TOUS les champs (clés) et leurs valeurs correspondantes. | |
| 3. Inclus des champs comme : DENOMINATION, SIGLE, FORME JURIDIQUE, CAPITAL SOCIAL, ADRESSE, ACTIVITE PRINCIPALE, NUMERO RCCM, DIRIGEANTS, etc. | |
| Format de sortie OBLIGATOIRE : | |
| Uniquement un objet JSON valide (clé: valeur). | |
| - Normalise les clés en MAJUSCULES (ex: "DENOMINATION" au lieu de "Dénomination"). | |
| - Si une valeur est vide, mets null. | |
| - Ne mets pas de balises markdown ```json ... ```, juste le texte brut du JSON. | |
| """ | |
| # Envoi de toutes les pages + le prompt au modèle | |
| inputs = [prompt] + pages | |
| response = model.generate_content(inputs) | |
| # Nettoyage de la réponse pour garantir un JSON valide | |
| cleaned_text = response.text.replace("```json", "").replace("```", "").strip() | |
| # Conversion du texte en dictionnaire Python | |
| data_json = json.loads(cleaned_text) | |
| return data_json, "✅ Analyse terminée ! Le document a été lu. Vous pouvez maintenant poser vos questions ci-dessous." | |
| except Exception as e: | |
| return None, f"❌ Erreur lors de l'analyse : {str(e)}" | |
| def get_value_from_key(json_data, key_request): | |
| """ | |
| Étape 2 : Cherche la valeur demandée par l'utilisateur dans le JSON extrait. | |
| """ | |
| if not json_data: | |
| return "Erreur : Aucune donnée analysée. Veuillez d'abord cliquer sur 'Analyser le Document'." | |
| if not key_request: | |
| return "Veuillez entrer une clé (ex: Forme Juridique)." | |
| # Normalisation pour la recherche (tout mettre en majuscule) | |
| search_key = key_request.upper().strip() | |
| # 1. Recherche exacte | |
| if search_key in json_data: | |
| return json_data[search_key] | |
| # 2. Recherche partielle (si l'utilisateur tape "Capital" pour "CAPITAL SOCIAL") | |
| found_keys = [k for k in json_data.keys() if search_key in k] | |
| if found_keys: | |
| # On retourne la première correspondance trouvée + le nom de la clé réelle | |
| best_match = found_keys[0] | |
| return f"{json_data[best_match]} (Clé trouvée : {best_match})" | |
| return "⚠️ Clé introuvable. Vérifiez l'orthographe ou consultez les 'Données Brutes' pour voir les clés disponibles." | |
| # --- 3. INTERFACE GRADIO --- | |
| with gr.Blocks(title="Extracteur PDF Gemini") as demo: | |
| gr.Markdown("# 📑 Extracteur de Données PDF (RCCM & Contrats)") | |
| gr.Markdown("Uploadez un PDF, laissez l'IA le lire, puis demandez la valeur de n'importe quel champ.") | |
| with gr.Row(): | |
| # Colonne de gauche : Import et Analyse | |
| with gr.Column(scale=1): | |
| pdf_input = gr.File(label="1. Déposer votre PDF ici", file_count="single", type="filepath") | |
| analyze_btn = gr.Button("🚀 Lancer l'analyse du document", variant="primary") | |
| status_output = gr.Textbox(label="Statut de l'analyse", interactif=False) | |
| # Composant invisible pour stocker le JSON extrait | |
| json_state = gr.State() | |
| # Colonne de droite : Interrogation | |
| with gr.Column(scale=1): | |
| key_input = gr.Textbox(label="2. Quelle info cherchez-vous ?", placeholder="Ex: DENOMINATION, ADRESSE, CAPITAL...") | |
| get_val_btn = gr.Button("🔍 Obtenir la valeur") | |
| final_output = gr.Textbox(label="Résultat", lines=2, show_copy_button=True) | |
| with gr.Accordion("Voir toutes les données extraites (JSON)", open=False): | |
| json_display = gr.JSON(label="Données brutes") | |
| # --- LOGIQUE DES ÉVÉNEMENTS --- | |
| # Quand on clique sur Analyser | |
| analyze_btn.click( | |
| fn=analyze_pdf_content, | |
| inputs=[pdf_input], | |
| outputs=[json_state, status_output] | |
| ).then( | |
| # Mise à jour de l'affichage JSON brut une fois l'analyse finie | |
| fn=lambda x: x, inputs=[json_state], outputs=[json_display] | |
| ) | |
| # Quand on demande une clé spécifique | |
| get_val_btn.click( | |
| fn=get_value_from_key, | |
| inputs=[json_state, key_input], | |
| outputs=[final_output] | |
| ) | |
| # Lancement de l'application | |
| if __name__ == "__main__": | |
| demo.launch() |