Files changed (1) hide show
  1. app.py +194 -61
app.py CHANGED
@@ -4,7 +4,7 @@ import uuid
4
  import requests
5
  import os
6
  os.environ["USER_AGENT"] = "RAG-App/1.0"
7
- from typing import Dict, List, Any
8
  from dotenv import load_dotenv
9
 
10
  from bs4 import BeautifulSoup
@@ -18,7 +18,7 @@ from langchain_huggingface import HuggingFaceEmbeddings
18
  from langchain_community.vectorstores import Weaviate
19
  from langchain_community.vectorstores import FAISS
20
  from langchain_groq import ChatGroq
21
- from langchain_core.prompts import ChatPromptTemplate,MessagesPlaceholder
22
 
23
  from langchain_classic.chains.combine_documents import create_stuff_documents_chain
24
  from langchain_classic.chains import create_retrieval_chain
@@ -27,57 +27,58 @@ from langchain_core.runnables.history import RunnableWithMessageHistory
27
  from langchain_community.chat_message_histories import ChatMessageHistory
28
  from langchain_core.chat_history import BaseChatMessageHistory
29
 
 
 
30
  #================== CONFIG==================
31
 
32
  load_dotenv()
33
 
34
  set_llm_cache(InMemoryCache())
35
- api_key=os.environ["GROQ_API_KEY"]
36
- #os.environ["HF_API_KEY"]
37
  print("api chargée:" if api_key else "y'a probleme!!")
38
 
39
  #========== charger et decouper documents=================
40
 
41
- urls=[
42
  "https://fr.wikipedia.org/wiki/%C3%89levage",
43
  "https://fr.wikipedia.org/wiki/La_P%C3%AAche"
44
  ]
45
 
46
  loader = WebBaseLoader(urls,
47
  requests_kwargs={
48
- "headers":{
49
- "User-Agent":"RAG-App/1.0"
50
  }
51
  }
52
  )
53
- docs =loader.load()
54
 
55
- splitter = RecursiveCharacterTextSplitter(chunk_size= 1000, chunk_overlap=200)
56
- chunks= splitter.split_documents(docs)
57
 
58
  #============embeding et indexation vers faiss_db================
59
 
60
- embeddings= HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
61
 
62
- faiss_db=FAISS.from_documents(
63
  documents=chunks,
64
  embedding=embeddings
65
- )
66
 
67
- retriever=faiss_db.as_retriever(search_type="similarity", search_kwargs={"k":3})
68
 
69
  #=============== LLM et Prompt=================
70
 
71
  llm = ChatGroq(
72
  model="llama-3.3-70b-versatile",
73
  temperature=0.0,
74
- max_tokens=1200
75
- )
 
76
 
77
  prompt = ChatPromptTemplate.from_messages([
78
  ("system", """Tu es un assistant expert en dans le domaine de l'elevage et la pêche. Réponds clairement.
79
  Si tu ne connais pas, n'invente pas. Garde un ton amical.
80
-
81
  Contexte :
82
  {context}"""),
83
  MessagesPlaceholder(variable_name="chat_history"),
@@ -86,14 +87,14 @@ Contexte :
86
 
87
  #============= CHAINE DE RECUPERATION=======
88
 
89
- stuff_chain= create_stuff_documents_chain(llm, prompt)
90
- rag_chain=create_retrieval_chain(retriever, stuff_chain)
91
 
92
- import gradio as gr
93
 
94
  store = {}
95
 
96
- def get_session_history(session_id:str)->BaseChatMessageHistory:
97
  if session_id not in store:
98
  store[session_id] = ChatMessageHistory()
99
  return store[session_id]
@@ -108,54 +109,186 @@ convers_chain = RunnableWithMessageHistory(
108
  output_messages_key="answer"
109
  )
110
 
111
- # =============FONCTION CHAT ================
112
 
113
- SESSION_ID = str(uuid.uuid4()) # session globale
114
 
115
- def chat_fn(message, history):
 
 
 
 
 
 
 
 
116
  result = convers_chain.invoke(
117
  {"input": message},
118
  config={"configurable": {"session_id": SESSION_ID}}
119
  )
120
- return result.get("answer", str(result))
121
-
122
- # def chat_fn(message, history, request: gr.Request):
123
- # session_id = request.session_hash
124
 
125
- # result = convers_chain.invoke(
126
- # {"input": message},
127
- # config={"configurable": {"session_id": session_id}}
128
- # )
129
- # return result.get("answer", str(result))
130
-
131
- #session_id_state = gr.State(value=None)
132
-
133
- # def chat_fn(message, history, session_id_state):
134
- # if session_id_state is None:
135
- # session_id_state = str(uuid.uuid4())
136
-
137
- # result = convers_chain.invoke(
138
- # {"input": message},
139
- # config={"configurable": {"session_id": session_id_state}}
140
- # )
141
-
142
- # response = result.get("answer", str(result))
143
- # return response, session_id_state
144
-
145
-
146
- # ================= GRADIO ====================
147
-
148
- demo = gr.ChatInterface(
149
- fn=chat_fn,
150
- title="🤖 RAG:Specialist en Science Animale 👌",
151
- description="Posez vos questions sur l'élévage et la pêche",
152
- examples=[
153
- "C'est quoi la pêche ?",
154
- "Explique l'élévage",
155
- "Quelle est la différence entre l'élévage et pêche ?"
156
- ]
157
- )
 
 
 
 
 
 
 
 
 
 
 
 
158
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
 
160
  # ===================LANCEMENT ================
161
 
 
4
  import requests
5
  import os
6
  os.environ["USER_AGENT"] = "RAG-App/1.0"
7
+ from typing import Dict, List, Any, Generator
8
  from dotenv import load_dotenv
9
 
10
  from bs4 import BeautifulSoup
 
18
  from langchain_community.vectorstores import Weaviate
19
  from langchain_community.vectorstores import FAISS
20
  from langchain_groq import ChatGroq
21
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
22
 
23
  from langchain_classic.chains.combine_documents import create_stuff_documents_chain
24
  from langchain_classic.chains import create_retrieval_chain
 
27
  from langchain_community.chat_message_histories import ChatMessageHistory
28
  from langchain_core.chat_history import BaseChatMessageHistory
29
 
30
+ import gradio as gr
31
+
32
  #================== CONFIG==================
33
 
34
  load_dotenv()
35
 
36
  set_llm_cache(InMemoryCache())
37
+ api_key = os.environ["GROQ_API_KEY"]
 
38
  print("api chargée:" if api_key else "y'a probleme!!")
39
 
40
  #========== charger et decouper documents=================
41
 
42
+ urls = [
43
  "https://fr.wikipedia.org/wiki/%C3%89levage",
44
  "https://fr.wikipedia.org/wiki/La_P%C3%AAche"
45
  ]
46
 
47
  loader = WebBaseLoader(urls,
48
  requests_kwargs={
49
+ "headers": {
50
+ "User-Agent": "RAG-App/1.0"
51
  }
52
  }
53
  )
54
+ docs = loader.load()
55
 
56
+ splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
57
+ chunks = splitter.split_documents(docs)
58
 
59
  #============embeding et indexation vers faiss_db================
60
 
61
+ embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
62
 
63
+ faiss_db = FAISS.from_documents(
64
  documents=chunks,
65
  embedding=embeddings
66
+ )
67
 
68
+ retriever = faiss_db.as_retriever(search_type="similarity", search_kwargs={"k": 3})
69
 
70
  #=============== LLM et Prompt=================
71
 
72
  llm = ChatGroq(
73
  model="llama-3.3-70b-versatile",
74
  temperature=0.0,
75
+ max_tokens=1200,
76
+ streaming=True # Activer le streaming
77
+ )
78
 
79
  prompt = ChatPromptTemplate.from_messages([
80
  ("system", """Tu es un assistant expert en dans le domaine de l'elevage et la pêche. Réponds clairement.
81
  Si tu ne connais pas, n'invente pas. Garde un ton amical.
 
82
  Contexte :
83
  {context}"""),
84
  MessagesPlaceholder(variable_name="chat_history"),
 
87
 
88
  #============= CHAINE DE RECUPERATION=======
89
 
90
+ stuff_chain = create_stuff_documents_chain(llm, prompt)
91
+ rag_chain = create_retrieval_chain(retriever, stuff_chain)
92
 
93
+ # ====== GESTION DE L'HISTORIQUE ======
94
 
95
  store = {}
96
 
97
+ def get_session_history(session_id: str) -> BaseChatMessageHistory:
98
  if session_id not in store:
99
  store[session_id] = ChatMessageHistory()
100
  return store[session_id]
 
109
  output_messages_key="answer"
110
  )
111
 
112
+ # =============FONCTION CHAT AVEC STREAMING ================
113
 
114
+ SESSION_ID = str(uuid.uuid4()) # session globale pour l'historique
115
 
116
+ def chat_fn_stream(message: str, history: list) -> Generator[str, None, None]:
117
+ """
118
+ Fonction de chat avec streaming en temps réel.
119
+ Yield chaque token de la réponse au fur et à mesure.
120
+ """
121
+ # Récupérer l'historique de la session
122
+ session_history = get_session_history(SESSION_ID)
123
+
124
+ # Construire le contexte à partir de l'historique
125
  result = convers_chain.invoke(
126
  {"input": message},
127
  config={"configurable": {"session_id": SESSION_ID}}
128
  )
 
 
 
 
129
 
130
+ # Récupérer la réponse complète
131
+ full_response = result.get("answer", str(result))
132
+
133
+ # Simuler le streaming en yieldant caractère par caractère
134
+ partial_response = ""
135
+ for char in full_response:
136
+ partial_response += char
137
+ yield partial_response
138
+
139
+ def get_history_list() -> list:
140
+ """
141
+ Récupère l'historique de la conversation sous forme de liste
142
+ pour l'affichage dans la sidebar.
143
+ """
144
+ session_history = get_session_history(SESSION_ID)
145
+ messages = session_history.messages
146
+
147
+ history_list = []
148
+ for i in range(0, len(messages), 2):
149
+ if i + 1 < len(messages):
150
+ question = messages[i].content
151
+ answer = messages[i + 1].content
152
+ history_list.append({
153
+ "question": question[:100] + "..." if len(question) > 100 else question,
154
+ "full_question": question,
155
+ "full_answer": answer
156
+ })
157
+
158
+ return history_list
159
+
160
+ def load_conversation(question: str, history: list) -> list:
161
+ """
162
+ Charge une conversation précédente et affiche la réponse.
163
+ """
164
+ session_history = get_session_history(SESSION_ID)
165
+ messages = session_history.messages
166
+
167
+ # Trouver la question et sa réponse correspondante
168
+ for i in range(0, len(messages), 2):
169
+ if i + 1 < len(messages) and messages[i].content == question:
170
+ history.append({"role": "user", "content": question})
171
+ history.append({"role": "assistant", "content": messages[i + 1].content})
172
+ return history
173
+
174
+ return history
175
 
176
+ # ================= INTERFACE GRADIO AVEC HISTORIQUE ====================
177
+
178
+ with gr.Blocks(title="🤖 RAG: Specialist en Science Animale") as demo:
179
+ gr.Markdown("# 🤖 RAG: Specialist en Science Animale")
180
+ gr.Markdown("Posez vos questions sur l'élévage et la pêche")
181
+
182
+ with gr.Row():
183
+ # Sidebar pour l'historique
184
+ with gr.Column(scale=1, min_width=300):
185
+ gr.Markdown("### 📚 Historique des conversations")
186
+
187
+ # Bouton pour rafraîchir l'historique
188
+ refresh_btn = gr.Button("🔄 Rafraîchir l'historique")
189
+
190
+ # Liste des questions précédentes
191
+ history_list = gr.Dataframe(
192
+ headers=["Question", "Action"],
193
+ label="Questions précédentes",
194
+ interactive=True,
195
+ wrap=True
196
+ )
197
+
198
+ def update_history_list():
199
+ """Met à jour la liste des questions dans le dataframe."""
200
+ session_history = get_session_history(SESSION_ID)
201
+ messages = session_history.messages
202
+
203
+ data = []
204
+ for i in range(0, len(messages), 2):
205
+ if i + 1 < len(messages):
206
+ question = messages[i].content
207
+ data.append([question[:100] + "..." if len(question) > 100 else question, "📋 Voir"])
208
+
209
+ return data
210
+
211
+ refresh_btn.click(
212
+ fn=update_history_list,
213
+ outputs=[history_list]
214
+ )
215
+
216
+ # Zone principale de chat
217
+ with gr.Column(scale=3):
218
+ chatbot = gr.Chatbot(
219
+ label="Assistant RAG",
220
+ height=500
221
+ )
222
+
223
+ # Barre de saisie et bouton d'envoi
224
+ with gr.Row():
225
+ msg = gr.Textbox(
226
+ label="Votre question",
227
+ placeholder="Posez votre question sur l'élevage ou la pêche...",
228
+ scale=4
229
+ )
230
+ send_btn = gr.Button("Envoyer", variant="primary", scale=1)
231
+
232
+ # Bouton pour effacer la conversation
233
+ clear_btn = gr.Button("🗑️ Effacer la conversation")
234
+
235
+ # Exemples de questions
236
+ gr.Examples(
237
+ examples=[
238
+ "C'est quoi la pêche ?",
239
+ "Explique l'élévage",
240
+ "Quelle est la différence entre l'élévage et pêche ?"
241
+ ],
242
+ inputs=[msg]
243
+ )
244
+
245
+ # Fonction pour gérer l'envoi de message
246
+ def respond(message: str, history: list) -> tuple:
247
+ """Gère l'envoi du message et met à jour le chatbot."""
248
+ # Ajouter le message utilisateur à l'historique
249
+ history.append({"role": "user", "content": message})
250
+
251
+ # Obtenir la réponse
252
+ result = convers_chain.invoke(
253
+ {"input": message},
254
+ config={"configurable": {"session_id": SESSION_ID}}
255
+ )
256
+
257
+ response = result.get("answer", str(result))
258
+
259
+ # Ajouter la réponse à l'historique
260
+ history.append({"role": "assistant", "content": response})
261
+
262
+ return "", history
263
+
264
+ def clear_conversation():
265
+ """Efface la conversation actuelle."""
266
+ store[SESSION_ID] = ChatMessageHistory()
267
+ return [], []
268
+
269
+ # Gestionnaires d'événements
270
+ msg.submit(
271
+ respond,
272
+ inputs=[msg, chatbot],
273
+ outputs=[msg, chatbot]
274
+ )
275
+
276
+ send_btn.click(
277
+ respond,
278
+ inputs=[msg, chatbot],
279
+ outputs=[msg, chatbot]
280
+ )
281
+
282
+ clear_btn.click(
283
+ clear_conversation,
284
+ outputs=[chatbot, history_list]
285
+ )
286
+
287
+ # Charger l'historique initial
288
+ demo.load(
289
+ fn=update_history_list,
290
+ outputs=[history_list]
291
+ )
292
 
293
  # ===================LANCEMENT ================
294