Spaces:
Sleeping
Sleeping
Upload 3 files
Browse filesRAG Mistral AI (testé sur un corpus de 86 des 200 textes sélectionnés, soucis de graph TNSE à la fin du code #comment) & RAG Open AI (à tester).
Pas de fichier requirements mais toutes les librairies utilisées sont les maj les plus récentes disponibles.
MAJ Test_API_GenAI
- RAG_Mistral.py +120 -0
- RAG_OpenAI.py +95 -0
- Tests_API_GenAI.py +58 -49
RAG_Mistral.py
ADDED
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
"""
|
3 |
+
Created on Mon Feb 24 15:51:34 2025
|
4 |
+
|
5 |
+
@author: MIPO10053340
|
6 |
+
|
7 |
+
C:/Users/MIPO10053340/OneDrive - Groupe Avril/Bureau/Salon_Agriculture_2024/Micka_API_Call/Docs_pdf/Docs_pdf/
|
8 |
+
|
9 |
+
"""
|
10 |
+
|
11 |
+
# -*- coding: utf-8 -*-
|
12 |
+
"""
|
13 |
+
Optimisation du RAG avec MistralAI - Embeddings en batch
|
14 |
+
"""
|
15 |
+
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
|
22 |
+
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
|
23 |
+
from dotenv import load_dotenv
|
24 |
+
|
25 |
+
# Charger les variables d'environnement
|
26 |
+
load_dotenv()
|
27 |
+
MISTRAL_API_KEY = os.getenv('MISTRAL_API_KEY_static')
|
28 |
+
|
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 |
+
|
36 |
+
# 📌 Paramètres de segmentation
|
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):
|
74 |
+
"""Recherche les chunks les plus pertinents en fonction de la similarité des embeddings."""
|
75 |
+
question_embedding_response = client.embeddings.create(
|
76 |
+
model=model_embedding,
|
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
|
84 |
+
def generate_response(context, question):
|
85 |
+
"""Génère une réponse basée sur le contexte extrait du corpus avec une basse température et un contrôle de probabilité."""
|
86 |
+
messages = [
|
87 |
+
{"role": "system", "content": f"Voici des informations contextuelles à utiliser avec priorité : {context}"},
|
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)
|
99 |
+
|
100 |
+
# 📊 Affichage de la réponse
|
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'")
|
RAG_OpenAI.py
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import numpy as np
|
3 |
+
import fitz # PyMuPDF pour extraction PDF
|
4 |
+
import faiss
|
5 |
+
import openai
|
6 |
+
from sklearn.manifold import TSNE
|
7 |
+
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
|
8 |
+
from dotenv import load_dotenv
|
9 |
+
|
10 |
+
# Charger les variables d'environnement
|
11 |
+
load_dotenv()
|
12 |
+
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
|
13 |
+
|
14 |
+
# 📌 Initialisation du client OpenAI
|
15 |
+
openai.api_key = OPENAI_API_KEY
|
16 |
+
model_embedding = "text-embedding-ada-002"
|
17 |
+
model_chat = "gpt-4-turbo"
|
18 |
+
|
19 |
+
# 📌 Paramètres de segmentation
|
20 |
+
chunk_size = 256
|
21 |
+
chunk_overlap = 10
|
22 |
+
|
23 |
+
# 📌 Extraction et segmentation des PDF
|
24 |
+
def extract_and_chunk_pdfs(pdf_folder):
|
25 |
+
"""Extrait et segmente les textes des PDF en chunks optimisés pour OpenAI."""
|
26 |
+
documents = SimpleDirectoryReader(pdf_folder).load_data()
|
27 |
+
chunked_docs = [doc.text for doc in documents]
|
28 |
+
return chunked_docs
|
29 |
+
|
30 |
+
# 📌 Génération des embeddings par batch
|
31 |
+
def get_embeddings_in_batches(text_chunks, batch_size=5):
|
32 |
+
"""Génère les embeddings en batch pour éviter les dépassements de tokens."""
|
33 |
+
embeddings = []
|
34 |
+
for i in range(0, len(text_chunks), batch_size):
|
35 |
+
batch = text_chunks[i:i + batch_size]
|
36 |
+
response = openai.Embedding.create(
|
37 |
+
input=batch,
|
38 |
+
model=model_embedding
|
39 |
+
)
|
40 |
+
batch_embeddings = [data['embedding'] for data in response['data']]
|
41 |
+
embeddings.extend(batch_embeddings)
|
42 |
+
|
43 |
+
return np.array(embeddings).astype('float32')
|
44 |
+
|
45 |
+
# 📌 Chargement et embedding des documents
|
46 |
+
pdf_folder = 'C:/Users/MIPO10053340/OneDrive - Groupe Avril/Bureau/Salon_Agriculture_2024/Micka_API_Call/Docs_pdf/'
|
47 |
+
chunked_docs = extract_and_chunk_pdfs(pdf_folder)
|
48 |
+
embeddings = get_embeddings_in_batches(chunked_docs)
|
49 |
+
|
50 |
+
# 📌 Indexation des embeddings avec FAISS
|
51 |
+
dimension = embeddings.shape[1]
|
52 |
+
index = faiss.IndexFlatL2(dimension)
|
53 |
+
index.add(embeddings)
|
54 |
+
|
55 |
+
# 📌 Récupération des chunks les plus pertinents
|
56 |
+
def retrieve_relevant_chunks(question, k=5):
|
57 |
+
"""Recherche les chunks les plus pertinents en fonction de la similarité des embeddings."""
|
58 |
+
response = openai.Embedding.create(
|
59 |
+
input=[question],
|
60 |
+
model=model_embedding
|
61 |
+
)
|
62 |
+
question_embedding = np.array(response['data'][0]['embedding']).astype('float32').reshape(1, -1)
|
63 |
+
distances, indices = index.search(question_embedding, k)
|
64 |
+
return [chunked_docs[i] for i in indices[0]]
|
65 |
+
|
66 |
+
# 📌 Génération de réponse avec OpenAI
|
67 |
+
def generate_response(context, question):
|
68 |
+
"""Génère une réponse basée sur le contexte extrait du corpus."""
|
69 |
+
messages = [
|
70 |
+
{"role": "system", "content": f"Voici des informations contextuelles : {context}"},
|
71 |
+
{"role": "user", "content": question}
|
72 |
+
]
|
73 |
+
|
74 |
+
response = openai.ChatCompletion.create(
|
75 |
+
model=model_chat,
|
76 |
+
messages=messages
|
77 |
+
)
|
78 |
+
return response["choices"][0]["message"]["content"]
|
79 |
+
|
80 |
+
# 📌 Exécuter une requête utilisateur
|
81 |
+
user_question = "Quelles souches de poulet et poules se trouvent dans ce corpus de texte ?"
|
82 |
+
relevant_chunks = retrieve_relevant_chunks(user_question)
|
83 |
+
context = "\n".join(relevant_chunks)
|
84 |
+
answer = generate_response(context, user_question)
|
85 |
+
|
86 |
+
# 📊 Affichage de la réponse
|
87 |
+
print("\n🔹 Réponse OpenAI :")
|
88 |
+
print(answer)
|
89 |
+
|
90 |
+
# 💾 Sauvegarde des résultats
|
91 |
+
with open("openai_response.txt", "w", encoding="utf-8") as f:
|
92 |
+
f.write(f"Question : {user_question}\n")
|
93 |
+
f.write(f"Réponse :\n{answer}\n")
|
94 |
+
|
95 |
+
print("\n✅ Réponse enregistrée dans 'openai_response.txt'")
|
Tests_API_GenAI.py
CHANGED
@@ -14,21 +14,18 @@ import pandas as pd
|
|
14 |
from scipy.stats import entropy
|
15 |
|
16 |
# API Clients
|
17 |
-
from mistralai
|
18 |
-
from
|
19 |
|
20 |
-
import
|
21 |
-
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
|
22 |
-
import transformers_stream_generator
|
23 |
-
import einops
|
24 |
|
25 |
-
HF_TOKEN = "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"
|
26 |
|
27 |
# ⚙️ Configurations API (remplace par tes clés API)
|
28 |
MISTRAL_API_KEY = os.getenv('MISTRAL_API_KEY_static')
|
29 |
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY_static')
|
30 |
-
ANTHROPIC_API_KEY = os.getenv('ANTHROPIC_API_KEY_static')
|
31 |
-
LLAMA_API_KEY = os.getenv('LLAMA_API_KEY_static')
|
|
|
32 |
|
33 |
# 📌 Choix des modèles à utiliser
|
34 |
USE_MODELS = {
|
@@ -39,6 +36,7 @@ USE_MODELS = {
|
|
39 |
"deepseek": False
|
40 |
}
|
41 |
|
|
|
42 |
# 📊 Fonction pour calculer l'entropie des réponses
|
43 |
def calculate_entropy(text):
|
44 |
tokens = text.split()
|
@@ -49,53 +47,64 @@ def calculate_entropy(text):
|
|
49 |
def get_model_responses(question):
|
50 |
responses = {}
|
51 |
|
52 |
-
# 🔹 MISTRAL
|
53 |
if USE_MODELS["mistral"]:
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
|
60 |
# 🔹 GPT-4 (OpenAI)
|
61 |
if USE_MODELS["gpt-4"]:
|
62 |
-
#
|
63 |
-
client =
|
64 |
|
|
|
65 |
response = client.chat.completions.create(
|
66 |
-
model="gpt-4",
|
67 |
-
messages=[
|
|
|
|
|
68 |
)
|
69 |
-
|
70 |
-
text_response = response.choices[0].message.content
|
71 |
-
responses["gpt-4"] = {"response": text_response, "entropy": calculate_entropy(text_response)}
|
72 |
-
|
73 |
-
# 🔹 LLAMA (Hugging Face)
|
74 |
-
if USE_MODELS["llama"]:
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
# 🔹 QWEN (Hugging Face)
|
83 |
-
if USE_MODELS["qwen"]:
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
# 🔹 DEEPSEEK (Hugging Face)
|
92 |
-
if USE_MODELS["deepseek"]:
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
|
100 |
return responses
|
101 |
|
|
|
14 |
from scipy.stats import entropy
|
15 |
|
16 |
# API Clients
|
17 |
+
from mistralai import Mistral
|
18 |
+
from openai import OpenAI
|
19 |
|
20 |
+
# from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
|
|
|
|
|
|
|
21 |
|
|
|
22 |
|
23 |
# ⚙️ Configurations API (remplace par tes clés API)
|
24 |
MISTRAL_API_KEY = os.getenv('MISTRAL_API_KEY_static')
|
25 |
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY_static')
|
26 |
+
# ANTHROPIC_API_KEY = os.getenv('ANTHROPIC_API_KEY_static')
|
27 |
+
# LLAMA_API_KEY = os.getenv('LLAMA_API_KEY_static')
|
28 |
+
# HUGGINGFACE_TOKEN =os.getenv('HUGGINGFACE_TOKEN_static')
|
29 |
|
30 |
# 📌 Choix des modèles à utiliser
|
31 |
USE_MODELS = {
|
|
|
36 |
"deepseek": False
|
37 |
}
|
38 |
|
39 |
+
|
40 |
# 📊 Fonction pour calculer l'entropie des réponses
|
41 |
def calculate_entropy(text):
|
42 |
tokens = text.split()
|
|
|
47 |
def get_model_responses(question):
|
48 |
responses = {}
|
49 |
|
50 |
+
# # 🔹 MISTRAL
|
51 |
if USE_MODELS["mistral"]:
|
52 |
+
# Initialisation du client Mistral
|
53 |
+
client = Mistral(api_key=MISTRAL_API_KEY)
|
54 |
+
|
55 |
+
# Créer une complétion de chat
|
56 |
+
response = client.chat.complete(
|
57 |
+
model="mistral-medium",
|
58 |
+
messages=[
|
59 |
+
{"role": "user", "content": question}
|
60 |
+
]
|
61 |
+
)
|
62 |
+
# Extraire et afficher la réponse
|
63 |
+
text_response = response.choices[0].message.content
|
64 |
+
responses["mistral-medium"] = {"response": text_response, "entropy": calculate_entropy(text_response)}
|
65 |
|
66 |
# 🔹 GPT-4 (OpenAI)
|
67 |
if USE_MODELS["gpt-4"]:
|
68 |
+
# Initialisation du client OpenAI
|
69 |
+
client = OpenAI(api_key=OPENAI_API_KEY)
|
70 |
|
71 |
+
# Créer une complétion de chat
|
72 |
response = client.chat.completions.create(
|
73 |
+
model="gpt-4-turbo",
|
74 |
+
messages=[
|
75 |
+
{"role": "user", "content": question}
|
76 |
+
]
|
77 |
)
|
78 |
+
# Extraire et afficher la réponse
|
79 |
+
text_response = response.choices[0].message.content
|
80 |
+
responses["gpt-4-turbo"] = {"response": text_response, "entropy": calculate_entropy(text_response)}
|
81 |
+
|
82 |
+
# # 🔹 LLAMA (Hugging Face)
|
83 |
+
# if USE_MODELS["llama"]:
|
84 |
+
# model_id = "meta-llama/Llama-2-7b-chat-hf"
|
85 |
+
# tokenizer = AutoTokenizer.from_pretrained(model_id, use_auth_token=HUGGINGFACE_TOKEN)
|
86 |
+
# model = AutoModelForCausalLM.from_pretrained(model_id, use_auth_token=HUGGINGFACE_TOKEN)
|
87 |
+
# pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)
|
88 |
+
|
89 |
+
# text_response = pipe(question, max_length=300)[0]["generated_text"]
|
90 |
+
# responses["llama"] = {"response": text_response, "entropy": calculate_entropy(text_response)}
|
91 |
+
# # 🔹 QWEN (Hugging Face)
|
92 |
+
# if USE_MODELS["qwen"]:
|
93 |
+
# model_id = "Qwen/Qwen-7B-Chat"
|
94 |
+
# tokenizer = AutoTokenizer.from_pretrained(model_id, token=HUGGINGFACE_TOKEN, trust_remote_code=True)
|
95 |
+
# model = AutoModelForCausalLM.from_pretrained(model_id, token=HUGGINGFACE_TOKEN, trust_remote_code=True)
|
96 |
+
# pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)
|
97 |
+
# text_response = pipe(question, max_length=300)[0]["generated_text"]
|
98 |
+
# responses["qwen"] = {"response": text_response, "entropy": calculate_entropy(text_response)}
|
99 |
+
|
100 |
+
# # 🔹 DEEPSEEK (Hugging Face)
|
101 |
+
# if USE_MODELS["deepseek"]:
|
102 |
+
# model_id = "deepseek-ai/deepseek-7b-chat"
|
103 |
+
# tokenizer = AutoTokenizer.from_pretrained(model_id)
|
104 |
+
# model = AutoModelForCausalLM.from_pretrained(model_id)
|
105 |
+
# pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)
|
106 |
+
# text_response = pipe(question, max_length=300)[0]["generated_text"]
|
107 |
+
# responses["deepseek"] = {"response": text_response, "entropy": calculate_entropy(text_response)}
|
108 |
|
109 |
return responses
|
110 |
|