edurojas95 commited on
Commit
c983252
·
verified ·
1 Parent(s): 029e308

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +114 -0
app.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import os
3
+ from langchain_huggingface import HuggingFaceEmbeddings
4
+ from langchain_community.vectorstores import Chroma
5
+ from langchain_google_genai import ChatGoogleGenerativeAI
6
+
7
+ # ==========================================
8
+ # 1. CONFIGURACIÓN Y CRÉDITOS
9
+ # ==========================================
10
+ st.set_page_config(page_title="Kimün Chile", page_icon="🩸", layout="centered")
11
+
12
+ st.title("🩸 Kimün: sabiduría")
13
+ st.subheader(" Chatbot de Hematología Basado en Normativas MINSAL y SOCHIHEM")
14
+
15
+ st.markdown("""
16
+ **Desarrollado por:**
17
+ * **TM Eduardo Rojas Maturana**
18
+ * **Dr. TM Neftalí Guzmán Oyarzo**
19
+
20
+ *Facultad de Ciencias de la Salud, Carrera de Tecnología Médica.* *Laboratorio de Investigación en Salud de Precisión, Universidad Católica de Temuco.*
21
+ ---
22
+ """)
23
+
24
+ # ==========================================
25
+ # 2. CARGA DE BASE DE DATOS (Caché)
26
+ # ==========================================
27
+ @st.cache_resource(show_spinner="Cargando base de datos clínica...")
28
+ def cargar_base_datos():
29
+ # Solo inicializamos el modelo de embeddings, no descargamos PDFs
30
+ embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2")
31
+
32
+ # Apuntamos a la carpeta que subiste a Hugging Face
33
+ directorio_db = "./db_hematologia"
34
+
35
+ # Conectamos ChromaDB a esa carpeta
36
+ vectorstore = Chroma(persist_directory=directorio_db, embedding_function=embeddings)
37
+
38
+ # Buscador MMR para respuestas variadas y precisas
39
+ retriever = vectorstore.as_retriever(search_type="mmr", search_kwargs={"k": 15, "fetch_k": 40})
40
+ return retriever
41
+
42
+ retriever = cargar_base_datos()
43
+
44
+ # ==========================================
45
+ # 3. CONFIGURACIÓN DEL MODELO (Gemini)
46
+ # ==========================================
47
+ api_key = os.environ.get("GEMINI_API_KEY")
48
+ if not api_key:
49
+ st.error("⚠️ Error: Falta configurar la GEMINI_API_KEY en los secretos de Hugging Face.")
50
+ st.stop()
51
+
52
+ # Usamos temperature=0.1 para que sea riguroso y académico
53
+ llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash", temperature=0.1, google_api_key=api_key)
54
+
55
+ # ==========================================
56
+ # 4. MEMORIA Y CHAT UI
57
+ # ==========================================
58
+ if "mensajes" not in st.session_state:
59
+ st.session_state.mensajes = [
60
+ {"role": "assistant", "content": "¡Hola! Soy Kimün. Ingresa tu consulta sobre guías clínicas, protocolos o diagnósticos hematológicos."}
61
+ ]
62
+
63
+ # Dibujar historial
64
+ for mensaje in st.session_state.mensajes:
65
+ with st.chat_message(mensaje["role"]):
66
+ st.markdown(mensaje["content"])
67
+
68
+ # Entrada del usuario
69
+ pregunta = st.chat_input("Ej: ¿Cuáles son los criterios diagnósticos para SMD según SOCHIHEM?")
70
+
71
+ if pregunta:
72
+ # Mostramos la pregunta en pantalla
73
+ st.session_state.mensajes.append({"role": "user", "content": pregunta})
74
+ with st.chat_message("user"):
75
+ st.markdown(pregunta)
76
+
77
+ # Construimos el historial corto para dar contexto a la IA (Últimos 3 mensajes)
78
+ historial = ""
79
+ if len(st.session_state.mensajes) > 2:
80
+ ultimos_mensajes = st.session_state.mensajes[-4:-1]
81
+ historial = "\n".join([f"{m['role'].upper()}: {m['content']}" for m in ultimos_mensajes])
82
+
83
+ # Generamos la respuesta
84
+ with st.chat_message("assistant"):
85
+ with st.spinner("Buscando en la literatura clínica..."):
86
+
87
+ # Buscar en ChromaDB local
88
+ docs = retriever.invoke(pregunta)
89
+ contexto_unido = "\n\n---\n\n".join([doc.page_content for doc in docs])
90
+
91
+ prompt_final = f"""Eres un asistente académico experto en hematología, diseñado para enseñar a estudiantes de tecnología médica y medicina en Chile.
92
+
93
+ REGLAS ESTRICTAS:
94
+ 1. Basa tu respuesta ÚNICAMENTE en el contexto recuperado de las bases de datos proporcionadas.
95
+ 2. Si la respuesta no está, responde: 'Lo siento, esta información no se encuentra en las guías y libros ingresados en mi base de datos.' No inventes.
96
+ 3. Lee el historial de la conversación para entender si el estudiante está haciendo una pregunta de seguimiento sobre una patología anterior.
97
+ 4. Desarrolla la respuesta de forma estructurada, usando viñetas si hay listas de criterios o valores.
98
+
99
+ HISTORIAL DE LA CONVERSACIÓN RECIENTE:
100
+ {historial}
101
+
102
+ CONTEXTO RECUPERADO DE LA BASE DE DATOS:
103
+ {contexto_unido}
104
+
105
+ PREGUNTA ACTUAL DEL ESTUDIANTE:
106
+ {pregunta}
107
+
108
+ RESPUESTA ACADÉMICA:"""
109
+
110
+ respuesta = llm.invoke(prompt_final)
111
+ st.markdown(respuesta.content)
112
+
113
+ # Guardamos en memoria
114
+ st.session_state.mensajes.append({"role": "assistant", "content": respuesta.content})