Florian.Moret commited on
Commit
4bf8063
·
1 Parent(s): 1d1d204

update app avec rag

Browse files
Files changed (2) hide show
  1. app.py +68 -35
  2. requirements.txt +1 -0
app.py CHANGED
@@ -1,16 +1,68 @@
1
  #region# import libs
2
  import streamlit as st
3
  import os
 
 
 
 
 
 
 
 
 
4
  from mistralai import Mistral
 
 
 
5
 
6
  MISTRAL_API_KEY = os.getenv("api_mistral")
7
- model = 'mistral-large-latest'
8
  mistral_client = Mistral(api_key=MISTRAL_API_KEY)
9
  MAX_TOKENS = 1500
10
  #endregion
11
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  #region# Définition des prompts
13
- def generate_prompts(score:str, type: str, annee_min: str, annee_max:str ) -> dict:
14
  """
15
  Genere les prefixes et suffixes des prompts pour Mistral en fonction du score de vulgarisation, du type d'espece, et les années des documents
16
  Args:
@@ -30,14 +82,14 @@ def generate_prompts(score:str, type: str, annee_min: str, annee_max:str ) -> di
30
 
31
  if score == "1":
32
  prefix_prompt = f"""Tu es un assistant IA spécialisé en nutrition de la volaille. Ton utilisateur est un chercheur travaillant sur
33
- l'amélioration des régimes alimentaires pour optimiser la santé et la croissance des {type_description}.
34
  Réponds en fournissant en vulgarisant les informations.
35
  Pour fournir la réponse, tu dois te baser sur des publications/articles qui ont une date de publication entre {annee_min} et {annee_max}."""
36
  suffix_prompt = """Réponds en français et donne une réponse directe et claire.
37
  Fini par faire une bibliographie avec les références bibliographiquesque tu as utilisé."""
38
  elif score == "2":
39
  prefix_prompt = f"""Tu es un assistant IA spécialisé en nutrition de la volaille. Ton utilisateur est un chercheur travaillant sur
40
- l'amélioration des régimes alimentaires pour optimiser la santé et la croissance des {type_description}.
41
  Réponds en fournissant des explications claires et concises, adaptées à la question posée.
42
  Pour fournir la réponse, tu dois te baser sur des publications/articles qui ont une date de publication entre {annee_min} et {annee_max}.
43
  Tes réponses doivent être structurées, complètes et adaptées aux professionnels du secteur."""
@@ -47,7 +99,7 @@ def generate_prompts(score:str, type: str, annee_min: str, annee_max:str ) -> di
47
  Fini par faire une bibliographie avec les références bibliographiques que tu as utilisé."""
48
  elif score == "3":
49
  prefix_prompt = f"""Tu es un assistant IA spécialisé en nutrition de la volaille. Ton utilisateur est un chercheur travaillant sur
50
- l'amélioration des régimes alimentaires pour optimiser la santé et la croissance des {type_description}.
51
  Réponds en fournissant des explications détaillées et précises, adaptées à la complexité de la question posée.
52
  N'oublie pas de citer à la fin de ta réponse les références sur lesquelles tu t'es basé avec son année (entre {annee_min} et {annee_max}).
53
  Tes réponses doivent être structurées, complètes et adaptées aux professionnels du secteur."""
@@ -171,7 +223,7 @@ def response_details(response, verbose=True):
171
 
172
  return details
173
 
174
- def prompt_pipeline(user_prompt: str, niveau_detail: str, type_reponse: str, souche: str, annee_publication_min: str, annee_publication_max: str) -> dict:
175
  """
176
  Fonction visible de l'application pour appeler un prompt et obtenir sa reponse
177
  Args:
@@ -182,12 +234,12 @@ def prompt_pipeline(user_prompt: str, niveau_detail: str, type_reponse: str, sou
182
  Dict
183
  """
184
 
185
- prefix_prompt, suffix_prompt = generate_prompts(score=niveau_detail, type=type_reponse, annee_min=annee_publication_min, annee_max=annee_publication_max)
186
 
187
  reponse_mistral = send_prompt_to_mistral(
188
  type_reponse=type_reponse,
189
  user_prompt=user_prompt,
190
- temperature=0.10,
191
  n_comp=1,
192
  verbose=False,
193
  prefix_prompt=prefix_prompt,
@@ -199,32 +251,7 @@ def prompt_pipeline(user_prompt: str, niveau_detail: str, type_reponse: str, sou
199
  to_return["details"] = response_details(reponse_mistral, verbose=False)
200
 
201
  return to_return
202
- """
203
- Fonction visible de l'application pour appeler un prompt et obtenir sa reponse
204
-
205
- Args:
206
- prompt (str): Prompt utilisateur
207
- niveau_detail (str): Niveau de detail de la requete : 1, 2, 3. Plus haut = plus d'infos
208
- type_reponse (str): 'Ponte', 'Chair'
209
- """
210
-
211
- prefix_prompt, suffix_prompt = generate_prompts(score=niveau_detail, type=type_reponse, annee_min=annee_publication_min, annee_max=annee_publication_max)
212
-
213
- reponse_mistral = send_prompt_to_mistral(
214
- type_reponse=type_reponse,
215
- user_prompt=user_prompt,
216
- temperature=0.10,
217
- n_comp=1,
218
- verbose=False,
219
- prefix_prompt=prefix_prompt,
220
- suffix_prompt=suffix_prompt
221
- )
222
-
223
- to_return = {}
224
- to_return["reponse_propre"] = print_pretty_response(reponse_mistral, verbose=True)
225
- to_return["details"] = response_details(reponse_mistral, verbose=False)
226
-
227
- return to_return
228
  #endregion
229
 
230
  #region# Titre de l'application et mise en page
@@ -261,11 +288,17 @@ if st.button("Envoyer la question..."):
261
  if user_input and choix_prod and choix_vulgarisation and choix_annee :
262
  with st.spinner("Veuillez patienter quelques instants..."):
263
  # Génération de la réponse
 
 
 
 
 
264
  response0 = prompt_pipeline(
265
  user_prompt = user_input,
266
  niveau_detail=choix_vulgarisation,
267
  type_reponse=choix_prod,
268
  souche=None,
 
269
  annee_publication_max=max(choix_annee),
270
  annee_publication_min=min(choix_annee)
271
  )
 
1
  #region# import libs
2
  import streamlit as st
3
  import os
4
+
5
+ from mistralai import Mistral
6
+ import numpy as np
7
+ # import fitz # PyMuPDF pour extraction PDF
8
+ import faiss
9
+
10
+
11
+ import pickle
12
+ import matplotlib.pyplot as plt
13
  from mistralai import Mistral
14
+ from sklearn.manifold import TSNE
15
+ from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
16
+ from dotenv import load_dotenv
17
 
18
  MISTRAL_API_KEY = os.getenv("api_mistral")
19
+ model = "ministral-8b-latest" # ancien model : 'mistral-large-latest'
20
  mistral_client = Mistral(api_key=MISTRAL_API_KEY)
21
  MAX_TOKENS = 1500
22
  #endregion
23
+
24
+ #region# rag
25
+ model_embedding = "mistral-embed"
26
+ # 📌 Paramètres de segmentation
27
+ chunk_size = 256 # Réduction du chunk size pour un meilleur contrôle du contexte
28
+ chunk_overlap = 15
29
+ # 📌 Définition des chemins de stockage
30
+ index_path = "faiss_index.bin"
31
+ chunks_path = "chunked_docs.pkl"
32
+
33
+ print("🔄 Chargement des données existantes...")
34
+ index = faiss.read_index(index_path) # Charger l'index FAISS
35
+ with open(chunks_path, "rb") as f:
36
+ chunked_docs = pickle.load(f) # Charger les chunks de texte
37
+ print("✅ Index et chunks chargés avec succès !")
38
+
39
+
40
+ # 📌 Récupération des chunks les plus pertinents
41
+ def retrieve_relevant_chunks(question, k=5):
42
+ """Recherche les chunks les plus pertinents en fonction de la similarité des embeddings."""
43
+ question_embedding_response = mistral_client.embeddings.create(
44
+ model=model_embedding,
45
+ inputs=[question],
46
+ )
47
+ question_embedding = np.array(question_embedding_response.data[0].embedding).astype('float32').reshape(1, -1)
48
+
49
+ # Vérification de la compatibilité des dimensions
50
+ dimension = index.d
51
+ if question_embedding.shape[1] != dimension:
52
+ raise ValueError(f"⚠️ ERREUR : La dimension de l'embedding de la question ({question_embedding.shape[1]}) ne correspond pas aux embeddings indexés ({dimension}).")
53
+
54
+ distances, indices = index.search(question_embedding, k)
55
+
56
+ if len(indices[0]) == 0:
57
+ print("⚠️ Avertissement : Aucun chunk pertinent trouvé, réponse possible moins précise.")
58
+ return []
59
+
60
+ return [chunked_docs[i] for i in indices[0]]
61
+ #endregion
62
+
63
+
64
  #region# Définition des prompts
65
+ def generate_prompts(score:str, type: str, annee_min: str, annee_max:str, context ) -> dict:
66
  """
67
  Genere les prefixes et suffixes des prompts pour Mistral en fonction du score de vulgarisation, du type d'espece, et les années des documents
68
  Args:
 
82
 
83
  if score == "1":
84
  prefix_prompt = f"""Tu es un assistant IA spécialisé en nutrition de la volaille. Ton utilisateur est un chercheur travaillant sur
85
+ l'amélioration des régimes alimentaires pour optimiser la santé et la croissance des {type_description}. Voici des informations contextuelles à utiliser avec priorité : {context}.
86
  Réponds en fournissant en vulgarisant les informations.
87
  Pour fournir la réponse, tu dois te baser sur des publications/articles qui ont une date de publication entre {annee_min} et {annee_max}."""
88
  suffix_prompt = """Réponds en français et donne une réponse directe et claire.
89
  Fini par faire une bibliographie avec les références bibliographiquesque tu as utilisé."""
90
  elif score == "2":
91
  prefix_prompt = f"""Tu es un assistant IA spécialisé en nutrition de la volaille. Ton utilisateur est un chercheur travaillant sur
92
+ l'amélioration des régimes alimentaires pour optimiser la santé et la croissance des {type_description}. Voici des informations contextuelles à utiliser avec priorité : {context}.
93
  Réponds en fournissant des explications claires et concises, adaptées à la question posée.
94
  Pour fournir la réponse, tu dois te baser sur des publications/articles qui ont une date de publication entre {annee_min} et {annee_max}.
95
  Tes réponses doivent être structurées, complètes et adaptées aux professionnels du secteur."""
 
99
  Fini par faire une bibliographie avec les références bibliographiques que tu as utilisé."""
100
  elif score == "3":
101
  prefix_prompt = f"""Tu es un assistant IA spécialisé en nutrition de la volaille. Ton utilisateur est un chercheur travaillant sur
102
+ l'amélioration des régimes alimentaires pour optimiser la santé et la croissance des {type_description}. Voici des informations contextuelles à utiliser avec priorité : {context}.
103
  Réponds en fournissant des explications détaillées et précises, adaptées à la complexité de la question posée.
104
  N'oublie pas de citer à la fin de ta réponse les références sur lesquelles tu t'es basé avec son année (entre {annee_min} et {annee_max}).
105
  Tes réponses doivent être structurées, complètes et adaptées aux professionnels du secteur."""
 
223
 
224
  return details
225
 
226
+ def prompt_pipeline(user_prompt: str, niveau_detail: str, type_reponse: str, souche: str, annee_publication_min: str, annee_publication_max: str, context) -> dict:
227
  """
228
  Fonction visible de l'application pour appeler un prompt et obtenir sa reponse
229
  Args:
 
234
  Dict
235
  """
236
 
237
+ prefix_prompt, suffix_prompt = generate_prompts(score=niveau_detail, type=type_reponse, annee_min=annee_publication_min, annee_max=annee_publication_max, context= context)
238
 
239
  reponse_mistral = send_prompt_to_mistral(
240
  type_reponse=type_reponse,
241
  user_prompt=user_prompt,
242
+ temperature=0.1,
243
  n_comp=1,
244
  verbose=False,
245
  prefix_prompt=prefix_prompt,
 
251
  to_return["details"] = response_details(reponse_mistral, verbose=False)
252
 
253
  return to_return
254
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
  #endregion
256
 
257
  #region# Titre de l'application et mise en page
 
288
  if user_input and choix_prod and choix_vulgarisation and choix_annee :
289
  with st.spinner("Veuillez patienter quelques instants..."):
290
  # Génération de la réponse
291
+
292
+ #todo mettre relevant chunks et context =
293
+ relevant_chunks= retrieve_relevant_chunks(user_input)
294
+ context = "\n".join(relevant_chunks)
295
+
296
  response0 = prompt_pipeline(
297
  user_prompt = user_input,
298
  niveau_detail=choix_vulgarisation,
299
  type_reponse=choix_prod,
300
  souche=None,
301
+ context=context,
302
  annee_publication_max=max(choix_annee),
303
  annee_publication_min=min(choix_annee)
304
  )
requirements.txt CHANGED
@@ -43,3 +43,4 @@ typing_extensions==4.12.2
43
  tzdata==2025.1
44
  urllib3==2.3.0
45
  torch==2.6.0
 
 
43
  tzdata==2025.1
44
  urllib3==2.3.0
45
  torch==2.6.0
46
+ faiss-cpu==1.10.0