LostPikachu commited on
Commit
f056b9f
·
verified ·
1 Parent(s): 8ae11fa

Upload 3 files

Browse files

RAG Mistral AI intégrant la sauvegarde du fichier faiss_inde.bin et chunked_docs.pkl s'il n'existe pas, sinon, si la base a déjà été vectorisée, le programme appel directement l'API du LLM de mistral

Files changed (3) hide show
  1. RAG_Mistral.py +55 -39
  2. chunked_docs.pkl +3 -0
  3. faiss_index.bin +3 -0
RAG_Mistral.py CHANGED
@@ -16,6 +16,7 @@ import os
16
  import numpy as np
17
  import fitz # PyMuPDF pour extraction PDF
18
  import faiss
 
19
  import matplotlib.pyplot as plt
20
  from mistralai import Mistral
21
  from sklearn.manifold import TSNE
@@ -29,7 +30,7 @@ MISTRAL_API_KEY = os.getenv('MISTRAL_API_KEY_static')
29
  # 📌 Initialisation du client Mistral
30
  client = Mistral(api_key=MISTRAL_API_KEY)
31
  model_embedding = "mistral-embed"
32
- model_chat = "mistral-large-latest"
33
  temperature = 0.1 # Réduction de la température pour privilégier la RAG
34
  probability = 0.9 # Ajustement de la probabilité pour plus de contrôle
35
 
@@ -37,37 +38,52 @@ probability = 0.9 # Ajustement de la probabilité pour plus de contrôle
37
  chunk_size = 256 # Réduction du chunk size pour un meilleur contrôle du contexte
38
  chunk_overlap = 15
39
 
40
- # 📌 Extraction et segmentation des PDF
41
- def extract_and_chunk_pdfs(pdf_folder):
42
- """Extrait et segmente les textes des PDF en chunks optimisés pour Mistral."""
43
- documents = SimpleDirectoryReader(pdf_folder).load_data()
44
- chunked_docs = [doc.text for doc in documents]
45
- return chunked_docs
46
-
47
- # 📌 Génération des embeddings par batch
48
- def get_embeddings_in_batches(text_chunks, batch_size=5):
49
- """Génère les embeddings en batch pour éviter les dépassements de tokens."""
 
 
 
 
 
 
 
 
 
 
50
  embeddings = []
51
- for i in range(0, len(text_chunks), batch_size):
52
- batch = text_chunks[i:i + batch_size]
 
53
  embeddings_batch_response = client.embeddings.create(
54
  model=model_embedding,
55
  inputs=batch,
56
  )
57
  batch_embeddings = [data.embedding for data in embeddings_batch_response.data]
58
  embeddings.extend(batch_embeddings)
 
59
 
60
- return np.array(embeddings).astype('float32')
61
-
62
- # 📌 Chargement et embedding des documents
63
- pdf_folder = 'C:/Users/MIPO10053340/OneDrive - Groupe Avril/Bureau/Salon_Agriculture_2024/Micka_API_Call/Docs_pdf/'
64
- chunked_docs = extract_and_chunk_pdfs(pdf_folder)
65
- embeddings = get_embeddings_in_batches(chunked_docs)
66
-
67
- # 📌 Indexation des embeddings avec FAISS
68
- dimension = embeddings.shape[1]
69
- index = faiss.IndexFlatL2(dimension)
70
- index.add(embeddings)
 
 
 
71
 
72
  # 📌 Récupération des chunks les plus pertinents
73
  def retrieve_relevant_chunks(question, k=5):
@@ -77,7 +93,18 @@ def retrieve_relevant_chunks(question, k=5):
77
  inputs=[question],
78
  )
79
  question_embedding = np.array(question_embedding_response.data[0].embedding).astype('float32').reshape(1, -1)
 
 
 
 
 
 
80
  distances, indices = index.search(question_embedding, k)
 
 
 
 
 
81
  return [chunked_docs[i] for i in indices[0]]
82
 
83
  # 📌 Génération de réponse avec MistralAI
@@ -88,11 +115,11 @@ def generate_response(context, question):
88
  {"role": "user", "content": question}
89
  ]
90
 
91
- response = client.chat.complete(model=model_chat, messages=messages, temperature=temperature, probability=probability)
92
  return response.choices[0].message.content
93
 
94
  # 📌 Exécuter une requête utilisateur
95
- user_question = "Quelles sont les souches de poulets ou poules présentent dans les publications de notre corpus utilisé pour la RAG"
96
  relevant_chunks = retrieve_relevant_chunks(user_question)
97
  context = "\n".join(relevant_chunks)
98
  answer = generate_response(context, user_question)
@@ -101,20 +128,9 @@ answer = generate_response(context, user_question)
101
  print("\n🔹 Réponse Mistral :")
102
  print(answer)
103
 
104
- # # 📊 Visualisation des embeddings avec t-SNE
105
- # tsne = TSNE(n_components=2, perplexity=min(30, max(2, embeddings.shape[0] - 1)), random_state=42)
106
- # embeddings_2d = tsne.fit_transform(embeddings)
107
-
108
- # plt.figure(figsize=(10, 8))
109
- # plt.scatter(embeddings_2d[:, 0], embeddings_2d[:, 1], alpha=0.5)
110
- # plt.title('Visualisation des embeddings avec t-SNE')
111
- # plt.xlabel('Dimension 1')
112
- # plt.ylabel('Dimension 2')
113
- # plt.show()
114
-
115
  # 💾 Sauvegarde des résultats
116
- with open("mistral_response.txt", "w", encoding="utf-8") as f:
117
  f.write(f"Question : {user_question}\n")
118
  f.write(f"Réponse :\n{answer}\n")
119
 
120
- print("\n✅ Réponse enregistrée dans 'mistral_response.txt'")
 
16
  import numpy as np
17
  import fitz # PyMuPDF pour extraction PDF
18
  import faiss
19
+ import pickle
20
  import matplotlib.pyplot as plt
21
  from mistralai import Mistral
22
  from sklearn.manifold import TSNE
 
30
  # 📌 Initialisation du client Mistral
31
  client = Mistral(api_key=MISTRAL_API_KEY)
32
  model_embedding = "mistral-embed"
33
+ model_chat = "ministral-8b-latest"
34
  temperature = 0.1 # Réduction de la température pour privilégier la RAG
35
  probability = 0.9 # Ajustement de la probabilité pour plus de contrôle
36
 
 
38
  chunk_size = 256 # Réduction du chunk size pour un meilleur contrôle du contexte
39
  chunk_overlap = 15
40
 
41
+ # 📌 Définition des chemins de stockage
42
+ index_path = "faiss_index.bin"
43
+ chunks_path = "chunked_docs.pkl"
44
+
45
+ # 📌 Vérification et chargement des données
46
+ if os.path.exists(index_path) and os.path.exists(chunks_path):
47
+ print("🔄 Chargement des données existantes...")
48
+ index = faiss.read_index(index_path) # Charger l'index FAISS
49
+ with open(chunks_path, "rb") as f:
50
+ chunked_docs = pickle.load(f) # Charger les chunks de texte
51
+ print("✅ Index et chunks chargés avec succès !")
52
+ else:
53
+ print("⚡ Création et stockage d'un nouvel index FAISS...")
54
+
55
+ # 📌 Extraction et segmentation des PDF
56
+ pdf_folder = 'C:/Users/MIPO10053340/OneDrive - Groupe Avril/Bureau/Salon_Agriculture_2024/Micka_API_Call/Docs_pdf/'
57
+ chunked_docs = SimpleDirectoryReader(pdf_folder).load_data()
58
+ chunked_docs = [doc.text for doc in chunked_docs]
59
+
60
+ # 📌 Génération des embeddings
61
  embeddings = []
62
+ batch_size = 5
63
+ for i in range(0, len(chunked_docs), batch_size):
64
+ batch = chunked_docs[i:i + batch_size]
65
  embeddings_batch_response = client.embeddings.create(
66
  model=model_embedding,
67
  inputs=batch,
68
  )
69
  batch_embeddings = [data.embedding for data in embeddings_batch_response.data]
70
  embeddings.extend(batch_embeddings)
71
+ embeddings = np.array(embeddings).astype('float32')
72
 
73
+ # 📌 Vérification avant d’indexer dans FAISS
74
+ if embeddings is None or len(embeddings) == 0:
75
+ raise ValueError("⚠️ ERREUR : Aucun embedding généré ! Vérifie l'étape de génération des embeddings.")
76
+
77
+ # 📌 Création et stockage de l'index FAISS
78
+ dimension = embeddings.shape[1]
79
+ index = faiss.IndexFlatL2(dimension)
80
+ index.add(embeddings)
81
+ faiss.write_index(index, index_path) # Sauvegarde de l'index
82
+
83
+ # 📌 Sauvegarde des chunks de texte
84
+ with open(chunks_path, "wb") as f:
85
+ pickle.dump(chunked_docs, f)
86
+ print("✅ Index et chunks sauvegardés !")
87
 
88
  # 📌 Récupération des chunks les plus pertinents
89
  def retrieve_relevant_chunks(question, k=5):
 
93
  inputs=[question],
94
  )
95
  question_embedding = np.array(question_embedding_response.data[0].embedding).astype('float32').reshape(1, -1)
96
+
97
+ # Vérification de la compatibilité des dimensions
98
+ dimension = index.d
99
+ if question_embedding.shape[1] != dimension:
100
+ raise ValueError(f"⚠️ ERREUR : La dimension de l'embedding de la question ({question_embedding.shape[1]}) ne correspond pas aux embeddings indexés ({dimension}).")
101
+
102
  distances, indices = index.search(question_embedding, k)
103
+
104
+ if len(indices[0]) == 0:
105
+ print("⚠️ Avertissement : Aucun chunk pertinent trouvé, réponse possible moins précise.")
106
+ return []
107
+
108
  return [chunked_docs[i] for i in indices[0]]
109
 
110
  # 📌 Génération de réponse avec MistralAI
 
115
  {"role": "user", "content": question}
116
  ]
117
 
118
+ response = client.chat.complete(model=model_chat, messages=messages, temperature=temperature)
119
  return response.choices[0].message.content
120
 
121
  # 📌 Exécuter une requête utilisateur
122
+ user_question = "Bonjour le Chat, je suis éléveur de poulets depuis plus de 20 ans et j'ai un doctorat de nutrition animale.Qu’est-ce qu’une protéine idéale en poule pondeuse ? Peux-tu suggérer une protéine idéale en pondeuse ? Merci d'être exhaustif et d'approfondir tes réponses et de ne pas survoler le sujet"
123
  relevant_chunks = retrieve_relevant_chunks(user_question)
124
  context = "\n".join(relevant_chunks)
125
  answer = generate_response(context, user_question)
 
128
  print("\n🔹 Réponse Mistral :")
129
  print(answer)
130
 
 
 
 
 
 
 
 
 
 
 
 
131
  # 💾 Sauvegarde des résultats
132
+ with open("mistral_response_types.txt", "w", encoding="utf-8") as f:
133
  f.write(f"Question : {user_question}\n")
134
  f.write(f"Réponse :\n{answer}\n")
135
 
136
+ print("\n✅ Réponse enregistrée dans 'mistral_response_types.txt'")
chunked_docs.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:002933b799b3b8d0824a2144045cd30f9a0bc3adcbbec594f3b3b0fab6f9b384
3
+ size 1940652
faiss_index.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2e097afeea3f73b331e09a0a81f4a09d920478ec100bb52c83ba550a6bf29600
3
+ size 2293805