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()