o
    GY)j#                     @  s   d Z ddlmZ ddlmZmZ ddlmZmZmZ d4ddZ	d5ddZ
d6ddZd7ddZd8ddZd9ddZd6ddZ	d:ddd;d!d"Zd#d$d<d)d*Z	d:d=d+d,Zddd>d.d/Z	d:ddd?d2d3ZdS )@zOShared minimum call duration checks for ingest, transcribe, and backlog repair.    )annotations)datetime	timedelta)AnyDictOptionalreturnOptional[datetime]c                 C  sr   | d u rd S t | tr| jr| jd dS | S ztt| dd}|jr,|jd dW S |W S  ty8   Y d S w )N)tzinfoZz+00:00)
isinstancer   r
   replacefromisoformatstr	Exception)valueparsed r   </home/aiteam/pcaa-dev/dashboard-backend/min_duration_util.pyparse_datetime	   s   
r   r   r   Optional[int]c              	   C  s.  | du s| dkr
dS t | trtdt|  S t | ttfr&tdt| S t|  }|s0dS d|v r|d}z;dd |D }t	|dkr]tdt|d d |d	 d
  |d  W S t	|dkrstdt|d d
 |d	  W S W n t
tfy   Y nw z
tdtt|W S  t
tfy   Y dS w )z=Parse seconds from int/float, timedelta, or HH:MM:SS strings.N r   :c                 S  s   g | ]}t |qS r   )float).0partr   r   r   
<listcomp>#   s    z(parse_duration_value.<locals>.<listcomp>   i     <      )r   r   maxinttotal_secondsr   r   stripsplitlen	TypeError
ValueError)r   textpartsnumsr   r   r   parse_duration_value   s4   

, r,   callDict[str, Any]c                 C  s   |  dp|  dp|  d}|  dp|  dp|  d}|rD|rDt|}t|}|rD|rDztdt||  W S  tyC   Y nw dD ]}|  |}|d	ura|d
krat|}|d	ura|  S qFdD ]}t|  |}|d	ury|dkry|  S qdd	S )zBest-effort duration from a source row or raw_calls row.

    Wall-clock (call_end - call_start) is preferred over billing fields
    (answeredtime/billsec) so short calls are not inflated at ingest.
    call_starttime	starttime
call_startcall_endtimeendtimecall_endr   duration_secondscall_duration_s
duration_sdurationNr   )answeredtimeanswered_timetalktime	talk_timebillsec)getr   r!   r"   r#   r   r,   )r-   startendstart_dtend_dtkeyrawr   r   r   r   call_duration_seconds0   s0   
rF   min_duration_sr"   boolc                 C  s   t | pddkS )Nr   )r"   )rG   r   r   r   min_duration_configuredP   s   rI   c                 C  s"   t | dp| dp| dS )Nr/   r0   r1   )r   r?   )r-   r   r   r   call_start_datetimeT   s   rJ   c                 C  s<   |du rdS t |}|du rdS t| }|du rdS ||kS )z
    True when the min-duration policy applies to this call.

    Calls that started before ``effective_at`` are grandfathered.
    NFT)r   rJ   )r-   effective_ateffr@   r   r   r   min_duration_applies_to_callZ   s   rM   c                 C  s   g }|  dp|  dp|  d}|  dp|  dp|  d}|rJ|rJt|}t|}|rJ|rJz|tdt||   W n	 tyI   Y nw dD ]}t|  |}|d	ur^|| qLd
D ]}t|  |}|d	urw|dkrw|| qa|s|d	S t|S )z>Shortest reliable metadata estimate (talk time vs wall clock).r/   r0   r1   r2   r3   r4   r   r5   N)r:   r;   r<   r=   r>   pulse)	r?   r   appendr!   r"   r#   r   r,   min)r-   
candidatesr@   rA   rB   rC   rD   r   r   r   r   min_duration_gate_secondsk   s2    

rR   Naudio_duration_srT   Optional[float]c                C  sZ   t |pd}|dkrdS t| |sdS |durt|t|k S t| }|du r)dS ||k S )z
    True when a call should not be ingested or processed.

    When ``audio_duration_s`` is provided (WAV probe), it is the authority.
    Otherwise uses the shortest metadata estimate from ``min_duration_gate_seconds``.
    r   FNT)r"   rM   r   rR   )r-   rG   rK   rT   min_sr9   r   r   r   should_skip_at_ingest   s   
rW   T)probe_audiorecording_urlOptional[str]rX   !tuple[bool, str, Optional[float]]c          
      C  s   t |pd}|dkst| |sdS ddlm}m} t|p"| dp"d }|rN||s.dS ||}	|	du r8dS |	|k rId	d
|	dd| d|	fS dd|	fS t| ||r\d	t	| |dfS dS )z
    Decide whether a call may be ingested/queued.

    Returns ``(should_skip, reason, probed_audio_seconds)``.
    When min duration applies and probing is enabled, the recording URL must
    be probed; unreachable audio blocks ingest (no DB row).
    r   )Fr   N)probe_wav_duration_from_urlrecording_url_probe_readyfileurlr   )Tz*recording URL not ready for duration probeNN)Tz-recording not reachable or not a readable WAVNTactual audio .1fs < min sF)
r"   rM   wav_probe_utilr\   r]   r   r?   r$   rW   skip_reason)
r-   rG   rK   rY   rX   rV   r\   r]   urlprobedr   r   r    evaluate_min_duration_for_ingest   s"   
rg   c                 C  s   t | ||S )z'Alias for ingest/STT min-duration gate.)rW   )r-   rG   rK   r   r   r   is_below_min_duration   s   rh   r   c                C  sZ   |d urdt |ddt| dS t| }|d u r"dt| dS d| dt| dS )Nr_   r`   ra   rb   zduration unknown (min zs required)z	duration )r   r"   rR   )r-   rG   rT   r9   r   r   r   rd      s   rd   bidcallidc                C  s   t ||||ds
dS t|p|dpd }|sdS | d}| d}| d}	| d| d	|f t|  }
| d
|	 d|f t|  }|
sP|r]| d| d|f dS | d| d|f dS )aD  
    Remove or terminal-mark calls below minimum duration.

    Only affects calls on or after ``effective_at``. Unprocessed rows are
    deleted. Rows that already have transcript or analytics are marked
    ``skipped_short`` so they stay out of the dashboard and STT queue.

    Returns True when an action was taken.
    rS   Frj   r   
_raw_calls_sarvamresponse_callanalyticsz
        SELECT 1 FROM `z~`
        WHERE callid = %s
          AND transcript IS NOT NULL
          AND TRIM(transcript) != ''
        LIMIT 1
        zSELECT 1 FROM `z` WHERE callid = %s LIMIT 1z
            UPDATE `z`
            SET transcription_status = 'skipped_short',
                status = -2
            WHERE callid = %s
            TzDELETE FROM `z` WHERE callid = %s)rW   r   r?   r$   executerH   fetchone)cursorri   rj   r-   rG   rK   rT   	raw_tablesarvam_tableanalytics_tablehas_transcripthas_analyticsr   r   r   purge_unprocessed_if_below_min   sF   




	rv   )r   r	   )r   r   r   r   )r-   r.   r   r   )rG   r"   r   rH   )r-   r.   r   r	   )r-   r.   r   rH   )N)r-   r.   rG   r"   rT   rU   r   rH   )
r-   r.   rG   r"   rY   rZ   rX   rH   r   r[   )r-   r.   rG   r"   r   rH   )r-   r.   rG   r"   rT   rU   r   r   )ri   r   rj   r   r-   r.   rG   r"   rT   rU   r   rH   )__doc__
__future__r   r   r   typingr   r   r   r   r,   rF   rI   rJ   rM   rR   rW   rg   rh   rd   rv   r   r   r   r   <module>   s2    



 


! (