o
    lQi+                  	   @  s   d Z ddlmZ ddlZddlZddlZddlZddlZddlm	Z	m
Z
 ddlZddlmZmZmZmZmZ ddlmZmZmZmZ dd	lmZmZmZmZ eeZd
ZdddddddddZ dd Z!G dd deZ"dS )z
AI Studio provider (PRIMARY): raw httpx.AsyncClient for true async concurrency.
Hits Gemini REST API directly. 429 handling with exponential backoff.
Cache verification via usage_metadata.cached_content_token_count.
    )annotationsN)AnyOptional   )BaseProviderTranscriptionRequestTranscriptionResponse
TokenUsageRequestStatus   )GEMINI_MODELTEMPERATURETHINKING_LEVELMAX_RETRIES_429)build_system_promptget_user_promptget_json_schemabuild_user_promptz0https://generativelanguage.googleapis.com/v1beta)requestssuccesshttp_429http_500
http_othertimeoutserrorsretriesc                  C  sb   t } td| d  d| d  d| d  d| d  d	| d
  d| d  d| d  d| d   d S )Nz[GEMINI-STATS] sent=r   z ok=r   z 429=r   z 500=r   z other_http=r   z
 timeouts=r   z errors=r   z	 retries=r   )
_api_statsloggerinfo)s r    2/home/ubuntu/transcripts/src/providers/aistudio.pylog_api_stats&   s    r"   c                   @  sp   e Zd Z		d0d1d	d
Zd2ddZd3ddZd4ddZ	d5d6ddZd7d%d&Zd8d)d*Z	d9d,d-Z
d:d.d/ZdS );AIStudioProviderFNapi_keystr	mock_modeboolcached_content_nameOptional[str]c                 C  s   || _ || _|| _t | _d S N)r$   r&   r(   r   _schema)selfr$   r&   r(   r    r    r!   __init__1   s   zAIStudioProvider.__init__returnc                 C  s   dS )Naistudior    r,   r    r    r!   get_provider_name8   s   z"AIStudioProvider.get_provider_namer   list[TranscriptionRequest]list[TranscriptionResponse]c              	     s   j rfdd|D S tt|tjddddd}tjt|dd}tj||d	4 I d H   fd
d|D }tj| I d H W  d   I d H  S 1 I d H sUw   Y  d S )Nc                   s   g | ]}  |qS r    )_mock_response.0reqr0   r    r!   
<listcomp>=   s    z/AIStudioProvider.send_batch.<locals>.<listcomp>g      $@g      4@g      >@)connectreadwritepoold   )max_connectionsmax_keepalive_connections)timeoutlimitsc                   s   g | ]	} | qS r    )_send_singler5   clientr,   	semaphorer    r!   r8   D   s    )	r&   asyncio	SemaphorelenhttpxTimeoutLimitsAsyncClientgather)r,   r   r@   rA   tasksr    rC   r!   
send_batch;   s   0zAIStudioProvider.send_batchr7   r   rD   httpx.AsyncClientrE   asyncio.Semaphorer   c                   s  |4 I d H  t td D ]}td  d7  < zt }|dkr&dnd }| j|||dI d H }t | d }|jdkrtd  d7  < |tk rvtd	  d7  < d
d|  }	td|j	 d|d  d|	 d t
|	I d H  W qt|j	tjdt ddW   W  d   I d H  S |jdkrtd  d7  < |jdkr|jd d }
|jdk rtd  d7  < d|
v s|jdkr|tk rtd	  d7  < d
d|  }	td|j d|j	 d|d  d|	 d	 t
|	I d H  W qt|j	tjd|j d|
 |dW   W  d   I d H  S td  d7  < | }| |j	||W   W  d   I d H  S  tjy } zRtd  d7  < |dk r_td	  d7  < td|j	 d W Y d }~qtd |j	 d! t|j	tjd"|d  d#| dW  Y d }~  W  d   I d H  S d }~w ty } z1td$  d7  < td%|j	 d|  t|j	tjt|dW  Y d }~  W  d   I d H  S d }~ww W d   I d H  n1 I d H sw   Y  t|j	tjd&dS )'Nr   r   r   MINIMAL)thinking_overridei  i  r   r   
   r   z429 on z, retry  in r   z
429 after z retries)
segment_idstatuserror_messagei  r      r   RESOURCE_EXHAUSTEDzHTTP z on z: rV   rW   rX   
latency_msr   r   zTimeout on z , retrying with thinking=MINIMALzDiscarding z+: timed out twice (bad sample / model hang)zDiscarded: timed out after z attempts: r   z
Error for zExhausted retries)ranger   r   time	monotonic	_call_apistatus_coder   warningrV   rF   sleepr   r
   RATE_LIMITEDtextERRORjson_parse_responserI   TimeoutExceptionerrorTIMEOUT	Exceptionr%   )r,   r7   rD   rE   attemptstartrS   resplatencywait
error_bodydataer    r    r!   rB   G   s   
$



,
*.
::*CzAIStudioProvider._send_singlerS   httpx.Responsec                   s   t  dt d| j }| jrt|j}nt }|pt }dd|j	|j
did|igdgtd| jd	|id
d}| jrC| j|d< nddt|jigi|d< |j||dI d H S )Nz/models/z:generateContent?key=user
inlineData)mimeTypers   re   )rolepartszapplication/jsonthinkingLevel)temperatureresponseMimeTyperesponseJsonSchemathinkingConfig)contentsgenerationConfigcachedContentrz   systemInstruction)rg   )AISTUDIO_BASEr   r$   r(   r   language_coder   r   upper	mime_typeaudio_base64r   r+   r   post)r,   r7   rD   rS   urluser_promptthinking_levelbodyr    r    r!   r`      s8   zAIStudioProvider._call_apirV   rs   dictrp   floatc              
   C  s  zd| dg }|st|tjdt|d d  |dW S |d  di  dg }d}|D ]}d	|v r9|d	 } nq-z|rBt|ni }W n tjyS   d
|i}Y nw | |}	t|tj	||	||dW S  t
y }
 zt|tjd|
 |dW  Y d }
~
S d }
~
ww )N
candidateszNo candidates in response: ,  r[   r   contentrz    re   raw_text)rV   rW   transcription_datatoken_usager\   raw_responsezParse error: )getr   r
   rf   rg   dumpsloadsJSONDecodeErrorget_token_usageSUCCESSrl   )r,   rV   rs   rp   r   rz   re   partparsedr   rt   r    r    r!   rh      sN   
z AIStudioProvider._parse_responseresponser   c                 C  s8   z| di }| dd}|dkW S  ty   Y dS w )NusageMetadatacachedContentTokenCountr   F)r   rl   )r,   r   usagecachedr    r    r!   verify_cache_hit   s   
z!AIStudioProvider.verify_cache_hitr	   c                 C  sf   z&| di }| dd}| dd}| dd}t||||| |dkdW S  ty2   t  Y S w )Nr   promptTokenCountr   candidatesTokenCountr   input_tokensoutput_tokenscached_tokenstotal_tokens	cache_hit)r   r	   rl   )r,   r   r   r   r   r   r    r    r!   r      s   
z AIStudioProvider.get_token_usagec                 C  s`   |j }d|j d| d|j d| ddddd|j d	}t|jtj|td
dddddddS )Nz [MOCK] Sample transcription for rU   z([MOCK] [noise] Sample transcription for neutralconversationalnormalr   )emotionspeaking_stylepaceaccent)transcriptiontaggedspeakerdetected_languager      rY   i  Tr   g      I@)rV   rW   r   r   r\   )r   original_filer   rV   r
   r   r	   )r,   r7   	lang_name	mock_datar    r    r!   r4     s(   zAIStudioProvider._mock_response)FN)r$   r%   r&   r'   r(   r)   )r.   r%   )r   r2   r.   r3   )r7   r   rD   rP   rE   rQ   r.   r   r*   )r7   r   rD   rP   rS   r)   r.   ru   )rV   r%   rs   r   rp   r   r.   r   )r   r   r.   r'   )r   r   r.   r	   )r7   r   r.   r   )__name__
__module____qualname__r-   r1   rO   rB   r`   rh   r   r   r4   r    r    r    r!   r#   /   s    


N
.
*
r#   )#__doc__
__future__r   rF   base64rg   loggingr^   typingr   r   rI   baser   r   r   r	   r
   configr   r   r   r   prompt_builderr   r   r   r   	getLoggerr   r   r   r   r"   r#   r    r    r    r!   <module>   s(    
	