Spaces:
Runtime error
Runtime error
Upload 19 files
Browse files- core/models.py +29 -9
core/models.py
CHANGED
|
@@ -15,14 +15,23 @@ from .constants import ENFORCE_TR0_RESILIENTES
|
|
| 15 |
warnings.filterwarnings("ignore")
|
| 16 |
|
| 17 |
# ------------------------------------------------------------------
|
| 18 |
-
# Disponibilidad de librerías de IA (
|
|
|
|
| 19 |
# ------------------------------------------------------------------
|
| 20 |
try:
|
| 21 |
-
from
|
| 22 |
-
|
| 23 |
-
IA_DISPONIBLE = True
|
| 24 |
except ImportError:
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
# Singletons perezosos (se rellenan al primer uso).
|
| 28 |
_nlp_classifier = None
|
|
@@ -30,6 +39,9 @@ _nlp_cargado = False
|
|
| 30 |
_ml_tr_model = None
|
| 31 |
_ml_cargado = False
|
| 32 |
|
|
|
|
|
|
|
|
|
|
| 33 |
|
| 34 |
def get_nlp_model():
|
| 35 |
"""Carga perezosa del clasificador zero-shot. Devuelve None si no se puede."""
|
|
@@ -37,7 +49,7 @@ def get_nlp_model():
|
|
| 37 |
if _nlp_cargado:
|
| 38 |
return _nlp_classifier
|
| 39 |
_nlp_cargado = True
|
| 40 |
-
if not
|
| 41 |
_nlp_classifier = None
|
| 42 |
return None
|
| 43 |
try:
|
|
@@ -66,7 +78,7 @@ def _entrenar_modelo_termodinamico():
|
|
| 66 |
Entrena al Random Forest para que devuelva HORAS de secado respondiendo
|
| 67 |
correctamente a la temperatura y humedad.
|
| 68 |
"""
|
| 69 |
-
if not
|
| 70 |
return None
|
| 71 |
from sklearn.ensemble import RandomForestRegressor
|
| 72 |
np.random.seed(42)
|
|
@@ -190,8 +202,16 @@ def calcular_tr_y_ic_dinamico(lluvia_mm, temp_c, humedad_pct, tipo_suelo_ic, usa
|
|
| 190 |
|
| 191 |
suelo_cat = 1 if tipo_suelo_ic >= 3.0 else (2 if tipo_suelo_ic >= 2.0 else 3)
|
| 192 |
|
| 193 |
-
# La IA
|
| 194 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 195 |
|
| 196 |
# [AUD-07] Penalización dinámica del coeficiente — Ec. 6.22 de la tesis:
|
| 197 |
# Ic_dinámico = Q(Ic) = Ic_base + Tr/48 (constante de normalización 48 h)
|
|
|
|
| 15 |
warnings.filterwarnings("ignore")
|
| 16 |
|
| 17 |
# ------------------------------------------------------------------
|
| 18 |
+
# Disponibilidad de librerías de IA (independientes entre sí).
|
| 19 |
+
# El Random Forest solo necesita sklearn; el NLP necesita transformers.
|
| 20 |
# ------------------------------------------------------------------
|
| 21 |
try:
|
| 22 |
+
from sklearn.ensemble import RandomForestRegressor # noqa: F401
|
| 23 |
+
ML_DISPONIBLE = True
|
|
|
|
| 24 |
except ImportError:
|
| 25 |
+
ML_DISPONIBLE = False
|
| 26 |
+
|
| 27 |
+
try:
|
| 28 |
+
from transformers import pipeline as _hf_pipeline # noqa: F401
|
| 29 |
+
NLP_DISPONIBLE = True
|
| 30 |
+
except ImportError:
|
| 31 |
+
NLP_DISPONIBLE = False
|
| 32 |
+
|
| 33 |
+
# Compatibilidad: "hay IA" si al menos uno de los dos modelos está disponible.
|
| 34 |
+
IA_DISPONIBLE = ML_DISPONIBLE or NLP_DISPONIBLE
|
| 35 |
|
| 36 |
# Singletons perezosos (se rellenan al primer uso).
|
| 37 |
_nlp_classifier = None
|
|
|
|
| 39 |
_ml_tr_model = None
|
| 40 |
_ml_cargado = False
|
| 41 |
|
| 42 |
+
# Caché de predicciones del Random Forest (clave: entradas redondeadas).
|
| 43 |
+
_TR_CACHE: dict = {}
|
| 44 |
+
|
| 45 |
|
| 46 |
def get_nlp_model():
|
| 47 |
"""Carga perezosa del clasificador zero-shot. Devuelve None si no se puede."""
|
|
|
|
| 49 |
if _nlp_cargado:
|
| 50 |
return _nlp_classifier
|
| 51 |
_nlp_cargado = True
|
| 52 |
+
if not NLP_DISPONIBLE:
|
| 53 |
_nlp_classifier = None
|
| 54 |
return None
|
| 55 |
try:
|
|
|
|
| 78 |
Entrena al Random Forest para que devuelva HORAS de secado respondiendo
|
| 79 |
correctamente a la temperatura y humedad.
|
| 80 |
"""
|
| 81 |
+
if not ML_DISPONIBLE:
|
| 82 |
return None
|
| 83 |
from sklearn.ensemble import RandomForestRegressor
|
| 84 |
np.random.seed(42)
|
|
|
|
| 202 |
|
| 203 |
suelo_cat = 1 if tipo_suelo_ic >= 3.0 else (2 if tipo_suelo_ic >= 2.0 else 3)
|
| 204 |
|
| 205 |
+
# La IA predice HORAS reales. Cacheamos la predicción con las entradas redondeadas:
|
| 206 |
+
# sklearn tarda ~3.8 ms por predicción de UNA muestra, y el motor la invoca una vez
|
| 207 |
+
# por día lluvioso; en un proyecto grande eso son decenas de miles de llamadas
|
| 208 |
+
# idénticas. El redondeo (0.5 mm / 0.5 °C / 0.5 %) deja Tr prácticamente igual y
|
| 209 |
+
# colapsa miles de llamadas a unas pocas. Resultado: hasta cientos de veces más rápido.
|
| 210 |
+
key = (round(lluvia_mm * 2) / 2, round(temp_c * 2) / 2, round(humedad_pct * 2) / 2, suelo_cat)
|
| 211 |
+
tr_horas = _TR_CACHE.get(key)
|
| 212 |
+
if tr_horas is None:
|
| 213 |
+
tr_horas = float(ml_tr_model.predict([[key[0], key[1], key[2], suelo_cat]])[0])
|
| 214 |
+
_TR_CACHE[key] = tr_horas
|
| 215 |
|
| 216 |
# [AUD-07] Penalización dinámica del coeficiente — Ec. 6.22 de la tesis:
|
| 217 |
# Ic_dinámico = Q(Ic) = Ic_base + Tr/48 (constante de normalización 48 h)
|