JairoCesar commited on
Commit
bd8f975
·
verified ·
1 Parent(s): f24c6ab

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +123 -91
app.py CHANGED
@@ -891,7 +891,93 @@ def create_relevance_chart(results):
891
  )
892
 
893
  return chart
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
894
 
 
 
 
 
 
895
  def generate_report_text(query, results):
896
  report_lines = ["="*50, "INFORME DEL DETECTIVE DE ALIMENTOS", "="*50, f"Fecha: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n", f"CONSULTA ORIGINAL DEL USUARIO:\n'{query}'\n", "-"*50]
897
  if results:
@@ -981,16 +1067,42 @@ if st.session_state.search_results is not None:
981
  if not results:
982
  st.warning(f"No se encontraron coincidencias claras para tu caso: '{st.session_state.user_query}'. Prueba a describir los síntomas de otra manera.")
983
  else:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
984
  col1, col2 = st.columns([3,1])
985
  with col1:
986
  st.success(f"Hemos encontrado {len(results)} posible(s) causa(s) relacionada(s) con tu caso.")
987
  with col2:
988
- report_data_text = generate_report_text(st.session_state.user_query, results)
989
- word_file_buffer = generate_word_report(report_data_text)
990
-
991
  if word_file_buffer:
992
  st.download_button(
993
- label="📄 Descargar Informe (Word)",
994
  data=word_file_buffer,
995
  file_name=f"Informe_Detective_Alimentos_{datetime.now().strftime('%Y%m%d')}.docx",
996
  mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
@@ -1000,11 +1112,8 @@ if st.session_state.search_results is not None:
1000
  st.subheader("Análisis de Relevancia de las Coincidencias")
1001
  st.altair_chart(create_relevance_chart(results), use_container_width=True)
1002
 
1003
- best_match_data = results[0]
1004
- best_match = best_match_data['entry']
1005
  with st.expander(f"**Análisis Detallado de la Principal Coincidencia: {best_match.get('condicion_asociada')}**", expanded=True):
1006
  col1_expander, col2_expander = st.columns([3, 1])
1007
-
1008
  with col1_expander:
1009
  st.markdown("##### Desglose de la Puntuación de Relevancia:")
1010
  score_col1, score_col2, score_col3 = st.columns(3)
@@ -1013,95 +1122,18 @@ if st.session_state.search_results is not None:
1013
  score_col3.metric("PUNTUACIÓN TOTAL", f"{best_match_data['score']['total']}", delta="Máxima coincidencia")
1014
 
1015
  with col2_expander:
1016
- st.write("")
1017
- if foodb_index:
1018
- with st.popover("🔬 Componentes Moleculares del Diagnóstico"):
1019
- st.info("Análisis de los compuestos en los alimentos mencionados que están directamente implicados en el diagnóstico principal.")
1020
- user_foods_mentioned = st.session_state.entities.get("alimentos", [])
1021
-
1022
- if not user_foods_mentioned:
1023
- st.warning("No se identificó un alimento específico para buscar.")
1024
- else:
1025
- initial_clues = set()
1026
- direct_text = best_match.get("compuesto_alimento", "").lower()
1027
- cleaned_text = re.sub(r'\(.*?\)', '', direct_text)
1028
- initial_clues.update(re.findall(r'\b[a-zA-Z-]+\b', cleaned_text))
1029
-
1030
- main_diagnosis_symptoms = set(s.lower() for s in best_match.get("sintomas_clave", []))
1031
- for compound, triggered_symptoms in KNOWN_TRIGGERS_MAP.items():
1032
- if main_diagnosis_symptoms.intersection(triggered_symptoms):
1033
- initial_clues.add(compound.lower())
1034
 
1035
- final_search_keywords = set()
1036
- for clue in initial_clues:
1037
- final_search_keywords.add(clue)
1038
- if clue in COMPOUND_SYNONYM_MAP:
1039
- final_search_keywords.update(COMPOUND_SYNONYM_MAP[clue])
1040
-
1041
- if not final_search_keywords:
1042
- st.warning(f"No se pudieron determinar los compuestos moleculares clave para '{best_match.get('condicion_asociada')}'.")
1043
- else:
1044
- logger.info(f"Buscando compuestos moleculares con las palabras clave: {final_search_keywords}")
1045
- best_food_matches = find_best_foodb_matches(user_foods_mentioned, foodb_index.keys(), FOOD_NAME_TO_FOODB_KEY)
1046
-
1047
- if not best_food_matches:
1048
- st.warning("No se encontraron datos moleculares para los alimentos específicos mencionados.")
1049
- else:
1050
- found_any_data = False
1051
- for food_key in best_food_matches:
1052
- compounds_data = foodb_index.get(food_key, [])
1053
- relevant_compounds = []
1054
- for item in compounds_data:
1055
- compound_name_lower = item['compound'].lower()
1056
- if any(target in compound_name_lower for target in final_search_keywords):
1057
- relevant_compounds.append(item)
1058
-
1059
- if relevant_compounds:
1060
- found_any_data = True
1061
- with st.container(border=True):
1062
- st.subheader(f"Análisis de: {food_key.capitalize()}")
1063
- st.markdown("###### 🔬 Compuestos Relevantes para el Diagnóstico:")
1064
- unique_compounds_shown = set()
1065
- for item in relevant_compounds:
1066
- if item['compound'] not in unique_compounds_shown:
1067
- st.write(f"**Compuesto:** {item['compound']}")
1068
- st.caption(f"Relevante para '{best_match.get('condicion_asociada')}'.")
1069
- unique_compounds_shown.add(item['compound'])
1070
-
1071
- if not found_any_data:
1072
- 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.")
1073
-
1074
  st.markdown("---")
1075
  with st.container(border=True):
1076
- st.markdown("##### 🧠 Posibles Efectos Neuropsicológicos de los Componentes")
1077
- user_foods = st.session_state.entities.get("alimentos", [])
1078
- relevant_compounds = set()
1079
- if user_foods:
1080
- for food in user_foods:
1081
- if food in FOOD_TO_COMPOUND_MAP:
1082
- relevant_compounds.update(FOOD_TO_COMPOUND_MAP[food])
1083
- found_neuro_effect = False
1084
- if relevant_compounds:
1085
- for compound in sorted(list(relevant_compounds)):
1086
- if compound in INTEGRATED_NEURO_FOOD_MAP:
1087
- found_neuro_effect = True
1088
- effect_info = INTEGRATED_NEURO_FOOD_MAP[compound]
1089
- with st.container(border=True):
1090
- st.subheader(f"Componente: {compound.capitalize()}")
1091
- st.markdown(f"**Efecto:** {effect_info['efecto_neuropsicologico']}")
1092
- if not found_neuro_effect:
1093
- st.info("No se encontraron efectos neuropsicológicos específicos en la base de datos para los componentes de los alimentos mencionados.")
1094
 
1095
  st.markdown("---")
1096
- with st.spinner("✍️ Generando un análisis personalizado con IA..."):
1097
- if 'best_match_analysis' not in st.session_state.analysis_cache:
1098
- try:
1099
- analysis_text = generate_detailed_analysis(st.session_state.user_query, best_match)
1100
- st.session_state.analysis_cache['best_match_analysis'] = analysis_text
1101
- except Exception as e:
1102
- logger.error(f"Falló la generación del análisis detallado principal: {e}")
1103
- st.session_state.analysis_cache['best_match_analysis'] = "❌ Lo sentimos, no se pudo generar el análisis detallado en este momento debido a un problema con la IA. Por favor, intenta de nuevo más tarde."
1104
- st.markdown(st.session_state.analysis_cache['best_match_analysis'])
1105
 
1106
  if len(results) > 1:
1107
  with st.expander("🔍 **Explora otras posibilidades relevantes (Diagnóstico Diferencial)**"):
 
891
  )
892
 
893
  return chart
894
+
895
+ def generate_neuro_report_text(entities, food_map, neuro_map):
896
+ """
897
+ Genera una sección de texto para el informe de Word sobre los efectos neuropsicológicos.
898
+ """
899
+ report_lines = ["\n\n" + "="*50, "🧠 POSIBLES EFECTOS NEUROPSICOLÓGICOS DE LOS COMPONENTES", "="*50 + "\n"]
900
+ user_foods = entities.get("alimentos", [])
901
+ relevant_compounds = set()
902
+ if user_foods:
903
+ for food in user_foods:
904
+ if food in food_map:
905
+ relevant_compounds.update(food_map[food])
906
+
907
+ found_neuro_effect = False
908
+ if relevant_compounds:
909
+ for compound in sorted(list(relevant_compounds)):
910
+ if compound in neuro_map:
911
+ found_neuro_effect = True
912
+ effect_info = neuro_map[compound]
913
+ report_lines.append(f"--- Componente: {compound.capitalize()} ---")
914
+ report_lines.append(f"Efecto: {effect_info['efecto_neuropsicologico']}\n")
915
+
916
+ if not found_neuro_effect:
917
+ report_lines.append("No se encontraron efectos neuropsicológicos específicos en la base de datos para los componentes de los alimentos mencionados.")
918
+
919
+ return "\n".join(report_lines)
920
+
921
+ def generate_molecular_report_text(best_match, entities, foodb_index, food_name_map, synonym_map, triggers_map):
922
+ """
923
+ Genera una sección de texto para el informe de Word sobre el análisis molecular.
924
+ """
925
+ report_lines = ["\n\n" + "="*50, "🔬 COMPONENTES MOLECULARES DEL DIAGNÓSTICO", "="*50 + "\n"]
926
+ user_foods_mentioned = entities.get("alimentos", [])
927
+
928
+ if not user_foods_mentioned:
929
+ report_lines.append("No se identificó un alimento específico para el análisis molecular.")
930
+ return "\n".join(report_lines)
931
+
932
+ initial_clues = set()
933
+ direct_text = best_match.get("compuesto_alimento", "").lower()
934
+ cleaned_text = re.sub(r'\(.*?\)', '', direct_text)
935
+ initial_clues.update(re.findall(r'\b[a-zA-Z-]+\b', cleaned_text))
936
+
937
+ main_diagnosis_symptoms = set(s.lower() for s in best_match.get("sintomas_clave", []))
938
+ for compound, triggered_symptoms in triggers_map.items():
939
+ if main_diagnosis_symptoms.intersection(triggered_symptoms):
940
+ initial_clues.add(compound.lower())
941
+
942
+ final_search_keywords = set()
943
+ for clue in initial_clues:
944
+ final_search_keywords.add(clue)
945
+ if clue in synonym_map:
946
+ final_search_keywords.update(synonym_map[clue])
947
+
948
+ if not final_search_keywords:
949
+ report_lines.append(f"No se pudieron determinar los compuestos moleculares clave para '{best_match.get('condicion_asociada')}'.")
950
+ return "\n".join(report_lines)
951
+
952
+ best_food_matches = find_best_foodb_matches(user_foods_mentioned, foodb_index.keys(), food_name_map)
953
+
954
+ if not best_food_matches:
955
+ report_lines.append("No se encontraron datos moleculares para los alimentos específicos mencionados.")
956
+ return "\n".join(report_lines)
957
+
958
+ found_any_data = False
959
+ for food_key in best_food_matches:
960
+ compounds_data = foodb_index.get(food_key, [])
961
+ relevant_compounds = []
962
+ for item in compounds_data:
963
+ if any(target in item['compound'].lower() for target in final_search_keywords):
964
+ relevant_compounds.append(item)
965
+
966
+ if relevant_compounds:
967
+ found_any_data = True
968
+ report_lines.append(f"\n--- Análisis de: {food_key.capitalize()} ---")
969
+ unique_compounds_shown = set()
970
+ for item in relevant_compounds:
971
+ if item['compound'] not in unique_compounds_shown:
972
+ report_lines.append(f"Compuesto: {item['compound']}")
973
+ report_lines.append(f"(Relevante para '{best_match.get('condicion_asociada')}')\n")
974
+ unique_compounds_shown.add(item['compound'])
975
 
976
+ if not found_any_data:
977
+ report_lines.append(f"No se encontraron los compuestos específicos de '{best_match.get('condicion_asociada')}' en los alimentos analizados.")
978
+
979
+ return "\n".join(report_lines)
980
+
981
  def generate_report_text(query, results):
982
  report_lines = ["="*50, "INFORME DEL DETECTIVE DE ALIMENTOS", "="*50, f"Fecha: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n", f"CONSULTA ORIGINAL DEL USUARIO:\n'{query}'\n", "-"*50]
983
  if results:
 
1067
  if not results:
1068
  st.warning(f"No se encontraron coincidencias claras para tu caso: '{st.session_state.user_query}'. Prueba a describir los síntomas de otra manera.")
1069
  else:
1070
+ # --- PASO 1: GENERAR TODO EL CONTENIDO DEL INFORME EN LA MEMORIA ---
1071
+ best_match_data = results[0]
1072
+ best_match = best_match_data['entry']
1073
+
1074
+ # Generar análisis detallado con IA (la parte más lenta) y guardarlo en caché
1075
+ if 'best_match_analysis' not in st.session_state.analysis_cache:
1076
+ with st.spinner("✍️ Generando an��lisis personalizado con IA..."):
1077
+ try:
1078
+ analysis_text = generate_detailed_analysis(st.session_state.user_query, best_match)
1079
+ st.session_state.analysis_cache['best_match_analysis'] = analysis_text
1080
+ except Exception as e:
1081
+ logger.error(f"Falló la generación del análisis detallado principal: {e}")
1082
+ st.session_state.analysis_cache['best_match_analysis'] = "❌ Lo sentimos, no se pudo generar el análisis detallado en este momento debido a un problema con la IA."
1083
+
1084
+ # Recuperar o usar el texto ya generado
1085
+ ai_analysis_text = st.session_state.analysis_cache['best_match_analysis']
1086
+
1087
+ # Generar los otros componentes de texto para el informe
1088
+ base_report_text = generate_report_text(st.session_state.user_query, results)
1089
+ neuro_report_text = generate_neuro_report_text(st.session_state.entities, FOOD_TO_COMPOUND_MAP, INTEGRATED_NEURO_FOOD_MAP)
1090
+ molecular_report_text = generate_molecular_report_text(best_match, st.session_state.entities, foodb_index, FOOD_NAME_TO_FOODB_KEY, COMPOUND_SYNONYM_MAP, KNOWN_TRIGGERS_MAP)
1091
+
1092
+ # Unir todo en un solo string para el informe de Word
1093
+ complete_report_string = f"{base_report_text}\n\n{ai_analysis_text}\n{neuro_report_text}\n{molecular_report_text}"
1094
+
1095
+ # Generar el archivo de Word en memoria con todo el contenido
1096
+ word_file_buffer = generate_word_report(complete_report_string)
1097
+
1098
+ # --- PASO 2: CONSTRUIR LA INTERFAZ DE USUARIO USANDO EL CONTENIDO PRE-GENERADO ---
1099
  col1, col2 = st.columns([3,1])
1100
  with col1:
1101
  st.success(f"Hemos encontrado {len(results)} posible(s) causa(s) relacionada(s) con tu caso.")
1102
  with col2:
 
 
 
1103
  if word_file_buffer:
1104
  st.download_button(
1105
+ label="📄 Descargar Informe Completo (Word)",
1106
  data=word_file_buffer,
1107
  file_name=f"Informe_Detective_Alimentos_{datetime.now().strftime('%Y%m%d')}.docx",
1108
  mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
 
1112
  st.subheader("Análisis de Relevancia de las Coincidencias")
1113
  st.altair_chart(create_relevance_chart(results), use_container_width=True)
1114
 
 
 
1115
  with st.expander(f"**Análisis Detallado de la Principal Coincidencia: {best_match.get('condicion_asociada')}**", expanded=True):
1116
  col1_expander, col2_expander = st.columns([3, 1])
 
1117
  with col1_expander:
1118
  st.markdown("##### Desglose de la Puntuación de Relevancia:")
1119
  score_col1, score_col2, score_col3 = st.columns(3)
 
1122
  score_col3.metric("PUNTUACIÓN TOTAL", f"{best_match_data['score']['total']}", delta="Máxima coincidencia")
1123
 
1124
  with col2_expander:
1125
+ with st.popover("🔬 Componentes Moleculares"):
1126
+ # Muestra el texto del informe molecular que ya generamos
1127
+ st.markdown(molecular_report_text.replace("=", ""))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1128
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1129
  st.markdown("---")
1130
  with st.container(border=True):
1131
+ # Muestra el texto del informe neuropsicológico que ya generamos
1132
+ st.markdown(neuro_report_text.replace("=", ""))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1133
 
1134
  st.markdown("---")
1135
+ # Muestra el análisis detallado con IA que ya generamos
1136
+ st.markdown(ai_analysis_text)
 
 
 
 
 
 
 
1137
 
1138
  if len(results) > 1:
1139
  with st.expander("🔍 **Explora otras posibilidades relevantes (Diagnóstico Diferencial)**"):