JairoCesar commited on
Commit
c0d765f
路
verified 路
1 Parent(s): 3ea969c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +77 -23
app.py CHANGED
@@ -1,5 +1,5 @@
1
  # ==============================================================================
2
- # EL DETECTIVE DE ALIMENTOS - EDICI脫N H脥BRIDA DE ALTA DISPONIBILIDAD
3
  # Desarrollado por: Jairo Alexander & Diana Milena Soler Martinez
4
  # Motor: Gemini 2.5 Flash Lite + FooDB.ca Graph + Fast-Path Local Engine
5
  # ==============================================================================
@@ -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
 
@@ -132,7 +132,7 @@ FOOD_TO_COMPOUND_MAP = {
132
  "crema de leche": ["case铆na", "lactosa"],
133
  "helado": ["lactosa", "case铆na", "az煤car refinado"],
134
 
135
- # FRUTAS, PLATOS Y FRUTAS TROPICALES
136
  "noni": ["escopoletina", "fenoles", "salicilatos", "fructosa", "histamina"],
137
  "jugo de noni": ["escopoletina", "fenoles", "salicilatos", "fructosa", "histamina"],
138
  "bandeja paisa": ["fodmaps", "lectinas", "histamina", "tiramina", "fitatos", "nitritos"],
@@ -446,26 +446,47 @@ COMPOUND_SYNONYM_MAP = {
446
  "prote铆nas": ["protein", "amino acid"]
447
  }
448
 
 
449
  MASTER_SYMPTOM_MAP = {
450
  "dolor abdominal": {
451
- "frases_es": ["dolor de est贸mago", "dolor de panza", "dolor abdominal", "retortijones", "c贸licos", "calambres abdominales"],
452
  "keywords_en": ["abdominal", "pain", "stomach", "cramp", "colic", "gastrointestinal"]
453
  },
454
  "hinchaz贸n": {
455
- "frases_es": ["hinchaz贸n abdominal", "vientre hinchado", "distensi贸n abdominal", "hinchaz贸n", "distensi贸n", "estomago se infla", "inflamado", "inflado", "infla", "hincha"],
456
  "keywords_en": ["bloating", "distension", "flatulence", "swelling"]
457
  },
458
  "dolor de cabeza": {
459
- "frases_es": ["dolor de cabeza", "migra帽a", "cefalea", "jaqueca", "me duele la cabeza"],
460
  "keywords_en": ["headache", "migraine"]
461
  },
462
  "ansiedad": {
463
- "frases_es": ["ansiedad", "nerviosismo", "agitaci贸n", "angustia"],
464
  "keywords_en": ["anxiety", "nervousness"]
465
  },
466
  "insomnio": {
467
- "frases_es": ["insomnio", "no puedo dormir", "dificultad para dormir", "desvelado", "no duermo"],
468
  "keywords_en": ["insomnia", "sleep trouble"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
469
  }
470
  }
471
 
@@ -476,7 +497,10 @@ MASTER_SYMPTOM_MAP = {
476
  def sanitize_text(text):
477
  if not text:
478
  return ""
479
- return re.sub(r'[.,;()驴?隆!:"\'\-]', ' ', text).lower().strip()
 
 
 
480
 
481
  STOPWORDS_ES = {
482
  "de", "la", "el", "los", "las", "un", "una", "unos", "unas", "y", "o", "u",
@@ -512,7 +536,7 @@ def get_compounds_for_food(food_name, food_map):
512
  if norm in food_map:
513
  return food_map[norm]
514
 
515
- # 3. Correcci贸n difusa de erratas de tipeo
516
  fuzzy_matches = difflib.get_close_matches(food_clean, list(food_map.keys()), n=1, cutoff=0.6)
517
  if fuzzy_matches:
518
  logger.info(f"馃挕 Errata corregida autom谩ticamente: '{food_clean}' -> '{fuzzy_matches[0]}'")
@@ -539,7 +563,7 @@ def get_compounds_for_food(food_name, food_map):
539
  if inferred:
540
  return list(inferred)
541
 
542
- # 6. INFERENCIA UNIVERSAL POR FAMILIA BIOL脫GICA
543
  if any(w in food_clean for w in ["carne", "cerdo", "res", "pollo", "pavo", "cordero", "pato", "chicharr贸n", "tocino"]):
544
  inferred.update(["histamina", "purinas", "prote铆nas"])
545
  elif any(w in food_clean for w in ["pescado", "at煤n", "marisco", "camar贸n", "sardina", "langostino", "pulpo"]):
@@ -599,7 +623,7 @@ def extract_entities_with_gemini(query):
599
  system_prompt = f"""
600
  Rol: Extractor M茅dico JSON experto en nutrici贸n y s铆ntomas.
601
  Tarea: Analiza el texto del usuario y extrae un JSON estricto con dos claves:
602
- - "alimentos": lista de alimentos o bebidas mencionados en espa帽ol, forma simple (ej: "jugo de naranja", "chontaduro", "noni", "bandeja paisa", "queso", "vino tinto").
603
  - "sintomas": lista de s铆ntomas mencionados en espa帽ol, forma cl铆nica simple (ej: "insomnio", "dolor de cabeza", "hinchaz贸n").
604
 
605
  Input: "{query}"
@@ -629,7 +653,7 @@ def reinforce_entities_with_keywords(entities, query, food_map, master_symptom_m
629
  if food_keyword in query_sanitized:
630
  current_foods.add(food_keyword)
631
 
632
- # PATR脫N SINT脕CTICO DE EXTRACCI脫N DE RESPALDO (Captura frases como "jugo de noni", "si tomo X", "como X")
633
  if not current_foods:
634
  match_jugo = re.search(r'\b(jugo|zumo|batido|licuado)\s+de\s+([a-zA-Z谩茅铆贸煤帽脕脡脥脫脷脩]+)\b', query_sanitized)
635
  if match_jugo:
@@ -710,6 +734,7 @@ def find_best_matches_hybrid(entities, data, user_query="", food_compound_map=No
710
  })
711
  return sorted(results, key=lambda x: x['score']['total'], reverse=True)
712
 
 
713
  def build_local_hypothesis(entities, food_compound_map, neuro_map):
714
  user_foods = entities.get("alimentos", [])
715
  user_symptoms = entities.get("sintomas", [])
@@ -718,10 +743,17 @@ def build_local_hypothesis(entities, food_compound_map, neuro_map):
718
 
719
  symptom_text = " ".join(user_symptoms).lower()
720
 
721
- es_dermatologico = any(k in symptom_text for k in ["piel", "rasca", "picaz贸n", "picazon", "manchas", "urticaria", "erupci贸n", "erupcion", "alergia", "ronchas", "granitos"])
722
- es_cefalea = any(k in symptom_text for k in ["dolor de cabeza", "migra帽a", "cefalea", "jaqueca", "dolor", "cabeza"])
723
- es_insomnio = any(k in symptom_text for k in ["insomnio", "no puedo dormir", "sue帽o", "desvelado", "desvelo", "despierto"])
724
- es_gastro = any(k in symptom_text for k in ["hinchaz贸n", "hinchazon", "gases", "diarrea", "dolor abdominal", "retortij贸n", "retortijon", "c贸lico", "colico", "inflamado", "inflama", "pesadez", "est贸mago", "estomago"])
 
 
 
 
 
 
 
725
 
726
  candidates = []
727
  for food in user_foods:
@@ -735,14 +767,26 @@ def build_local_hypothesis(entities, food_compound_map, neuro_map):
735
  alimentos_str = ", ".join(user_foods).capitalize()
736
  sintomas_str = ", ".join(user_symptoms)
737
 
738
- if es_cefalea:
739
  condicion_fallback = f"Cefalea o Migra帽a Alimentaria relacionada con {alimentos_str}"
 
 
740
  elif es_insomnio:
741
  condicion_fallback = f"Alteraci贸n del Sue帽o o Insomnio relacionado con {alimentos_str}"
742
- elif es_gastro:
743
  condicion_fallback = f"Distensi贸n o Malestar Gastrointestinal relacionado con {alimentos_str}"
744
  elif es_dermatologico:
745
  condicion_fallback = f"Reacci贸n Dermatol贸gica o Urticaria relacionada con {alimentos_str}"
 
 
 
 
 
 
 
 
 
 
746
  else:
747
  condicion_fallback = f"Sensibilidad o Intolerancia Alimentaria a {alimentos_str}"
748
 
@@ -759,14 +803,26 @@ def build_local_hypothesis(entities, food_compound_map, neuro_map):
759
  compuestos_str = ", ".join(compuestos_unicos)
760
  alimentos_str = ", ".join(alimentos_unicos).capitalize()
761
 
762
- if es_cefalea:
763
  condicion = f"Cefalea o Migra帽a Vasoactiva asociada a {compuestos_str} en {alimentos_str}"
 
 
764
  elif es_dermatologico:
765
  condicion = f"Reacci贸n Histamin茅rgica / Dermatol贸gica por {compuestos_str} en {alimentos_str}"
766
  elif es_insomnio:
767
  condicion = f"Alteraci贸n del Sue帽o e Insomnio por respuesta a {compuestos_str} en {alimentos_str}"
768
- elif es_gastro:
769
  condicion = f"Distensi贸n Abdominal e Intolerancia Digestiva a {compuestos_str} en {alimentos_str}"
 
 
 
 
 
 
 
 
 
 
770
  else:
771
  condicion = f"Hipersensibilidad o Intolerancia a {compuestos_str} en {alimentos_str}"
772
 
@@ -810,7 +866,6 @@ def generate_ai_hypothesis_on_the_fly(query, entities):
810
  )
811
  raw = response.text.strip()
812
 
813
- # EXTRACCI脫N ROBUSTA DE JSON POR REGEX (Captura JSON dentro de cualquier formato)
814
  json_match = re.search(r'\{.*\}', raw, re.DOTALL)
815
  if json_match:
816
  raw_clean = json_match.group(0)
@@ -993,7 +1048,6 @@ def generate_neuro_report_text(entities, food_map, neuro_map):
993
 
994
  return "\n".join(report_lines)
995
 
996
- # FIX PAR脕METROS DE REPORTE MOLECULAR (8 PAR脕METROS POSICIONALES)
997
  def generate_molecular_report_text(best_match, entities, _foodb_index, _foodb_lower_map, food_name_map, synonym_map, food_compound_map, neuro_map):
998
  report_lines = ["\n### 馃敩 An谩lisis Molecular y Efectos Bioactivos"]
999
  user_foods = entities.get("alimentos", [])
 
1
  # ==============================================================================
2
+ # EL DETECTIVE DE ALIMENTOS - EDICI脫N H脥BRIDA MULTISIST脡MICA (10 SISTEMAS ORG脕NICOS)
3
  # Desarrollado por: Jairo Alexander & Diana Milena Soler Martinez
4
  # Motor: Gemini 2.5 Flash Lite + FooDB.ca Graph + Fast-Path Local Engine
5
  # ==============================================================================
 
37
  **Si tus s铆ntomas son severos, busca ayuda m茅dica urgente.**
38
  """
39
 
40
+ # --- CONFIGURACI脫N DE CLIENTE GEMINI CON VARIABLE GEMINI_API_KEY ---
41
  def get_gemini_client():
42
  api_key = os.getenv("GEMINI_API_KEY")
43
 
 
132
  "crema de leche": ["case铆na", "lactosa"],
133
  "helado": ["lactosa", "case铆na", "az煤car refinado"],
134
 
135
+ # FRUTAS, PLATOS Y TROPICALES
136
  "noni": ["escopoletina", "fenoles", "salicilatos", "fructosa", "histamina"],
137
  "jugo de noni": ["escopoletina", "fenoles", "salicilatos", "fructosa", "histamina"],
138
  "bandeja paisa": ["fodmaps", "lectinas", "histamina", "tiramina", "fitatos", "nitritos"],
 
446
  "prote铆nas": ["protein", "amino acid"]
447
  }
448
 
449
+ # 10 CATEGOR脥AS SINTOM脕TICAS MULTISIST脡MICAS
450
  MASTER_SYMPTOM_MAP = {
451
  "dolor abdominal": {
452
+ "frases_es": ["dolor de est贸mago", "dolor de panza", "dolor abdominal", "retortijones", "c贸licos", "calambres abdominales", "gastritis", "acidez", "reflujo", "pesadez"],
453
  "keywords_en": ["abdominal", "pain", "stomach", "cramp", "colic", "gastrointestinal"]
454
  },
455
  "hinchaz贸n": {
456
+ "frases_es": ["hinchaz贸n abdominal", "vientre hinchado", "distensi贸n abdominal", "hinchaz贸n", "distensi贸n", "estomago se infla", "inflamado", "inflado", "infla", "hincha", "gases", "flatulencia"],
457
  "keywords_en": ["bloating", "distension", "flatulence", "swelling"]
458
  },
459
  "dolor de cabeza": {
460
+ "frases_es": ["dolor de cabeza", "migra帽a", "cefalea", "jaqueca", "me duele la cabeza", "duele la cabeza", "dolor de sien", "dolor en la cabeza", "pesadez de cabeza"],
461
  "keywords_en": ["headache", "migraine"]
462
  },
463
  "ansiedad": {
464
+ "frases_es": ["ansiedad", "nerviosismo", "agitaci贸n", "angustia", "desrealizaci贸n", "irritabilidad", "cambios de 谩nimo"],
465
  "keywords_en": ["anxiety", "nervousness"]
466
  },
467
  "insomnio": {
468
+ "frases_es": ["insomnio", "no puedo dormir", "dificultad para dormir", "desvelado", "no duermo", "desvelo", "sue帽o fragmentado"],
469
  "keywords_en": ["insomnia", "sleep trouble"]
470
+ },
471
+ "alergia cut谩nea": {
472
+ "frases_es": ["piel", "rasca", "picaz贸n", "picazon", "manchas", "urticaria", "erupci贸n", "erupcion", "alergia", "ronchas", "granitos", "eccema", "salpullido"],
473
+ "keywords_en": ["rash", "itching", "urticaria", "eczema"]
474
+ },
475
+ "reactividad respiratoria": {
476
+ "frases_es": ["asma", "tos", "respirar", "pecho", "sibilancia", "ahogo", "falta de aire", "congesti贸n nasal", "stornudos", "rinitis"],
477
+ "keywords_en": ["asthma", "cough", "wheezing", "rhinitis"]
478
+ },
479
+ "respuesta cardiovascular": {
480
+ "frases_es": ["palpitaciones", "taquicardia", "ritmo card铆aco", "presi贸n", "presion", "rubor", "sofoco", "picos de presi贸n"],
481
+ "keywords_en": ["palpitations", "tachycardia", "flushing"]
482
+ },
483
+ "dolor articular": {
484
+ "frases_es": ["articulaci贸n", "articulacion", "rodilla", "coyuntura", "rigidez", "calambre", "gota", "espalda", "m煤sculo", "musculo", "dolor articular"],
485
+ "keywords_en": ["joint pain", "gout", "stiffness"]
486
+ },
487
+ "molestia renal": {
488
+ "frases_es": ["ri帽贸n", "ri帽on", "orina", "orinar", "c谩lculo", "calculo", "piedra", "ardor al orinar", "c贸lico renal"],
489
+ "keywords_en": ["kidney", "urine", "calculus"]
490
  }
491
  }
492
 
 
497
  def sanitize_text(text):
498
  if not text:
499
  return ""
500
+ # Normaliza puntuaci贸n y colapsa m煤ltiples espacios a un solo espacio simple
501
+ text_clean = re.sub(r'[.,;()驴?隆!:"\'\-]', ' ', text).lower()
502
+ text_clean = re.sub(r'\s+', ' ', text_clean).strip()
503
+ return text_clean
504
 
505
  STOPWORDS_ES = {
506
  "de", "la", "el", "los", "las", "un", "una", "unos", "unas", "y", "o", "u",
 
536
  if norm in food_map:
537
  return food_map[norm]
538
 
539
+ # 3. Correcci贸n difusa de erratas de tipeo (difflib)
540
  fuzzy_matches = difflib.get_close_matches(food_clean, list(food_map.keys()), n=1, cutoff=0.6)
541
  if fuzzy_matches:
542
  logger.info(f"馃挕 Errata corregida autom谩ticamente: '{food_clean}' -> '{fuzzy_matches[0]}'")
 
563
  if inferred:
564
  return list(inferred)
565
 
566
+ # 6. INFERENCIA UNIVERSAL POR FAMILIA BIOL脫GICA (Para alimentos no registrados)
567
  if any(w in food_clean for w in ["carne", "cerdo", "res", "pollo", "pavo", "cordero", "pato", "chicharr贸n", "tocino"]):
568
  inferred.update(["histamina", "purinas", "prote铆nas"])
569
  elif any(w in food_clean for w in ["pescado", "at煤n", "marisco", "camar贸n", "sardina", "langostino", "pulpo"]):
 
623
  system_prompt = f"""
624
  Rol: Extractor M茅dico JSON experto en nutrici贸n y s铆ntomas.
625
  Tarea: Analiza el texto del usuario y extrae un JSON estricto con dos claves:
626
+ - "alimentos": lista de alimentos o bebidas mencionados en espa帽ol, forma simple (ej: "jugo de naranja", "chontaduro", "bandeja paisa", "queso", "vino tinto").
627
  - "sintomas": lista de s铆ntomas mencionados en espa帽ol, forma cl铆nica simple (ej: "insomnio", "dolor de cabeza", "hinchaz贸n").
628
 
629
  Input: "{query}"
 
653
  if food_keyword in query_sanitized:
654
  current_foods.add(food_keyword)
655
 
656
+ # PATR脫N SINT脕CTICO DE RESCATAR ALIMENTOS SI LA LISTA EST脕 VAC脥A
657
  if not current_foods:
658
  match_jugo = re.search(r'\b(jugo|zumo|batido|licuado)\s+de\s+([a-zA-Z谩茅铆贸煤帽脕脡脥脫脷脩]+)\b', query_sanitized)
659
  if match_jugo:
 
734
  })
735
  return sorted(results, key=lambda x: x['score']['total'], reverse=True)
736
 
737
+ # FASE 3: CLASIFICACI脫N CL脥NICA MULTISIST脡MICA EN 10 CATEGOR脥AS ORG脕NICAS
738
  def build_local_hypothesis(entities, food_compound_map, neuro_map):
739
  user_foods = entities.get("alimentos", [])
740
  user_symptoms = entities.get("sintomas", [])
 
743
 
744
  symptom_text = " ".join(user_symptoms).lower()
745
 
746
+ # DETECCI脫N DE 10 SISTEMAS ORG脕NICOS
747
+ es_neurologico = any(k in symptom_text for k in ["dolor de cabeza", "migra帽a", "cefalea", "jaqueca", "dolor de sien", "mareo", "v茅rtigo", "vertigo", "neblina mental", "cabeza"])
748
+ es_psicologico = any(k in symptom_text for k in ["ansiedad", "angustia", "nerviosismo", "depresi贸n", "depresion", "irritabilidad", "desrealizaci贸n", "desrealizacion", "agitaci贸n", "agitacion"])
749
+ es_insomnio = any(k in symptom_text for k in ["insomnio", "no puedo dormir", "sue帽o", "desvelado", "desvelo", "despierto", "dormir"])
750
+ es_gastrointestinal = any(k in symptom_text for k in ["hinchaz贸n", "hinchazon", "gases", "diarrea", "dolor abdominal", "retortij贸n", "retortijon", "c贸lico", "colico", "inflamado", "inflama", "pesadez", "est贸mago", "estomago", "n谩useas", "nausea", "acidez", "reflujo"])
751
+ es_dermatologico = any(k in symptom_text for k in ["piel", "rasca", "picaz贸n", "picazon", "manchas", "urticaria", "erupci贸n", "erupcion", "alergia", "ronchas", "granitos", "eccema"])
752
+ 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"])
753
+ es_cardiovascular = any(k in symptom_text for k in ["palpitaciones", "taquicardia", "ritmo card铆aco", "presi贸n", "presion", "rubor", "sofoco", "fr铆o"])
754
+ es_articular = any(k in symptom_text for k in ["articulaci贸n", "articulacion", "rodilla", "coyuntura", "rigidez", "calambre", "gota", "espalda", "m煤sculo", "musculo"])
755
+ es_renal_urinario = any(k in symptom_text for k in ["ri帽贸n", "ri帽on", "orina", "orinar", "c谩lculo", "calculo", "piedra", "ardor al orinar"])
756
+ es_sexual_hormonal = any(k in symptom_text for k in ["deseo sexual", "libido", "disfunci贸n", "disfuncion", "menstrual", "ciclo", "hormonal"])
757
 
758
  candidates = []
759
  for food in user_foods:
 
767
  alimentos_str = ", ".join(user_foods).capitalize()
768
  sintomas_str = ", ".join(user_symptoms)
769
 
770
+ if es_neurologico:
771
  condicion_fallback = f"Cefalea o Migra帽a Alimentaria relacionada con {alimentos_str}"
772
+ elif es_psicologico:
773
+ condicion_fallback = f"Alteraci贸n Neuropsicol贸gica o Estado de 脕nimo relacionado con {alimentos_str}"
774
  elif es_insomnio:
775
  condicion_fallback = f"Alteraci贸n del Sue帽o o Insomnio relacionado con {alimentos_str}"
776
+ elif es_gastrointestinal:
777
  condicion_fallback = f"Distensi贸n o Malestar Gastrointestinal relacionado con {alimentos_str}"
778
  elif es_dermatologico:
779
  condicion_fallback = f"Reacci贸n Dermatol贸gica o Urticaria relacionada con {alimentos_str}"
780
+ elif es_respiratorio:
781
+ condicion_fallback = f"Reactividad Respiratoria o Vasomotora relacionada con {alimentos_str}"
782
+ elif es_cardiovascular:
783
+ condicion_fallback = f"Respuesta Vasoactiva / Cardiovascular relacionada con {alimentos_str}"
784
+ elif es_articular:
785
+ condicion_fallback = f"Inflamaci贸n Musculoesquel茅tica o Articular asociada a {alimentos_str}"
786
+ elif es_renal_urinario:
787
+ condicion_fallback = f"Sobrecarga Renal / Urinaria asociada a {alimentos_str}"
788
+ elif es_sexual_hormonal:
789
+ condicion_fallback = f"Modulaci贸n Hormonal o Reproductiva asociada a {alimentos_str}"
790
  else:
791
  condicion_fallback = f"Sensibilidad o Intolerancia Alimentaria a {alimentos_str}"
792
 
 
803
  compuestos_str = ", ".join(compuestos_unicos)
804
  alimentos_str = ", ".join(alimentos_unicos).capitalize()
805
 
806
+ if es_neurologico:
807
  condicion = f"Cefalea o Migra帽a Vasoactiva asociada a {compuestos_str} en {alimentos_str}"
808
+ elif es_psicologico:
809
+ condicion = f"Alteraci贸n Neuropsicol贸gica / Estado de 脕nimo asociada a {compuestos_str} en {alimentos_str}"
810
  elif es_dermatologico:
811
  condicion = f"Reacci贸n Histamin茅rgica / Dermatol贸gica por {compuestos_str} en {alimentos_str}"
812
  elif es_insomnio:
813
  condicion = f"Alteraci贸n del Sue帽o e Insomnio por respuesta a {compuestos_str} en {alimentos_str}"
814
+ elif es_gastrointestinal:
815
  condicion = f"Distensi贸n Abdominal e Intolerancia Digestiva a {compuestos_str} en {alimentos_str}"
816
+ elif es_respiratorio:
817
+ condicion = f"Reactividad Respiratoria / Vasomotora asociada a {compuestos_str} en {alimentos_str}"
818
+ elif es_cardiovascular:
819
+ condicion = f"Respuesta Vasoactiva / Cardiovascular por {compuestos_str} en {alimentos_str}"
820
+ elif es_articular:
821
+ condicion = f"Inflamaci贸n Musculoesquel茅tica / Articular por {compuestos_str} en {alimentos_str}"
822
+ elif es_renal_urinario:
823
+ condicion = f"Sobrecarga Renal / Urinaria asociada a {compuestos_str} en {alimentos_str}"
824
+ elif es_sexual_hormonal:
825
+ condicion = f"Modulaci贸n Hormonal / Reproductiva asociada a {compuestos_str} en {alimentos_str}"
826
  else:
827
  condicion = f"Hipersensibilidad o Intolerancia a {compuestos_str} en {alimentos_str}"
828
 
 
866
  )
867
  raw = response.text.strip()
868
 
 
869
  json_match = re.search(r'\{.*\}', raw, re.DOTALL)
870
  if json_match:
871
  raw_clean = json_match.group(0)
 
1048
 
1049
  return "\n".join(report_lines)
1050
 
 
1051
  def generate_molecular_report_text(best_match, entities, _foodb_index, _foodb_lower_map, food_name_map, synonym_map, food_compound_map, neuro_map):
1052
  report_lines = ["\n### 馃敩 An谩lisis Molecular y Efectos Bioactivos"]
1053
  user_foods = entities.get("alimentos", [])