
    KCj                         d Z ddlmZ ddlmZ ddlZddlmZ ddlm	Z	 ddl
mZ  e       Z ee      Zdd	d
ddddZ G d d      Z e       Zy)u  
ML model loader.

Production rule: if a model fails to load at startup, the application
MUST refuse to start, not start in a half-working state and fail on the
first real request. A health check that says "I'm up" while secretly
missing the yield model is worse than a crash — it's a silent SLA
violation the client discovers from a support ticket, not from monitoring.

All 6 models are loaded once, here, and held in memory for the lifetime
of the worker process. They are never reloaded per-request.
    )Path)AnyN)get_settings)ModelNotLoadedError)
get_loggerzsarimax_climate.pklzxgb_feasibility.pklzxgb_yield.pklzdt_trend.pklzrf_recommendation.pklzsarimax_market.pkl)sarimax_climatexgb_feasibility	xgb_yielddt_trendrf_recommendationsarimax_marketc                   r    e Zd ZdZddZddZddZddZdede	fd	Z
edefd
       Zedee   fd       Zy)ModelRegistryz?Holds every loaded model in memory and exposes typed accessors.returnNc                 \    i | _         d| _        t        t        j                        | _        y )NF)_models_loadedr   settings	MODEL_DIR
_model_dirselfs    GC:\Crop_Prediction\Backend\crop-ai-system\app\models_loader\registry.py__init__zModelRegistry.__init__'   s"    ')x112    c                    t         j                  d| j                   d       g }g }t        j	                         D ]}  \  }}| j                  |z  }|j                         s|j                  t        |             @	 t        j                  |      | j                  |<   t         j                  d| d|         |rt        dd|       |rt        dd	|       | j                          d
| _        t         j                  dt        | j                         d       y # t        $ r0}|j                  t        |      t        |      f       Y d }~d }~ww xY w)NzLoading models from z ...zLoaded model 'z' from z;Required model files are missing. The service cannot start.zMissing files: messagedetailzAOne or more model files failed to load. The service cannot start.zFailed to load: TzAll z models loaded successfully)loggerinfor   REQUIRED_MODEL_FILESitemsexistsappendstrjoblibloadr   	Exceptionr   _validate_loaded_modelsr   len)r   missingfailedkeyfilenamepathexcs          r   load_allzModelRegistry.load_all,   sC   *4??*;4@A1779 		5MC??X-D;;=s4y)5$*KK$5S!nSE?@		5 %U(	2  %[)&2 
 	$$&d3t||,--HIJ!  5s4y#c(3445s   ==D$$	E-%EEc           
      L   g d}|D ]M  }| j                   j                  |      }t        |t              rd|vs3t	        dd| dt        |              dD ]I  }| j                   j                  |      }t        |t              r/t	        dd| dt        |              y	)
a3  
        Sanity-check the structure of each loaded artifact. Catches the case
        where a .pkl file loads without raising an exception but doesn't
        contain what the inference code expects (e.g. wrong dict shape from
        a bad training run accidentally copied to the model directory).
        )r	   r
   r   r   modelz2A model file is present but has an invalid format.'z&' expected dict with 'model' key, got r   )r   r   z,' expected dict of {key: fitted_model}, got N)r   get
isinstancedictr   type)r   bundle_modelsr.   objs       r   r*   z%ModelRegistry._validate_loaded_modelsK   s     Z  	C,,""3'Cc4(G3,>)Pse#I$s)U 	 9 	C,,""3'Cc4()Pse#QRVWZR[Q\] 	r   c                 6    | j                   st        dd      y )Nz2Models are not yet loaded. Service is starting up.z2ModelRegistry accessed before load_all() completedr   )r   r   r   s    r   _ensure_loadedzModelRegistry._ensure_loadedc   s!    ||%LK  r   r.   c                 |    | j                          || j                  vrt        d| d      | j                  |   S )NzModel 'z' was not loaded)r   )r=   r   r   )r   r.   s     r   r6   zModelRegistry.getj   s>    dll"%u<L.MNN||C  r   c                     | j                   S N)r   r   s    r   is_readyzModelRegistry.is_readyp   s    ||r   c                 H    t        | j                  j                               S r@   )listr   keysr   s    r   loaded_model_keyszModelRegistry.loaded_model_keyst   s    DLL%%'((r   )r   N)__name__
__module____qualname____doc__r   r2   r*   r=   r&   r   r6   propertyboolrA   rC   rE    r   r   r   r   $   sg    I3
K>0!s !s ! $   )49 ) )r   r   )rI   pathlibr   typingr   r'   app.core.configr   app.core.exceptionsr   app.core.logging_configr   r   rF   r    r"   r   model_registryrL   r   r   <module>rS      sa       ( 3 .>	H	 -, 0* R) R)n r   