
    ic                     "   d dl Z d dlZd dlmZ d dlmZmZ d dlmZmZm	Z	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 d d
lmZ d dlmZmZ  ee      ZdZdefdZ G d d      Zdee ef   de fdZ!dee ef   ddfdZ"dee ef   de fdZ#y)    N)ThreadPoolExecutor)datetime	timedelta)DictAnyListOptional)DataFetcher)SignalProcessor)StatisticalAnalyzer)DeepAnalysisAgent)normalize_markdown_output)
get_logger)insert_user_profiling_row!insert_user_profiling_staging_row   returnc                      	 t        t        j                  dd            } t	        dt        t        |             S # t        $ r d} Y 'w xY w)NDB_POOL_SIZE7r      )intosgetenv
ValueErrormaxmin_FETCH_TASKS)pool_szs    E/var/www/html/userprofiledev.eatanceapp.com/profiling_orchestrator.py_inner_fetch_pool_workersr!      sH    bii45 q#lG,--  s   ; A	A	c                   D   e Zd ZdZd Zdeeef   fdZ	 	 d$de	de
e	   de
e	   deeef   fd	Zde	de	d
e	deeef   fdZ	 d%de	deeef   de
e   ddfdZ	 d%de	deeef   de
e   ddfdZ	 	 d&de	deeef   de
e	   dedef
dZde	dededeeef   fdZdeeef   deeef   fdZdeeef   deeeef      deeef   fdZ	 d%deeeef      de
eeef      deeef   fdZ	 d%de	deeef   de	de
eeef      deeef   f
d Zdeeef   defd!Zd"eeef   defd#Zy)'ProfilingOrchestratora+  
    Coordinates the profiling pipeline for a single user.
    Manages time windows, data fetching, and signal processing.

    Call :func:`storage.user_profiling.ensure_profiling_storage_tables` once per process
    before constructing orchestrators (API / batch startup), not in ``__init__``.
    c                     || _         t        |      | _        t               | _        t        |      | _        t               | _        d| _	        i | _
        y )N)
db_session<   )_dbr
   fetcherr   	processorr   statistical_analyzerr   deep_analyzerdefault_window_days_last_timings)selfdb_connections     r    __init__zProfilingOrchestrator.__init__(   sI     "=1(*$7=$Q!.0 $& /1    r   c                 ,    t        | j                        S )zNReturns milestone timings (seconds) from the last profile + deep_analysis run.)dictr-   )r.   s    r    get_last_timingsz&ProfilingOrchestrator.get_last_timings4   s    D&&''r1   Nuser_idwindow_daysactivity_gate_daysc                 t   || j                   }|K|dkD  rF| j                  j                  ||      s*t        j	                  d||       | j                  |||      S t        j	                  d| d| d       i | _        t        j                         }t        j                         }|t        |      z
  }|j                  d      }|j                  d      }| j                  |||      }	t        j                         }
t        |
|z
  d      | j                  d	<   t        j	                  d
| j                  d	    d       | j                  |	      }| j                  j!                  |      }| j#                  ||	||      }||| j%                  |      d}| j&                  j)                  |      }||d<   t        j                         }t        ||
z
  d      | j                  d<   t        ||z
  d      | j                  d<   t        j	                  d| j                  d    d| j                  d    d       |S )a^  
        Runs the full signal extraction pipeline for a user.

        If ``activity_gate_days`` is a positive int and the user has no rows in
        ``user_activity_logs`` in that window, returns a minimal **inactive** profile
        (no heavy fetches). Pass ``None`` to disable the gate (e.g. batch already
        filtered by activity).
        r   uO   User %s: no user_activity_logs in last %s days — inactive placeholder profilez%Starting profile generation for User z
 (Window: z days)daysz%Y-%m-%d %H:%M:%S   fetch_szMilestone: fetch done in s)metadatasignalsdata_completeness
statisticssignals_stats_sprofile_total_sz!Milestone: signals+stats done in zs | profile total )r,   r(   user_has_recent_activity_logsloggerinfo_inactive_user_profiler-   timeperf_counterr   nowr   strftime_fetch_all_raw_dataround_process_all_signalsfetch_user_basic_details_generate_metadata_check_data_completenessr*   analyze)r.   r5   r6   r7   t_profile_startend_date
start_date	str_startstr_endraw_datat_fetch_doner?   basic_detailsr>   profile_datastatst_profile_dones                    r    generate_user_profile_dataz0ProfilingOrchestrator.generate_user_profile_data8   sX    22K).@1.D<<==gGYZe&
 227KI[\\;G9J{m[abc++-<<>	{ ;;
''(;<	##$78 ++GYH((*(-l_.La(P9%/0B0B90M/NaPQ ++H5==gF**7Hk=Y !!%!>!>w!G
 ))11,?%*\"**,05n|6SUV0W,-05n6VXY0Z,-78J8JK\8]7^^pqu  rD  rD  EV  rW  qX  XY  Z  	[r1   activity_daysc                 b   | j                   j                  |      }t        j                         }|t	        |      z
  }|j                  d       d|j                  d       }d| d| d}dddd| _        |t        |      t        j                         j                  d      |d	i d
|ddidS )zFMinimal profile + markdown text when user has no recent activity logs.r9   %Y-%m-%du    – z$This user is not active in the last z/ days (no rows in `user_activity_logs` between z).        )r<   rB   rC   r5   nameprofile_datedata_window_daysinactive
confidence)r>   r?   r@   _inactive_markdownrA   )r(   rO   r   rJ   r   rK   r-   _display_name_from_user_row)	r.   r5   r6   r_   basicendstartrange_labelmds	            r    rG   z,ProfilingOrchestrator._inactive_user_profiley   s     55g>llni]33
34E#,,z:R9ST2=/ B88C}BH 	
 ""
 #3E: ( 7 7
 C$/	 !+"$'-
 	
r1   r[   deep_analysis_markdownc                 z    t        |      }t        | j                        |d<   t        | j                  |||       y)zOUpsert **published** dbo.user_profiling (+ tracker). Used by API / forced runs.pipeline_timingsN)r3   r-   r   r'   r.   r5   r[   rp   snapshots        r    persist_user_profilingz,ProfilingOrchestrator.persist_user_profiling   s7     %'+D,>,>'?#$!$((GX?UVr1   c                 z    t        |      }t        | j                        |d<   t        | j                  |||       y)zHUpsert **staging** only (scheduled batch). Call publish after full scan.rr   N)r3   r-   r   r'   rs   s        r    persist_user_profiling_stagingz4ProfilingOrchestrator.persist_user_profiling_staging   s7     %'+D,>,>'?#$)$((GXG]^r1   	max_turnspersistc                 H   |j                  d      dk(  rn|j                  d      xs dj                         xs d}t        j                  d|       d| j                  d<   t        |      }|r| j                  |||       |S |j                  d      d	k(  r=t        j                  d
| d       d}t        |      }|r| j                  |||       |S t        j                  d|        | j                  |      }|j                  d      xs i j                  di       }	|	j                  dg       |	j                  dg       }}
|
s|r.t        j                  dt        |
       dt        |       d       t        j                         }| j                  j                  |||      }t        t        j                         |z
  d      | j                  d<   t        j                  d| j                  d    d       t        ||nd      }|r| j                  |||       |S )z
        Triggers the structured deep analysis flow.
        Skips LLM for inactive users (no recent activity logs) and low-signal users.
        r@   rg   ri    zBThis user has no qualifying recent activity in user_activity_logs.z-Skipping deep analysis for User %s (inactive)rb   deep_analysis_s
low_signalz Skipping Deep Analysis for User z (low-signal)zEInsufficient data for deep analysis. Profile is marked as low-signal.z"Triggering Deep Analysis for User r?   order
item_pairscategory_pairszBought together: z item pairs, z category pairs)rx   r;   z!Milestone: deep_analysis done in r=   )getstriprE   rF   r-   r   ru   _build_profile_summarylenrH   rI   r+   runrM   )r.   r5   r[   rx   ry   msgmarkdown_outlow_msgprofile_summaryorder_sipcpt_deep_startresults                 r    run_deep_analysisz'ProfilingOrchestrator.run_deep_analysis   s    /0J>##$89?RFFH T  KKGQ47D014S9L++G\<P/0L@KK:7)=QR]G4W=L++G\<P8	BC55lC##I.4"99'2F\2.<Lb0QBKK+CG9M#b'/Z[((*##''I'V05d6G6G6IL6XZ[0\,-78J8JK\8]7^^_`a06;MSUV''|Lr1   rm   rl   c           	           j                   j                        }|D cg c]%  }|j                  d      s|j                  d      ' c} fd} fd} fd} fd}	 fd}
 fd} fd}t               }i }t	        |	      5 }|j                  |      }|j                  |      }|j                  |      }|j                  |	      }|j                  |
      }|j                  |      }|j                  |      }|j                         |d
<   |j                         |d<   |j                         |d<   |j                         |d<   |j                         |d<   |j                         |d<   |j                         |d<   d d d        |d   ||d
   |d   |d   |d   |d   |d   dS c c}w # 1 sw Y   .xY w)Nidc                  :    j                   j                         S N)r(   fetch_order_items)	order_idsr.   s   r    r   zDProfilingOrchestrator._fetch_all_raw_data.<locals>.fetch_order_items   s    <<11)<<r1   c                  >    j                   j                         S r   )r(   fetch_activity_logsrl   r.   rm   r5   s   r    fetch_activitieszCProfilingOrchestrator._fetch_all_raw_data.<locals>.fetch_activities   s    <<33GUCHHr1   c                  >    j                   j                         S r   )r(   fetch_impressionsr   s   r    r   zDProfilingOrchestrator._fetch_all_raw_data.<locals>.fetch_impressions   s    <<11'5#FFr1   c                  >    j                   j                         S r   )r(   fetch_reviews_and_ratingsr   s   r    fetch_reviewsz@ProfilingOrchestrator._fetch_all_raw_data.<locals>.fetch_reviews   s    <<99'5#NNr1   c                  >    j                   j                         S r   )r(   fetch_cart_datar   s   r    fetch_cartsz>ProfilingOrchestrator._fetch_all_raw_data.<locals>.fetch_carts   s    <<//DDr1   c                  :     j                   j                        S r   )r(   fetch_dietary_preferences)r.   r5   s   r    fetch_dietaryz@ProfilingOrchestrator._fetch_all_raw_data.<locals>.fetch_dietary   s    <<99'BBr1   c                  >    j                   j                         S r   )r(   fetch_cart_add_to_cart_signalsr   s   r    fetch_cart_add_to_cartzIProfilingOrchestrator._fetch_all_raw_data.<locals>.fetch_cart_add_to_cart   s    <<>>wsSSr1   )max_workersorder_items
activitiesimpressionsreviewscartsdietary_rawcart_add_to_cart)r   ordersr   r   r   r   r   r   )r(   fetch_ordersr   r!   r   submitr   )r.   r5   rm   rl   r   or   r   r   r   r   r   r   workersresultsexecutorfuture_order_itemsfuture_activitiesfuture_impressionsfuture_reviewsfuture_cartsfuture_dietaryfuture_cart_add_to_cartr   s   ````                   @r    rL   z)ProfilingOrchestrator._fetch_all_raw_data   s   **7E3?*0@&QAEE$KQUU4[&@		=	I	G	O	E	C	T ,-G4!)1B!C (0@ A!)1B!C%__];N#??;7L%__];N&.oo6L&M#%7%>%>%@GM"$5$<$<$>GL!%7%>%>%@GM"!/!6!6!8GI+224GG%3%:%:%<GM"*A*H*H*JG&' 5$ ",/"=1"=1y)W%"=1 '(: ;	
 		
W A4 54s   GG C=G

Grawc                    dD ]"  }|j                  |      t        d| d       | j                  j                  |d         | j                  j	                  |d   |d         | j                  j                  |d         | j                  j                  |d         | j                  |d	   |d         | j                  |d
   |j                  d      xs i       dS )N)r   r   r   r   r   r   r   zRaw data key 'zU' is missing or None; fetch must return a list/dict for each key. Check data_fetcher.r   r   r   r   r   r   r   r   )activityr~   
impression	sentimentdietary_evidencecart)	r   r   r)   process_activity_signalsprocess_order_signalsprocess_impression_signalsprocess_sentiment_signals_process_dietary_evidence_process_cart_signals)r.   r   keys      r    rN   z*ProfilingOrchestrator._process_all_signals  s    lCwws|# >#  7L  "M  N  N m ??L@QR^^99#h-]I[\..CCCDVWAA#i.Q $ > >s=?QSVWdSe f..s7|SWWEW=X=^\^_
 	
r1   raw_pref	raw_itemsc                 ^    |j                  dg       |j                  d      t        |      dS )Ndietary_preferencesspecial_requests)declared_slugsr   
item_count)r   r   )r.   r   r   s      r    r   z/ProfilingOrchestrator._process_dietary_evidence#  s1     'll+@"E (-? @i.
 	
r1   	raw_cartsr   c                    t        |      t        t        |D cg c]%  }|j                  d      s|j                  d      ' c}            g g g ddddddd}|ra|j                  d      xs g |d<   |j                  d      xs g |d<   |j                  d	      xs g |d	<   |j                  d
      r|d
   |d<   |S c c}w )Nrestaurant_idrb   r   )#add_to_cart_events_per_item_ordered,count_distinct_items_added_but_never_ordered1count_distinct_items_added_then_removed_from_cart"total_add_to_cart_events_in_windowtotal_items_ordered_in_window)
cart_countunique_restaurants_affecteditems_in_cart_windowtop_considered_not_bought!considered_not_bought_by_categoryadd_to_cart_statsitems_in_windowr   r   r   r\   r   )r   setr   )r.   r   r   couts        r    r   z+ProfilingOrchestrator._process_cart_signals-  s     i.+.sT]3xT]qabafafgvawAEE/4JT]3x/y+z$&)+137:@AEF6712"
 *:*>*>?P*Q*WUWC&'/?/C/CD_/`/fdfC+, $$%HIOR 34  ##G,+;G+D'(
) 4ys
   B?B?windowrZ   c                 p    t        |xs i       }||t        j                         j                  d      |dS )Nra   rc   )rj   r   rJ   rK   )r.   r5   r   r   rZ   rd   s         r    rP   z(ProfilingOrchestrator._generate_metadataJ  s:     +=+>B?$LLN33J? &	
 	
r1   c                     t        |      S )z0Delegates to module-level build_profile_summary.)build_profile_summary)r.   r[   s     r    r   z,ProfilingOrchestrator._build_profile_summaryY  s    $\22r1   r?   c                     |xs i }|j                  d      xs i j                  d      xs i j                  dd      }|j                  d      xs i j                  dd      }|dk(  r|dk  ry|d	kD  ry
y)Nr~   metricstotal_ordersr   r   total_events   r}      high_signalmedium_signal)r   )r.   r?   sigorder_countactivity_counts        r    rQ   z.ProfilingOrchestrator._check_data_completeness]  s{    m(.B33I>D"II.Z[\''*-388K! 2? r1   )NZ   r   )NT)__name__
__module____qualname____doc__r0   r   strfloatr4   r   r	   r   r^   rG   ru   rw   boolr   rL   rN   r   r   r   rP   r   rQ    r1   r    r#   r#      s   
2($sEz"2 ( &*,.	?? c]? %SM	?
 
c3h?B

 
 	

 
c3h
J 15		W	W 38n	W !)		W
 
	W 15		_	_ 38n	_ !)		_
 
	_ $(++ 38n+ C=	+
 + 
+Z7
3 7
s 7
 7
cSVh 7
r
S#X 
4S> 

$sCx. 
TRVWZ\_W_R`Ma 
fjknpsksft 
 6:S#X' #4S>2 
c3h	D 37

 #s(^
 	

  S#X/
 
c3h
34S> 3c 3	S#X 	3 	r1   r#   rowc                 *   | sydD ]+  }| j                  |      xs dj                         }|s)|c S  | j                  d      xs dj                         }| j                  d      xs dj                         }|s|r| d| j                         S dS )zADerive display name from users table row (column names may vary).r{   )rd   	full_namedisplay_name
first_name	last_name )r   r   )r   r   valfirstlasts        r    rj   rj   i  s    4wws|!r((*J 5 WW\"(b//1EGGK &B--/D).$eWAdV""$?R?r1   profilec                 x   | sy| j                  dd       | j                  di       }|j                  dd       |j                  dd       |j                  dd       | j                  di       }|j                  di       }t        |t              r|j                  dd       |j                  d	i       }t        |t              rX|j                  dd       |j                  d
d       |j                  di       }t        |t              r|j                  dd       |j                  di       }t        |t              r|j                  dd       |j                  di       }t        |t              r|j                  dd       |j                  di       }t        |t              r|j                  dd       yy)z
    Mutates profile to remove internal/redundant fields before API or dashboard response.
    Pipeline and model summary still use full data; call this only when returning to client.
    Nri   rA   rh   recency	stabilityr?   r   r~   concentrationvelocitystd_dev_days_between_ordersr   text_evidencer   r   r   screen_exposure)popr   
isinstancer3   )	r  r\   r?   r   r~   r  r   dietaryr   s	            r    sanitize_profile_for_apir  v  si   
 KK$d+KKb)E	IIlD!	IIi	IIk4 kk)R(G{{:r*H(D![$'KK$E%		+t$		/4(99Z,h%LL6=K,I)T"ot,kk,b1G'4 L$'\2.J*d#($/ $r1   r[   c                    | j                  d      xs i }| j                  d      xs i }| j                  d      xs i }| j                  dd      }|j                  d      xs i }|j                  d      xs i }|j                  d      xs i }|j                  d	      xs i }|j                  d
      xs i }	|j                  d      xs i }
|j                  d      xs i }|j                  d      xs i }|j                  d      xs dj                         }d|j                  d       d|j                  d       d|j                  d       d| d	}|r	d| d|z   }|g}|j                  d|j                  dd       d|j                  dd       d|j                  d d       d       |j                  d!|j                  d"d       d#|j                  d$d       d       |j                  d%      r3|d%   d&d' }|j                  d(d)j                  d* |D               d       |j                  d+|j                  d,d       d-|j                  d.      xs g d&d/  d       |j                  d0|	j                  d1       d2|	j                  d3       d4       |j                  d5|
j                  d6d       d7|
j                  d8d       d       |j                  dd      }|j                  d9      xs g d&d/ }|j                  d:      xs g d&d/ }|dkD  r|s|r|rS|j                  d;|D cg c]4  }|j                  d<      |j                  d=      |j                  d>      f6 c} d       |re|j                  d?|D cg c]4  }|j                  d@      |j                  dA      |j                  d>      f6 c} d       n|j                  dB       |j                  dC      xs i i dD}|j                  dE      s|j                  dF      r8|j                  dG|j                  dEi        dH|j                  dFi        d       |j                  dI      xs g }|j                  dJ      xs i }|j                  dK      xs g }|j                  dLdM      }|dkD  r|s"|j                  dN      s|j                  dO      r|j                  dP|d&d/  dQ|j                  dN      xs g d&d'  dR|j                  dO      xs g d&d'  d       |r|r|j                  dS|d&d/  d       n|dkD  r|s|j                  dT       |j                  dU|j                  dVd       dW|j                  dXg        dY|j                  dZ      xs i j                  d[d       d\|j                  dZ      xs i j                  d]d       d	       |j                  d^|j                  d_d       d       |r|j                  d`|j                  da      xs i j                  db       dc|j                  da      xs i j                  dd       de       |j                  df|j                  dg      xs i j                  dh       di|j                  dg      xs i j                  dj       de       |j                  dk|j                  dl      xs i j                  dm       dn|j                  dl      xs i j                  do       de       |j                  dp|j                  dq       d       |j                  dr      xs i }|rK|j                  ds|j                  dtd       du|j                  dvd       dw|j                  dxd       d       |j                  dr      xs i }|j                  dy      xs g d&d/ }|j                  dz      xs g d&d/ }|s|ry|r2|j                  d{|D cg c]  }|j                  d|       c} d       |rC|j                  d}|D cg c]$  }|j                  d~      |j                  d      f& c} d       |j                  d9      xs g }|j                  d:      xs g }|j                  dC      xs i i dD} |j                  dI      xs g }!|j                  dJ      xs i }"|j                  dK      xs g }#|j                  dLdM      }$|j                  d| d| d|  d|! d|" d|# d|$ d       dj                  |      j	                  dd      j                         S c c}w c c}w c c}w c c}w )z
    Builds a readable paragraph summary of the profile for the deep analysis agent.
    Does not trim; summarises key facts into prose so the agent gets context without raw JSON.
    Can be used by orchestrator or by other entry points (e.g. API).
    r>   r?   rA   r@   unknownr~   r   loyalty	inventoryr  	financialr   r   rd   r{   zUser r5   u    — profile date re   z	, window rf   z days. Data completeness: .zName: z. zOrders: r   r   z total, total spent total_spentz, avg order value avg_order_valuezUnique restaurants: unique_restaurants_countz; reorder ratio reorder_ratiotop_restaurantsNr   z Top restaurants by order count: z, c              3   2   K   | ]  }t        |        y wr   )r   ).0xs     r    	<genexpr>z(build_profile_summary.<locals>.<genexpr>  s     AVRUQ#a&RUs   zTop items ordered: total_items_orderedz total; top items list: 	top_itemsr   z"Velocity: avg days between orders avg_days_between_ordersz, last order last_order_days_agoz days ago. zCoupon usage: coupon_order_countz orders with coupon, ratio coupon_ratior   r   zItem pairs (ordered together): item_aitem_btimes_togetherz#Category pairs (ordered together): 
category_a
category_bzYBought together: 0 item pairs, 0 category pairs (orders exist but no multi-item combos). order_temporal)hourdayr/  r0  z.Order temporal (when they place orders): hour z, day location_orderlocation_timelocation_tripletlocation_significantFby_hourby_dayz,Location (where they order): location_order=z, location_time by_hour=z	, by_day=zBLocation triplet (location+time+category, only when significant): zRLocation triplet: not computed (location+order or location+time below threshold). z
Activity: r   z events; top searches top_searchesz; filters: pure_veg filterspure_veg_countz	, offers offers_countzImpressions: total_impressionsu-   Statistics — temporal: dominant hour share temporaldominant_hour_sharez
, entropy entropyz; z concentration (HHI): restaurant r  restaurant_hhiz, item item_hhizengagement: browse-to-order 
engagementbrowse_to_order_ratioz, search-to-order search_to_order_ratiozmath confidence rh   r   z6Cart add-to-cart: add_to_cart_events_per_item_ordered r   z/, count_distinct_items_added_but_never_ordered r   z4, count_distinct_items_added_then_removed_from_cart r   r   r   z+Top items added to cart but never ordered: 	item_namez'Considered but not bought by category: category_name7distinct_items_added_but_never_ordered_in_this_categoryz, RAW ORDER SIGNALS (exact data): item_pairs=z, category_pairs=z, order_temporal=z, location_order=z, location_time=z, location_triplet=z, location_significant=r  z  )r   r   appendjoinreplace)%r[   metar?   r\   completenessr   order_metricsorder_loyalty	order_invorder_velocity	order_fin
activity_simpression_srd   
first_linepartstop
num_ordersr   	cat_pairspr.  	loc_orderloc_timeloc_tripletloc_sig
cart_statscart_stop_not_boughtnot_bought_by_catraw_item_pairsraw_cat_pairsraw_order_temporalraw_location_orderraw_location_timeraw_location_tripletraw_location_significants%                                        r    r   r     s+    J'-2Dy)/RG\*0bE##$7CLkk'"(bGKK	*0bMKK	*0bMK(.BI[[,2NK(.BIZ(.BJ;;|,2LHHV"))+D
#$$6txx7O6P Q((-.//I,WX	Z  dV2&3
LE	LL
=$$^Q78 9$((:; <(,,->BC2	G
 
LL
}001KQOP Q&**?A>?r	C *+-.r27		AVRUAV8V7WWYZ[	LL
imm,A1EF G%MM+6<"bqAB"	F 
LL
,^-?-?@Y-Z,[ \$(()>?@	M 
LL
';Q?@ A~q12"	6
 "">15J++l+1r2A6J-.4"bq9IA~5  }G  7H  }GwxhxZ[Z_Z_`pZq7r  }G  7H  6I  IK  L 9  IR  ;S  IR  DEAEE,<OQRQVQVWcQdfgfkfkl|f};~  IR  ;S  :T  TV  W LLk [[!12Mr"6MN&!^%7%7%><^=O=OPVXZ=[<\\bcqcucuv{}  dA  cB  BD  E	
 ,-3I{{?+1rH++017RKkk0%8GA~Y/8<<3ILL>y!}oMegogsgst}g~  hE  CE  GI  HI  gJ  fK  KT  V^  Vb  Vb  ck  Vl  Vr  pr  tv  uv  Uw  Tx  xz  { ;abmnpopbqarrtuvaqr	LL
Z^^NA67 8"~r:; <(nnY7=2BBCSUVWX Y>>),277JK2	O 
LL=!1!12Eq!I J"MN;UYYz=R=XVX<]<]^s<t;u v		*-388CDBH	
 	.		/0J0Pb/U/UVf/g.h iYY/52:::FGrK	
 	*EIIl,C,Ir+N+NOf+g*h i %		, 7 =2BBCZ[\\^`	
 	'		,(?'@BCYYv&,"
LLHX}  @A  JB  IC C@@JO}  @A  AB  @C CEEO^^  UH  JK  FL  EM  MOP [[ &BFjj!<=CRaHN$GHNBPRQRS*LL=[i>j[iVWquu[?Q[i>j=kkmn LL9  `q  ;r  `q  [\AEE/<RTUTYTY  [T  UU  <V  `q  ;r  :s  su  v
 [[.4"NKK 017RM %56Q2b:Q %56<"O4:";;'9:@b&{{+A5I	LL	$% &' ),- .,--=>O=P Q011HIaHbbc	e 88E?""4-3355q 7H ;Sx ?k ;rs   79d=
9e
-e
!)e
)$r   rH   concurrent.futuresr   r   r   typingr   r   r   r	   data_fetcherr
   signal_processingr   statistical_analysisr   deep_analysisr   deep_analysis.helpersr   core.logger_configr   storage.user_profilingr   r   r   rE   r   r   r!   r#   r   rj   r  r   r   r1   r    <module>rq     s    	  1 ( , , $ - 4 + ; )
 
H	 .3 .G GT

@T#s(^ 
@ 
@!0d38n !0 !0HU6S#X U63 U6r1   