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