o
    @boj'                     @  sz   d Z ddlmZ ddlmZmZ ddlmZmZ ddlm	Z	m
Z
 ddd	Ze
d
 ZeG dd dZeG dd dZdS )u?   Objeto en memoria CallSession: métricas de una llamada activa.    )annotations)	dataclassfield)datetimetimezone)AnyLiteralreturnr   c                   C  s   t tjS N)r   nowr   utc r   r   >/var/www/html/bot-asterisk-ari/backend/call_metrics/session.pyutc_now
   s   r   )userbotc                   @  sN   e Zd ZU dZded< ded< ded< ded< eed	Zd
ed< dddZdS )
TurnTimingu5   Duración de una intervención del usuario o del bot.TurnRoleroleintduration_msr   
started_atended_atdefault_factorydict[str, Any]metar	   c                 C  s4   | j | j| j | j d| jrd| jiS i S )Nr   r   r   r   r   )r   r   r   	isoformatr   r   selfr   r   r   to_dict   s   zTurnTiming.to_dictN)r	   r   )	__name__
__module____qualname____doc____annotations__r   dictr   r!   r   r   r   r   r      s   
 r   c                   @  s  e Zd ZU dZded< eedZded< dZded	< dZ	ded
< dZ
ded< dZded< dZded< dZded< dZded< dZded< dZded< dZded< dZded< dZded< dZded< dZded< dZded< dZded< dZded< dZded< dZded < dZded!< dZded"< dZded#< dZded$< eedZ d%ed&< dZ!ded'< dZ"ded(< dZ#ded)< dZ$ded*< d+Z%d,ed-< dZ&ded.< e'dld1d2Z(e'dmd4d5Z)e'dld6d7Z*e'dld8d9Z+e'dld:d;Z,e'dld<d=Z-e'dld>d?Z.dndodBdCZ/dndodDdEZ0ddddFdpdKdLZ1dddMdqdNdOZ2ddPdrdSdTZ3dddUdsdXdYZ4dddZdtd]d^Z5dud`daZ6dvdbdcZ7ddddwdfdgZ8dxdjdkZ9dS )yCallSessionu   Métricas acumuladas en memoria durante una llamada.

    Se crea al iniciar la llamada y se persiste una sola vez al finalizar
    (ChannelDestroyed / StasisEnd / hangup).
    strcall_idr   r   
start_timeNdatetime | Noneanswer_timefirst_bot_audio_timeend_timez
str | Nonedocument_idnumber	directionr   r   
user_turns	bot_turnsstt_requestsllm_requeststts_requeststotal_prompt_tokenstotal_completion_tokens        floatstt_audio_secondstts_characters_llm_latency_sum_ms_tts_latency_sum_ms_stt_latency_sum_ms_response_latency_sum_ms_response_latency_countinterruptionssilence_secondsdisconnect_reasonzlist[TurnTiming]turn_timingsstt_providertts_providerllm_provider	llm_modelFbool
_persisted_pending_user_ready_atr	   float | Nonec                 C  s    | j sd S td| j | j  S )Nr:   )r/   maxr+   total_secondsr   r   r   r   duration_seconds[   s   zCallSession.duration_seconds
int | Nonec                 C  s2   | j sdS | jp
| j}tdt| j |  d S )z<Ms desde answer (o start) hasta el primer audio TTS del bot.Nr   i  )r.   r-   r+   rO   r   rP   )r    baser   r   r   time_to_first_audio_msa   s   z"CallSession.time_to_first_audio_msc                 C     | j dkrd S | j| j  S Nr   )r6   r>   r   r   r   r   avg_llm_latency_msi      
zCallSession.avg_llm_latency_msc                 C  rU   rV   )r7   r?   r   r   r   r   avg_tts_latency_mso   rX   zCallSession.avg_tts_latency_msc                 C  rU   rV   )r5   r@   r   r   r   r   avg_stt_latency_msu   rX   zCallSession.avg_stt_latency_msc                 C  s   | j dkrdS | j| j  S )uH   Latencia promedio STT-listo → audio TTS listo (cuello de botella e2e).r   N)rB   rA   r   r   r   r   avg_response_latency_ms{   s   
z#CallSession.avg_response_latency_msc                 C  s4   | j }|d u s|dkrd S tdtd| j| d S )Nr   g      Y@r:   )rQ   minrO   rD   )r    durr   r   r   silence_percent   s   zCallSession.silence_percentwhenNonec                 C     | j d u r|p	t | _ d S d S r
   )r-   r   r    r_   r   r   r   mark_answered      
zCallSession.mark_answeredc                 C  ra   r
   )r.   r   rb   r   r   r   mark_first_bot_audio   rd   z CallSession.mark_first_bot_audio)r   r   
silence_msr   r   r   rf   c                C  s   |pt  }|p|dkr|ntj| |d  tjd}|  jd7  _|dkr/|  j|d 7  _| j	t
dtd|||d || _d S )Nr        @@tz   r   r   )r   r   fromtimestamp	timestampr   r   r3   rD   rF   appendr   rO   rM   )r    r   r   r   rf   endstartr   r   r   record_user_turn   s(   

zCallSession.record_user_turn)r   r   c                C  sf   |pt  }|p|dkr|ntj| |d  tjd}|  jd7  _| jt	dt
d|||d d S )Nr   rg   rh   rj   r   r   )r   r   rk   rl   r   r   r4   rF   rm   r   rO   )r    r   r   r   rn   ro   r   r   r   record_bot_turn   s"   
zCallSession.record_bot_turn)audio_seconds
latency_msrr   c                C  s@   |  j d7  _ |  jtd|7  _|dkr|  j|7  _d S d S Nrj   r:   r   )r5   r@   rO   r<   )r    rs   rr   r   r   r   
record_stt   s
   zCallSession.record_stt)prompt_tokenscompletion_tokensrv   rw   c                C  sN   |  j d7  _ |  jtd|7  _|  jtd|7  _|  jtd|7  _d S rt   )r6   r>   rO   r8   r9   )r    rs   rv   rw   r   r   r   
record_llm   s   zCallSession.record_llm)
charactersaudio_ready_atry   rz   c                C  s   |  j d7  _ |  jtd|7  _|dkr|  j|7  _|p t }| | | jd urK|| j  d }|dkrF|  j|7  _|  j	d7  _	d | _d S d S )Nrj   r:   r   rg   )
r7   r?   rO   r=   r   re   rM   rP   rA   rB   )r    rs   ry   rz   readye2e_msr   r   r   
record_tts   s   



zCallSession.record_ttssecondsc                 C  s   |dkr|  j |7  _ d S d S rV   )rD   )r    r~   r   r   r   add_silence_seconds   s   zCallSession.add_silence_secondsc                 C  s   |  j d7  _ d S )Nrj   )rC   r   r   r   r   record_interruption   s   zCallSession.record_interruption)r_   reasonc                C  s2   | j d u r|p	t | _ |r| js|| _d S d S d S r
   )r/   r   rE   )r    r   r_   r   r   r   finalize   s
   


zCallSession.finalizeestimated_costr   c                 C  sT  i d| j d| jd| jd| jd| jd| jd| jd| jd	| jd
| j	d| j
d| jd| jd| jd| jd| jd| jt| jd| jt|d| jdur[t| jdnd| jdurgt| jdnd| jdurst| jdnd| jdurt| jdnd| jt| jd| jdurt| jdnd| jdd | jD | j| j| j| j ddS )zDict listo para INSERT MySQL.r*   r0   r1   r2   r+   r-   r.   r/   rQ   rT   r3   r4   r5   r6   r7   r8   r9         N   c                 S  s   g | ]}|  qS r   )r!   ).0tr   r   r   
<listcomp>2  s    z&CallSession.to_row.<locals>.<listcomp>)sttttsllmrJ   )r<   r=   r   rW   rY   rZ   r[   rC   rD   r^   rE   turn_timings_jsonproviders_json)!r*   r0   r1   r2   r+   r-   r.   r/   rQ   rT   r3   r4   r5   r6   r7   r8   r9   roundr<   r=   rW   rY   rZ   r[   rC   rD   r^   rE   rF   rG   rH   rI   rJ   )r    r   r   r   r   to_row   s~   	







zCallSession.to_row)r	   rN   )r	   rR   r
   )r_   r,   r	   r`   )
r   r   r   r,   r   r,   rf   r   r	   r`   )r   r   r   r,   r   r,   r	   r`   )rs   r;   rr   r;   r	   r`   )rs   r;   rv   r   rw   r   r	   r`   )rs   r;   ry   r   rz   r,   r	   r`   )r~   r;   r	   r`   )r	   r`   )r   r)   r_   r,   r	   r`   )r   r;   r	   r   ):r"   r#   r$   r%   r&   r   r   r+   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   listrF   rG   rH   rI   rJ   rL   rM   propertyrQ   rT   rW   rY   rZ   r[   r^   rc   re   rp   rq   ru   rx   r}   r   r   r   r   r   r   r   r   r(   %   s   
 !

r(   N)r	   r   )r%   
__future__r   dataclassesr   r   r   r   typingr   r   r   r   r   r(   r   r   r   r   <module>   s    
