reichaves commited on
Commit
5077cbf
1 Parent(s): 04fea78

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +37 -18
app.py CHANGED
@@ -1,10 +1,12 @@
1
  # -*- coding: utf-8
2
- # Reinaldo Chaves (reichaves@gmail.com)
3
- # Este projeto implementa um sistema de Retrieval-Augmented Generation (RAG) conversacional
4
- # usando Streamlit, LangChain, e modelos de linguagem de grande escala - para entrevistar conteúdo de URLs
5
- # Geração de respostas usando o modelo llama-3.2-90b-text-preview da Meta
6
- # Embeddings de texto usando o modelo all-MiniLM-L6-v2 do Hugging Face
7
-
 
 
8
  import streamlit as st
9
  from langchain.chains import create_history_aware_retriever, create_retrieval_chain
10
  from langchain.chains.combine_documents import create_stuff_documents_chain
@@ -26,10 +28,11 @@ from langchain_core.outputs import ChatResult
26
  from langchain_groq import ChatGroq
27
  from pydantic import Field
28
 
29
- # Configurar o tema para dark
30
  st.set_page_config(page_title="RAG Q&A Conversacional", layout="wide", initial_sidebar_state="expanded", page_icon="🤖", menu_items=None)
31
 
32
- # Aplicar o tema dark com CSS
 
33
  st.markdown("""
34
  <style>
35
  /* Estilo global */
@@ -135,7 +138,7 @@ st.markdown("""
135
  </style>
136
  """, unsafe_allow_html=True)
137
 
138
- # Sidebar com orientações
139
  st.sidebar.markdown("<h2 class='orange-title'>Orientações</h2>", unsafe_allow_html=True)
140
  st.sidebar.markdown("""
141
  * Se encontrar erros de processamento, reinicie com F5.
@@ -162,14 +165,15 @@ Este projeto não se responsabiliza pelos conteúdos criados a partir deste site
162
  Este aplicativo foi desenvolvido por Reinaldo Chaves. Para mais informações, contribuições e feedback, visite o [repositório do projeto no GitHub](https://github.com/reichaves/entrevista_url_llama3).
163
  """)
164
 
 
165
  st.markdown("<h1 class='yellow-title'>Chatbot com modelos opensource - entrevista URLs ✏️</h1>", unsafe_allow_html=True)
166
  st.write("Insira uma URL e converse com o conteúdo dela - aqui é usado o modelo de LLM llama-3.2-90b-text-preview e a plataforma de embeddings é all-MiniLM-L6-v2")
167
 
168
- # Solicitar as chaves de API
169
  groq_api_key = st.text_input("Insira sua chave de API Groq (depois pressione Enter):", type="password")
170
  huggingface_api_token = st.text_input("Insira seu token de API HuggingFace (depois pressione Enter):", type="password")
171
 
172
- # Wrapper personalizado para ChatGroq com rate limiting
173
  class RateLimitedChatGroq(BaseChatModel):
174
  llm: ChatGroq = Field(default_factory=lambda: ChatGroq())
175
 
@@ -199,26 +203,29 @@ class RateLimitedChatGroq(BaseChatModel):
199
  def _llm_type(self):
200
  return "rate_limited_chat_groq"
201
 
 
202
  if groq_api_key and huggingface_api_token:
203
- # Configurar o token da API do Hugging Face
204
  os.environ["HUGGINGFACEHUB_API_TOKEN"] = huggingface_api_token
205
-
206
- # Configurar a chave de API do Groq no ambiente
207
  os.environ["GROQ_API_KEY"] = groq_api_key
208
 
209
- # Inicializar o modelo de linguagem e embeddings
210
  rate_limited_llm = RateLimitedChatGroq(groq_api_key=groq_api_key, model_name="llama-3.2-90b-text-preview", temperature=0)
211
  embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
212
 
 
213
  session_id = st.text_input("Session ID", value="default_session")
214
 
 
215
  if 'store' not in st.session_state:
216
  st.session_state.store = {}
217
 
 
218
  url = st.text_input("Insira a URL para análise:")
219
 
220
  if url:
221
  try:
 
222
  response = requests.get(url)
223
  response.raise_for_status()
224
  soup = BeautifulSoup(response.text, 'html.parser')
@@ -226,7 +233,7 @@ if groq_api_key and huggingface_api_token:
226
  # Extract text from the webpage
227
  text = soup.get_text(separator='\n', strip=True)
228
 
229
- # Limit the text to a certain number of characters (e.g., 50,000)
230
  max_chars = 50000
231
  if len(text) > max_chars:
232
  text = text[:max_chars]
@@ -235,16 +242,19 @@ if groq_api_key and huggingface_api_token:
235
  # Create a Document object
236
  document = Document(page_content=text, metadata={"source": url})
237
 
 
238
  text_splitter = RecursiveCharacterTextSplitter(chunk_size=5000, chunk_overlap=500)
239
  splits = text_splitter.split_documents([document])
240
 
241
- # Create FAISS vector store
242
  vectorstore = FAISS.from_documents(splits, embeddings)
243
 
244
  st.success(f"Processado {len(splits)} pedaços de documentos (chunks) da URL.")
245
 
 
246
  retriever = vectorstore.as_retriever()
247
 
 
248
  contextualize_q_system_prompt = (
249
  "Given a chat history and the latest user question "
250
  "which might reference context in the chat history, "
@@ -258,8 +268,10 @@ if groq_api_key and huggingface_api_token:
258
  ("human", "{input}"),
259
  ])
260
 
 
261
  history_aware_retriever = create_history_aware_retriever(rate_limited_llm, retriever, contextualize_q_prompt)
262
 
 
263
  system_prompt = (
264
  "Você é um assistente especializado em analisar conteúdo de páginas web. "
265
  "Sempre coloque no final das respostas: 'Todas as informações devem ser checadas com a(s) fonte(s) original(ais)'"
@@ -283,20 +295,24 @@ if groq_api_key and huggingface_api_token:
283
  "Sempre termine as respostas com: 'Todas as informações precisam ser checadas com as fontes das informações'."
284
  )
285
 
 
286
  qa_prompt = ChatPromptTemplate.from_messages([
287
  ("system", system_prompt),
288
  MessagesPlaceholder("chat_history"),
289
  ("human", "{input}"),
290
  ])
291
 
 
292
  question_answer_chain = create_stuff_documents_chain(rate_limited_llm, qa_prompt)
293
  rag_chain = create_retrieval_chain(history_aware_retriever, question_answer_chain)
294
 
 
295
  def get_session_history(session: str) -> BaseChatMessageHistory:
296
  if session not in st.session_state.store:
297
  st.session_state.store[session] = ChatMessageHistory()
298
  return st.session_state.store[session]
299
 
 
300
  conversational_rag_chain = RunnableWithMessageHistory(
301
  rag_chain, get_session_history,
302
  input_messages_key="input",
@@ -304,6 +320,7 @@ if groq_api_key and huggingface_api_token:
304
  output_messages_key="answer"
305
  )
306
 
 
307
  user_input = st.text_input("Sua pergunta:")
308
  if user_input:
309
  with st.spinner("Processando sua pergunta..."):
@@ -313,10 +330,12 @@ if groq_api_key and huggingface_api_token:
313
  config={"configurable": {"session_id": session_id}},
314
  )
315
  st.write("Assistente:", response['answer'])
316
-
 
317
  with st.expander("Ver histórico do chat"):
318
  for message in session_history.messages:
319
  st.write(f"**{message.type}:** {message.content}")
 
320
  except requests.RequestException as e:
321
  st.error(f"Erro ao acessar a URL: {str(e)}")
322
  except Exception as e:
 
1
  # -*- coding: utf-8
2
+ # Author: Reinaldo Chaves (reichaves@gmail.com)
3
+ # This project implements a conversational Retrieval-Augmented Generation (RAG) system
4
+ # using Streamlit, LangChain, and large language models to interview content from URLs
5
+ # Response generation uses the llama-3.2-90b-text-preview model from Meta
6
+ # Text embeddings use the all-MiniLM-L6-v2 model from Hugging Face
7
+ # I am grateful for Krish C Naik's classes (https://www.youtube.com/user/krishnaik06)
8
+
9
+ # Import necessary libraries
10
  import streamlit as st
11
  from langchain.chains import create_history_aware_retriever, create_retrieval_chain
12
  from langchain.chains.combine_documents import create_stuff_documents_chain
 
28
  from langchain_groq import ChatGroq
29
  from pydantic import Field
30
 
31
+ # Configure Streamlit page settings
32
  st.set_page_config(page_title="RAG Q&A Conversacional", layout="wide", initial_sidebar_state="expanded", page_icon="🤖", menu_items=None)
33
 
34
+ # Apply dark theme using custom CSS
35
+ # This section includes CSS to style various Streamlit components for a dark theme
36
  st.markdown("""
37
  <style>
38
  /* Estilo global */
 
138
  </style>
139
  """, unsafe_allow_html=True)
140
 
141
+ # Sidebar with guidelines
142
  st.sidebar.markdown("<h2 class='orange-title'>Orientações</h2>", unsafe_allow_html=True)
143
  st.sidebar.markdown("""
144
  * Se encontrar erros de processamento, reinicie com F5.
 
165
  Este aplicativo foi desenvolvido por Reinaldo Chaves. Para mais informações, contribuições e feedback, visite o [repositório do projeto no GitHub](https://github.com/reichaves/entrevista_url_llama3).
166
  """)
167
 
168
+ # Main title and description
169
  st.markdown("<h1 class='yellow-title'>Chatbot com modelos opensource - entrevista URLs ✏️</h1>", unsafe_allow_html=True)
170
  st.write("Insira uma URL e converse com o conteúdo dela - aqui é usado o modelo de LLM llama-3.2-90b-text-preview e a plataforma de embeddings é all-MiniLM-L6-v2")
171
 
172
+ # Request API keys from the user
173
  groq_api_key = st.text_input("Insira sua chave de API Groq (depois pressione Enter):", type="password")
174
  huggingface_api_token = st.text_input("Insira seu token de API HuggingFace (depois pressione Enter):", type="password")
175
 
176
+ # Custom wrapper for ChatGroq with rate limiting
177
  class RateLimitedChatGroq(BaseChatModel):
178
  llm: ChatGroq = Field(default_factory=lambda: ChatGroq())
179
 
 
203
  def _llm_type(self):
204
  return "rate_limited_chat_groq"
205
 
206
+ # Main application logic
207
  if groq_api_key and huggingface_api_token:
208
+ # Set API tokens as environment variables
209
  os.environ["HUGGINGFACEHUB_API_TOKEN"] = huggingface_api_token
 
 
210
  os.environ["GROQ_API_KEY"] = groq_api_key
211
 
212
+ # Initialize language model and embeddings
213
  rate_limited_llm = RateLimitedChatGroq(groq_api_key=groq_api_key, model_name="llama-3.2-90b-text-preview", temperature=0)
214
  embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
215
 
216
+ # Create a session ID for chat history management
217
  session_id = st.text_input("Session ID", value="default_session")
218
 
219
+ # Initialize session state for storing chat history
220
  if 'store' not in st.session_state:
221
  st.session_state.store = {}
222
 
223
+ # Get URL input from user
224
  url = st.text_input("Insira a URL para análise:")
225
 
226
  if url:
227
  try:
228
+ # Fetch and process the webpage content
229
  response = requests.get(url)
230
  response.raise_for_status()
231
  soup = BeautifulSoup(response.text, 'html.parser')
 
233
  # Extract text from the webpage
234
  text = soup.get_text(separator='\n', strip=True)
235
 
236
+ # Limit the text to a maximum number of characters
237
  max_chars = 50000
238
  if len(text) > max_chars:
239
  text = text[:max_chars]
 
242
  # Create a Document object
243
  document = Document(page_content=text, metadata={"source": url})
244
 
245
+ # Split the document into smaller chunks
246
  text_splitter = RecursiveCharacterTextSplitter(chunk_size=5000, chunk_overlap=500)
247
  splits = text_splitter.split_documents([document])
248
 
249
+ # Create FAISS vector store for efficient similarity search
250
  vectorstore = FAISS.from_documents(splits, embeddings)
251
 
252
  st.success(f"Processado {len(splits)} pedaços de documentos (chunks) da URL.")
253
 
254
+ # Set up the retriever
255
  retriever = vectorstore.as_retriever()
256
 
257
+ # Define the system prompt for contextualizing questions
258
  contextualize_q_system_prompt = (
259
  "Given a chat history and the latest user question "
260
  "which might reference context in the chat history, "
 
268
  ("human", "{input}"),
269
  ])
270
 
271
+ # Create a history-aware retriever
272
  history_aware_retriever = create_history_aware_retriever(rate_limited_llm, retriever, contextualize_q_prompt)
273
 
274
+ # Define the main system prompt for the chatbot
275
  system_prompt = (
276
  "Você é um assistente especializado em analisar conteúdo de páginas web. "
277
  "Sempre coloque no final das respostas: 'Todas as informações devem ser checadas com a(s) fonte(s) original(ais)'"
 
295
  "Sempre termine as respostas com: 'Todas as informações precisam ser checadas com as fontes das informações'."
296
  )
297
 
298
+ # Create the question-answering prompt template
299
  qa_prompt = ChatPromptTemplate.from_messages([
300
  ("system", system_prompt),
301
  MessagesPlaceholder("chat_history"),
302
  ("human", "{input}"),
303
  ])
304
 
305
+ # Create the question-answering chain
306
  question_answer_chain = create_stuff_documents_chain(rate_limited_llm, qa_prompt)
307
  rag_chain = create_retrieval_chain(history_aware_retriever, question_answer_chain)
308
 
309
+ # Function to get or create session history
310
  def get_session_history(session: str) -> BaseChatMessageHistory:
311
  if session not in st.session_state.store:
312
  st.session_state.store[session] = ChatMessageHistory()
313
  return st.session_state.store[session]
314
 
315
+ # Create a conversational RAG chain with message history
316
  conversational_rag_chain = RunnableWithMessageHistory(
317
  rag_chain, get_session_history,
318
  input_messages_key="input",
 
320
  output_messages_key="answer"
321
  )
322
 
323
+ # Get user input and process the question
324
  user_input = st.text_input("Sua pergunta:")
325
  if user_input:
326
  with st.spinner("Processando sua pergunta..."):
 
330
  config={"configurable": {"session_id": session_id}},
331
  )
332
  st.write("Assistente:", response['answer'])
333
+
334
+ # Display chat history
335
  with st.expander("Ver histórico do chat"):
336
  for message in session_history.messages:
337
  st.write(f"**{message.type}:** {message.content}")
338
+ # Error handling
339
  except requests.RequestException as e:
340
  st.error(f"Erro ao acessar a URL: {str(e)}")
341
  except Exception as e: