o
    \N)jل                     @  s  d Z ddlmZ ddlZddlZddlZddlmZ ddlmZm	Z	m
Z
mZmZ eeZdd
dZdddZdddZdZddddddddddddddddgZg dg dd Zh d!Zd"d#d#d$d%Zdd(d)Zdd+d,Zdd/d0Zdd3d4Zddd8d9Zddd;d<Zdd>d?ZddAdBZddCdDZ ddEdFZ!ddIdJZ"ddLdMZ#ddPdQZ$dRZ%dSZ&ddUdVZ'ddWdXZ(ddYdZZ)dd[d\Z*dd]d^Z+dd`daZ,		bdddedfZ-ddhdiZ.dddjdkZ/ddldmZ0ddpdqZ1ddsdtZ2ddudvddzd{Z3		u	ddd}d~Z4dS )zNLead-level insights: objections, BANT, and dynamic path-to-conversion actions.    )annotationsN)datetime)AnyCallableDictListOptionalvaluer   return	List[str]c                 C  s2   t | pd }|sg S td|}dd |D S )N z[\n;,|]+c                 S  s    g | ]}| d r| d qS )z -	)strip).0item r   @/home/aiteam/pcaa-dev/dashboard-backend/lead_insights_service.py
<listcomp>   s     z'split_insight_items.<locals>.<listcomp>)strr   resplit)r	   textitemsr   r   r   split_insight_items   s
   r   r   r   keywordsc                   sL   | sdS t d| }|D ] t fdd|D r#  d d   S qdS )NNot mentioned(?<=[.!?])\s+|\n+c                 3  s    | ]	}|   v V  qd S Nlowerr   keywordsentencer   r   	<genexpr>       zfind_snippet.<locals>.<genexpr>   )r   r   anyr   )r   r   	sentencesr   r!   r   find_snippet   s   r(   c                 C  s^   | d u rd S t | ttfr| S t | tr-|  }|sd S zt|W S  ty,   Y d S w d S r   )
isinstancedictlistr   r   jsonloads	Exceptionr	   r   r   r   r   _parse_json_field    s   
r0   budget	authorityneedtimelinecompetitors_mentionedzCompetitors Mentioned)	field_keydisplay_name
field_typeproducts_discussedzProducts / Services Discussedcustomer_sentiment_trendzCustomer Sentiment Trendkey_concernszKey Concernstextarea)
competitorzcompared withzcompared toversusvszother optionalternative)productserviceplanpackagepropertyproject	discussedlooking for)r6   r:   >   aanatbyinofonortoandforthefromwithr   r   lowr	   	reasoningevidence
confidenceentryDict[str, str]c                 C  s   t | tr8t| dpd pd}|t| dpd t| dp$d t| dp.d  p5ddS t| p<d }|sFttS |ddddS )	Nr	   r   rZ   r   r[   r\   rX   rY   )r)   r*   r   getr   r   EMPTY_BANT_ENTRY)r]   r	   r   r   r   r   _normalize_bant_entryJ   s   
ra   boolc                 C  s*   t | dpd  }t|o|dvS )Nr	   r   >   unknown-n/anot mentioned)r   r_   r   r   rb   )r]   r	   r   r   r   _is_bant_mentioned^   s   rg   callDict[str, Any]c                 C  sN   |  d}t|tr|r|S t|  dpi }| d}t|tr%|r%|S i S )Nbant_profileraw_responsecustomer_profile)r_   r)   r*   r0   )rh   profilerawrl   r   r   r   _resolve_call_bant_profilec   s   

ro   signalsList[Dict[str, Any]]c                 C  s   dd t D }d}| pg D ]Q}|s!t|dp|dpd }|dp'i }t|ts.qt D ]-}|dkr@d|vr@d|v r@dn|}||vrGq0t||}t|| rUq0t|r]|||< q0q||d	S )
Nc                 S  s   i | ]}|t tqS r   )r*   r`   )r   keyr   r   r   
<dictcomp>p   s    z(_aggregate_lead_bant.<locals>.<dictcomp>r   customer_profile_summarybant_summaryrj   r4   needs)summaryrm   )	BANT_KEYSr   r_   r   r)   r*   ra   rg   )rp   rm   rw   signalrj   rr   
source_key
normalizedr   r   r   _aggregate_lead_banto   s(    
 

r|      max_lenintc                 C  s\   t | pd }|sdS tjd|dd}|d  }t||kr,|d |d   d S |S )Nr   z(?<=[.!?])\s+   )maxsplitr      ...)r   r   r   r   lenrstrip)r   r~   cleanedpartsr"   r   r   r   _first_sentence   s   r   P   c                 C  s8   t | pd }t||kr|S |d |d   d S )Nr   r   r   )r   r   r   r   )r   r~   r   r   r   r   	_truncate   s   r   callsc                 C  s  g }| pg D ]}t |dpi }t|}i }tD ]!}|dkr)d|vr)d|v r)dn|}||v r:t||d ||< q||d|d|d|dt|d	pY|d
pYd t|dph|dphd t|dpu|dt|dp|dpd t|dp|dpd 	 |d||t|dp|dpd t|dp|dp|dpd t
|dtr|dng d q|S )Nrk   r4   rv   r	   callidcall_starttime	direction	agentnamerw   overall_summaryr   call_purposeobjections_concernsobjection_type	sentimentneutralquality_scoreru   rt   
next_steps)r   r   r   r   rw   intent
objectionsr   r   r   bantrj   ru   rt   r   )r0   r_   ro   rx   ra   appendr   r   r   r   r)   r+   )r   rp   rh   rn   rj   r   rr   rz   r   r   r   _collect_call_signals   sJ    "
r   detailsc                   s   t | dpd }|r|dvr|S |r|d ni }|dp!d  |d}|dp/g }t fdd	d
D r=dS |rK|d urKt|dk rKdS t fdd	dD rXdS t fdd	dD redS t|dkrmdS dS )Nlead_statusr   >   Unknownrc   rd   r   r   r   r   c                 3      | ]}| v V  qd S r   r   r   wordr   r   r   r#          z%_infer_sales_stage.<locals>.<genexpr>)purchasebuyclosepaymentbookingorderClosing7   zObjection handlingc                 3  r   r   r   r   r   r   r   r#      r   )demoproposalquotepricing
Evaluationc                 3  r   r   r   r   r   r   r   r#      r   )followcallbackinformationinquiry	Discovery   NurturezInitial contact)r   r_   r   r   r&   floatr   )r   rp   
crm_statuslatestqualityr   r   r   r   _infer_sales_stage   s$   
r   c           
        s  dd |D }|rt |t| nt| dpd}dd |D }t dd |D }t dd |D }t|| | }|d	 }||d
 7 }||d 8 }|rU|sU|sU|d7 }|r[|d ni   drf|d8 } drzt fdddD rz|d7 }t| | tfdddD r|d7 }ntfdddD r|d8 }t| dpt|pd}	|	dkr|dkr|d7 }ttdt	dt
|S )Nc                 S  s&   g | ]}| d durt|d  qS )r   N)r_   r   r   sr   r   r   r      s   & z4_estimate_conversion_probability.<locals>.<listcomp>avg_quality_scorer   c                 S  s"   g | ]}t |d pd qS )r   r   )r   r_   r   r   r   r   r   r      s   " c                 s      | ]	}d |v rdV  qdS )positiver   Nr   r   r   r   r   r#      r$   z3_estimate_conversion_probability.<locals>.<genexpr>c                 s  r   )negativer   Nr   r   r   r   r   r#      r$   g?         r   
   r   c                 3  s     | ]}| d    v V  qdS )r   Nr   r   )r   r   r   r#      s    
)r   visitr   r   r   c                 3  r   r   r   r   stager   r   r#      r   )hot	qualifiedclosingwonc                 3  r   r   r   r   r   r   r   r#      r   )lostunqualifiedjunk   total_conversationsr   <   _   )sumr   r   r_   r&   r   r   r   maxminround)
r   rp   scoresavg_quality
sentimentsr   r   r   probabilityconversation_countr   )r   r   r    _estimate_conversion_probability   s6   &

r   c                 C  st   g }| sdgS | d  dpi }ddddd}| D ]\}}t| |p&d	 }|r2| d
v r7|| q|S )Nz'qualification details from the customerr   r   zbudget or pricing expectationsz#decision-maker and approval processzspecific needs and use caseztimeline and urgencyr1   r   >   rc   rd   re   rf   )r_   r   r   r   r   r   )rp   gapslatest_bantmappingrr   labelr	   r   r   r   
_bant_gaps   s   
r   	raw_stepsList[Dict[str, str]]c                 C  s   t | tsg S g }| D ]X}t |tsqt|dp|dpd }t|dp4|dp4|dp4d }t|dpI|dpI|d	pId }|rZ|rZ||||d
 t|dkrc |S q|S )Ntitleactionr   sayscriptmessage	rationaleworks_becausereasonr   r   r   r   )r)   r+   r*   r   r_   r   r   r   )r   r{   stepr   r   r   r   r   r   _normalize_action_steps
  s    

 **r   r   c                 C  sT  |sg S |d }t | |}t| |}g }t|dpd}|dp#d}|r0d|d d}	nd	|  d
}	|dt|dpAd |	d| d|dd dd dd |D }
|
r|
d }|dpgd}|dt|d d| d dd|dpd dd n|d r|d!d"|d  d   d#d$d t|}t	| d%pd
 }|d&kr|
s|d'd(| d)| d*d+| d,d nX|r|d }|d-|d.d  d/| d0d1| d2| d3| d4d n2|r|d5kr|d6d7| d8d9d n|dpd}|d:d;| d<d1| d=| d>d |d d? S )@Nr   rw   r   r   zyour recent inquiryz4I reviewed our last conversation where we discussed .zA. I wanted to pick up from there and help you with the next step.z+I am following up on our recent call about z8. I have a few specific points based on what you shared.zReconnect on r   zthe last conversationzLatest call intent is "z" with r   r   zJ sentiment; a contextual opener shows you listened and reduces repetition.r   c                 S  s   g | ]	}| d s|qS )customer_satisfiedr_   )r   objr   r   r   r   ?  s    z4_generate_action_steps_heuristic.<locals>.<listcomp>	objectionzthe concern you raisedz	Address: r   zYou had mentioned ur   . I want to make sure we resolve that clearly before moving forward — can I walk you through how we handle this?zUnresolved objection detected (typeconcernzN). Removing this blocker is the highest-impact move before advancing the deal.r   z#Confirm prior concerns are resolvedzLast time you raised z?. Does that still feel addressed, or is anything still unclear?zWEven handled objections can resurface; confirming closure protects conversion momentum.next_task_due_dateF   zAdvance toward commitmentzABased on our conversations, you seem close to a decision (stage: z, ~zj% conversion likelihood). Would it help to schedule a demo or finalize the next commercial step this week?z5Strong buying signals (quality/sentiment) and stage "z0" suggest pushing for a concrete next milestone.zQualify  z6To recommend the best option, I still need clarity on zC. Could you share a bit more so I can tailor the next step for you?zStage "z" with ~u(   % conversion likelihood — filling the z+ gap will sharpen fit and next-step timing.rd   zAlign on scheduled follow-upz&I have us marked for follow-up around zS. Does that timing still work, or should we adjust based on where things stand now?zRKeeps CRM task timing aligned with the customer's current intent and availability.zSet a concrete next stepzGiven your u    engagement so far, I'd like to propose a clear next step — a short follow-up call or sharing specific material. What would be most useful for you?z" at ~u]   % conversion likelihood — locking a specific next action prevents the lead from going cold.r   )r   r   r   r_   r   r   r   r   r   r   r   r   )r   rp   r   r   r   r   stepssummary_hookr   opener
unresolvedtopobjection_textr   next_duegap_textr   r   r   r    _generate_action_steps_heuristic  s   






r  invoke_chatCallable[..., Optional[str]]c                 C  sL  |sg S t ||}t||}|d|d|d|d|d|d|||d d |d d t|d	}d
tj|dtd }z| |}W n tyc }	 zt	d|	 g W  Y d }	~	S d }	~	ww |shg S |
d}
|d}|
dksz||
kr|g S zt||
|d  }W n ty   g  Y S w t|d}t|dkr|S g S )N	lead_namer   
owner_namer   r   r   r      )r  r   r  r   r   r   inferred_stageconversion_probability_pctr   r   	bant_gapsaE  You are a sales coach generating lead follow-up guidance.
Use ONLY the evidence in LEAD CONTEXT. Do not invent facts, pricing, or commitments.
Return STRICT JSON with key action_steps: an array of 2 or 3 objects.
Each object must have: title (short action name), say (exact words the agent should use on the next call), rationale (one sentence explaining why this works based on summary/intent/objections/sentiment/stage/probability).
Prioritize unresolved objections, then stage-appropriate advancement, then qualification gaps.
Keep each say under 280 characters.

LEAD CONTEXT:
T)ensure_asciidefaultzLead action-step LLM failed: %s{}r   action_stepsr   )r   r   r_   r   r,   dumpsr   r.   loggerwarningfindrfindr-   r   r   )r  r   rp   r   r   r   contextpromptanswerexcstartendparsedr   r   r   r   _generate_action_steps_llm  sP   






r  zNot Mentioned)	requestedrequired	confirmed	scheduled
interestedapproved	availableeligibleagreedaccepteddeclined	cancelledcanceledfieldc                 C  s   t | dpd  }|tv rtt| S t | dp |p d  }td|}dd |D }|r7|S |rCdd |dD S g S )	Nr7   r   r8   z
[^a-z0-9]+c                 S  s$   g | ]}t |d kr|tvr|qS )r   )r   _STOP_WORDSr   r   r   r   r     s   $ z'_keywords_for_field.<locals>.<listcomp>c                 S  s   g | ]
}|r|t vr|qS r   )r.  r   tokenr   r   r   r     s    _)r   r_   r   r   FIELD_KEY_KEYWORDSr+   r   r   )r-  r7   r8   wordsr   r   r   r   _keywords_for_field  s   r4  c                 C  s"   t | pd  }| p|dv S )Nr   >   not mentionnanilnonerc   rd   re   rf   )r   r   r   r/   r   r   r   _is_not_mentioned  s   r9  c                   sX   t | dpd  }t | dpd  }| d|  t fddtD S )Nr7   r   r8   r   c                 3  r   r   r   )r   hinthaystackr   r   r#     r   z#_is_yes_no_field.<locals>.<genexpr>)r   r_   r   r   r&   _YES_NO_FIELD_HINTS)r-  r7   r   r   r;  r   _is_yes_no_field  s   r>  c                   sx   t | pd    stS  dv r  S d}d  dtfdd|D r+dS d}t fd	d|D r:d
S tS )Nr   >   noyes)z not zn't z never z cannot z can't z won't z dont z don't z no z
 declined z refuse z unavailable r   c                 3  r   r   r   r   marker)paddedr   r   r#     r   z*_infer_yes_no_from_text.<locals>.<genexpr>No)z yesyeahsurer"  r(  r)  r#  zwill zcan okayzok c                 3  r   r   r   rA  loweredr   r   r#   &  r   Yes)r   r   r   NOT_MENTIONEDr   r&   )r   negative_markerspositive_markersr   )rI  rC  r   _infer_yes_no_from_text  s   rN  c                   sP   | r|sdS t d| }|D ]}|  t fdd|D r%|   S qdS )Nr   r   c                 3  r   r   r   r   rH  r   r   r#   1  r   z*_find_matching_sentence.<locals>.<genexpr>)r   r   r   r&   r   )r   r   r'   r"   r   rH  r   _find_matching_sentence+  s   rO  r"   c                   s   t | pd }|stS | }t |dpd   td|}|r@t fdddD r@|d }|r@|	  dS td	|}|rNd
 v rNdS tjd|tj
d}|red v rg|ddS d S d S )Nr   r7   zkvisit(?:ing)?\s+(?:your\s+|the\s+|our\s+)?([a-z][a-z\s]{0,20}?)(?:\s+(?:tomorrow|today|next|on\b)|[.?!,]|$)c                 3  r   r   r   r/  r7   r   r   r#   B  r   z/_smart_compact_from_sentence.<locals>.<genexpr>nextr   r   r   r   r   z Visitz\b(?:demo|demonstration)\br   rJ  z[(?:competitor|compared with|compared to|versus|vs\.?)\s+([A-Za-z0-9][A-Za-z0-9\s&.-]{0,30})flagsr>   z .,!?)r   r   rK  r   r_   r   searchr&   groupr   
IGNORECASE)r"   r-  r   rI  visit_matchplace
demo_matchcompetitor_matchr   rP  r   _smart_compact_from_sentence6  s0   r\  r   Optional[Dict[str, Any]]	max_wordsc                 C  s   t | pd }|stS |rt||}|r|tkr|S | }|D ]1}|| }|dk r/q!||t| d  d}	|	rRtd|	}
d	|
d | d  S q!td|}
d	|
d | dS )Nr   r   u    :,-–—.\s+r   z.,!?)
r   r   rK  r\  r   r  r   r   r   join)r"   r   r-  r^  r   smartrI  r    idxtailr3  r   r   r   _compact_phrase_from_sentenceT  s&   
rd  r9   c                 C  s   t |pd  }|dkr td| }|r tdd|dS |dkr1td| }|r1|dS |d	krBtd
| }|rB|dS |dkrXtjd| tjd}|rX|d S dS )Nr   phonez\+?\d[\d\s\-()]{8,}\dr_  r   r   emailz.[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}numberz\b\d+(?:[.,]\d+)?\bdatez\b(?:today|tomorrow|yesterday|\d{1,2}[/-]\d{1,2}(?:[/-]\d{2,4})?|(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*\s+\d{1,2})\brS  )	r   r   r   r   rU  subrV  rW  r   )r"   r9   matchr   r   r   _extract_typed_valueq  s,   

rk  c                 C  s*   t | pd }t|rtS t||pi S )Nr   )r   r   r9  rK  _enforce_compact_value)r	   r-  r   r   r   r   _normalize_capture_value  s   rm  c                 C  s   t | pd } t| rtS t|rt| }|tkr|S t |dp#d  }t| |}|r2|S t	
d| }t|dkrGd|d d } | d} t| dkr\| d d	  d
 } | p_tS )Nr   r9   r   r_  r	  r   z.,!? r   9   r   )r   r   r9  rK  r>  rN  r_   r   rk  r   r   r   r`  r   )r   r-  inferredr9   typedr3  r   r   r   rl    s$   

rl  transcript_textsentiment_trendc             	     s>  t | dpd    dkr|ptS  dkrMg }|d d D ]}t |dp*d }|s1q!|t|t| | dd q!dd	d
 |D }|pLtS t| }t | dpXd   t	 fdd
dD rtt
t|g d }|sxtS t||}	|	stS t| rt|	S t|	| d}
|
r|
S tt|	|| d| S )Nr7   r   r;   r<      r   )r-  r^  z, c                 s  s     | ]}|r|t kr|V  qd S r   )rK  )r   phraser   r   r   r#     s    z0_heuristic_data_capture_value.<locals>.<genexpr>c                 3  r   r   r   r/  rP  r   r   r#     r   rQ  )r   visitingtomorrowr   meetingr9   )r-  )r   r_   r   r   rK  r   rd  r4  r`  r&   r+   r*   fromkeysrO  r>  rN  rk  rl  )r-  rq  rr  r   phrasesr   r   joinedr   r"   rp  r   rP  r   _heuristic_data_capture_value  s6   
r{  fieldsc              
   C  sJ  |r|  si S dd |D }|si S |dd  }dtj|dd d| }z| |}W n tyF } ztd| i W  Y d }~S d }~ww |sKi S |d	}|d
}	|dks]|	|kr_i S zt|||	d  }
W n tyw   i  Y S w |
	d}t
|tsi S i }|D ]}t|	dpd  }|sqt|	||||< q|S )Nc                 S  sB   g | ]}| d r| d | dp| d | dpddqS )r7   r8   r9   r   )r7   r   r   r   )r   r-  r   r   r   r     s    z._generate_data_capture_llm.<locals>.<listcomp>i a  Extract only the specific value for each field from the conversation transcript.
Use ONLY facts stated in the transcript. Do not invent details.
Return STRICT JSON with key data_capture: an object mapping each field_key to a string value.

Rules:
- Do not copy complete sentences from the transcript.
- Return concise normalized values (1-5 words where possible).
- Use short labels or entities, not narration.
- If information is unavailable, return exactly "Not Mentioned".
- If a yes/no answer can be inferred, return only "Yes" or "No".

Examples:
Transcript: "I will visit your office tomorrow."
Field next_steps -> "Office Visit"

Transcript: "Can you arrange a demo next week?"
Field demo_requested -> "Yes"

FIELDS:
T)r  z

TRANSCRIPT:
z Lead data-capture LLM failed: %sr  r  r  r   data_capturer7   r   )r   r,   r  r.   r  r  r  r  r-   r_   r)   r*   r   rm  )r  r|  rq  field_specsclipped_transcriptr  r  r  r  r  r  raw_captureoutputr-  r7   r   r   r   _generate_data_capture_llm  sT   	



r  F)r  use_llmOptional[List[Dict[str, Any]]]&Optional[Callable[..., Optional[str]]]r  c                C  s   | pt }|si S i }|r|r| rt|||}|D ]/}t|dp#d }	|	s*q||	}
|	|vs7t|
rBt||||d||	< qt|
|||	< q|S )Nr7   r   )rq  rr  r   )DEFAULT_DATA_CAPTURE_FIELDSr   r  r   r_   r9  r{  rm  )r|  rq  rr  r   r  r  active_fieldscapturer-  r7   existingr   r   r   _build_data_capture  s(   	
r  data_capture_fieldsc                 C  sd  |  dpg }t|}ddd |D }dd |D }g }t }	|D ]?}
t|
 dD ]5}| }||	v r7q,|	| |
 d}|d urIt|nd	}|||
 d
pTd|
 dpZd|dkd q,q#|d d }|sx|rxdd |d d D }t	| |}t
| |}g }|r|rt|| ||}t|dk rt| ||}d}|r|d	  dpd}d|v rd}nd|v rd}nt|  dpd	dk rd}t|}t|d d s|rt|g dt|g dt|g dt|g dd }tD ]}t|d | st|| |d |< qt||||||d!}t  d" d#|d d p"d$|||||||d d% d&d'S )(Nr   
c                 s  s"    | ]}t |d pdV  qdS )
transcriptr   N)r   r_   r   rh   r   r   r   r#   E  s     z&build_lead_insights.<locals>.<genexpr>c                 S  s   g | ]}| d r|d  qS )rw   r   )r   ry   r   r   r   r   F  s    z'build_lead_insights.<locals>.<listcomp>r   r   r   r   r   rw   r   )r   r   how_handledr   r   c              	   S  sB   g | ]}| d d  d| dpd d| dpd dqS )	r   Callz call with r   agentz on r   zunknown dater   )r_   r   r  r   r   r   r   ]  s    "r   Positiver   r   r   zNeeds attentionzMixed / neutralr   zNeeds follow-uprm   r2   )r2   pricer   costamount	expensive)decisionapprovalapprovemanagerownerr3   )r4   requirementrI   r$  require)r5   whenrh  monthweeksoonurgentr1   )rq  rr  r   r  r  Zr   z5Insights generated from available lead conversations.r   )previous_summaryr   r  r  )generated_atrw   r   r   r}  path_to_conversion)r_   r   r`  setr   r   addr   r   r   r   r  r   r  r|   rg   r(   rx   ra   r  r   utcnow	isoformat)r   r  r  r  r   rp   rq  	summariesr   seen_objectionsrh   r   rr   r   quality_numr  r   conversion_probabilityr  rr  latest_sentimentaggregated_bantfallbackr}  r   r   r   build_lead_insights=  s   






r  )r	   r   r
   r   )r   r   r   r   r
   r   )r	   r   r
   r   )r]   r   r
   r^   )r]   r^   r
   rb   )rh   ri   r
   ri   )rp   rq   r
   ri   )r}   )r   r   r~   r   r
   r   )r   )r   rq   r
   rq   )r   ri   rp   rq   r
   r   )r   ri   rp   rq   r
   r   )rp   rq   r
   r   )r   r   r
   r   )r   ri   rp   rq   r   rq   r
   r   )
r  r  r   ri   rp   rq   r   rq   r
   r   )r-  ri   r
   r   )r	   r   r
   rb   )r-  ri   r
   rb   )r   r   r
   r   )r"   r   r-  ri   r
   r   )Nr   )
r"   r   r   r   r-  r]  r^  r   r
   r   )r"   r   r9   r   r
   r   r   )r	   r   r-  r]  r
   r   )r   r   r-  ri   r
   r   )
r-  ri   rq  r   rr  r   r   rq   r
   r   )r  r  r|  rq   rq  r   r
   r^   )r|  r  rq  r   rr  r   r   rq   r  r  r  rb   r
   r^   )NFN)
r   ri   r  r  r  rb   r  r  r
   ri   )5__doc__
__future__r   r,   loggingr   r   typingr   r   r   r   r   	getLogger__name__r  r   r(   r0   rx   r  r2  r.  r`   ra   rg   ro   r|   r   r   r   r   r   r   r   r  r  rK  r=  r4  r9  r>  rN  rO  r\  rd  rk  rm  rl  r{  r  r  r  r   r   r   r   <module>   s~    














%

$

 
9




)
!



)M%