
    xGj                         d Z ddlZddlmZ ddlmZ ddlmZ ddlm	Z	 ddl
mZ ddlmZ  ee      ZddlZd	 Z e       Zd
 Z edd      Zdededededee   f
dZde	dededededeeef   fdZy)u  
Aggregation layer.

Runs all 6 models concurrently using a thread pool (model inference via
joblib/xgboost/statsmodels is CPU-bound and releases the GIL during the
heavy numeric work, so threads — not full async — give real parallelism
here without the complexity of multiprocessing).

This module is called from the Celery task (app/workers/tasks.py), NOT
directly from an API request handler — see the architecture decision
in docs/architecture.md. That keeps slow ML work off the web-serving
threads entirely.
    N)ThreadPoolExecutor)Any)
get_logger)ModelRegistry)model_runners)FeatureBuilderc            
      6   dd l } | j                  j                  | j                  j                  | j                  j	                  t
              ddddd            }	 t        |      5 }t        j                  |      cd d d        S # 1 sw Y   y xY w#  i cY S xY w)Nr   z..datalookupz
crops.json)	ospathnormpathjoindirname__file__open_jsonload)r   r   fs      DC:\Crop_Prediction\Backend\crop-ai-system\app\services\aggregator.py_load_cropsr      sy    77BGGLL)BD$PVX`bnopD$Z 	!1::a=	! 	! 	!	s*   B 'B<	B BB B Bc                 `    t         j                  | j                               }|r|d   dz  S d S )Nwater_req_mmg      (@)_CROPSgetlower)croppropss     r   _monthly_water_reqr   &   s-    JJtzz|$E-2E.!D(<<       zmodel-infer)max_workersthread_name_prefixclimatefeasibility
yield_predtrendreturnc                    g }|j                  d      dk(  r%| j                  d      dk(  r|j                  d       |j                  d      dk(  r7|j                  dd      dk  r"|j                  d	      s|j                  d
       |j                  d      dk(  r%|j                  d      dk(  r|j                  d       |S )Nlabelsuitableanomaly_labelhighuq   Climate anomaly is high but feasibility model says suitable — treat the suitable label with caution this month.expected_yield_ton_har   g      ?degradedzGYield prediction is unusually low despite a suitable feasibility label.r'   downwardu   Multi-year yield trend is downward even though this month looks suitable — consider the longer-term pattern, not just this month.)r   append)r$   r%   r&   r'   	conflictss        r   _detect_conflictsr3   .   s     Iw:-'++o2NRX2X@	
 	 J.NN2A6<z*U	
 yyZ'KOOG,D
,RE	

 r    registryfeature_builderdistrictr   monthc                    t        j                         }|j                  |||      }t        j	                  t
        j                  | ||      t        j	                  t
        j                  | |||      t        j	                  t
        j                  | |      t        j	                  t
        j                  | |      t        j	                  t
        j                  | |||j                  |      t        j	                  t
        j                  | ||      d}|j                         D 	ci c]  \  }}	||	j                          }
}}	t        |
d   |
d   |
d   |
d         }|
j                         D cg c]*  \  }}t        |t               s|j#                  d      s)|, }}}|rt$        j'                  d|        t)        t        j                         |z
  dz        }|
d   |
d   |
d   |
d   |
d	   |
d
   |||d	S c c}	}w c c}}w )u   
    Synchronous, blocking function — this is exactly what we want inside
    a Celery worker task. Building it as a plain function (not async)
    keeps it trivially testable and avoids mixing asyncio with the
    thread-pool model calls.
    )r$   r%   yield_predictionr'   recommendationmarketr$   r%   r9   r'   r/   z)Analysis completed with degraded models: i  r:   r;   )	r$   r%   r9   r'   r:   r;   r2   degraded_modelsprocessing_ms)timeperf_counterbuild	_executorsubmitr   run_climate_modelrun_feasibility_modelrun_yield_modelrun_trend_modelrun_recommendation_modelrun_market_modelitemsresultr3   
isinstancedictr   loggerwarningint)r4   r5   r6   r   r7   startfeature_vectorfutureskeyfutureresultsr2   kvr<   
elapsed_mss                   r   run_full_analysisrY   K   s    E$**8T5AN ##M$C$CXxY^_ ''(K(KXWegkmuv%,,]-J-JHVde!!-"?"?>Z#**22h'<'<d
 ""=#A#A8XW[\
G 8?}}GVsFMMO#GGG!	GM2"#WW%5I
 &-]]_bTQ
1d8KPQPUPUV`PaqbObB?BSTUd'')E1T9:J 9%}-#$67!!"23(#*#
 
 H cs   'G?2HHH)__doc__r>   concurrent.futuresr   typingr   app.core.logging_configr   app.models_loader.registryr   app.servicesr   app.services.feature_builderr   __name__rM   jsonr   r   r   r   rA   rL   liststrr3   rO   rY    r    r   <module>rf      s     1  . 4 & 7	H	  
=
 1O	 $26?C	#Y:44#4 4 	4
 4 
#s(^4r    