PDFChat / app.py
lozanopastor's picture
Update app.py
ac23cc4 verified
raw
history blame
7.02 kB
import streamlit as st
import gradio as gr
from PyPDF2 import PdfReader
from langchain.text_splitter import RecursiveCharacterTextSplitter
import os
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS
from langchain_groq import ChatGroq
from langchain.chains.question_answering import load_qa_chain
from langchain.prompts import PromptTemplate
from dotenv import load_dotenv
import re
# Load environment variables
load_dotenv()
os.getenv("GROQ_API_KEY")
def get_pdf_text(pdf_docs):
"""Extrae texto de los archivos PDF cargados."""
text = ""
for pdf in pdf_docs:
pdf_reader = PdfReader(pdf)
for page in pdf_reader.pages:
text += page.extract_text()
return text
def get_text_chunks(text):
"""Divide el texto extra铆do en fragmentos manejables."""
text_splitter = RecursiveCharacterTextSplitter(chunk_size=5000, chunk_overlap=500)
chunks = text_splitter.split_text(text)
return chunks
def get_vector_store(text_chunks):
"""Crea y guarda un almac茅n de vectores FAISS a partir de fragmentos de texto."""
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
vector_store = FAISS.from_texts(text_chunks, embedding=embeddings)
vector_store.save_local("faiss_index")
def get_conversational_chain():
"""Configura una cadena conversacional usando el modelo Groq LLM."""
prompt_template = """
Responde la pregunta en espa帽ol de la manera m谩s detallada posible a partir del contexto proporcionado. Si la respuesta no est谩 en
el contexto proporcionado, simplemente di, "la respuesta no est谩 disponible en el contexto." No proporciones respuestas incorrectas.
Contexto:
{context}?
Pregunta:
{question}
Respuesta:
"""
model = ChatGroq(
temperature=0.3,
model_name="deepseek-r1-distill-llama-70b",
groq_api_key=os.getenv("GROQ_API_KEY")
)
prompt = PromptTemplate(template=prompt_template, input_variables=["context", "question"])
chain = load_qa_chain(model, chain_type="stuff", prompt=prompt)
return chain
def eliminar_texto_entre_tags(texto):
patron = r'<think>.*?</think>'
texto_limpio = re.sub(patron, '', texto, flags=re.DOTALL)
return texto_limpio
def user_input(user_question):
"""Maneja las consultas del usuario recuperando respuestas del almac茅n de vectores."""
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
new_db = FAISS.load_local("faiss_index", embeddings, allow_dangerous_deserialization=True)
docs = new_db.similarity_search(user_question)
chain = get_conversational_chain()
response = chain(
{"input_documents": docs, "question": user_question},
return_only_outputs=True
)
# Depuraci贸n: Imprimir la respuesta original
original_response = response['output_text']
print("Original Response:", original_response)
# Extraer el proceso de pensamiento
thought_process = ""
if "<think>" in response['output_text'] and "</think>" in response['output_text']:
thought_process_match = re.search(r"<think>(.*?)</think>", response['output_text'], re.DOTALL)
if thought_process_match:
thought_process = thought_process_match.group(1).strip()
# Eliminar el proceso de pensamiento de la respuesta principal
clean_response = eliminar_texto_entre_tags(original_response)
# Depuraci贸n: Imprimir la respuesta limpia
print("Cleaned Response:", clean_response)
# Mostrar el proceso de pensamiento del modelo en el expander
with st.expander("Proceso de Pensamiento del Modelo"):
st.write(thought_process)
st.markdown(f"### Respuesta:\n{clean_response}")
def main():
"""Funci贸n principal para ejecutar la aplicaci贸n Streamlit."""
st.set_page_config(page_title="Chat PDF", page_icon=":books:", layout="wide")
# Configuraci贸n de la apariencia de la aplicaci贸n
st.markdown(
"""
<style>
body {
background-color: #1E90FF;
color: white;
}
.sidebar .sidebar-content {
background-color: #00008B;
}
.main {
background-color: #00008B;
color: white;
}
.stButton>button {
background-color: #0b0175;
color: white;
}
/* Estilos personalizados para los botones espec铆ficos */
.custom-button button {
background-color: transparent;
border: 2px solid gray;
color: gray;
transition: all 0.3s ease;
margin-right: 10px; /* Espacio entre botones */
}
.custom-button button:hover {
background-color: gray;
color: white;
}
.custom-button {
display: flex;
gap: 10px; /* Espacio entre botones */
}
</style>
""",
unsafe_allow_html=True
)
st.title("PDF Consultor")
with st.sidebar:
pdf_docs = st.file_uploader(
"Subir archivo PDF",
accept_multiple_files=True,
type=["pdf"]
)
if st.button("Procesar"):
with st.spinner("Procesando el archivo..."):
raw_text = get_pdf_text(pdf_docs)
text_chunks = get_text_chunks(raw_text)
get_vector_store(text_chunks)
st.success("隆PDF procesado exitosamente!")
# Botones para preguntas predefinidas con estilo personalizado
col1, col2, col3 = st.columns(3)
with col1:
st.markdown('<div class="custom-button">', unsafe_allow_html=True)
button1 = st.button("Resumen", key="resumen_button"):
st.markdown('</div>', unsafe_allow_html=True)
with col2:
st.markdown('<div class="custom-button">', unsafe_allow_html=True)
button2 = st.button("Entidad", key="entidad_button"):
st.markdown('</div>', unsafe_allow_html=True)
with col3:
st.markdown('<div class="custom-button">', unsafe_allow_html=True)
button3 = st.button("Fecha implantaci贸n", key="fecha_button"):
st.markdown('</div>', unsafe_allow_html=True)
if button1:
# Do something...
user_input("Realiza un resumen sobre los aspectos m谩s relevantes comentados en el documento")
if button2:
# Do something...
user_input("A qu茅 entidad pertenece el contenido del documento?")
if button3:
# Do something...
user_input("En qu茅 fecha se implantar谩 el contenido del documento?")
user_question = st.text_input("Introduce tu pregunta", placeholder="驴Qu茅 quieres saber?")
if user_question:
with st.spinner("Obteniendo tu respuesta..."):
user_input(user_question)
if __name__ == "__main__":
main()