devalender commited on
Commit
6dc83fe
·
verified ·
1 Parent(s): faa46a0

Delete app2

Browse files
Files changed (1) hide show
  1. app2 +0 -175
app2 DELETED
@@ -1,175 +0,0 @@
1
- import gradio as gr
2
- import fitz # PyMuPDF
3
- import base64
4
- import os
5
- import re
6
- from io import BytesIO
7
- from PIL import Image
8
- from huggingface_hub import InferenceClient
9
-
10
- # ─── Config ───────────────────────────────────────────────────────────────────
11
- MODEL_ID = "google/gemma-4-E4B-it" # multimodal, léger, parfait pour cette tâche
12
- HF_TOKEN = os.environ.get("HF_TOKEN") # défini en secret dans HF Spaces
13
-
14
- # ─── Helpers ──────────────────────────────────────────────────────────────────
15
-
16
- def pdf_first_page_to_base64(pdf_path: str) -> tuple[str, Image.Image]:
17
- """Extrait la première page du PDF et retourne image base64 + PIL Image."""
18
- doc = fitz.open(pdf_path)
19
- page = doc[0]
20
- # Rendu à 150 DPI — assez pour lire, assez léger pour l'API
21
- mat = fitz.Matrix(150 / 72, 150 / 72)
22
- pix = page.get_pixmap(matrix=mat)
23
- doc.close()
24
-
25
- img_bytes = pix.tobytes("png")
26
- b64 = base64.b64encode(img_bytes).decode("utf-8")
27
- pil_img = Image.open(BytesIO(img_bytes))
28
- return b64, pil_img
29
-
30
-
31
- def sanitize_filename(name: str) -> str:
32
- """Nettoie le nom retourné par le modèle pour en faire un nom de fichier valide."""
33
- # Garder uniquement lettres, chiffres, tirets, underscores
34
- name = name.strip().strip('"').strip("'")
35
- name = re.sub(r"[^\w\s\-]", "", name)
36
- name = re.sub(r"\s+", "_", name)
37
- name = name[:80] # max 80 caractères
38
- return name if name else "document_sans_nom"
39
-
40
-
41
- # ─── Fonction principale ───────────────────────────────────────────────────────
42
-
43
- def name_pdf(pdf_file, user_prompt: str, langue: str) -> tuple:
44
- """
45
- 1. Convertit la page 1 du PDF en image
46
- 2. Envoie image + prompt à Gemma 4 E4B via Inference API
47
- 3. Retourne le nom suggéré
48
- """
49
- if pdf_file is None:
50
- return None, "", "⚠️ Veuillez uploader un fichier PDF."
51
-
52
- if not HF_TOKEN:
53
- return None, "", "❌ Token HF manquant. Configurez HF_TOKEN dans les secrets du Space."
54
-
55
- # Étape 1 — Convertir PDF → image
56
- try:
57
- b64_image, pil_preview = pdf_first_page_to_base64(pdf_file.name)
58
- except Exception as e:
59
- return None, "", f"❌ Erreur lecture PDF : {e}"
60
-
61
- # Étape 2 — Construire le prompt
62
- langue_instruction = {
63
- "Français": "Réponds uniquement en français.",
64
- "English": "Reply only in English.",
65
- "Arabe / عربي": "أجب باللغة العربية فقط.",
66
- }.get(langue, "")
67
-
68
- system_prompt = (
69
- "Tu es un assistant spécialisé dans la gestion documentaire. "
70
- "Tu analyses la première page d'un document et tu proposes un nom de fichier court, "
71
- "descriptif et professionnel. "
72
- "Retourne UNIQUEMENT le nom du fichier, sans extension, sans explication, sans guillemets."
73
- )
74
-
75
- user_message = (
76
- f"{user_prompt}\n\n"
77
- f"{langue_instruction}\n\n"
78
- "Propose un nom de fichier court (3 à 6 mots maximum), en snake_case, "
79
- "basé sur le contenu visible de cette page."
80
- )
81
-
82
- # Étape 3 — Appel à l'Inference API (multimodal)
83
- try:
84
- client = InferenceClient(token=HF_TOKEN)
85
-
86
- response = client.chat_completion(
87
- model=MODEL_ID,
88
- messages=[
89
- {"role": "system", "content": system_prompt},
90
- {
91
- "role": "user",
92
- "content": [
93
- {
94
- "type": "image_url",
95
- "image_url": {
96
- "url": f"data:image/png;base64,{b64_image}"
97
- },
98
- },
99
- {"type": "text", "text": user_message},
100
- ],
101
- },
102
- ],
103
- max_tokens=60,
104
- temperature=0.3,
105
- )
106
-
107
- raw_name = response.choices[0].message.content.strip()
108
- clean_name = sanitize_filename(raw_name)
109
-
110
- except Exception as e:
111
- return pil_preview, "", f"❌ Erreur API Hugging Face : {e}"
112
-
113
- return pil_preview, clean_name, f"✅ Nom suggéré : **{clean_name}.pdf**"
114
-
115
-
116
- # ─── Interface Gradio ──────────────────────────────────────────────────────────
117
-
118
- DESCRIPTION = """
119
- # 📄 PDF Auto-Namer
120
- ### Propulsé par Gemma 4 E4B (multimodal) via Hugging Face Inference API
121
-
122
- Uploadez un PDF → l'IA analyse la première page → vous obtenez un nom de fichier propre.
123
- """
124
-
125
- EXAMPLES = [
126
- [None, "Lis la première page et donne un nom professionnel à ce document", "Français"],
127
- [None, "Give this document a short, professional filename", "English"],
128
- ]
129
-
130
- with gr.Blocks(theme=gr.themes.Soft(), title="PDF Auto-Namer") as demo:
131
- gr.Markdown(DESCRIPTION)
132
-
133
- with gr.Row():
134
- with gr.Column(scale=1):
135
- pdf_input = gr.File(
136
- label="📂 Uploader votre PDF",
137
- file_types=[".pdf"],
138
- type="filepath",
139
- )
140
- prompt_input = gr.Textbox(
141
- label="💬 Prompt personnalisé",
142
- placeholder="Ex: Donne un nom court et professionnel à ce document...",
143
- value="Analyse la première page et propose un nom de fichier court et descriptif.",
144
- lines=3,
145
- )
146
- langue_input = gr.Radio(
147
- label="🌍 Langue de sortie",
148
- choices=["Français", "English", "Arabe / عربي"],
149
- value="Français",
150
- )
151
- submit_btn = gr.Button("🚀 Générer le nom", variant="primary", size="lg")
152
-
153
- with gr.Column(scale=1):
154
- preview_img = gr.Image(label="👁️ Aperçu — Page 1 du PDF", type="pil")
155
- name_output = gr.Textbox(
156
- label="📝 Nom de fichier suggéré",
157
- placeholder="Le nom apparaîtra ici...",
158
- interactive=False,
159
- )
160
- status_output = gr.Markdown("")
161
-
162
- submit_btn.click(
163
- fn=name_pdf,
164
- inputs=[pdf_input, prompt_input, langue_input],
165
- outputs=[preview_img, name_output, status_output],
166
- )
167
-
168
- gr.Markdown(
169
- "---\n"
170
- "ℹ️ *Ce Space utilise l'[Inference API HF](https://huggingface.co/inference-api) "
171
- "— aucun modèle n'est chargé localement. Modèle : `google/gemma-4-E4B-it`.*"
172
- )
173
-
174
- if __name__ == "__main__":
175
- demo.launch()