Cherryblade29 commited on
Commit
1e187f1
·
verified ·
1 Parent(s): ed46846

Upload prompt_to.py

Browse files
Files changed (1) hide show
  1. prompt_to.py +500 -0
prompt_to.py ADDED
@@ -0,0 +1,500 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sqlite3
3
+ import json
4
+ import pandas as pd
5
+ import re
6
+ from agno.agent import Agent
7
+ from agno.models.groq import Groq
8
+ import streamlit as st
9
+ from dotenv import load_dotenv
10
+ import graphviz
11
+ from clean_database import clean_database
12
+
13
+ # Charger les variables d'environnement depuis le fichier .env
14
+ load_dotenv()
15
+
16
+ # Fonctions de normalisation de la base de données
17
+ def detecter_format(fichier):
18
+ extension = os.path.splitext(fichier)[1].lower()
19
+ if extension in [".db", ".sqlite"]:
20
+ return "sqlite"
21
+ elif extension == ".json":
22
+ return "json"
23
+ elif extension == ".csv":
24
+ return "csv"
25
+ elif extension in [".xls", ".xlsx"]:
26
+ return "excel"
27
+ else:
28
+ return "inconnu"
29
+
30
+ def json_to_sqlite(fichier_json):
31
+ with open(fichier_json, 'r', encoding='utf-8') as file:
32
+ data = json.load(file)
33
+ db_name = 'temp_json.db'
34
+ conn = sqlite3.connect(db_name)
35
+ cursor = conn.cursor()
36
+ table_name = "data"
37
+ columns = ', '.join(data[0].keys())
38
+ placeholders = ', '.join('?' * len(data[0]))
39
+ cursor.execute(f"CREATE TABLE IF NOT EXISTS {table_name} ({columns})")
40
+ for row in data:
41
+ cursor.execute(f"INSERT INTO {table_name} ({columns}) VALUES ({placeholders})", tuple(row.values()))
42
+ conn.commit()
43
+ conn.close()
44
+ return db_name
45
+
46
+ def csv_to_sqlite(fichier_csv):
47
+ df = pd.read_csv(fichier_csv, encoding='utf-8')
48
+ db_name = 'temp_csv.db'
49
+ conn = sqlite3.connect(db_name)
50
+ df.to_sql('data', conn, if_exists='replace', index=False)
51
+ conn.close()
52
+ return db_name
53
+
54
+ def excel_to_sqlite(fichier_excel):
55
+ df = pd.read_excel(fichier_excel, encoding='utf-8')
56
+ db_name = 'temp_excel.db'
57
+ conn = sqlite3.connect(db_name)
58
+ df.to_sql('data', conn, if_exists='replace', index=False)
59
+ conn.close()
60
+ return db_name
61
+
62
+ def preparer_bdd(input_path):
63
+ format_detecte = detecter_format(input_path)
64
+ if format_detecte == "sqlite":
65
+ return input_path
66
+ elif format_detecte == "json":
67
+ return json_to_sqlite(input_path)
68
+ elif format_detecte == "csv":
69
+ return csv_to_sqlite(input_path)
70
+ elif format_detecte == "excel":
71
+ return excel_to_sqlite(input_path)
72
+ else:
73
+ st.error("Format non supporté. Utilisez un fichier .db, .json, .csv, .xls ou .xlsx")
74
+ return None
75
+
76
+ def extraire_bdd(db_path):
77
+ with sqlite3.connect(db_path) as conn:
78
+ cursor = conn.cursor()
79
+ tables = [table[0] for table in cursor.execute(
80
+ "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';"
81
+ ).fetchall()]
82
+ if not tables:
83
+ st.warning("Aucune table trouvée.")
84
+ return ""
85
+ output_bdd = ""
86
+ for table in tables:
87
+ output_bdd += f"\n📌 Table `{table}` :\n"
88
+ cursor.execute(f"PRAGMA table_info({table});")
89
+ columns = cursor.fetchall()
90
+ col_names = [col[1] for col in columns]
91
+ col_types = [col[2] for col in columns]
92
+ output_bdd += f"📝 Colonnes: {', '.join(f'{name} ({ctype})' for name, ctype in zip(col_names, col_types))}\n"
93
+ cursor.execute(f"SELECT * FROM {table}")
94
+ rows = cursor.fetchall()
95
+ if rows:
96
+ output_bdd += "\n".join(f" -> {row}" for row in rows) + "\n"
97
+ else:
98
+ output_bdd += "⚠️ Aucune donnée trouvée.\n"
99
+ return output_bdd
100
+
101
+ # Création de l'agent Groq pour la vérification de la normalisation
102
+ normalization_checker = Agent(
103
+ model=Groq(id="deepseek-r1-distill-llama-70b", temperature=0.0, top_p=0),
104
+ description="Vérifie si une base de données est normalisée.",
105
+ instructions=[
106
+ "Analyse la structure de la base de données fournie en entrée.",
107
+ "Détermine si elle respecte les formes normales (1NF, 2NF, 3NF, BCNF).",
108
+ "Migre les données de l'ancienne base de données vers la nouvelle base de données normalisée sans générer de code SQL.",
109
+ "Assurez-vous que toutes les données sont correctement transférées et que les relations sont maintenues.",
110
+ "Si la base n'est pas normalisée, propose une version améliorée sans générer de schéma SQL."
111
+ ],
112
+ markdown=True
113
+ )
114
+
115
+ def analyser_bdd(output_bdd: str):
116
+ prompt = f"""
117
+ Voici la structure et les données de la base SQLite :
118
+ {output_bdd}
119
+ Tu es un expert en base de données exécute l'algorithme suivant pour normaliser et migrer la base de données. Affiche **uniquement** le résultat final sans explication détaillée et Ne pas ajouter de nouvelles colonnes non mentionnées dans la base de données d'origine.
120
+ ---
121
+ ### **Algorithme de normalisation et migration**
122
+ Début
123
+ Initialiser une variable `resultat_final` pour accumuler les résultats.
124
+ # Analyser la structure actuelle de la base de données
125
+ Pour chaque table `T` dans la base de données faire
126
+ Détecter la clé primaire existante ou en attribuer une si nécessaire.
127
+ # Appliquer la 1NF : Atomisation des attributs
128
+ Si `T` contient des attributs non atomiques alors
129
+ Transformer les attributs en valeurs atomiques.
130
+ Assigner les clés primaires et ajouter les clés étrangères si nécessaire.
131
+ Fin Si
132
+ # Appliquer la 2NF : Éliminer les dépendances fonctionnelles partielles
133
+ Si `T` contient une clé primaire composite et des attributs qui dépendent d’une partie seulement de la clé alors
134
+ Décomposer `T` en nouvelles tables en respectant la 2NF.
135
+ Assigner les clés primaires et ajouter les clés étrangères si nécessaire.
136
+ Fin Si
137
+ # Appliquer la 3NF : Éliminer les dépendances transitives
138
+ Si `T` contient des dépendances transitives (un attribut dépend d’un autre attribut non clé) alors
139
+ Décomposer `T` en nouvelles tables pour isoler ces dépendances.
140
+ Assigner les clés primaires et ajouter les clés étrangères si nécessaire.
141
+ Fin Si
142
+ # Appliquer la BCNF : Suppression des dépendances anormales
143
+ Si `T` contient une dépendance fonctionnelle où un attribut non clé détermine une clé candidate alors
144
+ Décomposer `T` en nouvelles relations respectant la BCNF.
145
+ Assigner les clés primaires et ajouter les clés étrangères si nécessaire.
146
+ Fin Si
147
+ # Migrer les données
148
+ Pour chaque nouvelle table normalisée faire
149
+ Identifier les données à migrer depuis l'ancienne base de données.
150
+ Transformer ou réorganiser les données selon le schéma normalisé proposé.
151
+ Insérer les données transformées dans la nouvelle table normalisée.
152
+ Fin Pour
153
+ # Le résultat doit absolument respecter cette structure.
154
+ Ajouter "📝 Nouvelles tables proposées :" à `resultat_final`.
155
+ Pour chaque nouvelle table `N` créée faire
156
+ Ajouter "📌 Table `nom_nouvelle_table` :" à `resultat_final`.
157
+ Ajouter "📝 Colonnes: colonne1 (type1), colonne2 (type2), ..." à `resultat_final`.
158
+ Ajouter "🔑 Clé primaire: `colonne_PK`" si définie.
159
+ Ajouter "🔗 Clé étrangère: `colonne_FK` → `table_referencée` (`colonne_referencée`)" si applicable.
160
+ Ajouter "📋 Données :" à `resultat_final`.
161
+ Pour chaque enregistrement migré dans la table faire
162
+ Ajouter " - `valeur1`, `valeur2`, ..." à `resultat_final`.
163
+ Fin Pour
164
+ Fin Pour
165
+ # Vérification finale avant affichage
166
+ Afficher `resultat_final`
167
+ Afficher "✅ Normalisation complète et migration réussie."
168
+ Fin
169
+ ---
170
+ """
171
+ response = normalization_checker.run(prompt)
172
+ resultat = response.content.strip()
173
+ resultat_sans_think = re.sub(r"<think>.*?</think>", "", resultat, flags=re.DOTALL).strip()
174
+ return resultat_sans_think
175
+
176
+ # Création de l'agent 2 (vérifie la proposition de normalisation)
177
+ normalization_validator = Agent(
178
+ model=Groq(id="qwen-qwq-32b", temperature=0.0, top_p=0),
179
+ description="Vérifie si la base de données normalisée proposée est correcte.",
180
+ instructions=[
181
+ "Analyse la normalisation proposée et vérifie si elle respecte les formes normales.",
182
+ "Compare la proposition avec la base de données générée pour s'assurer de leur correspondance.",
183
+ "Donne une proposition améliorée si nécessaire."
184
+ ],
185
+ markdown=True
186
+ )
187
+
188
+ def verifier_normalisation(proposition_normalisee: str, output_bdd: str):
189
+ prompt = f"""
190
+ Voici la base de données générée après application de la normalisation :
191
+ Vérifie si la normalisation proposée correspond bien à {output_bdd}.
192
+ Voici une proposition de base de données normalisée :
193
+ {proposition_normalisee}
194
+ - Tu es un expert en base de données exécute l'algorithme suivant pour vérifier si la base obtenue correspond bien à la normalisation attendue. Affiche **uniquement** le résultat final sans explication détaillée.
195
+ ---
196
+ ### **Algorithme de vérification et correction des formes normales**
197
+ Début
198
+ Initialiser une variable `corrections_appliquees` = False
199
+ Pour chaque table dans la base de données faire
200
+ Si tous les attributs sont atomiques alors
201
+ printf("📌 Vérification de la table `nom_table`")
202
+ printf("✅ La table `nom_table` est en 1NF")
203
+ Si la table ne contient pas de dépendances fonctionnelles partielles alors
204
+ printf("✅ La table `nom_table` est en 2NF")
205
+ Si la table ne contient pas de dépendances transitives alors
206
+ printf("✅ La table `nom_table` est en 3NF")
207
+ Si chaque dépendance fonctionnelle est basée sur une clé candidate alors
208
+ printf("✅ La table `nom_table` est en BCNF")
209
+ Sinon
210
+ printf("❌ La table `nom_table` ne respecte pas la BCNF → Correction appliquée.")
211
+ Appliquer la correction en décomposant la table en relations BCNF.
212
+ corrections_appliquees = True
213
+ Fin Si
214
+ Sinon
215
+ printf("❌ La table `nom_table` ne respecte pas la 3NF → Correction appliquée.")
216
+ Appliquer la correction en éliminant les dépendances transitives.
217
+ corrections_appliquees = True
218
+ Fin Si
219
+ Sinon
220
+ printf("❌ La table `nom_table` ne respecte pas la 2NF → Correction appliquée.")
221
+ Appliquer la correction en éliminant les dépendances partielles.
222
+ corrections_appliquees = True
223
+ Fin Si
224
+ Sinon
225
+ printf("❌ La table `nom_table` ne respecte pas la 1NF → Correction appliquée.")
226
+ Appliquer la correction en atomisant les attributs.
227
+ corrections_appliquees = True
228
+ Fin Si
229
+ Fin Pour
230
+ Si corrections_appliquees == True alors
231
+ printf("⚠️ Des corrections ont été appliquées durant la vérification.")
232
+ Fin Si
233
+ printf("🔍 Normalisation terminée.")
234
+ Fin
235
+ ---
236
+ """
237
+ response = normalization_validator.run(prompt)
238
+ resultat = response.content.strip()
239
+ resultat_sans_think = re.sub(r"<think>.*?</think>", "", resultat, flags=re.DOTALL).strip()
240
+ return resultat_sans_think
241
+
242
+ # Création de l'agent 3 (crée la nouvelle bdd normalisée)
243
+ sql_generator = Agent(
244
+ model=Groq(id="whisper-large-v3", temperature=0.0, top_p=0),
245
+ description="Crée la nouvelle bdd normalisée.",
246
+ instructions=[
247
+ "Analyse le résultat de normalisation et génère les requêtes SQL pour créer la nouvelle bdd."
248
+ ],
249
+ markdown=True
250
+ )
251
+
252
+ def génération_des_requêtes(proposition_normalisee: str):
253
+ prompt = f"""
254
+ Voici une proposition de base de données normalisée :
255
+ {proposition_normalisee}
256
+ Génère uniquement les requêtes SQL pour créer et insérer des données dans la nouvelle base de données normalisée (crée les nouvelle tables et insérée tous les donnez et n'ajoutes rien).
257
+ """
258
+ response = sql_generator.run(prompt)
259
+ resultat = response.content.strip()
260
+ resultat_sans_think = re.sub(r"<think>.*?</think>", "", resultat, flags=re.DOTALL).strip()
261
+ return resultat_sans_think
262
+
263
+ def nettoyer_requetes_sql(texte):
264
+ # Expression régulière pour capturer les requêtes CREATE TABLE et INSERT INTO
265
+ pattern = r"(CREATE TABLE.*?;|INSERT INTO.*?;)"
266
+ requetes_sql = re.findall(pattern, texte, re.DOTALL | re.IGNORECASE)
267
+ return "\n\n".join(req.strip() for req in requetes_sql)
268
+
269
+ # --- Fonctions utilitaires ---
270
+ def create_sqlite_db_from_file(sql_file, db_name):
271
+ if os.path.exists(db_name):
272
+ os.remove(db_name)
273
+
274
+ conn = sqlite3.connect(db_name)
275
+ cursor = conn.cursor()
276
+
277
+ with open(sql_file, 'r') as file:
278
+ sql_script = file.read()
279
+
280
+ cursor.executescript(sql_script)
281
+ conn.commit()
282
+ conn.close()
283
+
284
+ def get_database_structure(db_name):
285
+ conn = sqlite3.connect(db_name)
286
+ cursor = conn.cursor()
287
+
288
+ # Récupérer les tables
289
+ cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
290
+ tables = cursor.fetchall()
291
+
292
+ structure = ""
293
+ for table in tables:
294
+ table_name = table[0]
295
+ structure += f"Table: {table_name}\n"
296
+
297
+ # Récupérer les colonnes
298
+ cursor.execute(f"PRAGMA table_info({table_name});")
299
+ columns = cursor.fetchall()
300
+ for column in columns:
301
+ structure += f" Colonne: {column[1]} (Type: {column[2]})\n"
302
+
303
+ conn.close()
304
+ return structure
305
+
306
+ def get_sample_data(db_name, limit=3):
307
+ conn = sqlite3.connect(db_name)
308
+ cursor = conn.cursor()
309
+ sample_text = ""
310
+ cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
311
+ tables = cursor.fetchall()
312
+ for table in tables:
313
+ table_name = table[0]
314
+ sample_text += f"\nExtrait de la table {table_name} :\n"
315
+ df = pd.read_sql_query(f"SELECT * FROM {table_name} LIMIT {limit}", conn)
316
+ sample_text += df.to_string(index=False)
317
+ sample_text += "\n"
318
+ conn.close()
319
+ return sample_text
320
+
321
+ def transform_prompt_to_sql(prompt, db_structure):
322
+ instructions = f"""
323
+ Voici la structure de la base de données :
324
+ {db_structure}
325
+ Voici la requête de l'utilisateur :
326
+ {prompt}
327
+
328
+ Transforme ce prompt en une requête SQL en utilisant la structure de la base de données fournie.
329
+ """
330
+ response = sql_transformer.run(instructions)
331
+ return response.content.strip()
332
+
333
+ def clean_sql_query(response):
334
+ # Utiliser une expression régulière pour extraire uniquement la requête SQL
335
+ match = re.search(r'```sql\s*(.*?)\s*```', response, re.DOTALL)
336
+ if match:
337
+ return match.group(1).strip()
338
+ else:
339
+ raise ValueError("Impossible d'extraire la requête SQL de la réponse.")
340
+
341
+ def execute_sql_query(db_name, sql_query):
342
+ conn = sqlite3.connect(db_name)
343
+ cursor = conn.cursor()
344
+ cursor.execute(sql_query)
345
+ results = cursor.fetchall()
346
+ conn.close()
347
+ return results
348
+
349
+ def visualize_database_schema_from_sql(sql_file):
350
+ with open(sql_file, 'r') as file:
351
+ sql_script = file.read()
352
+
353
+ # Extraction des tables et colonnes
354
+ tables = {}
355
+ pks = {}
356
+ fks = []
357
+
358
+ create_table_pattern = re.compile(r'CREATE TABLE\s+(\w+)\s*\((.*?)\);', re.DOTALL | re.IGNORECASE)
359
+ fk_pattern = re.compile(r'FOREIGN KEY\s*\((\w+)\)\s*REFERENCES\s+(\w+)\s*\((\w+)\)', re.IGNORECASE)
360
+ pk_inline_pattern = re.compile(r'^(\w+)\s+\w+.*PRIMARY KEY', re.IGNORECASE)
361
+ pk_constraint_pattern = re.compile(r'PRIMARY KEY\s*\((.*?)\)', re.IGNORECASE)
362
+
363
+
364
+ for match in create_table_pattern.finditer(sql_script):
365
+ table_name = match.group(1)
366
+ body = match.group(2)
367
+ lines = [line.strip() for line in body.split(',') if line.strip()]
368
+ columns = []
369
+ primary_keys = []
370
+
371
+ for line in lines:
372
+ if line.upper().startswith("FOREIGN KEY"):
373
+ fk_match = fk_pattern.search(line)
374
+ if fk_match:
375
+ source_col = fk_match.group(1)
376
+ ref_table = fk_match.group(2)
377
+ ref_col = fk_match.group(3)
378
+ fks.append((table_name, source_col, ref_table, ref_col))
379
+ elif line.upper().startswith("PRIMARY KEY"):
380
+ pk_match = pk_constraint_pattern.search(line)
381
+ if pk_match:
382
+ pk_cols = [pk.strip() for pk in pk_match.group(1).split(',')]
383
+ primary_keys.extend(pk_cols)
384
+ else:
385
+ parts = line.split()
386
+ if len(parts) == 0:
387
+ continue # ligne vide ou espace
388
+ col_name = parts[0].strip("()") # on enlève les parenthèses résiduelles
389
+ if col_name.isidentifier(): # vérifie que c’est un nom valide
390
+ if col_name not in columns: # Vérifie si la colonne n'est pas déjà présente
391
+ columns.append(col_name)
392
+ inline_pk = pk_inline_pattern.match(line)
393
+ if inline_pk:
394
+ if inline_pk.group(1) not in primary_keys: # Vérifie si la clé primaire n'est pas déjà présente
395
+ primary_keys.append(inline_pk.group(1))
396
+
397
+ tables[table_name] = columns
398
+ pks[table_name] = primary_keys
399
+
400
+
401
+ # Construction du graphe avec style MERISE
402
+ dot = graphviz.Digraph(format='png')
403
+ dot.attr('node', shape='plaintext')
404
+
405
+ for table, columns in tables.items():
406
+ rows = []
407
+ for col in columns:
408
+ if col in pks.get(table, []):
409
+ rows.append(f'<TR><TD ALIGN="LEFT"><U>{col}</U></TD></TR>')
410
+ else:
411
+ rows.append(f'<TR><TD ALIGN="LEFT">{col}</TD></TR>')
412
+
413
+ label = f"""<<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0">
414
+ <TR><TD BGCOLOR="lightgray"><B>{table}</B></TD></TR>
415
+ {''.join(rows)}
416
+ </TABLE>>"""
417
+
418
+ dot.node(table, label=label)
419
+
420
+ for src_table, src_col, tgt_table, tgt_col in fks:
421
+ dot.edge(src_table, tgt_table, label=f"{src_col} → {tgt_col}")
422
+
423
+ st.graphviz_chart(dot)
424
+
425
+ # --- Config Agent ---
426
+ sql_transformer = Agent(
427
+ model=Groq(id="llama3-70b-8192", temperature=0.0, top_p=0),
428
+ description="Transforme une requête en langage naturel en requête SQL.",
429
+ instructions=[
430
+ "Analyse la requête fournie en entrée.",
431
+ "Transforme la requête en langage naturel en une requête SQL.",
432
+ ],
433
+ markdown=True
434
+ )
435
+
436
+ # --- Interface Streamlit ---
437
+ st.set_page_config(page_title="Assistant SQL avec LLM", layout="wide")
438
+ st.title("🧠📊 Assistant SQL intelligent (avec LLM)")
439
+
440
+ db_name = "database.db"
441
+ sql_file = "output.sql"
442
+
443
+ # Champ de saisie pour le fichier d'entrée
444
+ input_file = st.file_uploader("Choisissez un fichier (.db, .json, .csv, .xls ou .xlsx)", type=["db", "sqlite", "json", "csv", "xls", "xlsx"])
445
+
446
+ if input_file:
447
+ # Enregistrer le fichier téléchargé temporairement
448
+ temp_file_path = f"temp_{input_file.name}"
449
+ with open(temp_file_path, "wb") as f:
450
+ f.write(input_file.getbuffer())
451
+
452
+ prepared_db_path = preparer_bdd(temp_file_path)
453
+ if prepared_db_path:
454
+ st.success(f"Base de données prête : {prepared_db_path}")
455
+ clean_database(prepared_db_path)
456
+ st.success("Base de données nettoyée.")
457
+ output_bdd = extraire_bdd(prepared_db_path)
458
+ if output_bdd:
459
+ proposition_normalisee = output_bdd
460
+ while True:
461
+ resultat = analyser_bdd(proposition_normalisee)
462
+ verification = verifier_normalisation(resultat, output_bdd)
463
+ if "⚠️ Des corrections ont été appliquées durant la vérification." in verification:
464
+ proposition_normalisee = verification
465
+ else:
466
+ st.text("\n🔍 Résultat final de l'analyse :\n" + resultat)
467
+ st.text("\n✅ Vérification de la normalisation :\n" + verification)
468
+ break
469
+
470
+ # Générer les requêtes SQL pour la nouvelle base de données normalisée
471
+ sql_content = génération_des_requêtes(resultat)
472
+ requetes_nettoyees = nettoyer_requetes_sql(sql_content)
473
+
474
+ # Écrire les requêtes SQL dans le fichier output.sql
475
+ with open(sql_file, "w", encoding='utf-8') as fichier_sql:
476
+ fichier_sql.write(requetes_nettoyees)
477
+
478
+ st.success(f"Fichier SQL généré: {sql_file}")
479
+ create_sqlite_db_from_file(sql_file, db_name)
480
+
481
+ # Visualiser le schéma de la base de données
482
+ st.subheader("Schéma des relations entre les tables")
483
+ visualize_database_schema_from_sql(sql_file)
484
+
485
+ # Champ de saisie pour les requêtes en langage naturel
486
+ prompt = st.text_input("💬 Pose ta question :", placeholder="Ex: Liste les patients atteints de diabète")
487
+
488
+ if prompt:
489
+ st.write("🛠️ Génération SQL en cours…")
490
+ structure = get_database_structure(db_name)
491
+ response = transform_prompt_to_sql(prompt, structure)
492
+ sql_query = clean_sql_query(response)
493
+ st.code(sql_query, language="sql")
494
+
495
+ try:
496
+ df = execute_sql_query(db_name, sql_query)
497
+ st.success("✅ Requête exécutée avec succès !")
498
+ st.dataframe(df)
499
+ except Exception as e:
500
+ st.error(f"❌ Erreur lors de l'exécution de la requête : {e}")