+
    ZjFH                        a  R t!0 t R t^ RIt^ RIt^ RIt^ RIt^ RIHtHtH	t	H
t
HtHt ^ RIHtHt ^ RIt^ RIt^ RIHt ^ RIt^ RIt^ RIt^ RIHt ^ RIHt ^ RIHt RRR	R
RRRR/t] ^ k  ! R R4      t R# )zT
Prophet Service Module
Handles Facebook Prophet time series forecasting operations
N)DictListOptionalAnyTupleUnion)datetime	timedelta)Prophet)
get_logger)
MySQLModelMMEQQEYYEAc                     a  ] tR t^t o Rt/ t]P                  ! 4       tRt	]P                  ! 4       t
R tV 3R lR ltV 3R lR ltV 3R lR	 ltV 3R
 lR ltV 3R lR ltV 3R lR ltR tV 3R lR ltV 3R lR ltR(V 3R lR lltR)V 3R lR lltR*V 3R lR lltR+V 3R lR lltV 3R lR ltV 3R  lR! ltV 3R" lR# ltV 3R$ lR% ltV 3R& ltR'tV tR# ),ProphetServicez<Service for handling Facebook Prophet forecasting operationsFc                    \        R 4      V n        \        4       V n        V P	                  4        V P                  4        R# )prophet_serviceN)r   loggerr   _db_ensure_table_ensure_model_dirselfs   &ID:\Projects\python\client-ideal-oms_pyapi\app\services\prophet_service.py__init__ProphetService.__init__$   s0     !23<     c                    < V ^8  d   QhRS[ /#    returnstr)format__classdict__s   "r   __annotate__ProphetService.__annotate__.   s     7 7 7r!   c                4    ^ RI Hp VP                  R,          # )    )current_appPROPHET_MODEL_DIR)flaskr.   config)r   r.   s   & r   _get_model_dirProphetService._get_model_dir.   s    %!!"566r!   c                   < V ^8  d   QhRR/# r$   r%   N )r(   r)   s   "r   r*   r+   2   s     : :4 :r!   c                R    \         P                  ! V P                  4       R R7       R# )T)exist_okN)osmakedirsr2   r   s   &r   r    ProphetService._ensure_model_dir2   s    
D'')D9r!   c                   < V ^8  d   QhRR/# r5   r6   )r(   r)   s   "r   r*   r+   5   s     1 1t 1r!   c                2   \         P                  '       d   R # \         P                  ;_uu_ 4        \         P                  '       d    R R R 4       R # RpV P                  P	                  V4       R\         n        R R R 4       R #   + '       g   i     R # ; i)Na  
                CREATE TABLE IF NOT EXISTS `ml_ml_prophet_models` (
                    `id`          INT UNSIGNED NOT NULL AUTO_INCREMENT,
                    `model_id`    VARCHAR(120) NOT NULL,
                    `file_path`   VARCHAR(512) NOT NULL,
                    `config`      JSON         NOT NULL,
                    `data_points` INT UNSIGNED NOT NULL DEFAULT 0,
                    `train_start` DATE         NOT NULL,
                    `train_end`   DATE         NOT NULL,
                    `created_at`  DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP,
                    `updated_at`  DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                    PRIMARY KEY (`id`),
                    UNIQUE KEY `uq_model_id` (`model_id`),
                    KEY `idx_created_at` (`created_at`)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
            T)r   _table_ensured_table_lockr   execute_query)r   ddls   & r   r   ProphetService._ensure_table5   sf    (((''',,, ('C  HH""3',0N)) ('''s   B(BB	c                &   < V ^8  d   QhRS[ RS[ /# r$   model_idr%   r&   )r(   r)   s   "r   r*   r+   N   s     H H H Hr!   c                    R P                  R V 4       4      p\        P                  P                  V P                  4       V R24      # ) c              3   b   "   T F%  qP                  4       '       g   VR9   d   TMRx  K'  	  R# 5i)-_N)rI   rJ   )isalnum).0cs   & r   	<genexpr>2ProphetService._model_file_path.<locals>.<genexpr>O   s%     YPX1yy{{a:o!3FPXs   -/z.joblib)joinr9   pathr2   )r   rE   safe_ids   && r   _model_file_pathProphetService._model_file_pathN   s<    ''YPXYYww||D//1gYg3FGGr!   c                ,   < V ^8  d   QhRS[ RS[RS[ /# )r$   rE   payloadr%   r'   r   )r(   r)   s   "r   r*   r+   R   s"      c D S r!   c                X    V P                  V4      p\        P                  ! W#^R7       V# )   )compress)rS   joblibdump)r   rE   rV   	file_paths   &&& r   _save_to_diskProphetService._save_to_diskR   s&    ))(3	G3r!   c                ,   < V ^8  d   QhRS[ RS[ RS[/# )r$   rE   r]   r%   rW   )r(   r)   s   "r   r*   r+   W   s"     & & & & &r!   c                    \         P                  P                  V4      '       g   \        R V RV R24      h\        P
                  ! V4      # )zModel file for 'z' not found at '')r9   rQ   isfileFileNotFoundErrorr[   load)r   rE   r]   s   &&&r   _load_from_diskProphetService._load_from_diskW   sC    ww~~i((#&6xj@PQZP[[\$]^^{{9%%r!   c           	     r    R pV P                   P                  WqV\        P                  ! V4      WEV34       R# )a  
            INSERT INTO ml_prophet_models (model_id, file_path, config, data_points, train_start, train_end)
            VALUES (%s, %s, %s, %s, %s, %s)
            ON DUPLICATE KEY UPDATE
                file_path=VALUES(file_path), config=VALUES(config),
                data_points=VALUES(data_points), train_start=VALUES(train_start),
                train_end=VALUES(train_end), updated_at=CURRENT_TIMESTAMP
        N)r   r@   jsondumps)r   rE   r]   r1   data_pointstrain_start	train_endsqls   &&&&&&& r   _upsert_metadataProphetService._upsert_metadata\   s2     	sy$**V:Lkhq$rsr!   c                6   < V ^8  d   QhRS[ RS[S[,          /# rD   )r'   r   r   )r(   r)   s   "r   r*   r+   g   s     	 	 	 	r!   c                    V P                   P                  R V34      pV'       g   R# V^ ,          p\        VP                  R4      \        4      '       d!   \
        P                  ! VR,          4      VR&   V# )z;SELECT * FROM ml_prophet_models WHERE model_id = %s LIMIT 1Nr1   )r   r@   
isinstancegetr'   ri   loads)r   rE   rowsrows   &&  r   _fetch_metadataProphetService._fetch_metadatag   s_    xx%%IH;
 1gcggh'-- JJs8}5CM
r!   c                &   < V ^8  d   QhRS[ RS[/# rD   rW   )r(   r)   s   "r   r*   r+   r   s      s t r!   c                \   \         P                  ;_uu_ 4        V\         P                  9   d"   \         P                  V,          uuRRR4       #  RRR4       V P                  V4      pVf   \	        RV R24      h V P                  WR,          4      p\         P                  ;_uu_ 4        T\         P                  T&   RRR4       T#   + '       g   i     L; i  \         d.    T P                  P                  RT34       \        RT R24      hi ; i  + '       g   i     T# ; i)u8   Three-layer fetch: process cache → DB metadata + disk.NzModel 'z' not foundr]   1DELETE FROM ml_prophet_models WHERE model_id = %sz<' file is missing. Orphaned record removed. Please re-train.)
r   _cache_lock_cacherx   
ValueErrorrf   rd   r   r@   RuntimeError)r   rE   metarV   s   &&  r   _resolve_modelProphetService._resolve_modelr   s    '''>000%,,X6 ('0 (
 ##H-<wxj<==	**8+5FGG '''.5N!!(+ (+ (' ! 	HH""#VYaXcd(#_` 	 ('s#   ,C>C .DC	8DD+	c                V   < V ^8  d   QhRS[ S[,          RS[RS[RS[P                  /# )r$   datadate_columnvalue_columnr%   )r   r   r'   pd	DataFrame)r(   r)   s   "r   r*   r+      s5      ?  ?tDz  ?  ?Z]  ?hjhtht  ?r!   c                $    \         P                  ! V4      pW$P                  9   d0   \         P                  ! WB,          4      WB&   VP	                  V4      pW4P                  9   d!   \         P
                  ! WC,          RR7      WC&   VP                  4       pV P                  P                  R\        V4       R24       V#   \         dD   pT P                  P                  R\        T4       24       \        R\        T4       24      hRp?ii ; i)z
Prepare data for Prophet model

Args:
    data: List of dictionaries with date and value columns
    date_column: Name of the date column
    value_column: Name of the value column

Returns:
    Pandas DataFrame formatted for Prophet
coerce)errorszPrepared DataFrame with z rows for ProphetzError preparing DataFrame: zInvalid data format: N)r   r   columnsto_datetimesort_values
to_numericdropnar   infolen	Exceptionerrorr'   r   )r   r   r   r   dfes   &&&&  r   _prepare_dataframe!ProphetService._prepare_dataframe   s    	?d#B jj("$.."A^^K0 zz)#%==1A(#S  BKK7By@QRSI 	?KK ;CF8DE4SVH=>>	?s   B>C D>D

DNc          
      x   < V ^8  d   QhRS[ S[,          RS[S[,          RS[S[,          RS[S[S[3,          /# )r$   r   rE   r1   r%   )r   r   r   r'   r   )r(   r)   s   "r   r*   r+      sM     L L4jL 3-L 	L
 
c3hLr!   c                    V P                  V4      p\        V4      ^8  d   \        R4      hRRRRRRRRR	R
RRRRRRRR/	pV'       d   VP                  V4       \	        R'/ VB pVP                  V4       V'       g(   R\        P                  ! 4       P                  R4       2pVR,          P                  4       P                  R4      pVR,          P                  4       P                  R4      pRVRVRVR\        P                  ! 4       R\        V4      RVRV/p	\        P                  ;_uu_ 4        V P                  W)4      p
V P                  W*V\        V4      Wx4       V	\        P                  V&   RRR4       V P                   P#                  RV R\        V4       R24       R VR!R"R\        V4      RVR#R$VR,          P                  4       P%                  4       R%VR,          P                  4       P%                  4       //#   + '       g   i     L; i  \&         d.   pT P                   P)                  R&\+        T4       24       h Rp?ii ; i)(z
Train a Prophet model

Args:
    data: Time series data
    model_id: Optional model identifier for storage
    config: Prophet configuration parameters

Returns:
    Training results with model info
z?Insufficient data for training (minimum 2 data points required)seasonality_modeadditiveyearly_seasonalityTweekly_seasonalitydaily_seasonalityFchangepoint_prior_scaleg?seasonality_prior_scaleg      $@holidays_prior_scalechangepoint_rangeg?interval_widthprophet_z%Y%m%d_%H%M%Sds%Y-%m-%dmodelr1   training_data
created_atrk   rl   rm   NzTrained Prophet model z with z data pointsrE   statustrainedtraining_date_rangestartendzError training Prophet model: r6   )r   r   r   updater
   fitr   nowstrftimeminmaxr   r}   r^   ro   r~   r   r   	isoformatr   r   r'   )r   r   rE   r1   r   prophet_configr   rl   rm   rV   r]   r   s   &&&&        r   train_modelProphetService.train_model   s#   ";	((.B2w{ !bcc #J$d$d#U)4)4&#S $
N %%f- -n-EIIbM %hlln&=&=o&N%OPT(,,.11*=KT(,,.11*=I./2hllnmSW{KG
  +++ ..xA	%%h>3r7T_k29%%h/ ,
 KK5hZvc"gYl[\ H)s2w.%RX\\^5572d8<<>335(	 	 ,+$  	KK >s1vhGH	s9   AH 
C,H 6AH
8BH 
H	H I((IIc                N   < V ^8  d   QhRS[ RS[RS[ RS[RS[S[ S[3,          /# )r$   rE   periodsfreqinclude_historyr%   )r'   intboolr   r   )r(   r)   s   "r   r*   r+     sL     B BB B 	B
 B 
c3hBr!   c                    V P                  V4      pVR,          p\        P                  W34      pVP                  W#R7      pVP	                  V4      pV'       g   \        VR,          4      M^ p	. p
\        V	\        V4      4       F  pV
P                  RVR,          P                  V,          P                  R4      R\        R\        \        VR,          P                  V,          4      ^4      4      R\        R\        \        VR,          P                  V,          4      ^4      4      R	\        R\        \        VR	,          P                  V,          4      ^4      4      /4       K  	  R
VRVRVRV
R\        P                  ! 4       P                  4       /pV'       de   VR,          pRVR,          P                   P                  R4      P#                  4       RVR,          P                  ^4      P#                  4       /VR&   V P$                  P'                  RV RV R24       V#   \(         d.   pT P$                  P+                  R\-        T4       24       h Rp?ii ; i)a(  
Generate forecast using trained model

Args:
    model_id: ID of the trained model
    periods: Number of periods to forecast
    freq: Frequency of forecast ('D' for daily, 'H' for hourly, etc.)
    include_history: Whether to include historical data in response

Returns:
    Forecast results
r   r   r   r   r   r   yhatg        
yhat_lower
yhat_upperrE   forecast_periods	frequencyforecastgenerated_atyhistorical_datazGenerated forecast for model z: z periodszError generating forecast: N)r   _FREQ_ALIASESrt   make_future_dataframepredictr   rangeappendilocr   r   roundfloatr   r   r   dttolistr   r   r   r   r'   )r   rE   r   r   r   
model_infor   futurer   	start_idxforecast_rowsiresultr   r   s   &&&&&          r   generate_forecast ProphetService.generate_forecast  s#   &/	,,X6Jw'E !$$T0D 000LF }}V,H
 APJ78UVIM9c(m4$$(4."5"5a"8"A"A*"M#c5x7G7L7LQ7O1PRS+T"U #c5x7M7R7RST7U1VXY+Z"[ #c5x7M7R7RST7U1VXY+Z"[	&  5 H"GTM 8 8 :F  *? ;--0099*ELLNs+11!4;;=-()
 KK<XJb	QYZ[M 	KK ;CF8DE	s   FH* "BH* *I"5(II"c                >   < V ^8  d   QhRS[ RS[RS[ RS[RS[RS[ /# )r$   rE   r   r   widthheightr%   )r'   r   )r(   r)   s   "r   r*   r+   H  sG     1 11 1 	1
 1 1 
1r!   c                    V P                  V4      pVR,          p\        P                  W34      pVP                  W#R7      pVP	                  V4      p	VP                  W^d,          V^d,          3R7      p
\        P                  ! 4       pV
P                  VR^dRR7       VP                  ^ 4       \        P                  ! VP                  4       4      P                  R4      pVP                  4        \        P                  ! V
4       V P                   P#                  RV 24       R	V 2#   \$         d.   pT P                   P'                  R
\)        T4       24       h Rp?ii ; i)a  
Generate forecast plot as base64 encoded image

Args:
    model_id: ID of the trained model
    periods: Number of periods to forecast
    freq: Frequency of forecast
    width: Plot width in pixels
    height: Plot height in pixels

Returns:
    Base64 encoded PNG image
r   r   )figsizepngtight)r(   dpibbox_incheszutf-8zGenerated plot for model zdata:image/png;base64,zError generating plot: N)r   r   rt   r   r   plotioBytesIOsavefigseekbase64	b64encodegetvaluedecodeclosepltr   r   r   r   r'   )r   rE   r   r   r   r   r   r   r   r   figbufferimage_base64r   s   &&&&&&        r   generate_plotProphetService.generate_plotH  s/   *	,,X6Jw'E !$$T0D 000LF}}V,H **Xc	6#:/F*GC ZZ\FKKu#7KKKKN!++FOO,=>EEgNLLLNIIcNKK8
CD+L>:: 	KK 7Ax@A	s   D*D- -E%8(E  E%c                L   < V ^8  d   QhRS[ RS[S[S[ S[3,          ,          /# rD   )r'   r   r   r   )r(   r)   s   "r   r*   r+   {  s(     
 
s 
xS#X/G 
r!   c                4   \         P                  ;_uu_ 4        V\         P                  9   do   \         P                  V,          pRVR,          RVR,          RVR,          P                  4       RVP	                  R4      RVP	                  R4      /uuRRR4       #  RRR4       V P                  V4      pVf   R# RVR,          RVR,          R\        VR,          4      R\        VR,          4      R\        VR,          4      /#   + '       g   i     Lq; i)z
Get information about a trained model

Args:
    model_id: ID of the model

Returns:
    Model information or None if not found
rk   r1   r   rl   rm   N)r   r}   r~   r   rt   rx   r'   )r   rE   rM   r   s   &&  r   get_model_infoProphetService.get_model_info{  s     '''>000"))(3!1]#3Xq{ !L/";";"=!155#7aeeKFX ('0 ( ##H-<4.$x.#d<013tM23[#d;FWBX
 	
 ('s   A9DD	c                F   < V ^8  d   QhRS[ S[S[S[3,          ,          /# r#   )r   r   r'   r   )r(   r)   s   "r   r*   r+     s!      T$sCx.1 r!   c                   V P                   P                  R4      p. pV F  p\        VR,          \        4      '       d
   VR,          M\        P
                  ! VR,          4      pVP                  RVR,          RVR,          RVR\        VR,          4      R\        VR,          4      R\        VR,          4      /4       K  	  V# )z?
List all trained models

Returns:
    List of model summaries
zxSELECT model_id, data_points, config, train_start, train_end, created_at FROM ml_prophet_models ORDER BY created_at DESCr1   rE   rk   rl   rm   r   )r   r@   rs   dictri   ru   r   r'   )r   rv   r   rw   r1   s   &    r   list_modelsProphetService.list_models  s     xx%%>
 C&0X&E&ES]4::VYZbVcKdFMMC
O]C<N&-S5G1HS[!12L#c,FWBX   r!   c                &   < V ^8  d   QhRS[ RS[/# rD   )r'   r   )r(   r)   s   "r   r*   r+     s      S T r!   c                   V P                  V4      p\        P                  ;_uu_ 4        V\        P                  9   pRRR4       Vf   X'       g   R# \        P                  ;_uu_ 4        \        P                  P	                  VR4       RRR4       V'       dK    \
        P                  P                  VR,          4      '       d   \
        P                  ! VR,          4       V P                  P                  RV34       R#   + '       g   i     L; i  + '       g   i     L; i  \         d)   pT P                  P                  RT 24        Rp?LsRp?ii ; i)zy
Delete a trained model

Args:
    model_id: ID of the model to delete

Returns:
    True if deleted, False if not found
NFr]   zCould not delete model file: r|   T)rx   r   r}   r~   popr9   rQ   rc   removeOSErrorr   warningr   r@   )r   rE   r   in_cacher   s   &&   r   delete_modelProphetService.delete_model  s     ##H-'''>#8#88H (<'''!!%%h5 ( I77>>${"344IId;/0 	RU]T_`! ('
 ('  I##&CA3$GHHIs5   D,!D+D, 
D, D	D)	,E7EEc                L   < V ^8  d   QhRS[ S[,          RS[S[S[3,          /# )r$   r   r%   )r   r   r   r   r'   )r(   r)   s   "r   r*   r+     s(     ! !d !dCi8H !r!   c                   \        V\        4      '       d   \        V4      ^8  d   R	# RR0p\        V4       F  w  r4\        V\        4      '       g   RRV R23u # VP                  VP                  4       4      '       g   RRV R23u #  \        P                  ! VR,          4        \        TR,          4       K  	  R
#    RRT 23u u # ; i   RRT 23u u # ; i)z
Validate input data format for Prophet

Args:
    data: Input data to validate

Returns:
    Tuple of (is_valid, error_message)
Fr   r   zData point z must be a dictionaryz must contain 'ds' and 'y' keysz"Invalid date format in data point z$Invalid numeric value in data point )Fz/Data must be a list with at least 2 data points)TrG   )
rs   listr   	enumerater   issubsetkeysr   r   r   )r   r   required_keysr   items   &&   r   validate_data_format#ProphetService.validate_data_format  s     $%%TQKKs GAdD))A3.CDDD ))$))+66A3.MNNNGtDz*
Id3i  '& G B1#FFF
I DQCHHHs   C+C	C	C c                <   < V ^8  d   Qh/ S[ S[S[3,          ;R&   # )r$   r~   )r   r'   r   )r(   r)   s   "r   r*   r+      s      cN r!   )r   r   )r   r   )NN)   DT)r  r  i   iX  ) __name__
__module____qualname____firstlineno____doc__r~   	threadingLockr}   r>   r?   r   r2   r   r   rS   r^   rf   ro   rx   r   r   r   r   r   r   r   r  r  __annotate_func____static_attributes____classdictcell__)r)   s   @r   r   r      s     FF.."KN.."K!7 7: :1 12H H 
& &
	t	 	 < ?  ?LL L\B BH1 1f
 
6 * :! !Y  r!   r   c                b    V ^8  d   Qh/ ^ \         9   d   \        \        \        3,          ;R&   # )r$   r   )__conditional_annotations__r   r'   )r(   s   "r   r*   r*      s'      0 M LtCH~ L1r!   )"r!  r  r9   ri   loggingr  typingr   r   r   r   r   r   r   r	   pandasr   numpynpprophetr
   r   r   r[   matplotlib.pyplotpyplotr   app.utils.helpersr   app.models.mysql_modelr   r   r   r*   )r!  s   @r   <module>r,     sd   
 
    : : (     	   ( - "%dCsD#t L LM Mr!   