Dabococo commited on
Commit
da7151a
·
verified ·
1 Parent(s): 3fa8fb2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +51 -52
app.py CHANGED
@@ -4,10 +4,8 @@ import os
4
  import base64
5
  from io import BytesIO
6
  import pandas as pd
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"))
@@ -15,49 +13,45 @@ client = Groq(api_key=os.getenv("GROQ_API_KEY"))
15
  def image_to_base64(image):
16
  """Convert PIL image to base64 string for Groq API."""
17
  buffered = BytesIO()
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."""
@@ -67,12 +61,18 @@ def process_image_and_get_response(image):
67
  # Convert image to base64
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(
75
- model="meta-llama/llama-4-scout-17b-16e-instruct", # Ton modèle vision
76
  messages=[
77
  {
78
  "role": "user",
@@ -85,30 +85,29 @@ def process_image_and_get_response(image):
85
  ]
86
  }
87
  ],
88
- temperature=0.5, # Pour plus de précision sur l'extraction
89
- max_completion_tokens=2048, # Fonctionne avec la nouvelle version groq
90
  top_p=1,
91
- stream=False, # Simplifie le parsing
92
  stop=None
93
  )
94
 
95
- response = completion.choices[0].message.content
96
 
97
- # Parse la réponse en DataFrame pour Excel
98
  df = parse_markdown_table_to_df(response)
99
  excel_file = None
100
- if df is not None and not df.empty:
101
  # Crée un fichier Excel temporaire
102
  with tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx") as tmp:
103
  with pd.ExcelWriter(tmp.name, engine='openpyxl') as writer:
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
 
4
  import base64
5
  from io import BytesIO
6
  import pandas as pd
7
+ import re
 
8
  import tempfile
 
9
 
10
  # Initialize Groq client
11
  client = Groq(api_key=os.getenv("GROQ_API_KEY"))
 
13
  def image_to_base64(image):
14
  """Convert PIL image to base64 string for Groq API."""
15
  buffered = BytesIO()
16
+ image.save(buffered, format="JPEG")
17
  return base64.b64encode(buffered.getvalue()).decode("utf-8")
18
 
19
+ def parse_markdown_table_to_df(text):
20
+ """Parse un tableau Markdown en Pandas DataFrame de manière robuste."""
21
+ # Extraire le tableau Markdown avec une regex
22
+ table_pattern = r'(\|.*?\n(?:\|[-| :]*?\n)?(?:\|.*?\n)+)'
23
  match = re.search(table_pattern, text, re.DOTALL)
24
+ if not match:
25
+ return pd.DataFrame({"Erreur": ["Aucun tableau Markdown trouvé dans la réponse"]})
 
26
 
27
+ table_text = match.group(1).strip()
28
+ lines = table_text.split('\n')
 
 
 
 
29
 
30
+ # Ignorer les lignes vides et la ligne des séparateurs (|---|)
31
+ lines = [line.strip() for line in lines if line.strip() and not re.match(r'\|[-| :]*\|', line)]
32
 
33
+ if not lines:
34
+ return pd.DataFrame({"Erreur": ["Tableau vide ou mal formé"]})
35
+
36
+ # Extraire les en-têtes
37
+ headers = [h.strip() for h in lines[0].split('|')[1:-1]] # Ignore les | aux extrémités
38
+ if not headers:
39
+ return pd.DataFrame({"Erreur": ["Aucun en-tête valide trouvé"]})
40
+
41
+ # Extraire les lignes de données
42
+ rows = []
43
+ for line in lines[1:]:
44
+ cells = [cell.strip() for cell in line.split('|')[1:-1]] # Ignore les | aux extrémités
45
+ if len(cells) == len(headers): # Vérifie l'alignement
46
+ rows.append(cells)
47
+ else:
48
+ # Si le nombre de colonnes ne correspond pas, remplir avec des chaînes vides
49
+ cells.extend([''] * (len(headers) - len(cells)))
50
+ rows.append(cells[:len(headers)])
51
+
52
+ # Créer le DataFrame
53
+ df = pd.DataFrame(rows, columns=headers)
54
+ return df if not df.empty else pd.DataFrame({"Erreur": ["Aucune donnée valide extraite"]})
55
 
56
  def process_image_and_get_response(image):
57
  """Process the uploaded image, send to Groq vision model, parse response to table, and generate Excel."""
 
61
  # Convert image to base64
62
  base64_image = image_to_base64(image)
63
 
64
+ # Prompt optimisé pour un Markdown propre
65
+ prompt = (
66
+ "Extrait le tableau en entier de cette image et recopie-le à l'identique ici au format Markdown. "
67
+ "Utilise des | pour les colonnes et une ligne |---|---| pour les séparateurs. "
68
+ "N'inclus aucun texte avant ou après le tableau. "
69
+ "Assure-toi que chaque ligne a exactement le même nombre de colonnes que les en-têtes, "
70
+ "en remplissant les cellules vides avec '' si nécessaire."
71
+ )
72
 
73
  try:
74
  completion = client.chat.completions.create(
75
+ model="meta-llama/llama-4-scout-17b-16e-instruct",
76
  messages=[
77
  {
78
  "role": "user",
 
85
  ]
86
  }
87
  ],
88
+ temperature=0.5,
89
+ max_completion_tokens=2048,
90
  top_p=1,
91
+ stream=False,
92
  stop=None
93
  )
94
 
95
+ response = completion.choices[0].message.content.strip()
96
 
97
+ # Parse la réponse en DataFrame
98
  df = parse_markdown_table_to_df(response)
99
  excel_file = None
100
+ if not df.empty and "Erreur" not in df.columns:
101
  # Crée un fichier Excel temporaire
102
  with tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx") as tmp:
103
  with pd.ExcelWriter(tmp.name, engine='openpyxl') as writer:
104
  df.to_excel(writer, sheet_name='Tableau_Extrait', index=False)
105
  excel_file = tmp.name
106
  else:
107
+ # Si parsing échoue, crée un Excel avec un message d'erreur
 
108
  with tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx") as tmp:
109
  with pd.ExcelWriter(tmp.name, engine='openpyxl') as writer:
110
+ df.to_excel(writer, sheet_name='Erreur', index=False)
111
  excel_file = tmp.name
112
 
113
  return response, excel_file