Spaces:
Sleeping
Sleeping
File size: 5,480 Bytes
74390ec 9ef5861 74390ec 225b022 74390ec 6402d0a b85c2f0 6402d0a b85c2f0 6402d0a b85c2f0 6402d0a 450b116 6402d0a 2cb9f23 74390ec 6402d0a 74390ec 9ef5861 27cafa5 74390ec 6402d0a 450b116 27cafa5 450b116 27cafa5 450b116 27cafa5 6402d0a 9ef5861 6402d0a 0dd06b3 6402d0a 0dd06b3 6402d0a 0dd06b3 6402d0a 0dd06b3 6402d0a 2cb9f23 0dd06b3 6402d0a 81b3fa7 6402d0a 3813ca8 6402d0a 3813ca8 6402d0a 3813ca8 6402d0a 74390ec 6b186dd 7633bea 6402d0a 7633bea 6402d0a 0dd06b3 6402d0a 0dd06b3 6402d0a 0dd06b3 6402d0a 0dd06b3 6402d0a 0dd06b3 6402d0a 0dd06b3 3813ca8 6402d0a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
import streamlit as st
from PyPDF2 import PdfReader
from langchain.text_splitter import RecursiveCharacterTextSplitter
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_dotenv()
# Configuración inicial
st.set_page_config(page_title="PDF Consultor 🔍", page_icon="🔍", layout="wide")
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
# CSS personalizado
st.markdown("""
<style>
.response-box { padding: 20px; background-color: #f8f9fa; border-radius: 10px; border-left: 5px solid #252850; margin: 20px 0; }
.metadata-box { padding: 20px; background-color: #f0f2f6; border-radius: 10px; margin-bottom: 20px; }
.step-number { font-size: 24px; font-weight: bold; }
</style>
""", unsafe_allow_html=True)
# Funciones auxiliares
def eliminar_proceso_pensamiento(texto):
limpio = re.sub(r'<think>.*?</think>', '', texto, flags=re.DOTALL)
return limpio.strip(), re.search(r'<think>(.*?)</think>', texto, re.DOTALL).group(1) if "<think>" in texto else "No disponible"
def get_pdf_text(pdf_docs):
return "".join([page.extract_text() for pdf in pdf_docs for page in PdfReader(pdf).pages])
def get_vector_store(text_chunks):
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
return FAISS.from_texts(text_chunks, embedding=embeddings)
def get_conversational_chain():
prompt_template = """
Responde en español exclusivamente con la información solicitada usando el contexto.
Si no hay información, di "No disponible".
Contexto:
{context}
Pregunta:
{question}
Respuesta:
"""
model = ChatGroq(temperature=0.2, model_name="deepseek-r1-distill-llama-70b", groq_api_key=GROQ_API_KEY)
return load_qa_chain(model, chain_type="stuff", prompt=PromptTemplate(template=prompt_template, input_variables=["context", "question"]))
def procesar_consulta(pregunta):
if 'vector_store' not in st.session_state:
st.error("Por favor carga un documento primero")
return
chain = get_conversational_chain()
docs = st.session_state.vector_store.similarity_search(pregunta)
with st.spinner("Analizando documento..."):
response = chain({"input_documents": docs, "question": pregunta}, return_only_outputs=True)
respuesta_final, pensamiento = eliminar_proceso_pensamiento(response['output_text'])
mostrar_respuesta(respuesta_final, pensamiento)
def mostrar_respuesta(respuesta, pensamiento):
st.markdown(f'<div class="response-box">{respuesta}</div>', unsafe_allow_html=True)
with st.expander("💭 Pensamiento del modelo"):
st.write(pensamiento)
def generar_sugerencias():
if 'vector_store' not in st.session_state:
return []
docs = st.session_state.vector_store.similarity_search("", k=3)
context = "\n".join([doc.page_content for doc in docs])
prompt_template = """
Genera exactamente 3 preguntas simples en español basadas en este contexto.
Contexto:
{context}
Preguntas sugeridas:
"""
model = ChatGroq(temperature=0.4, model_name="deepseek-r1-distill-llama-70b", groq_api_key=GROQ_API_KEY)
response = model.invoke(prompt_template.format(context=context))
preguntas = [line.split('. ', 1)[1] for line in response.content.split("\n") if line.strip() and line[0].isdigit()]
return preguntas[:3]
# Aplicación principal
def main():
st.title("PDF Consultor 🔍")
# Estados de sesión
if 'documento_cargado' not in st.session_state:
st.session_state.documento_cargado = False
st.session_state.sugerencias = []
st.session_state.pregunta_actual = ""
# Sidebar de carga de documentos
with st.sidebar:
st.markdown('<p class="step-number">1. Subir archivos</p>', unsafe_allow_html=True)
pdf_docs = st.file_uploader("Subir PDF(s)", accept_multiple_files=True, type=["pdf"])
if pdf_docs and not st.session_state.documento_cargado:
with st.spinner("Procesando documento..."):
raw_text = get_pdf_text(pdf_docs)
text_chunks = RecursiveCharacterTextSplitter(chunk_size=5000, chunk_overlap=500).split_text(raw_text)
vector_store = get_vector_store(text_chunks)
st.session_state.vector_store = vector_store
st.session_state.documento_cargado = True
st.session_state.sugerencias = generar_sugerencias()
st.success("Documento procesado exitosamente.")
st.experimental_rerun()
# Mostrar sugerencias y formulario principal
if st.session_state.documento_cargado:
if st.session_state.sugerencias:
st.subheader("💡 Preguntas sugeridas:")
for pregunta in st.session_state.sugerencias:
if st.button(pregunta):
procesar_consulta(pregunta)
with st.form("consulta_form"):
pregunta_usuario = st.text_input("Escribe tu pregunta:", placeholder="Ej: ¿Qué normativa regula este proceso?")
enviar = st.form_submit_button("Enviar ▶")
if enviar and pregunta_usuario:
procesar_consulta(pregunta_usuario)
if __name__ == "__main__":
main()
|