Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -684,15 +684,13 @@ def find_best_matches_hybrid(entities, data):
|
|
| 684 |
|
| 685 |
@retry(wait=wait_random_exponential(min=1, max=10), stop=stop_after_attempt(3))
|
| 686 |
|
| 687 |
-
def
|
| 688 |
"""
|
| 689 |
-
Encuentra
|
| 690 |
-
utilizando un algoritmo de "embudo de especificidad".
|
| 691 |
"""
|
| 692 |
if not user_foods_es:
|
| 693 |
-
return
|
| 694 |
|
| 695 |
-
# 1. Traducir y ordenar los términos de búsqueda del más al menos específico
|
| 696 |
search_terms_en = set()
|
| 697 |
for food_es in user_foods_es:
|
| 698 |
for key_es, value_en_list in food_name_map.items():
|
|
@@ -700,35 +698,28 @@ def find_best_foodb_match(user_foods_es, foodb_index_keys, food_name_map):
|
|
| 700 |
search_terms_en.update(value_en_list)
|
| 701 |
|
| 702 |
if not search_terms_en:
|
| 703 |
-
return
|
| 704 |
|
| 705 |
sorted_terms = sorted(list(search_terms_en), key=len, reverse=True)
|
| 706 |
-
|
| 707 |
-
# 2. Búsqueda por prioridades (Embudo de Especificidad)
|
| 708 |
|
| 709 |
-
|
|
|
|
|
|
|
| 710 |
for term in sorted_terms:
|
|
|
|
| 711 |
for key in foodb_index_keys:
|
| 712 |
-
if term == key.lower():
|
| 713 |
-
|
| 714 |
-
|
| 715 |
-
|
| 716 |
-
# Prioridad 2: Coincidencia de Inicio de Palabra
|
| 717 |
-
for term in sorted_terms:
|
| 718 |
for key in foodb_index_keys:
|
| 719 |
-
if key.lower().startswith(term):
|
| 720 |
-
|
| 721 |
-
|
| 722 |
-
|
| 723 |
-
# Prioridad 3: Coincidencia General (contiene)
|
| 724 |
-
for term in sorted_terms:
|
| 725 |
for key in foodb_index_keys:
|
| 726 |
-
if term in key.lower():
|
| 727 |
-
|
| 728 |
-
|
| 729 |
-
|
| 730 |
-
logger.warning(f"No se encontró ninguna coincidencia molecular para los términos: {sorted_terms}")
|
| 731 |
-
return None # No se encontró ninguna coincidencia
|
| 732 |
|
| 733 |
def generate_detailed_analysis(query, match):
|
| 734 |
if not model: return "Error: El modelo de IA no está disponible."
|
|
@@ -920,81 +911,49 @@ if st.session_state.search_results is not None:
|
|
| 920 |
|
| 921 |
st.write("")
|
| 922 |
if foodb_index:
|
| 923 |
-
with st.popover("🔬 Componentes Moleculares
|
| 924 |
|
| 925 |
-
|
| 926 |
-
|
| 927 |
-
st.info("Compuestos en el alimento más relevante que podrían estar relacionados con tus síntomas.")
|
| 928 |
|
| 929 |
user_foods_mentioned = st.session_state.entities.get("alimentos", [])
|
| 930 |
-
user_symptoms_es = st.session_state.entities.get("sintomas", [])
|
| 931 |
|
| 932 |
-
if not user_foods_mentioned
|
| 933 |
-
st.warning("
|
| 934 |
else:
|
| 935 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 936 |
|
| 937 |
-
if not
|
| 938 |
st.warning("No se encontraron datos moleculares para los alimentos específicos mencionados.")
|
| 939 |
else:
|
| 940 |
-
|
| 941 |
-
|
| 942 |
-
|
| 943 |
-
symptom_keywords_en = {kw for sym in user_symptoms_es if sym in MASTER_SYMPTOM_MAP for kw in MASTER_SYMPTOM_MAP[sym].get('keywords_en', [])}
|
| 944 |
-
|
| 945 |
-
causative_compounds = []
|
| 946 |
-
remedial_compounds = []
|
| 947 |
-
|
| 948 |
-
for item in compounds_data:
|
| 949 |
-
compound_name = item['compound']
|
| 950 |
-
effects_en = item.get("effects", [])
|
| 951 |
|
| 952 |
-
#
|
| 953 |
-
|
| 954 |
-
|
| 955 |
-
|
| 956 |
-
|
| 957 |
-
|
| 958 |
-
|
| 959 |
-
|
| 960 |
-
if
|
| 961 |
-
|
| 962 |
-
|
| 963 |
-
|
| 964 |
-
|
| 965 |
-
|
| 966 |
-
|
| 967 |
-
|
| 968 |
-
|
| 969 |
-
|
| 970 |
-
|
| 971 |
-
is_causative = True
|
| 972 |
-
|
| 973 |
-
if is_causative:
|
| 974 |
-
causative_compounds.append(item)
|
| 975 |
-
elif is_remedial:
|
| 976 |
-
remedial_compounds.append(item)
|
| 977 |
-
|
| 978 |
-
# 3. Mostrar los resultados de forma priorizada
|
| 979 |
-
if causative_compounds:
|
| 980 |
-
st.markdown("###### 🔬 Posibles Compuestos Desencadenantes:")
|
| 981 |
-
for item in causative_compounds[:5]:
|
| 982 |
-
st.write(f"**Compuesto:** {item['compound']}")
|
| 983 |
-
# Mostramos por qué es un desencadenante conocido, o los efectos relevantes
|
| 984 |
-
if item['compound'] in KNOWN_TRIGGERS_MAP:
|
| 985 |
-
st.write(f"**Efectos Relevantes:** Desencadenante conocido de {', '.join([s for s in user_symptoms_es if s in KNOWN_TRIGGERS_MAP[item['compound']]])}")
|
| 986 |
-
else:
|
| 987 |
-
relevant_effects = [eff for eff in item['effects'] if any(kw in eff.lower() and not eff.lower().startswith(REMEDIAL_PREFIXES) for kw in symptom_keywords_en)]
|
| 988 |
-
st.write(f"**Efectos Relevantes:** {', '.join(relevant_effects)}")
|
| 989 |
-
elif remedial_compounds:
|
| 990 |
-
st.markdown("###### 💊 Compuestos con Efectos Potencialmente Beneficiosos:")
|
| 991 |
-
st.caption("No se encontraron compuestos desencadenantes directos en la base de datos.")
|
| 992 |
-
for item in remedial_compounds[:5]:
|
| 993 |
-
st.write(f"**Compuesto:** {item['compound']}")
|
| 994 |
-
relevant_effects = [eff for eff in item['effects'] if any(kw in eff.lower() and eff.lower().startswith(REMEDIAL_PREFIXES) for kw in symptom_keywords_en)]
|
| 995 |
-
st.write(f"**Efectos Relevantes:** {', '.join(relevant_effects)}")
|
| 996 |
-
else:
|
| 997 |
-
st.write("No se encontraron compuestos relevantes para tus síntomas en este alimento.")
|
| 998 |
|
| 999 |
st.markdown("---")
|
| 1000 |
|
|
|
|
| 684 |
|
| 685 |
@retry(wait=wait_random_exponential(min=1, max=10), stop=stop_after_attempt(3))
|
| 686 |
|
| 687 |
+
def find_best_foodb_matches(user_foods_es, foodb_index_keys, food_name_map, limit=3):
|
| 688 |
"""
|
| 689 |
+
Encuentra una lista de las mejores coincidencias de alimentos en FoodB, priorizando la especificidad.
|
|
|
|
| 690 |
"""
|
| 691 |
if not user_foods_es:
|
| 692 |
+
return []
|
| 693 |
|
|
|
|
| 694 |
search_terms_en = set()
|
| 695 |
for food_es in user_foods_es:
|
| 696 |
for key_es, value_en_list in food_name_map.items():
|
|
|
|
| 698 |
search_terms_en.update(value_en_list)
|
| 699 |
|
| 700 |
if not search_terms_en:
|
| 701 |
+
return []
|
| 702 |
|
| 703 |
sorted_terms = sorted(list(search_terms_en), key=len, reverse=True)
|
|
|
|
|
|
|
| 704 |
|
| 705 |
+
found_matches = []
|
| 706 |
+
|
| 707 |
+
# Búsqueda por prioridades
|
| 708 |
for term in sorted_terms:
|
| 709 |
+
# Prioridad 1: Coincidencia perfecta
|
| 710 |
for key in foodb_index_keys:
|
| 711 |
+
if term == key.lower() and key not in found_matches:
|
| 712 |
+
found_matches.append(key)
|
| 713 |
+
# Prioridad 2: Coincidencia de inicio
|
|
|
|
|
|
|
|
|
|
| 714 |
for key in foodb_index_keys:
|
| 715 |
+
if key.lower().startswith(term) and key not in found_matches:
|
| 716 |
+
found_matches.append(key)
|
| 717 |
+
# Prioridad 3: Coincidencia general
|
|
|
|
|
|
|
|
|
|
| 718 |
for key in foodb_index_keys:
|
| 719 |
+
if term in key.lower() and key not in found_matches:
|
| 720 |
+
found_matches.append(key)
|
| 721 |
+
|
| 722 |
+
return found_matches[:limit]
|
|
|
|
|
|
|
| 723 |
|
| 724 |
def generate_detailed_analysis(query, match):
|
| 725 |
if not model: return "Error: El modelo de IA no está disponible."
|
|
|
|
| 911 |
|
| 912 |
st.write("")
|
| 913 |
if foodb_index:
|
| 914 |
+
with st.popover("🔬 Componentes Moleculares del Diagnóstico"):
|
| 915 |
|
| 916 |
+
st.info("Análisis de los compuestos en los alimentos mencionados que están directamente implicados en el diagnóstico principal.")
|
|
|
|
|
|
|
| 917 |
|
| 918 |
user_foods_mentioned = st.session_state.entities.get("alimentos", [])
|
|
|
|
| 919 |
|
| 920 |
+
if not user_foods_mentioned:
|
| 921 |
+
st.warning("No se identificó un alimento específico para buscar.")
|
| 922 |
else:
|
| 923 |
+
# 1. IDENTIFICAR LOS COMPUESTOS OBJETIVO DEL DIAGNÓSTICO
|
| 924 |
+
target_compounds_text = best_match.get("compuesto_alimento", "").lower()
|
| 925 |
+
# Extraer palabras clave del texto (ej. "purinas", "histamina")
|
| 926 |
+
target_keywords = set(re.findall(r'\b\w+\b', re.sub(r'\(.*?\)', '', target_compounds_text)))
|
| 927 |
+
|
| 928 |
+
# 2. ENCONTRAR LOS ALIMENTOS MÁS RELEVANTES
|
| 929 |
+
best_food_matches = find_best_foodb_matches(user_foods_mentioned, foodb_index.keys(), FOOD_NAME_TO_FOODB_KEY)
|
| 930 |
|
| 931 |
+
if not best_food_matches:
|
| 932 |
st.warning("No se encontraron datos moleculares para los alimentos específicos mencionados.")
|
| 933 |
else:
|
| 934 |
+
found_any_data = False
|
| 935 |
+
for food_key in best_food_matches:
|
| 936 |
+
compounds_data = foodb_index.get(food_key, [])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 937 |
|
| 938 |
+
# 3. BUSCAR LOS COMPUESTOS OBJETIVO EN CADA ALIMENTO
|
| 939 |
+
relevant_compounds = []
|
| 940 |
+
for item in compounds_data:
|
| 941 |
+
compound_name_lower = item['compound'].lower()
|
| 942 |
+
# Comprobar si el nombre del compuesto está relacionado con los objetivos
|
| 943 |
+
if any(keyword in compound_name_lower for keyword in target_keywords):
|
| 944 |
+
relevant_compounds.append(item)
|
| 945 |
+
|
| 946 |
+
if relevant_compounds:
|
| 947 |
+
found_any_data = True
|
| 948 |
+
with st.container(border=True):
|
| 949 |
+
st.subheader(f"Análisis de: {food_key.capitalize()}")
|
| 950 |
+
st.markdown("###### 🔬 Compuestos Relevantes para el Diagnóstico:")
|
| 951 |
+
for item in relevant_compounds[:5]:
|
| 952 |
+
st.write(f"**Compuesto:** {item['compound']}")
|
| 953 |
+
st.caption(f"Este compuesto está directamente relacionado con '{best_match.get('condicion_asociada')}'.")
|
| 954 |
+
|
| 955 |
+
if not found_any_data:
|
| 956 |
+
st.warning(f"No se encontraron los compuestos específicos de '{best_match.get('condicion_asociada')}' en los alimentos analizados en la base de datos FoodB.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 957 |
|
| 958 |
st.markdown("---")
|
| 959 |
|