Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -7,6 +7,7 @@ import pandas as pd
|
|
| 7 |
from markdown import markdown
|
| 8 |
from bs4 import BeautifulSoup
|
| 9 |
import tempfile
|
|
|
|
| 10 |
|
| 11 |
# Initialize Groq client
|
| 12 |
client = Groq(api_key=os.getenv("GROQ_API_KEY"))
|
|
@@ -17,16 +18,46 @@ def image_to_base64(image):
|
|
| 17 |
image.save(buffered, format="JPEG") # Ou PNG si besoin
|
| 18 |
return base64.b64encode(buffered.getvalue()).decode("utf-8")
|
| 19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
def parse_markdown_table_to_df(text):
|
| 21 |
-
"""Parse
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
soup = BeautifulSoup(html, "html.parser")
|
| 24 |
table = soup.find("table")
|
| 25 |
if not table:
|
| 26 |
-
return None
|
| 27 |
headers = [th.text.strip() for th in table.find_all("th")]
|
| 28 |
-
rows = [[td.text.strip() for td in tr.find_all("td")] for tr in table.find_all("tr")[1:]]
|
| 29 |
-
|
|
|
|
| 30 |
|
| 31 |
def process_image_and_get_response(image):
|
| 32 |
"""Process the uploaded image, send to Groq vision model, parse response to table, and generate Excel."""
|
|
@@ -37,7 +68,7 @@ def process_image_and_get_response(image):
|
|
| 37 |
base64_image = image_to_base64(image)
|
| 38 |
|
| 39 |
# Ton prompt optimisé
|
| 40 |
-
prompt = "Extrait le tableau en entier de cette image et recopie-le à l'identique ici pour que je puisse le copier coller. Utilise un format de tableau Markdown (avec des | et --- pour les séparateurs) pour une structure parfaite."
|
| 41 |
|
| 42 |
try:
|
| 43 |
completion = client.chat.completions.create(
|
|
@@ -73,10 +104,12 @@ def process_image_and_get_response(image):
|
|
| 73 |
df.to_excel(writer, sheet_name='Tableau_Extrait', index=False)
|
| 74 |
excel_file = tmp.name
|
| 75 |
else:
|
| 76 |
-
# Fallback :
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
|
|
|
|
|
|
| 80 |
|
| 81 |
return response, excel_file
|
| 82 |
|
|
@@ -89,10 +122,10 @@ iface = gr.Interface(
|
|
| 89 |
inputs=gr.Image(type="pil", label="Uploader une image contenant un tableau"),
|
| 90 |
outputs=[
|
| 91 |
gr.Textbox(label="Réponse de l'IA (tableau Markdown pour copier-coller)"),
|
| 92 |
-
gr.File(label="Télécharger le fichier
|
| 93 |
],
|
| 94 |
title="Extraction de Tableau depuis Image avec Groq et Export Excel",
|
| 95 |
-
description="Uploader une image avec un tableau. L'IA extrait et formate en Markdown, puis génère un Excel."
|
| 96 |
)
|
| 97 |
|
| 98 |
# Launch the interface
|
|
|
|
| 7 |
from markdown import markdown
|
| 8 |
from bs4 import BeautifulSoup
|
| 9 |
import tempfile
|
| 10 |
+
import re # Ajouté pour extraire le tableau Markdown de la réponse complète
|
| 11 |
|
| 12 |
# Initialize Groq client
|
| 13 |
client = Groq(api_key=os.getenv("GROQ_API_KEY"))
|
|
|
|
| 18 |
image.save(buffered, format="JPEG") # Ou PNG si besoin
|
| 19 |
return base64.b64encode(buffered.getvalue()).decode("utf-8")
|
| 20 |
|
| 21 |
+
def extract_markdown_table(text):
|
| 22 |
+
"""Extraire uniquement la partie tableau Markdown de la réponse texte complète."""
|
| 23 |
+
# Utilise une regex pour trouver le bloc commençant par | et contenant des lignes de tableau
|
| 24 |
+
table_pattern = r'(\|.*?\n(?:\|.*?\n)+)'
|
| 25 |
+
match = re.search(table_pattern, text, re.DOTALL)
|
| 26 |
+
if match:
|
| 27 |
+
return match.group(1).strip()
|
| 28 |
+
return None
|
| 29 |
+
|
| 30 |
def parse_markdown_table_to_df(text):
|
| 31 |
+
"""Parse un tableau Markdown en Pandas DataFrame, de manière plus robuste."""
|
| 32 |
+
# Extraire d'abord le tableau pur
|
| 33 |
+
table_md = extract_markdown_table(text)
|
| 34 |
+
if not table_md:
|
| 35 |
+
return None
|
| 36 |
+
|
| 37 |
+
# Convertir Markdown en HTML
|
| 38 |
+
html = markdown(table_md)
|
| 39 |
+
|
| 40 |
+
# Utiliser pandas.read_html pour parser directement le tableau HTML
|
| 41 |
+
try:
|
| 42 |
+
dfs = pd.read_html(html)
|
| 43 |
+
if dfs:
|
| 44 |
+
df = dfs[0] # Prend le premier tableau trouvé
|
| 45 |
+
# Nettoyer les colonnes et lignes (strip espaces)
|
| 46 |
+
df.columns = [col.strip() if isinstance(col, str) else col for col in df.columns]
|
| 47 |
+
df = df.applymap(lambda x: x.strip() if isinstance(x, str) else x)
|
| 48 |
+
return df if not df.empty else None
|
| 49 |
+
except ValueError:
|
| 50 |
+
pass # Si pas de tableau valide
|
| 51 |
+
|
| 52 |
+
# Fallback avec BeautifulSoup si read_html échoue
|
| 53 |
soup = BeautifulSoup(html, "html.parser")
|
| 54 |
table = soup.find("table")
|
| 55 |
if not table:
|
| 56 |
+
return None
|
| 57 |
headers = [th.text.strip() for th in table.find_all("th")]
|
| 58 |
+
rows = [[td.text.strip() for td in tr.find_all("td")] for tr in table.find_all("tr")[1:]]
|
| 59 |
+
df = pd.DataFrame(rows, columns=headers) if headers and rows else pd.DataFrame(rows)
|
| 60 |
+
return df if not df.empty else None
|
| 61 |
|
| 62 |
def process_image_and_get_response(image):
|
| 63 |
"""Process the uploaded image, send to Groq vision model, parse response to table, and generate Excel."""
|
|
|
|
| 68 |
base64_image = image_to_base64(image)
|
| 69 |
|
| 70 |
# Ton prompt optimisé
|
| 71 |
+
prompt = "Extrait le tableau en entier de cette image et recopie-le à l'identique ici pour que je puisse le copier coller. Utilise un format de tableau Markdown (avec des | et --- pour les séparateurs) pour une structure parfaite. Ne ajoute rien d'autre que le tableau Markdown."
|
| 72 |
|
| 73 |
try:
|
| 74 |
completion = client.chat.completions.create(
|
|
|
|
| 104 |
df.to_excel(writer, sheet_name='Tableau_Extrait', index=False)
|
| 105 |
excel_file = tmp.name
|
| 106 |
else:
|
| 107 |
+
# Fallback amélioré : Si parsing échoue, crée un Excel avec la réponse brute dans une cellule unique
|
| 108 |
+
df_fallback = pd.DataFrame({"Réponse brute": [response]})
|
| 109 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx") as tmp:
|
| 110 |
+
with pd.ExcelWriter(tmp.name, engine='openpyxl') as writer:
|
| 111 |
+
df_fallback.to_excel(writer, sheet_name='Réponse_Brute', index=False)
|
| 112 |
+
excel_file = tmp.name
|
| 113 |
|
| 114 |
return response, excel_file
|
| 115 |
|
|
|
|
| 122 |
inputs=gr.Image(type="pil", label="Uploader une image contenant un tableau"),
|
| 123 |
outputs=[
|
| 124 |
gr.Textbox(label="Réponse de l'IA (tableau Markdown pour copier-coller)"),
|
| 125 |
+
gr.File(label="Télécharger le fichier Excel")
|
| 126 |
],
|
| 127 |
title="Extraction de Tableau depuis Image avec Groq et Export Excel",
|
| 128 |
+
description="Uploader une image avec un tableau. L'IA extrait et formate en Markdown, puis génère un Excel rempli."
|
| 129 |
)
|
| 130 |
|
| 131 |
# Launch the interface
|