import accelerate import gradio as gr import joblib import numpy as np import requests import torch import os from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig from langchain.memory import ConversationBufferMemory # Configuración del modelo de lenguaje MODEL_NAME = "mistralai/Mistral-7B-Instruct-v0.3" device = "cuda" if torch.cuda.is_available() else "cpu" HF_TOKEN = os.getenv("HF_TOKEN") # Obtiene el token de la variable de entorno # Verificación de token if not HF_TOKEN: raise ValueError("❌ ERROR: No se encontró HF_TOKEN. Asegúrate de definirlo en las variables de entorno.") print("🔄 Cargando modelo de lenguaje...") tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, token=HF_TOKEN) bnb_config = BitsAndBytesConfig(load_in_8bit=True) # Cargar en 8-bit para reducir memoria model = AutoModelForCausalLM.from_pretrained( MODEL_NAME, torch_dtype=torch.float16, # Usa menos RAM que float32 low_cpu_mem_usage=True, # Reduce uso de memoria en CPU device_map={"": "cpu"}, token=HF_TOKEN ) # Memoria conversacional memory = ConversationBufferMemory() # Cargar modelo de la colmena modelo_path = "modelo_colmena.pkl" if os.path.exists(modelo_path): modelo_colmena = joblib.load(modelo_path) else: modelo_colmena = None # API de Node-RED NODE_RED_URL = "https://appairedecolmena.es/colmena1/datos" USERNAME = "user" PASSWORD = "velutina" def obtener_datos_colmena(): """Obtiene los datos más recientes de Node-RED con autenticación.""" try: respuesta = requests.get(NODE_RED_URL, auth=(USERNAME, PASSWORD), timeout=5) if respuesta.status_code == 200: datos = respuesta.json() if "data" in datos and isinstance(datos["data"], list) and datos["data"]: return datos["data"][-1] # Último registro return {"error": "No hay datos recientes en Node-RED."} else: return {"error": f"Error en la API: {respuesta.status_code}"} except Exception as e: return {"error": str(e)} def filtrar_datos_por_pregunta(mensaje, datos): """Filtra los datos de la colmena según la pregunta del usuario.""" if "temperatura" in mensaje: return f"🌡 Temperatura interior: {datos['temperaturaInterior']}°C, exterior: {datos['temperatura_exterior']}°C." elif "humedad" in mensaje: return f"💧 Humedad interior: {datos['humedadInterior']}%, exterior: {datos['humedad_exterior']}%." elif "co2" in mensaje: return f"🌿 CO2: {datos['co2']} ppm." elif "ventilador" in mensaje: estado = "ENCENDIDO" if int(datos['ver_ventilador']) == 1 else "APAGADO" return f"🔄 Ventilador: {estado}." elif "calefactor" in mensaje: estado = "ENCENDIDO" if int(datos['ver_calefactor']) == 1 else "APAGADO" return f"🔥 Calefactor: {estado}." elif "ultrasonido" in mensaje: estado = "ENCENDIDO" if int(datos['ver_ultrasonido']) == 1 else "APAGADO" return f"🔊 Ultrasonido: {estado}." else: return "🤖 No entiendo la pregunta. Pregunta sobre temperatura, humedad, CO2, ventilador, calefactor o ultrasonido." def conversar_con_colmena(mensaje): """Genera una respuesta combinando el modelo de lenguaje con los datos de la colmena.""" datos = obtener_datos_colmena() if "error" in datos: return datos["error"] datos_relevantes = filtrar_datos_por_pregunta(mensaje.lower(), datos) contexto = f"Datos actuales de la colmena: {datos_relevantes}\nUsuario: {mensaje}\nColmena:" inputs = tokenizer(contexto, return_tensors="pt").to(device) print(f"🔄 Enviando entrada al modelo: {contexto}") # 👈 Agrega este print para ver el contexto en consola with torch.no_grad(): output = model.generate( **inputs, max_length=150, # Reduce el tamaño máximo para evitar que se quede colgado do_sample=True, # Sampling activado para más variabilidad top_k=50, # Controla la aleatoriedad para evitar salidas vacías temperature=0.7, # Ajusta la creatividad de la respuesta pad_token_id=tokenizer.eos_token_id # Evita errores de padding ) # ✅ Paréntesis correctamente cerrado # Decodificar la salida del modelo respuesta = tokenizer.decode(output[0], skip_special_tokens=True).strip() # Imprimir la respuesta generada para depuración print(f"✅ Respuesta generada por la IA: '{respuesta}'") # 👈 Para ver si está vacío # Manejo de respuestas vacías if not respuesta: return "🤖 No pude generar una respuesta. Inténtalo de nuevo con otra pregunta." iface = gr.Interface( fn=conversar_con_colmena, inputs="text", outputs="text", title="🐝 Chat con la Colmena", description="Habla con la colmena en tiempo real sobre su estado." ) iface.launch()