kebson commited on
Commit
802bc1f
·
verified ·
1 Parent(s): 8ef23e0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +137 -0
app.py CHANGED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import google.generativeai as genai
4
+ from pdf2image import convert_from_path
5
+ import json
6
+
7
+ # --- 1. CONFIGURATION ---
8
+ # Récupération de la clé API depuis les secrets de Hugging Face
9
+ api_key = os.environ.get("GOOGLE_API_KEY")
10
+
11
+ if not api_key:
12
+ raise ValueError("La clé API 'GOOGLE_API_KEY' n'est pas définie dans les Secrets du Space.")
13
+
14
+ genai.configure(api_key=api_key)
15
+
16
+ # On utilise le modèle Flash, très rapide et excellent pour la lecture de documents
17
+ model = genai.GenerativeModel('gemini-1.5-flash')
18
+
19
+ # --- 2. FONCTIONS DU BACKEND ---
20
+
21
+ def analyze_pdf_content(pdf_file):
22
+ """
23
+ Étape 1 : Convertit le PDF en images et demande à Gemini d'extraire TOUTES les données.
24
+ """
25
+ if pdf_file is None:
26
+ return None, "Veuillez d'abord uploader un fichier PDF."
27
+
28
+ try:
29
+ # Conversion du PDF en liste d'images (une par page)
30
+ # Sur Hugging Face, poppler est installé via packages.txt
31
+ pages = convert_from_path(pdf_file)
32
+
33
+ # Le prompt demande une extraction structurée JSON
34
+ prompt = """
35
+ Tu es un assistant administratif expert. Analyse ce document (qui est probablement un registre de commerce RCCM ou similaire).
36
+
37
+ Tâche :
38
+ 1. Lis TOUTES les pages fournies sous forme d'images.
39
+ 2. Extrais TOUS les champs (clés) et leurs valeurs correspondantes.
40
+ 3. Inclus des champs comme : DENOMINATION, SIGLE, FORME JURIDIQUE, CAPITAL SOCIAL, ADRESSE, ACTIVITE PRINCIPALE, NUMERO RCCM, DIRIGEANTS, etc.
41
+
42
+ Format de sortie OBLIGATOIRE :
43
+ Uniquement un objet JSON valide (clé: valeur).
44
+ - Normalise les clés en MAJUSCULES (ex: "DENOMINATION" au lieu de "Dénomination").
45
+ - Si une valeur est vide, mets null.
46
+ - Ne mets pas de balises markdown ```json ... ```, juste le texte brut du JSON.
47
+ """
48
+
49
+ # Envoi de toutes les pages + le prompt au modèle
50
+ inputs = [prompt] + pages
51
+ response = model.generate_content(inputs)
52
+
53
+ # Nettoyage de la réponse pour garantir un JSON valide
54
+ cleaned_text = response.text.replace("```json", "").replace("```", "").strip()
55
+
56
+ # Conversion du texte en dictionnaire Python
57
+ data_json = json.loads(cleaned_text)
58
+
59
+ return data_json, "✅ Analyse terminée ! Le document a été lu. Vous pouvez maintenant poser vos questions ci-dessous."
60
+
61
+ except Exception as e:
62
+ return None, f"❌ Erreur lors de l'analyse : {str(e)}"
63
+
64
+ def get_value_from_key(json_data, key_request):
65
+ """
66
+ Étape 2 : Cherche la valeur demandée par l'utilisateur dans le JSON extrait.
67
+ """
68
+ if not json_data:
69
+ return "Erreur : Aucune donnée analysée. Veuillez d'abord cliquer sur 'Analyser le Document'."
70
+
71
+ if not key_request:
72
+ return "Veuillez entrer une clé (ex: Forme Juridique)."
73
+
74
+ # Normalisation pour la recherche (tout mettre en majuscule)
75
+ search_key = key_request.upper().strip()
76
+
77
+ # 1. Recherche exacte
78
+ if search_key in json_data:
79
+ return json_data[search_key]
80
+
81
+ # 2. Recherche partielle (si l'utilisateur tape "Capital" pour "CAPITAL SOCIAL")
82
+ found_keys = [k for k in json_data.keys() if search_key in k]
83
+
84
+ if found_keys:
85
+ # On retourne la première correspondance trouvée + le nom de la clé réelle
86
+ best_match = found_keys[0]
87
+ return f"{json_data[best_match]} (Clé trouvée : {best_match})"
88
+
89
+ return "⚠️ Clé introuvable. Vérifiez l'orthographe ou consultez les 'Données Brutes' pour voir les clés disponibles."
90
+
91
+ # --- 3. INTERFACE GRADIO ---
92
+
93
+ with gr.Blocks(title="Extracteur PDF Gemini") as demo:
94
+ gr.Markdown("# 📑 Extracteur de Données PDF (RCCM & Contrats)")
95
+ gr.Markdown("Uploadez un PDF, laissez l'IA le lire, puis demandez la valeur de n'importe quel champ.")
96
+
97
+ with gr.Row():
98
+ # Colonne de gauche : Import et Analyse
99
+ with gr.Column(scale=1):
100
+ pdf_input = gr.File(label="1. Déposer votre PDF ici", file_count="single", type="filepath")
101
+ analyze_btn = gr.Button("🚀 Lancer l'analyse du document", variant="primary")
102
+ status_output = gr.Textbox(label="Statut de l'analyse", interactif=False)
103
+
104
+ # Composant invisible pour stocker le JSON extrait
105
+ json_state = gr.State()
106
+
107
+ # Colonne de droite : Interrogation
108
+ with gr.Column(scale=1):
109
+ key_input = gr.Textbox(label="2. Quelle info cherchez-vous ?", placeholder="Ex: DENOMINATION, ADRESSE, CAPITAL...")
110
+ get_val_btn = gr.Button("🔍 Obtenir la valeur")
111
+ final_output = gr.Textbox(label="Résultat", lines=2, show_copy_button=True)
112
+
113
+ with gr.Accordion("Voir toutes les données extraites (JSON)", open=False):
114
+ json_display = gr.JSON(label="Données brutes")
115
+
116
+ # --- LOGIQUE DES ÉVÉNEMENTS ---
117
+
118
+ # Quand on clique sur Analyser
119
+ analyze_btn.click(
120
+ fn=analyze_pdf_content,
121
+ inputs=[pdf_input],
122
+ outputs=[json_state, status_output]
123
+ ).then(
124
+ # Mise à jour de l'affichage JSON brut une fois l'analyse finie
125
+ fn=lambda x: x, inputs=[json_state], outputs=[json_display]
126
+ )
127
+
128
+ # Quand on demande une clé spécifique
129
+ get_val_btn.click(
130
+ fn=get_value_from_key,
131
+ inputs=[json_state, key_input],
132
+ outputs=[final_output]
133
+ )
134
+
135
+ # Lancement de l'application
136
+ if __name__ == "__main__":
137
+ demo.launch()