JairoCesar commited on
Commit
5a55c0b
·
verified ·
1 Parent(s): 132718d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -66
app.py CHANGED
@@ -1,5 +1,5 @@
1
- # ==================== El Detective de Alimentos (Versión 8.1 - Diagnóstico Diferencial) =====================================
2
- # Mejoras: Presentación de un "Top 3" de resultados con justificación de síntomas.
3
 
4
  import streamlit as st
5
  import google.generativeai as genai
@@ -18,7 +18,7 @@ st.set_page_config(
18
  layout="wide"
19
  )
20
 
21
- # ... (Configuración de Gemini y carga de datos no cambia) ...
22
  # Configurar logging
23
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
24
  logger = logging.getLogger("food_detective_app")
@@ -74,39 +74,43 @@ def load_data():
74
  alimentos_data, lista_condiciones, foodb_index = load_data()
75
 
76
 
77
- # --- DICCIONARIOS Y FUNCIONES AUXILIARES (CON CAMBIOS) ---
78
- # ... (Los diccionarios no cambian) ...
79
  FOOD_TO_COMPOUND_MAP = {
80
- "pan": ["gluten"], "trigo": ["gluten"], "harina de trigo": ["gluten"], "cebada": ["gluten"], "centeno": ["gluten"], "pasta": ["gluten"], "galletas": ["gluten"], "avena": ["gluten"], "pizza": ["gluten"], "torta": ["gluten"],
81
  "leche": ["lácteos", "caseína", "lactosa"], "queso": ["lácteos", "caseína", "lactosa", "histamina", "tiramina"], "yogur": ["lácteos", "caseína", "lactosa"], "mantequilla": ["lácteos", "caseína", "lactosa"], "crema": ["lácteos"], "helado": ["lácteos"],
82
- "manzana": ["salicilatos", "fructosa"], "almendras": ["salicilatos", "arginina"], "uvas": ["salicilatos"], "pasas": ["salicilatos"], "naranja": ["salicilatos"], "brócoli": ["salicilatos", "goitrógenos", "fodmaps"], "cúrcuma": ["salicilatos"],
 
83
  "azucar": ["azúcar", "fructosa"], "dulces": ["azúcar"], "refrescos": ["azúcar", "fructosa"], "gaseosas": ["azúcar", "fructosa"], "miel": ["fructosa", "fodmaps"], "jarabe de maiz": ["fructosa"],
84
- "vino tinto": ["histamina", "tiramina", "sulfitos"], "vino rojo": ["histamina", "tiramina", "sulfitos"], "vino": ["histamina", "tiramina", "sulfitos"], "cerveza": ["histamina", "tiramina", "purinas", "gluten"], "chocolate": ["cafeína", "tiramina", "níquel", "arginina"],
85
- "embutidos": ["histamina", "tiramina", "nitritos"], "pescado enlatado": ["histamina"], "tomate": ["histamina", "solaninas", "ácidos"],
86
- "aguacate": ["fodmaps", "polioles"], "cebolla": ["fodmaps"], "ajo": ["fodmaps"], "legumbres": ["fodmaps", "gos"],
87
- "carne": ["alfa-gal", "purinas", "hierro"], "carnes rojas": ["purinas", "alfa-gal", "hierro"],
88
- "mariscos": ["purinas", "sulfitos", "alérgenos", "yodo"], "huevo": ["alérgenos"], "soya": ["alérgenos"],
89
- "café": ["cafeína", "ácidos"], "nueces": ["arginina", "salicilatos", "níquel"]
 
90
  }
91
  CONDITION_SYNONYMS = {
92
  "síndrome del intestino irritable (sii).": ["intolerancia a los fodmaps", "intolerancia a los gos (fodmap)", "intolerancia a gomas fermentables"],
93
  "gota / hiperuricemia.": ["acido urico aumentado"], "intolerancia a la lactosa.": ["déficit de lactasa"],
94
  "enfermedad celíaca (clásica).": ["dermatitis herpetiforme"], "migraña.": ["dolor de cabeza", "cefalea"]
95
  }
 
 
96
  FOOD_NAME_TO_FOODB_KEY = {
97
  "pan": ["bread"], "pasta": ["pasta"], "galleta": ["cookie"], "pizza": ["pizza"], "cebada": ["barley"], "centeno": ["rye"],
98
  "leche": ["milk"], "queso": ["cheese"], "huevo": ["egg"], "carne": ["beef", "pork", "lamb", "meat"], "ternera": ["beef"], "cerdo": ["pork"], "cordero": ["lamb"], "pollo": ["chicken"],
99
- "manzana": ["apple"], "naranja": ["orange"], "uva": ["grape"], "plátano": ["banana"], "aguacate": ["avocado"], "limón": ["lemon"],
100
- "tomate": ["tomato"], "patata": ["potato"], "cebolla": ["onion"], "ajo": ["garlic"], "espinaca": ["spinach"],
101
- "vino": ["wine"], "cerveza": ["beer"], "café": ["coffee"], "chocolate": ["chocolate"], "miel": ["honey"],
102
- "almendra": ["almond"], "nuez": ["walnut"], "cacahuete": ["peanut"], "arroz": ["rice"], "maíz": ["corn"],
103
- "pescado": ["fish"], "atún": ["tuna", "salmón": "salmon", "marisco": "shellfish", "camarón": "shrimp"]
104
  }
 
 
105
  def sanitize_text(text):
106
  if not text: return ""
107
  return re.sub(r'[.,;()]', '', text).lower().strip()
108
  def extract_and_infer_with_gemini(query, condiciones):
109
- # ... (Sin cambios)
110
  if not model: return None
111
  condiciones_str = "\n".join([f"- {c}" for c in condiciones])
112
  system_prompt = f"""
@@ -131,8 +135,6 @@ def extract_and_infer_with_gemini(query, condiciones):
131
  logger.error(f"Error en la extracción/inferencia con Gemini: {e}")
132
  st.error(f"Hubo un problema al interpretar tu consulta con la IA.")
133
  return None
134
-
135
- # --- FUNCIÓN DE BÚSQUEDA MODIFICADA PARA DEVOLVER MÁS INFO ---
136
  def find_best_matches_hybrid(entities, data):
137
  if not entities or not data: return []
138
  user_symptoms = set(sanitize_text(s) for s in entities.get("sintomas", []))
@@ -160,7 +162,7 @@ def find_best_matches_hybrid(entities, data):
160
  results = []
161
  for entry in target_data:
162
  score_details = {'condition': 0, 'food': 0, 'symptoms': 0, 'total': 0}
163
- matched_symptoms = [] # <-- NUEVO: Guardamos las pistas
164
  if inferred_condition_raw and sanitize_text(entry.get("condicion_asociada", "")) == inferred_condition_raw:
165
  score_details['condition'] = 100
166
  entry_compounds_text = sanitize_text(entry.get("compuesto_alimento", ""))
@@ -172,7 +174,7 @@ def find_best_matches_hybrid(entities, data):
172
  for key in entry_symptoms_keys:
173
  if key in user_symptom or user_symptom in key:
174
  symptom_score += 10
175
- matched_symptoms.append(key) # <-- NUEVO: Añadimos la pista
176
  break
177
  score_details['symptoms'] = symptom_score
178
  total_score = sum(score_details.values())
@@ -181,7 +183,6 @@ def find_best_matches_hybrid(entities, data):
181
  if not results: return []
182
  sorted_results = sorted(results, key=lambda x: x['score']['total'], reverse=True)
183
  return sorted_results
184
- # ... (El resto de funciones auxiliares no cambia) ...
185
  def generate_detailed_analysis(query, match):
186
  if not model: return "Error: El modelo de IA no está disponible."
187
  prompt_parts = [
@@ -232,26 +233,12 @@ def create_relevance_chart(results):
232
  ).properties(title='Principales Coincidencias según tu Caso').configure_axis(labelFontSize=12, titleFontSize=14).configure_title(fontSize=16, anchor='start')
233
  return chart
234
  def log_feedback(query, result, feedback):
235
- log_entry = {
236
- "timestamp": datetime.now().isoformat(),
237
- "query": query,
238
- "best_match_condition": result['entry']['condicion_asociada'],
239
- "score": result['score']['total'],
240
- "feedback": feedback
241
- }
242
  os.makedirs("logs", exist_ok=True)
243
  with open(os.path.join("logs", "feedback_log.txt"), "a", encoding="utf-8") as f:
244
  f.write(json.dumps(log_entry, ensure_ascii=False) + "\n")
245
- def extract_foods_from_string(food_string):
246
- match = re.search(r'\(([^)]+)\)$', food_string)
247
- if match:
248
- foods_part = match.group(1)
249
- return [food.strip().lower() for food in foods_part.split(',') if food.strip()]
250
- else:
251
- main_part = re.sub(r'^\w+\s*\(.*?\)\s*', '', food_string).strip()
252
- return [food.strip().lower() for food in main_part.split(',') if food.strip()]
253
 
254
- # --- INTERFAZ DE USUARIO Y LÓGICA PRINCIPAL (CON CAMBIOS) ---
255
  col_img, col_text = st.columns([1, 4], gap="medium")
256
  with col_img:
257
  if os.path.exists("imagen.png"):
@@ -277,7 +264,7 @@ with st.form(key="search_form"):
277
  submitted = st.form_submit_button("Analizar mi caso", type="primary")
278
 
279
  if submitted:
280
- clear_search_state() # Limpiamos el estado en cada nueva búsqueda
281
  if not query:
282
  st.warning("Por favor, describe lo que sientes y lo que comiste.")
283
  elif alimentos_data is None:
@@ -312,14 +299,47 @@ if st.session_state.search_results is not None:
312
  chart = create_relevance_chart(results)
313
  st.altair_chart(chart, use_container_width=True)
314
 
315
- # --- ANÁLISIS DEL RESULTADO PRINCIPAL ---
316
  best_match_data = results[0]
317
  best_match = best_match_data['entry']
318
  with st.expander(f"**Análisis Detallado de la Principal Coincidencia: {best_match.get('condicion_asociada')}**", expanded=True):
319
- # ... (código del desglose de puntuación y popover de FoodB no cambia)
320
- # (El código para mostrar el análisis detallado del #1 es el mismo que antes)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
321
  with st.spinner("✍️ Generando un análisis personalizado con IA..."):
322
- # Usamos un caché para no regenerar el análisis si ya existe
323
  if 'best_match_analysis' not in st.session_state.analysis_cache:
324
  st.session_state.analysis_cache['best_match_analysis'] = generate_detailed_analysis(st.session_state.user_query, best_match)
325
  st.markdown(st.session_state.analysis_cache['best_match_analysis'])
@@ -333,27 +353,24 @@ if st.session_state.search_results is not None:
333
  log_feedback(st.session_state.user_query, best_match_data, "no_util")
334
  st.warning("Gracias. Usaremos tu feedback para mejorar.")
335
 
336
- # --- NUEVA SECCIÓN PARA "DIAGNÓSTICO DIFERENCIAL" ---
337
  if len(results) > 1:
338
  with st.expander("**Otras Posibilidades Relevantes (Diagnóstico Diferencial)**"):
339
- # Mostramos las siguientes 2 o 3 posibilidades
340
  for i, result in enumerate(results[1:4]):
341
- entry = result['entry']
342
- score = result['score']
343
- st.subheader(f"{i+2}. {entry.get('condicion_asociada')}")
344
- col1, col2 = st.columns([2,1])
345
- with col1:
346
- st.write(f"**Puntuación Total de Relevancia:** {score['total']}")
347
- if result.get('matched_symptoms'):
348
- st.write(f"**Pistas Clave (Síntomas Coincidentes):** {', '.join(result['matched_symptoms']).capitalize()}")
349
- st.write(f"**Alimentos Típicos Asociados:** {entry.get('compuesto_alimento')}")
350
-
351
- with col2:
352
- analysis_key = f"analysis_{i+2}"
353
- if st.button(f"Generar análisis para esta opción", key=analysis_key):
354
- with st.spinner("Generando análisis..."):
355
- st.session_state.analysis_cache[analysis_key] = generate_detailed_analysis(st.session_state.user_query, entry)
356
-
357
- if analysis_key in st.session_state.analysis_cache:
358
- st.info(st.session_state.analysis_cache[analysis_key])
359
- st.markdown("---")
 
1
+ # ==================== El Detective de Alimentos (Versión 9.0 - Maestra) =====================================
2
+ # Mejoras: Corrección de errores de sintaxis, expansión masiva de diccionarios y refinamientos de UI.
3
 
4
  import streamlit as st
5
  import google.generativeai as genai
 
18
  layout="wide"
19
  )
20
 
21
+ # --- CONFIGURACIÓN Y CARGA DE DATOS (SIN CAMBIOS) ---
22
  # Configurar logging
23
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
24
  logger = logging.getLogger("food_detective_app")
 
74
  alimentos_data, lista_condiciones, foodb_index = load_data()
75
 
76
 
77
+ # --- DICCIONARIOS DE MAPEADO EXPANDIDOS ---
 
78
  FOOD_TO_COMPOUND_MAP = {
79
+ "pan": ["gluten"], "trigo": ["gluten"], "harina": ["gluten"], "cebada": ["gluten"], "centeno": ["gluten"], "pasta": ["gluten"], "galletas": ["gluten"], "avena": ["gluten"], "pizza": ["gluten"], "torta": ["gluten"], "pastel": ["gluten"], "cerveza": ["gluten", "histamina", "tiramina", "purinas"],
80
  "leche": ["lácteos", "caseína", "lactosa"], "queso": ["lácteos", "caseína", "lactosa", "histamina", "tiramina"], "yogur": ["lácteos", "caseína", "lactosa"], "mantequilla": ["lácteos", "caseína", "lactosa"], "crema": ["lácteos"], "helado": ["lácteos"],
81
+ "manzana": ["salicilatos", "fructosa"], "pera": ["fructosa", "polioles"], "mango": ["fructosa"], "cereza": ["fructosa", "salicilatos"], "sandía": ["fructosa"], "almendras": ["salicilatos", "arginina", "oxalatos"], "uvas": ["salicilatos", "fructosa"], "pasas": ["salicilatos", "fructosa"], "naranja": ["salicilatos", "ácidos"], "limón": ["salicilatos", "ácidos"], "fresa": ["salicilatos"], "arándano": ["salicilatos"],
82
+ "brócoli": ["salicilatos", "goitrógenos", "fodmaps"], "coliflor": ["goitrógenos", "fodmaps"], "repollo": ["goitrógenos", "fodmaps"], "col": ["goitrógenos", "fodmaps"], "cúrcuma": ["salicilatos"],
83
  "azucar": ["azúcar", "fructosa"], "dulces": ["azúcar"], "refrescos": ["azúcar", "fructosa"], "gaseosas": ["azúcar", "fructosa"], "miel": ["fructosa", "fodmaps"], "jarabe de maiz": ["fructosa"],
84
+ "vino tinto": ["histamina", "tiramina", "sulfitos"], "vino rojo": ["histamina", "tiramina", "sulfitos"], "vino": ["histamina", "tiramina", "sulfitos"], "chocolate": ["cafeína", "tiramina", "níquel", "arginina", "oxalatos"],
85
+ "embutidos": ["histamina", "tiramina", "nitritos"], "pescado enlatado": ["histamina"], "atún en lata": ["histamina"], "sardinas": ["histamina", "purinas"], "tomate": ["histamina", "solaninas", "ácidos", "lectinas"],
86
+ "aguacate": ["fodmaps", "polioles", "histamina"], "cebolla": ["fodmaps", "fructanos"], "ajo": ["fodmaps", "fructanos"], "legumbres": ["fodmaps", "gos", "lectinas", "fitatos"], "lentejas": ["fodmaps", "gos", "lectinas"], "garbanzos": ["fodmaps", "gos", "lectinas"], "frijoles": ["fodmaps", "gos", "lectinas"],
87
+ "carne": ["alfa-gal", "purinas", "hierro", "histamina"], "carnes rojas": ["purinas", "alfa-gal", "hierro"], "hígado": ["purinas", "hierro", "vitamina a"],
88
+ "mariscos": ["purinas", "sulfitos", "alérgenos", "yodo", "níquel"], "huevo": ["alérgenos"], "soya": ["alérgenos", "fitatos", "goitrógenos"], "soja": ["alérgenos", "fitatos", "goitrógenos"],
89
+ "café": ["cafeína", "ácidos"], "té": ["cafeína", "taninos", "oxalatos"], "nueces": ["arginina", "salicilatos", "níquel", "oxalatos"], "maní": ["alérgenos", "arginina", "lectinas", "aflatoxinas"], "cacahuetes": ["alérgenos", "arginina", "lectinas", "aflatoxinas"],
90
+ "pimiento": ["solaninas", "lectinas"], "berenjena": ["solaninas", "lectinas"], "patata": ["solaninas", "lectinas"]
91
  }
92
  CONDITION_SYNONYMS = {
93
  "síndrome del intestino irritable (sii).": ["intolerancia a los fodmaps", "intolerancia a los gos (fodmap)", "intolerancia a gomas fermentables"],
94
  "gota / hiperuricemia.": ["acido urico aumentado"], "intolerancia a la lactosa.": ["déficit de lactasa"],
95
  "enfermedad celíaca (clásica).": ["dermatitis herpetiforme"], "migraña.": ["dolor de cabeza", "cefalea"]
96
  }
97
+
98
+ # --- DICCIONARIO TRADUCTOR CORREGIDO Y EXPANDIDO ---
99
  FOOD_NAME_TO_FOODB_KEY = {
100
  "pan": ["bread"], "pasta": ["pasta"], "galleta": ["cookie"], "pizza": ["pizza"], "cebada": ["barley"], "centeno": ["rye"],
101
  "leche": ["milk"], "queso": ["cheese"], "huevo": ["egg"], "carne": ["beef", "pork", "lamb", "meat"], "ternera": ["beef"], "cerdo": ["pork"], "cordero": ["lamb"], "pollo": ["chicken"],
102
+ "manzana": ["apple"], "naranja": ["orange"], "uva": ["grape"], "plátano": ["banana"], "aguacate": ["avocado"], "limón": ["lemon"], "fresa": ["strawberry"], "pera": ["pear"], "mango": ["mango"],
103
+ "tomate": ["tomato"], "patata": ["potato"], "cebolla": ["onion"], "ajo": ["garlic"], "espinaca": ["spinach"], "zanahoria": ["carrot"], "pimiento": ["bell pepper"], "brócoli": ["broccoli"],
104
+ "vino": ["wine", "red wine", "white wine"], "cerveza": ["beer"], "café": ["coffee"], "chocolate": ["chocolate"], "miel": ["honey"], "té": ["tea"],
105
+ "almendra": ["almond"], "nuez": ["walnut"], "cacahuete": ["peanut"], "arroz": ["rice"], "maíz": ["corn"], "lenteja": ["lentil"], "frijol": ["bean"],
106
+ "pescado": ["fish"], "atún": ["tuna"], "salmón": ["salmon"], "marisco": ["shellfish"], "camarón": ["shrimp"], "sardina": ["sardine"]
107
  }
108
+
109
+ # --- LÓGICA DE BÚSQUEDA Y ANÁLISIS (SIN CAMBIOS) ---
110
  def sanitize_text(text):
111
  if not text: return ""
112
  return re.sub(r'[.,;()]', '', text).lower().strip()
113
  def extract_and_infer_with_gemini(query, condiciones):
 
114
  if not model: return None
115
  condiciones_str = "\n".join([f"- {c}" for c in condiciones])
116
  system_prompt = f"""
 
135
  logger.error(f"Error en la extracción/inferencia con Gemini: {e}")
136
  st.error(f"Hubo un problema al interpretar tu consulta con la IA.")
137
  return None
 
 
138
  def find_best_matches_hybrid(entities, data):
139
  if not entities or not data: return []
140
  user_symptoms = set(sanitize_text(s) for s in entities.get("sintomas", []))
 
162
  results = []
163
  for entry in target_data:
164
  score_details = {'condition': 0, 'food': 0, 'symptoms': 0, 'total': 0}
165
+ matched_symptoms = []
166
  if inferred_condition_raw and sanitize_text(entry.get("condicion_asociada", "")) == inferred_condition_raw:
167
  score_details['condition'] = 100
168
  entry_compounds_text = sanitize_text(entry.get("compuesto_alimento", ""))
 
174
  for key in entry_symptoms_keys:
175
  if key in user_symptom or user_symptom in key:
176
  symptom_score += 10
177
+ matched_symptoms.append(key)
178
  break
179
  score_details['symptoms'] = symptom_score
180
  total_score = sum(score_details.values())
 
183
  if not results: return []
184
  sorted_results = sorted(results, key=lambda x: x['score']['total'], reverse=True)
185
  return sorted_results
 
186
  def generate_detailed_analysis(query, match):
187
  if not model: return "Error: El modelo de IA no está disponible."
188
  prompt_parts = [
 
233
  ).properties(title='Principales Coincidencias según tu Caso').configure_axis(labelFontSize=12, titleFontSize=14).configure_title(fontSize=16, anchor='start')
234
  return chart
235
  def log_feedback(query, result, feedback):
236
+ log_entry = {"timestamp": datetime.now().isoformat(), "query": query, "best_match_condition": result['entry']['condicion_asociada'], "score": result['score']['total'], "feedback": feedback}
 
 
 
 
 
 
237
  os.makedirs("logs", exist_ok=True)
238
  with open(os.path.join("logs", "feedback_log.txt"), "a", encoding="utf-8") as f:
239
  f.write(json.dumps(log_entry, ensure_ascii=False) + "\n")
 
 
 
 
 
 
 
 
240
 
241
+ # --- INTERFAZ DE USUARIO Y LÓGICA PRINCIPAL ---
242
  col_img, col_text = st.columns([1, 4], gap="medium")
243
  with col_img:
244
  if os.path.exists("imagen.png"):
 
264
  submitted = st.form_submit_button("Analizar mi caso", type="primary")
265
 
266
  if submitted:
267
+ clear_search_state()
268
  if not query:
269
  st.warning("Por favor, describe lo que sientes y lo que comiste.")
270
  elif alimentos_data is None:
 
299
  chart = create_relevance_chart(results)
300
  st.altair_chart(chart, use_container_width=True)
301
 
 
302
  best_match_data = results[0]
303
  best_match = best_match_data['entry']
304
  with st.expander(f"**Análisis Detallado de la Principal Coincidencia: {best_match.get('condicion_asociada')}**", expanded=True):
305
+ col1, col2 = st.columns([3, 1])
306
+ with col1:
307
+ st.markdown("##### Desglose de la Puntuación de Relevancia:")
308
+ score_col1, score_col2, score_col3, score_col4 = st.columns(4)
309
+ score_col1.metric("Puntos por Condición", f"{best_match_data['score']['condition']}")
310
+ score_col2.metric("Puntos por Alimento", f"{best_match_data['score']['food']}")
311
+ score_col3.metric("Puntos por Síntomas", f"{best_match_data['score']['symptoms']}")
312
+ score_col4.metric("PUNTUACIÓN TOTAL", f"{best_match_data['score']['total']}", delta="Máxima coincidencia")
313
+ with col2:
314
+ st.write("")
315
+ if foodb_index:
316
+ with st.popover("🔬 Principales componentes moleculares"):
317
+ user_foods_mentioned = st.session_state.entities.get("alimentos", [])
318
+ if not user_foods_mentioned:
319
+ st.info("El usuario no especificó un alimento, no se puede realizar la búsqueda molecular.")
320
+ else:
321
+ found_data = False
322
+ displayed_foodb_keys = set()
323
+ for alimento_es in user_foods_mentioned:
324
+ search_terms_en = []
325
+ for key_es, value_en_list in FOOD_NAME_TO_FOODB_KEY.items():
326
+ if key_es in alimento_es.lower():
327
+ search_terms_en.extend(value_en_list)
328
+ for term in set(search_terms_en):
329
+ for foodb_key, foodb_data in foodb_index.items():
330
+ if term in foodb_key and foodb_key not in displayed_foodb_keys:
331
+ found_data = True
332
+ displayed_foodb_keys.add(foodb_key)
333
+ with st.container(border=True):
334
+ st.subheader(f"Análisis de: {foodb_key.capitalize()}")
335
+ for item in foodb_data[:3]:
336
+ st.write(f"**Compuesto:** {item['compound']}")
337
+ st.write(f"**Efectos reportados:** {', '.join(item['effects'])}")
338
+ st.markdown("---")
339
+ if not found_data:
340
+ st.warning("Sin datos moleculares para este alimento.")
341
+ st.markdown("---")
342
  with st.spinner("✍️ Generando un análisis personalizado con IA..."):
 
343
  if 'best_match_analysis' not in st.session_state.analysis_cache:
344
  st.session_state.analysis_cache['best_match_analysis'] = generate_detailed_analysis(st.session_state.user_query, best_match)
345
  st.markdown(st.session_state.analysis_cache['best_match_analysis'])
 
353
  log_feedback(st.session_state.user_query, best_match_data, "no_util")
354
  st.warning("Gracias. Usaremos tu feedback para mejorar.")
355
 
 
356
  if len(results) > 1:
357
  with st.expander("**Otras Posibilidades Relevantes (Diagnóstico Diferencial)**"):
 
358
  for i, result in enumerate(results[1:4]):
359
+ with st.container(border=True):
360
+ entry = result['entry']
361
+ score = result['score']
362
+ st.subheader(f"{i+2}. {entry.get('condicion_asociada')}")
363
+ col1, col2 = st.columns([2,1])
364
+ with col1:
365
+ st.write(f"**Puntuación Total de Relevancia:** {score['total']}")
366
+ if result.get('matched_symptoms'):
367
+ st.write(f"**Pistas Clave (Síntomas Coincidentes):** {', '.join(result['matched_symptoms']).capitalize()}")
368
+ st.write(f"**Alimentos Típicos Asociados:** {entry.get('compuesto_alimento')}")
369
+ with col2:
370
+ analysis_key = f"analysis_{i+2}"
371
+ if st.button(f"Generar análisis para esta opción", key=analysis_key):
372
+ with st.spinner("Generando análisis..."):
373
+ st.session_state.analysis_cache[analysis_key] = generate_detailed_analysis(st.session_state.user_query, entry)
374
+ if analysis_key in st.session_state.analysis_cache:
375
+ st.info(st.session_state.analysis_cache[analysis_key])
376
+