JairoCesar commited on
Commit
f59f581
·
verified ·
1 Parent(s): 65b38db

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +31 -13
app.py CHANGED
@@ -37,7 +37,7 @@ Este análisis es una herramienta informativa de IA y **NO es un diagnóstico m
37
  **Si tus síntomas son severos, busca ayuda médica urgente.**
38
  """
39
 
40
- # --- CONFIGURACIÓN GEMINI CON LA VARIABLE GEMINI_API_KEY ---
41
  def get_gemini_client():
42
  api_key = os.getenv("GEMINI_API_KEY")
43
 
@@ -60,13 +60,31 @@ def get_gemini_client():
60
  try:
61
  return genai.Client(
62
  api_key=api_key,
63
- http_options=types.HttpOptions(timeout=10000) # 10 segundos
64
  )
65
  except Exception as e:
66
  logger.warning(f"❌ Error instanciando cliente Gemini: {e}")
67
  return None
68
 
69
- # --- CARGA ULTRA-RÁPIDA DE DATOS Y FOODB ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  @st.cache_resource
71
  def load_data():
72
  try:
@@ -95,6 +113,7 @@ def get_foodb_lower_map(_foodb_index):
95
 
96
  foodb_lower_map = get_foodb_lower_map(foodb_index)
97
 
 
98
  @st.cache_resource
99
  def get_global_learned_cache():
100
  return {}
@@ -220,6 +239,7 @@ FOOD_TO_COMPOUND_MAP = {
220
  "carne de res": ["histamina", "alfa-gal", "purinas"],
221
  "res": ["histamina", "alfa-gal", "purinas"],
222
  "café": ["cafeína", "salicilatos", "oxalatos"],
 
223
  "té": ["cafeína", "taninos", "oxalatos", "salicilatos"],
224
  "té negro": ["cafeína", "taninos", "oxalatos", "salicilatos"],
225
  "té verde": ["cafeína", "taninos", "oxalatos", "salicilatos"],
@@ -261,7 +281,7 @@ FOOD_NAME_TO_FOODB_KEY = {
261
  "vino": ["wine"], "vino tinto": ["wine", "red wine"], "cerveza": ["beer"], "chocolate": ["chocolate", "cocoa"],
262
  "tomate": ["tomato"], "aguacate": ["avocado"], "plátano": ["banana", "plantain"], "banano": ["banana"],
263
  "naranja": ["orange"], "jugo de naranja": ["orange juice", "orange"], "pan": ["bread", "wheat"],
264
- "trigo": ["wheat"], "café": ["coffee"], "té": ["tea"], "manzana": ["apple"], "pera": ["pear"],
265
  "fresa": ["strawberry"], "uva": ["grape"], "piña": ["pineapple"], "papaya": ["papaya"],
266
  "mango": ["mango"], "limón": ["lemon", "lime"], "espinaca": ["spinach"], "cebolla": ["onion"],
267
  "ajo": ["garlic"], "papa": ["potato"], "patata": ["potato"], "frijol": ["bean", "beans"],
@@ -269,7 +289,7 @@ FOOD_NAME_TO_FOODB_KEY = {
269
  }
270
 
271
  STRICT_COMPOUND_TRIGGERS = {
272
- "cafeína": ["cafeína", "caffeine", "café", "coffee", "espresso", "energizante", "guaraná"],
273
  "teobromina": ["teobromina", "theobromine", "cacao", "chocolate"],
274
  "solanina": ["solanina", "solanine", "solanáceas", "nightshades", "tomate", "berenjena", "patata", "papa"],
275
  "capsaicina": ["capsaicina", "capsaicin", "chile", "ají", "picante", "pimiento"],
@@ -445,7 +465,6 @@ COMPOUND_SYNONYM_MAP = {
445
  "proteínas": ["protein", "amino acid"]
446
  }
447
 
448
- # MAPA COMPLETO DE SÍNTOMAS (NUNCA DEJA VACÍA LA EXTRACCIÓN LOCAL)
449
  MASTER_SYMPTOM_MAP = {
450
  "dolor abdominal": {
451
  "frases_es": ["dolor de estómago", "dolor de panza", "dolor abdominal", "retortijones", "cólicos", "calambres abdominales", "gastritis", "acidez", "reflujo", "pesadez"],
@@ -504,7 +523,6 @@ MASTER_SYMPTOM_MAP = {
504
  def sanitize_text(text):
505
  if not text:
506
  return ""
507
- # Normaliza puntuación y colapsa múltiples espacios a un solo espacio simple
508
  text_clean = re.sub(r'[.,;()¿?¡!:"\'\-]', ' ', text).lower()
509
  text_clean = re.sub(r'\s+', ' ', text_clean).strip()
510
  return text_clean
@@ -543,7 +561,7 @@ def get_compounds_for_food(food_name, food_map):
543
  if norm in food_map:
544
  return food_map[norm]
545
 
546
- # 3. Corrección difusa de erratas de tipeo (difflib)
547
  fuzzy_matches = difflib.get_close_matches(food_clean, list(food_map.keys()), n=1, cutoff=0.6)
548
  if fuzzy_matches:
549
  logger.info(f"💡 Errata corregida automáticamente: '{food_clean}' -> '{fuzzy_matches[0]}'")
@@ -558,7 +576,7 @@ def get_compounds_for_food(food_name, food_map):
558
  if matched_compounds:
559
  return list(matched_compounds)
560
 
561
- # 5. Inferencia difusa por palabras individuales en nombres compuestos
562
  inferred = set()
563
  words = food_clean.split()
564
  for word in words:
@@ -570,7 +588,7 @@ def get_compounds_for_food(food_name, food_map):
570
  if inferred:
571
  return list(inferred)
572
 
573
- # 6. INFERENCIA UNIVERSAL POR FAMILIA BIOLÓGICA (Para alimentos no registrados)
574
  if any(w in food_clean for w in ["carne", "cerdo", "res", "pollo", "pavo", "cordero", "pato", "chicharrón", "tocino"]):
575
  inferred.update(["histamina", "purinas", "proteínas"])
576
  elif any(w in food_clean for w in ["pescado", "atún", "marisco", "camarón", "sardina", "langostino", "pulpo"]):
@@ -681,9 +699,9 @@ def reinforce_entities_with_keywords(entities, query, food_map, master_symptom_m
681
  current_symptoms.add(main_symptom)
682
  break
683
 
684
- # EXTRAER SÍNTOMAS ADICIONALES POR PALABRAS CLAVE DIRECTAS
685
  if not current_symptoms:
686
- if any(w in query_sanitized for w in ["diarrea", "diarreas", "soltura", "líquida"]):
687
  current_symptoms.add("diarrea")
688
  elif any(w in query_sanitized for w in ["hinchazón", "hinchazon", "gases", "inflamado"]):
689
  current_symptoms.add("hinchazón")
@@ -767,7 +785,7 @@ def build_local_hypothesis(entities, food_compound_map, neuro_map):
767
  es_psicologico = any(k in symptom_text for k in ["ansiedad", "angustia", "nerviosismo", "depresión", "depresion", "irritabilidad", "desrealización", "desrealizacion", "agitación", "agitacion"])
768
  es_insomnio = any(k in symptom_text for k in ["insomnio", "no puedo dormir", "sueño", "desvelado", "desvelo", "despierto", "dormir"])
769
  es_gastrointestinal = any(k in symptom_text for k in ["diarrea", "diarreas", "hinchazón", "hinchazon", "gases", "dolor abdominal", "retortijón", "retortijon", "cólico", "colico", "inflamado", "inflama", "pesadez", "estómago", "estomago", "náuseas", "nausea", "acidez", "reflujo"])
770
- es_dermatologico = any(k in symptom_text for k in ["piel", "rasca", "picazón", "picazon", "manchas", "urticaria", "erupción", "erupcion", "alergia", "ronchas", "granitos", "eccema"])
771
  es_respiratorio = any(k in symptom_text for k in ["asma", "tos", "respirar", "pecho", "sibilancia", "ahogo", "falta de aire", "congestión nasal", "congestion nasal", "estornudo", "rinitis"])
772
  es_cardiovascular = any(k in symptom_text for k in ["palpitaciones", "taquicardia", "ritmo cardíaco", "presión", "presion", "rubor", "sofoco", "frío"])
773
  es_articular = any(k in symptom_text for k in ["articulación", "articulacion", "rodilla", "coyuntura", "rigidez", "calambre", "gota", "espalda", "músculo", "musculo"])
 
37
  **Si tus síntomas son severos, busca ayuda médica urgente.**
38
  """
39
 
40
+ # --- CONFIGURACIÓN DE CLIENTE GEMINI CON GEMINI_API_KEY ---
41
  def get_gemini_client():
42
  api_key = os.getenv("GEMINI_API_KEY")
43
 
 
60
  try:
61
  return genai.Client(
62
  api_key=api_key,
63
+ http_options=types.HttpOptions(timeout=15.0) # 15 segundos
64
  )
65
  except Exception as e:
66
  logger.warning(f"❌ Error instanciando cliente Gemini: {e}")
67
  return None
68
 
69
+ # --- CASCADA DE MODELOS DE GEMINI CON FALLBACK ---
70
+ def generate_content_with_fallback(gemini_client, prompt):
71
+ """Prueba los modelos disponibles en la cuenta de Google AI Studio en cascada."""
72
+ models_to_try = ['gemini-2.5-flash-lite', 'gemini-2.5-flash', 'gemini-1.5-flash']
73
+ for model_name in models_to_try:
74
+ try:
75
+ response = gemini_client.models.generate_content(
76
+ model=model_name,
77
+ contents=prompt
78
+ )
79
+ if response and response.text:
80
+ logger.info(f"✅ Respuesta exitosa generada por el modelo: {model_name}")
81
+ return response.text
82
+ except Exception as e:
83
+ logger.warning(f"⚠️ Modelo {model_name} no disponible ({e}), probando siguiente modelo...")
84
+ continue
85
+ raise RuntimeError("Todos los modelos de Gemini fallaron o no están disponibles.")
86
+
87
+ # --- CARGA ULTRA-RÁPIDA DE DATOS Y FOODB (CERO COPIA EN MEMORIA) ---
88
  @st.cache_resource
89
  def load_data():
90
  try:
 
113
 
114
  foodb_lower_map = get_foodb_lower_map(foodb_index)
115
 
116
+ # --- CACHÉ GLOBAL DE APRENDIZAJE EN RAM ---
117
  @st.cache_resource
118
  def get_global_learned_cache():
119
  return {}
 
239
  "carne de res": ["histamina", "alfa-gal", "purinas"],
240
  "res": ["histamina", "alfa-gal", "purinas"],
241
  "café": ["cafeína", "salicilatos", "oxalatos"],
242
+ "cafe": ["cafeína", "salicilatos", "oxalatos"],
243
  "té": ["cafeína", "taninos", "oxalatos", "salicilatos"],
244
  "té negro": ["cafeína", "taninos", "oxalatos", "salicilatos"],
245
  "té verde": ["cafeína", "taninos", "oxalatos", "salicilatos"],
 
281
  "vino": ["wine"], "vino tinto": ["wine", "red wine"], "cerveza": ["beer"], "chocolate": ["chocolate", "cocoa"],
282
  "tomate": ["tomato"], "aguacate": ["avocado"], "plátano": ["banana", "plantain"], "banano": ["banana"],
283
  "naranja": ["orange"], "jugo de naranja": ["orange juice", "orange"], "pan": ["bread", "wheat"],
284
+ "trigo": ["wheat"], "café": ["coffee"], "cafe": ["coffee"], "té": ["tea"], "manzana": ["apple"], "pera": ["pear"],
285
  "fresa": ["strawberry"], "uva": ["grape"], "piña": ["pineapple"], "papaya": ["papaya"],
286
  "mango": ["mango"], "limón": ["lemon", "lime"], "espinaca": ["spinach"], "cebolla": ["onion"],
287
  "ajo": ["garlic"], "papa": ["potato"], "patata": ["potato"], "frijol": ["bean", "beans"],
 
289
  }
290
 
291
  STRICT_COMPOUND_TRIGGERS = {
292
+ "cafeína": ["cafeína", "caffeine", "café", "cafe", "coffee", "espresso", "energizante", "guaraná"],
293
  "teobromina": ["teobromina", "theobromine", "cacao", "chocolate"],
294
  "solanina": ["solanina", "solanine", "solanáceas", "nightshades", "tomate", "berenjena", "patata", "papa"],
295
  "capsaicina": ["capsaicina", "capsaicin", "chile", "ají", "picante", "pimiento"],
 
465
  "proteínas": ["protein", "amino acid"]
466
  }
467
 
 
468
  MASTER_SYMPTOM_MAP = {
469
  "dolor abdominal": {
470
  "frases_es": ["dolor de estómago", "dolor de panza", "dolor abdominal", "retortijones", "cólicos", "calambres abdominales", "gastritis", "acidez", "reflujo", "pesadez"],
 
523
  def sanitize_text(text):
524
  if not text:
525
  return ""
 
526
  text_clean = re.sub(r'[.,;()¿?¡!:"\'\-]', ' ', text).lower()
527
  text_clean = re.sub(r'\s+', ' ', text_clean).strip()
528
  return text_clean
 
561
  if norm in food_map:
562
  return food_map[norm]
563
 
564
+ # 3. Corrección difusa de erratas de tipeo
565
  fuzzy_matches = difflib.get_close_matches(food_clean, list(food_map.keys()), n=1, cutoff=0.6)
566
  if fuzzy_matches:
567
  logger.info(f"💡 Errata corregida automáticamente: '{food_clean}' -> '{fuzzy_matches[0]}'")
 
576
  if matched_compounds:
577
  return list(matched_compounds)
578
 
579
+ # 5. Inferencia difusa por palabras individuales
580
  inferred = set()
581
  words = food_clean.split()
582
  for word in words:
 
588
  if inferred:
589
  return list(inferred)
590
 
591
+ # 6. INFERENCIA UNIVERSAL POR FAMILIA BIOLÓGICA
592
  if any(w in food_clean for w in ["carne", "cerdo", "res", "pollo", "pavo", "cordero", "pato", "chicharrón", "tocino"]):
593
  inferred.update(["histamina", "purinas", "proteínas"])
594
  elif any(w in food_clean for w in ["pescado", "atún", "marisco", "camarón", "sardina", "langostino", "pulpo"]):
 
699
  current_symptoms.add(main_symptom)
700
  break
701
 
702
+ # EXTRAER SÍNTOMAS ADICIONALES POR PALABRAS CLAVE DIRECTAS EN CASO DE FALLO
703
  if not current_symptoms:
704
+ if any(w in query_sanitized for w in ["diarrea", "diarreas", "soltura", "líquida", "suelto"]):
705
  current_symptoms.add("diarrea")
706
  elif any(w in query_sanitized for w in ["hinchazón", "hinchazon", "gases", "inflamado"]):
707
  current_symptoms.add("hinchazón")
 
785
  es_psicologico = any(k in symptom_text for k in ["ansiedad", "angustia", "nerviosismo", "depresión", "depresion", "irritabilidad", "desrealización", "desrealizacion", "agitación", "agitacion"])
786
  es_insomnio = any(k in symptom_text for k in ["insomnio", "no puedo dormir", "sueño", "desvelado", "desvelo", "despierto", "dormir"])
787
  es_gastrointestinal = any(k in symptom_text for k in ["diarrea", "diarreas", "hinchazón", "hinchazon", "gases", "dolor abdominal", "retortijón", "retortijon", "cólico", "colico", "inflamado", "inflama", "pesadez", "estómago", "estomago", "náuseas", "nausea", "acidez", "reflujo"])
788
+ es_dermatologico = any(k in symptom_text for k in ["piel", "rasca", "picazón", "picazon", "manchas", "urticaria", "erupción", "erupcion", "alergia", "ronchas", "granitos"])
789
  es_respiratorio = any(k in symptom_text for k in ["asma", "tos", "respirar", "pecho", "sibilancia", "ahogo", "falta de aire", "congestión nasal", "congestion nasal", "estornudo", "rinitis"])
790
  es_cardiovascular = any(k in symptom_text for k in ["palpitaciones", "taquicardia", "ritmo cardíaco", "presión", "presion", "rubor", "sofoco", "frío"])
791
  es_articular = any(k in symptom_text for k in ["articulación", "articulacion", "rodilla", "coyuntura", "rigidez", "calambre", "gota", "espalda", "músculo", "musculo"])