import os import json from huggingface_hub import InferenceClient from usuarios import obtener_usuario_actual, obtener_datos_usuario MODEL_ID = "Qwen/Qwen2.5-7B-Instruct" MEMORIA_EMOCIONAL_FILE = "memoria_emocional.json" client = InferenceClient( provider="auto", token=os.getenv("HF_TOKEN"), ) def cargar_json(path, default): if os.path.exists(path): try: with open(path, "r", encoding="utf-8") as f: return json.load(f) except json.JSONDecodeError: return default return default def obtener_perfil(): usuario = obtener_usuario_actual() datos = obtener_datos_usuario(usuario) if usuario else None perfil = datos.get("perfil", {}) if datos else {} return { "nombre": perfil.get("nombre", usuario or "Usuario"), "edad": perfil.get("edad", ""), "peso": perfil.get("peso", ""), "altura": perfil.get("altura", ""), "genero": perfil.get("genero", ""), "actividad": perfil.get("actividad", ""), "meta": perfil.get("meta", ""), "condicion": perfil.get("condicion", ""), "alergias": perfil.get("alergias", ""), } def obtener_contexto_emocional(nombre): memoria = cargar_json(MEMORIA_EMOCIONAL_FILE, {}) bloque = memoria.get(nombre, {}) alertas = bloque.get("alertas_nutricion", []) if alertas: return alertas[-1] return None def resumir_historial(historial, limite=6): if not historial: return "Sin historial reciente." partes = [] for item in historial[-limite:]: if isinstance(item, dict): rol = item.get("role", "") content = item.get("content", "") if rol and content: partes.append(f"{rol}: {content}") return "\n".join(partes) if partes else "Sin historial reciente." def construir_system_prompt(perfil, alerta_emocional): extra_emocional = "" if alerta_emocional and alerta_emocional.get("tipo") == "ansiedad_comida": extra_emocional = ( "El usuario puede estar pasando por hambre emocional. " "Si habla de antojos, snacks o ganas de comer sin hambre, " "responde con empatía y sugiere pausar, hidratarse y elegir una opción ligera sin juzgar.\n" ) return f""" Eres Nuti, una asistente de nutrición muy inteligente, natural y útil. Hablas en español claro, cercano y nada robótico. Tu trabajo: - Si el usuario solo saluda o quiere conversación casual, síguele el rollo con naturalidad. - Si pregunta sobre nutrición, responde como experta pero fácil de entender. - Usa el perfil del usuario para personalizar. - No inventes diagnósticos médicos. - No respondas con listas rígidas a menos que ayuden. - No uses frases genéricas tipo "sé fuerte" o "todo estará bien" si no vienen al caso. - Responde breve a media longitud, útil y humana. Perfil del usuario: - Nombre: {perfil['nombre']} - Edad: {perfil['edad']} - Peso: {perfil['peso']} - Altura: {perfil['altura']} - Género: {perfil['genero']} - Actividad: {perfil['actividad']} - Meta: {perfil['meta']} - Condición: {perfil['condicion']} - Alergias: {perfil['alergias']} {extra_emocional} Si el mensaje es ambiguo, primero aclara o responde de forma conversacional. """.strip() def buscar_respuesta(mensaje, historial): perfil = obtener_perfil() nombre = str(perfil.get("nombre") or "Usuario").strip() or "Usuario" alerta_emocional = obtener_contexto_emocional(nombre) hf_token = os.getenv("HF_TOKEN") if not hf_token: return "No encuentro el HF_TOKEN en los Secrets del Space." system_prompt = construir_system_prompt(perfil, alerta_emocional) historial_texto = resumir_historial(historial) user_prompt = f""" Historial reciente: {historial_texto} Mensaje actual del usuario: {mensaje} Responde directamente al usuario. """.strip() try: completion = client.chat.completions.create( model=MODEL_ID, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ], temperature=0.8, max_tokens=220, ) respuesta = completion.choices[0].message.content.strip() return respuesta if respuesta else "No pude generar respuesta ahorita." except Exception as e: return f"Error al consultar el modelo: {str(e)}"