o
    +j                     @   s   d Z ddlZddlZddl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 ejejdd	 eeZG d
d dZdd Zdd Zdd Zdd Zedkr]e  dS dS )a  
Re-run sentiment scoring for calls that already have transcripts and analytics.

Uses per-BID sentiment config (keywords, hybrid/llm/keyword mode) without
re-running full quality parameter scoring unless --full-analysis is set.

Usage:
    python reanalyze_sentiment.py --bid 94
    python reanalyze_sentiment.py --bid 94 --limit 50 --delay 0.3
    python reanalyze_sentiment.py --bid 94 --dry-run
    python reanalyze_sentiment.py --bid 94 --full-analysis
    N)Config)DatabaseHandler)CallAnalyzer)resolve_call_sentiment)SentimentConfigHandlerz)%(asctime)s - %(levelname)s - %(message)s)levelformatc                   @   s&   e Zd Zdd ZdddZdd ZdS )	ConfigWrapperc                 C   s
   || _ d S N)_config)selfconfig r   reanalyze_sentiment.py__init__    s   
zConfigWrapper.__init__Nc                 C   s   t | j||S r
   getattrr   )r   keydefaultr   r   r   get#   s   zConfigWrapper.getc                 C   s   t | j|S r
   r   )r   r   r   r   r   __getattr__&   s   zConfigWrapper.__getattr__r
   )__name__
__module____qualname__r   r   r   r   r   r   r   r	      s    
r	   c                 C   sf   d| d| d| d}|   }| }|||f | p!g W  d    S 1 s,w   Y  d S )Nz'
        SELECT r.callid
        FROM `z_raw_calls` r
        JOIN `z8_sarvamresponse` s ON r.callid = s.callid
        JOIN `z_callanalytics` a ON r.callid = a.callid
        WHERE r.call_status = 'ANSWER'
          AND s.transcript IS NOT NULL
          AND s.transcript != ''
        ORDER BY r.call_starttime DESC
        LIMIT %s
    )get_connectioncursorexecutefetchall)
db_handlerbidlimitqueryconnr   r   r   r   fetch_calls*   s   

$r#   c           	   
   C   sZ  g }| pg D ]N}t |}|dsOt|dpd  }d }dD ]}||rAzt|t|d  }W n	 ty>   Y nw  nq"|d urKd| nd|d< |	| qg }|D ]}z|	tt|d 
dd W qY ttfyw   Y qYw |r~t|nd}|D ](}ztt|d 
dd}W n ttfy   d}Y nw ||krd	nd
|d< q|S )N
speaker_idspeaker )speaker_zspeaker r'   unknownr   agentcustomerrole)dictr   strstriplower
startswithintlen
ValueErrorappendreplaceAttributeErrormin)	speaker_segments
normalizedsegspeaker_displayspeaker_numprefixnumsmin_numnr   r   r   normalize_segments<   sB   

"rB   c                 C   sR   d| d}|   }| }||||f W d    d S 1 s"w   Y  d S )NzUPDATE `z4_callanalytics` SET sentiment = %s WHERE callid = %s)r   r   r   )r   r   callid	sentimentr!   r"   r   r   r   r   update_sentiment_only^   s
   
"rE   c                  C   s  t jdd} | jdddd | jdtdd	d
 | jdtddd
 | jdddd | jdddd |  }t|j}tt	 }t
|}t|}|  || t|||j}tdt|| |jr||D ]}t|tro|d n|d }td| qdd S |jrt|nd }	d}
d}|D ]}t|tr|d n|d }z|||}|std| W q|d}|std| W q|dpg }t|trzt|}W n tjtfy   g }Y nw t|}|dp|d}|jr|	j |||||d td| nt!|||d ||d \}}t"|||| td!|||d" |
d#7 }
|j#dkr,t$%|j# W q t&yK } z|d#7 }t'd$|| W Y d }~qd }~ww td%|
| d S )&Nz0Re-analyze customer sentiment for existing calls)descriptionz--bidTzBusiness ID)requiredhelpz--limitd   zMax calls to process)typer   rH   z--delayg        zDelay between calls (seconds)z	--dry-run
store_truezList calls without updating)actionrH   z--full-analysiszORe-run full analyze_call (quality + sentiment) instead of sentiment-only updatez&Found %s call(s) to process for BID %srC   r   z![dry-run] would process callid=%szCall %s not found, skipping.transcriptsz$Call %s has no transcript, skipping.r9   durationduration_seconds)actual_durationz'Full re-analysis complete for callid=%s)llm_sentimentr   handlerz'Updated sentiment=%s for callid=%s (%s)method   zFailed callid=%s: %szDone. updated=%s errors=%s)(argparseArgumentParseradd_argumentr2   float
parse_argsr.   r   r	   r   r   r   ensure_tableseed_defaults_if_emptyr#   r    loggerinfor3   dry_run
isinstancer-   full_analysisr   get_raw_call_detailswarningr   jsonloadsJSONDecodeError	TypeErrorrB   analyze_callr   rE   delaytimesleep	Exceptionerror)parserargsr   cfgr   sentiment_handlercallidsrowrC   analyzerupdatederrors	call_data
transcriptraw_segmentsr9   rP   labeldetailsexcr   r   r   maine   s   






r|   __main__)__doc__rU   rc   loggingri   r   r   r   r   analyze_calls_with_parametersr   sentiment_scoringr   sentiment_config_handlerr   basicConfigINFO	getLoggerr   r\   r	   r#   rB   rE   r|   r   r   r   r   <module>   s.    
"R
