Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -6,7 +6,7 @@
|
|
| 6 |
# \ VVVV/ \VVVV /
|
| 7 |
# \____/ \____/
|
| 8 |
# __________________________________________________________________________________________________________
|
| 9 |
-
# Versión Final Estable
|
| 10 |
# Adaptado por JAIRO ALEXANDER ERASO MD U Nacional de Colombia, basado en la solicitud del usuario.
|
| 11 |
#
|
| 12 |
|
|
@@ -69,10 +69,7 @@ def load_data():
|
|
| 69 |
with open(path_notificacion, 'r', encoding='utf-8') as f:
|
| 70 |
data_notificacion = json.load(f)
|
| 71 |
|
| 72 |
-
# Crear un diccionario para búsqueda rápida de datos de notificación por FICHA
|
| 73 |
notificacion_map = {item['FICHA']: item for item in data_notificacion}
|
| 74 |
-
|
| 75 |
-
# Generar una lista de nombres de eventos únicos para la búsqueda con IA
|
| 76 |
nombres_eventos_unicos = sorted(list(set(item['NOMBRES DE PROTOCOLOS'] for item in data_codigos)))
|
| 77 |
|
| 78 |
logger.info(f"✅ Datos cargados: {len(data_codigos)} registros de códigos y {len(data_notificacion)} eventos de notificación.")
|
|
@@ -93,34 +90,41 @@ data_codigos, notificacion_map, nombres_eventos_unicos = load_data()
|
|
| 93 |
# --- LÓGICA DE BÚSQUEDA ---
|
| 94 |
|
| 95 |
def search_direct(query, data, notif_map):
|
| 96 |
-
"""
|
|
|
|
|
|
|
|
|
|
| 97 |
query_lower = query.lower().strip()
|
| 98 |
-
results = set() # Usar un set para evitar duplicados de fichas
|
| 99 |
|
|
|
|
|
|
|
| 100 |
for item in data:
|
| 101 |
-
ficha = item.get("FICHA")
|
| 102 |
-
if not ficha:
|
| 103 |
-
continue
|
| 104 |
-
|
| 105 |
-
# Comprobar coincidencias en varios campos
|
| 106 |
if (query_lower == item.get("CIE 10", "").lower().strip() or
|
| 107 |
query_lower == item.get("CIE 11", "").lower().strip() or
|
| 108 |
-
query_lower ==
|
| 109 |
query_lower in item.get("NOMBRES DE PROTOCOLOS", "").lower()):
|
| 110 |
-
|
| 111 |
|
| 112 |
-
if not
|
| 113 |
return []
|
| 114 |
|
| 115 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
final_results = []
|
| 117 |
-
for ficha in
|
| 118 |
-
detalles_codigos = [d for d in data if d.get("FICHA") == ficha]
|
| 119 |
info_notificacion = notif_map.get(ficha)
|
| 120 |
if info_notificacion:
|
| 121 |
final_results.append({
|
| 122 |
"info_notificacion": info_notificacion,
|
| 123 |
-
"detalles_codigos":
|
| 124 |
})
|
| 125 |
|
| 126 |
return final_results
|
|
@@ -171,7 +175,6 @@ def search_with_gemini(query, event_list):
|
|
| 171 |
st.title("👨⚕️ Asesor Experto en Notificación SIVIGILA - Colombia")
|
| 172 |
st.markdown("Busque una enfermedad por nombre, sinónimo, código CIE-10 o CIE-11 para obtener información de notificación.")
|
| 173 |
|
| 174 |
-
# Inicialización de session_state para guardar los resultados
|
| 175 |
if 'search_results' not in st.session_state:
|
| 176 |
st.session_state.search_results = None
|
| 177 |
if 'last_query' not in st.session_state:
|
|
@@ -182,17 +185,14 @@ def clear_search_state():
|
|
| 182 |
st.session_state.search_results = None
|
| 183 |
st.session_state.last_query = ""
|
| 184 |
|
| 185 |
-
# Uso de st.form para agrupar widgets y evitar re-ejecuciones no deseadas
|
| 186 |
with st.form(key="search_form"):
|
| 187 |
query = st.text_input(
|
| 188 |
"Ingrese su búsqueda:",
|
| 189 |
placeholder="Ej: Dengue, T630, mordedura de serpiente, 3MC...",
|
| 190 |
help="Puede buscar por nombre de la enfermedad, palabras clave, o códigos CIE."
|
| 191 |
)
|
| 192 |
-
|
| 193 |
submitted = st.form_submit_button("Buscar", type="primary")
|
| 194 |
|
| 195 |
-
# La lógica de búsqueda se ejecuta solo cuando el formulario es enviado
|
| 196 |
if submitted:
|
| 197 |
if not query:
|
| 198 |
st.warning("Por favor, ingrese un término de búsqueda.")
|
|
@@ -202,11 +202,8 @@ if submitted:
|
|
| 202 |
else:
|
| 203 |
with st.spinner("Buscando..."):
|
| 204 |
results = []
|
| 205 |
-
|
| 206 |
-
# 1. Búsqueda directa
|
| 207 |
direct_results = search_direct(query, data_codigos, notificacion_map)
|
| 208 |
|
| 209 |
-
# 2. Si falla, usar IA
|
| 210 |
if not direct_results:
|
| 211 |
logger.info(f"Búsqueda directa para '{query}' no arrojó resultados. Usando Gemini...")
|
| 212 |
protocol_names = search_with_gemini(query, nombres_eventos_unicos)
|
|
@@ -231,17 +228,14 @@ if submitted:
|
|
| 231 |
else:
|
| 232 |
results = direct_results
|
| 233 |
|
| 234 |
-
# Guardar resultados en la memoria de la sesión
|
| 235 |
st.session_state.search_results = results
|
| 236 |
st.session_state.last_query = query
|
| 237 |
|
| 238 |
-
# Botón para limpiar los resultados, visible solo si hay resultados en pantalla
|
| 239 |
if st.session_state.search_results is not None:
|
| 240 |
st.button("Limpiar Búsqueda", on_click=clear_search_state)
|
| 241 |
|
| 242 |
st.markdown("---")
|
| 243 |
|
| 244 |
-
# La lógica de visualización lee siempre de la memoria de la sesión
|
| 245 |
if st.session_state.search_results is not None:
|
| 246 |
results = st.session_state.search_results
|
| 247 |
|
|
@@ -255,7 +249,6 @@ if st.session_state.search_results is not None:
|
|
| 255 |
codigos = result["detalles_codigos"]
|
| 256 |
|
| 257 |
with st.expander(f"**Evento: {info.get('Evento', 'Sin nombre')} (Ficha: {info.get('FICHA', 'N/A')})**", expanded=True):
|
| 258 |
-
|
| 259 |
st.subheader("Información de Notificación")
|
| 260 |
|
| 261 |
notif_super = info.get("Notificación superinmedita", "NO") == "SI"
|
|
|
|
| 6 |
# \ VVVV/ \VVVV /
|
| 7 |
# \____/ \____/
|
| 8 |
# __________________________________________________________________________________________________________
|
| 9 |
+
# Versión Final Estable con Búsqueda Específica
|
| 10 |
# Adaptado por JAIRO ALEXANDER ERASO MD U Nacional de Colombia, basado en la solicitud del usuario.
|
| 11 |
#
|
| 12 |
|
|
|
|
| 69 |
with open(path_notificacion, 'r', encoding='utf-8') as f:
|
| 70 |
data_notificacion = json.load(f)
|
| 71 |
|
|
|
|
| 72 |
notificacion_map = {item['FICHA']: item for item in data_notificacion}
|
|
|
|
|
|
|
| 73 |
nombres_eventos_unicos = sorted(list(set(item['NOMBRES DE PROTOCOLOS'] for item in data_codigos)))
|
| 74 |
|
| 75 |
logger.info(f"✅ Datos cargados: {len(data_codigos)} registros de códigos y {len(data_notificacion)} eventos de notificación.")
|
|
|
|
| 90 |
# --- LÓGICA DE BÚSQUEDA ---
|
| 91 |
|
| 92 |
def search_direct(query, data, notif_map):
|
| 93 |
+
"""
|
| 94 |
+
Realiza una búsqueda directa y devuelve solo los ítems que coinciden,
|
| 95 |
+
agrupados por su Ficha/Evento.
|
| 96 |
+
"""
|
| 97 |
query_lower = query.lower().strip()
|
|
|
|
| 98 |
|
| 99 |
+
# 1. Encontrar todos los ítems individuales que coinciden con la búsqueda
|
| 100 |
+
matching_items = []
|
| 101 |
for item in data:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
if (query_lower == item.get("CIE 10", "").lower().strip() or
|
| 103 |
query_lower == item.get("CIE 11", "").lower().strip() or
|
| 104 |
+
query_lower == item.get("FICHA", "").lower().strip() or
|
| 105 |
query_lower in item.get("NOMBRES DE PROTOCOLOS", "").lower()):
|
| 106 |
+
matching_items.append(item)
|
| 107 |
|
| 108 |
+
if not matching_items:
|
| 109 |
return []
|
| 110 |
|
| 111 |
+
# 2. Agrupar los ítems coincidentes por su número de Ficha
|
| 112 |
+
grouped_by_ficha = {}
|
| 113 |
+
for item in matching_items:
|
| 114 |
+
ficha = item.get("FICHA")
|
| 115 |
+
if ficha:
|
| 116 |
+
if ficha not in grouped_by_ficha:
|
| 117 |
+
grouped_by_ficha[ficha] = []
|
| 118 |
+
grouped_by_ficha[ficha].append(item)
|
| 119 |
+
|
| 120 |
+
# 3. Construir la lista de resultados final con los datos ya filtrados
|
| 121 |
final_results = []
|
| 122 |
+
for ficha, matched_details in grouped_by_ficha.items():
|
|
|
|
| 123 |
info_notificacion = notif_map.get(ficha)
|
| 124 |
if info_notificacion:
|
| 125 |
final_results.append({
|
| 126 |
"info_notificacion": info_notificacion,
|
| 127 |
+
"detalles_codigos": matched_details
|
| 128 |
})
|
| 129 |
|
| 130 |
return final_results
|
|
|
|
| 175 |
st.title("👨⚕️ Asesor Experto en Notificación SIVIGILA - Colombia")
|
| 176 |
st.markdown("Busque una enfermedad por nombre, sinónimo, código CIE-10 o CIE-11 para obtener información de notificación.")
|
| 177 |
|
|
|
|
| 178 |
if 'search_results' not in st.session_state:
|
| 179 |
st.session_state.search_results = None
|
| 180 |
if 'last_query' not in st.session_state:
|
|
|
|
| 185 |
st.session_state.search_results = None
|
| 186 |
st.session_state.last_query = ""
|
| 187 |
|
|
|
|
| 188 |
with st.form(key="search_form"):
|
| 189 |
query = st.text_input(
|
| 190 |
"Ingrese su búsqueda:",
|
| 191 |
placeholder="Ej: Dengue, T630, mordedura de serpiente, 3MC...",
|
| 192 |
help="Puede buscar por nombre de la enfermedad, palabras clave, o códigos CIE."
|
| 193 |
)
|
|
|
|
| 194 |
submitted = st.form_submit_button("Buscar", type="primary")
|
| 195 |
|
|
|
|
| 196 |
if submitted:
|
| 197 |
if not query:
|
| 198 |
st.warning("Por favor, ingrese un término de búsqueda.")
|
|
|
|
| 202 |
else:
|
| 203 |
with st.spinner("Buscando..."):
|
| 204 |
results = []
|
|
|
|
|
|
|
| 205 |
direct_results = search_direct(query, data_codigos, notificacion_map)
|
| 206 |
|
|
|
|
| 207 |
if not direct_results:
|
| 208 |
logger.info(f"Búsqueda directa para '{query}' no arrojó resultados. Usando Gemini...")
|
| 209 |
protocol_names = search_with_gemini(query, nombres_eventos_unicos)
|
|
|
|
| 228 |
else:
|
| 229 |
results = direct_results
|
| 230 |
|
|
|
|
| 231 |
st.session_state.search_results = results
|
| 232 |
st.session_state.last_query = query
|
| 233 |
|
|
|
|
| 234 |
if st.session_state.search_results is not None:
|
| 235 |
st.button("Limpiar Búsqueda", on_click=clear_search_state)
|
| 236 |
|
| 237 |
st.markdown("---")
|
| 238 |
|
|
|
|
| 239 |
if st.session_state.search_results is not None:
|
| 240 |
results = st.session_state.search_results
|
| 241 |
|
|
|
|
| 249 |
codigos = result["detalles_codigos"]
|
| 250 |
|
| 251 |
with st.expander(f"**Evento: {info.get('Evento', 'Sin nombre')} (Ficha: {info.get('FICHA', 'N/A')})**", expanded=True):
|
|
|
|
| 252 |
st.subheader("Información de Notificación")
|
| 253 |
|
| 254 |
notif_super = info.get("Notificación superinmedita", "NO") == "SI"
|