Spaces:
Build error
Build error
File size: 5,505 Bytes
802bc1f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | 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() |