o
    ZhH                     @   s  d Z ddlZddlZddl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mZm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 dd
lmZ ddlmZ dedefddZdedefddZdd ZdedefddZdedefddZ de!ee"f fddZ#defdd Z$d!d" Z%d#efd$d%Z&G d&d' d'eZ'G d(d) d)eZ(G d*d+ d+eZ)G d,d- d-eZ*G d.d/ d/eZ+dS )0zReplay API client.    N)AnyLiteralOptionalUnion)	HTTPError   )errors)BaseApiClient)HttpOptions)HttpRequest)HttpResponse)	BaseModelversion_stringreturnc                 C      t dd| S )z8Redacts version numbers in the form x.y.z from a string.z\d+\.\d+\.\d+z{VERSION_NUMBER}resub)r    r   V/var/www/html/lang_env/lib/python3.10/site-packages/google/genai/_replay_api_client.py_redact_version_numbers'      r   language_labelc                 C   r   )z;Removed because replay requests are used for all languages.z
gl-python/z{LANGUAGE_LABEL}/r   )r   r   r   r   _redact_language_label,   r   r   c                 C   s   i }|   D ]?\}}| dkrd||< q| dkr$tt|||< q| dkr3tt|||< q| dkr:q| dkrAq|||< q|S )z,Redacts headers that should not be recorded.zx-goog-api-keyz
{REDACTED}z
user-agentzx-goog-api-clientzx-goog-user-projectauthorization)itemslowerr   r   )headersZredacted_headersheader_nameheader_valuer   r   r   _redact_request_headers1   s$   



r    urlc                 C   s<   t dd| }t dd|}t dd|}t dd|}|S )Nz".*/projects/[^/]+/locations/[^/]+/z{VERTEX_URL_PREFIX}/z#.*-aiplatform.googleapis.com/[^/]+/z".*aiplatform.googleapis.com/[^/]+/z/https://generativelanguage.googleapis.com/[^/]+z{MLDEV_URL_PREFIX}r   )r!   resultr   r   r   _redact_request_urlH   s*   r#   pathc                 C   s&   d| v rd| v rt dd| }|S | S )Nz	projects/z
locations/zprojects/[^/]+/locations/[^/]+/z{PROJECT_AND_LOCATION_PATH}/r   )r$   r"   r   r   r   _redact_project_location_pathb   s   r%   bodyc                 C   s,   |   D ]\}}t|trt|| |< qdS )z,Redacts fields in the request body in place.N)r   
isinstancestrr%   )r&   keyvaluer   r   r   _redact_request_bodyp   s
   
r+   http_requestc                 C   s&   t | j| _t| j| _t| j d S N)r    r   r#   r!   r+   data)r,   r   r   r   redact_http_requestw   s   r/   c                  C   s,   t  jj} t | }| j}d| d| S )z-Prints the current file path and line number.zFile: z, Line: )inspectcurrentframef_backgetfilef_lineno)framefilepathlinenor   r   r   _current_file_path_and_line}   s   
r8   messagec                 C   s    t dtjddt d|  d S )NzDEBUG (testZPYTEST_CURRENT_TEST)z:
    )printosenvirongetr8   )r9   r   r   r   _debug_print   s   
r?   c                   @   sF   e Zd ZU dZeed< eed< eeef ed< eeeef  ed< dS )ReplayRequestz(Represents a single request in a replay.methodr!   r   body_segmentsN)	__name__
__module____qualname____doc__r(   __annotations__dictlistobjectr   r   r   r   r@      s   
 r@   c                   @   s|   e Zd ZU dZdZeed< eeef ed< e	eee
f  ed< dZee	e  ed< e	eee
f  ed< d	ed
dfddZdS )ReplayResponsez)Represents a single response in a replay.   status_coder   rB   Nbyte_segmentssdk_response_segments_ReplayResponse__contextr   c                 C   s    | j dd  | j dd  d S )NDatezServer-Timing)r   pop)selfrP   r   r   r   model_post_init   s   zReplayResponse.model_post_init)rC   rD   rE   rF   rM   intrG   rH   r(   rI   rJ   rN   r   bytesr   rT   r   r   r   r   rK      s   
 rK   c                   @   s"   e Zd ZU dZeed< eed< dS )ReplayInteractionzBRepresents a single interaction, request and response in a replay.requestresponseN)rC   rD   rE   rF   r@   rG   rK   r   r   r   r   rW      s   
 rW   c                   @   s&   e Zd ZU dZeed< ee ed< dS )
ReplayFilezRepresents a recorded session.	replay_idinteractionsN)rC   rD   rE   rF   r(   rG   rI   rW   r   r   r   r   rZ      s   
 rZ   c                       s  e Zd ZdZ							d>ded dedee ded	ee d
eej	j
j dee dee dee f fddZdefddZdd Zdd Zdd Zdd Zdd Zdd Zdd Zd ed!eeejef fd"d#Zd ed$efd%d&Zd efd'd(Zd)e fd*d+Z!	d?d ed,ed-ef fd.d/Z"	d?d ed,ed-ef fd0d1Z#d2eee$j%f d3ed4e&f fd5d6Z'd2eee$j%f d3ed4e&d-ef fd7d8Z(d9edef fd:d;Z)d9ef fd<d=Z*  Z+S )@ReplayApiClientzFFor integration testing, send recorded response or records a response.NFmode)recordreplayautoapir[   replays_directoryvertexaiapi_keycredentialsprojectlocationhttp_optionsc
           
         sJ   t  j||||||	d || _| jstjdd | _d | _|| _|| _d S )N)rd   re   rf   rg   rh   ri   ZGOOGLE_GENAI_REPLAYS_DIRECTORY)	super__init__rc   r<   r=   r>   replay_session_mode
_replay_id)
rS   r^   r[   rc   rd   re   rf   rg   rh   ri   	__class__r   r   rk      s    
zReplayApiClient.__init__c                 C   s   || _ |   d S r-   )rn   _initialize_replay_session)rS   r[   r   r   r   initialize_replay_session   s   z)ReplayApiClient.initialize_replay_sessionc                 C   s   |  | j| jS r-   )"_generate_file_path_from_replay_idrc   rn   rS   r   r   r   _get_replay_file_path   s   z%ReplayApiClient._get_replay_file_pathc                 C   s&   | j dv p| j dkotj|   S )N)r_   rb   ra   )rm   r<   r$   isfileru   rt   r   r   r   _should_call_api   s   

z ReplayApiClient._should_call_apic                 C   s   |   o| jdkS )Nrb   )rw   rm   rt   r   r   r   _should_update_replay   s   z%ReplayApiClient._should_update_replayc                 C   s   | j s	|   d S d S r-   )rl   rq   rt   r   r   r   (_initialize_replay_session_if_not_loaded   s   z8ReplayApiClient._initialize_replay_session_if_not_loadedc                 C   s   t d| j  d| _d| _|  }tj|}| jdkr%|s%t	d| j | jdv rL|rLt
|d}tt| | _W d    n1 sGw   Y  |  rZt| jg d| _d S d S )NzTest is using replay id: r   r`   z)Replay files do not exist for replay id: )r`   ra   r)r[   r\   )r?   rn   _replay_index_sdk_response_indexru   r<   r$   rv   rm   
ValueErroropenrZ   Zmodel_validatejsonloadsreadrl   rx   )rS   replay_file_pathZreplay_file_existsfr   r   r   rq      s$   z*ReplayApiClient._initialize_replay_sessionc                 C   sR   | d}t|dk rt| d|d u rg }n|g}|| tjj| d S )N/   zD: Session ID must be in the format of module/function/[vertex|mldev]z.json)splitlenr}   extendr<   r$   join)rS   Zreplay_directoryr[   Zsession_parts
path_partsr   r   r   rs     s   

z2ReplayApiClient._generate_file_path_from_replay_idc                 C   sz   |   r| js	d S |  }tjtj|dd t|d}|| jj	ddd W d    n1 s3w   Y  d | _d S )NT)exist_okw   )Zexclude_unsetindent)
rx   rl   ru   r<   makedirsr$   dirnamer~   writeZmodel_dump_json)rS   r   r   r   r   r   close  s   
zReplayApiClient.closer,   http_responsec                 C   s   |   sd S t| t|j|j|j|jgd}t|tr5t	t
|jt| dd | D |jg d}n0t|tjrLt	t
|jj| g|jg d}nt|tr[t	i g |gg d}n
tdtt| | jjt||d d S )	N)rA   r!   r   rB   c                 S   s   g | ]
}|d d d qS )Nd   s   ...r   ).0segr   r   r   
<listcomp>,  s    z7ReplayApiClient._record_interaction.<locals>.<listcomp>)r   rB   rN   rM   rO   )r   rB   rM   rO   )r   rB   rN   rO   z Unsupported http_response type: )rX   rY   )rx   r/   r@   rA   r!   r   r.   r'   r   rK   rH   rI   segmentsrN   rM   r   APIErrorrY   Z_to_replay_recordcoderV   r}   r(   typerl   r\   appendrW   )rS   r,   r   rX   rY   r   r   r   _record_interaction  sN   

	


z#ReplayApiClient._record_interactioninteractionc                 C   s   |j |jj ks	J |j|jjksJ d|j d|jj |j|jjks&J t|j}t| |g}|jj}||ksEJ d| d| d S )Nz"Request headers mismatch:
Actual: 
Expected: zRequest body mismatch:
Actual: )	r!   rX   r   rA   copydeepcopyr.   r+   rB   )rS   r,   r   Zrequest_data_copyZactual_request_bodyZexpected_request_bodyr   r   r   _match_requestH  s(   
zReplayApiClient._match_requestc                 C   sh   t | | jj| j }| || |  jd7  _d| _tj|j	 t
|j	jdd |j	jD |j	jdS )Nr   r   c                 S   s   g | ]}t |qS r   )r   dumps)r   segmentr   r   r   r   n  s    z?ReplayApiClient._build_response_from_replay.<locals>.<listcomp>)r   Zresponse_streambyte_stream)r/   rl   r\   r{   r   r|   r   r   Zraise_for_responserY   r   r   rB   rN   )rS   r,   r   r   r   r   _build_response_from_replayc  s   z+ReplayApiClient._build_response_from_replayresponse_modelc                 C   s   | j dkrd S | jj| jd  }|  r8t|tr|d }|r+d|jv r+|j	dd  |j
j|jdd d S t|trA|d }td|jdd |jdd	d
}|j
j| j }||ksfJ d| d| |  jd7  _d S )Nrb   r   r   http_headersrQ   T)exclude_nonezresponse_model: r   )r   r^   zSDK response mismatch:
Actual: r   )rm   rl   r\   r{   rx   r'   rI   Zmodel_fieldsr   rR   rY   rO   r   Z
model_dumpr;   r|   )rS   r   r   actualexpectedr   r   r   _verify_responseu  s.   




z ReplayApiClient._verify_responsestreamr   c              
      s   |    |  r\td|  z	t ||}W n tjy, } z| || |d }~ww |rMg }| D ]
}|	t
| q5t|j|}| || n| || td|j
  |S | |S Nzapi mode request: %szapi mode result: %s)ry   rw   r?   rj   _requestr   r   r   r   r   r   r   r   r   r   rS   r,   r   r"   eresult_segmentsr   ro   r   r   r     s(   
zReplayApiClient._requestc              
      s   |    |  retd|  zt ||I d H }W n tjy0 } z| || |d }~ww |rVg }| 2 z3 d H W }|	t
| q96 t|j|}| || n| || td|j
  |S | |S r   )ry   rw   r?   rj   _async_requestr   r   r   Zasync_segmentsr   r   r   r   r   r   r   ro   r   r   r     s,   
zReplayApiClient._async_request	file_path
upload_urlupload_sizec           	   
      s   t |tjr&| }| }||tj tdddt	
|dii d}n
tddd|ii d}|  rpz
t |||}W n" ty` } zt|jjtd|jjig}|jj|_|d }~ww | |ti t|g |S | |jS NPOST rV   zutf-8)rA   r!   r.   r   r   reason)r'   ioIOBasetellr   seekr<   SEEK_SETr   base64	b64encodedecoderw   rj   upload_filer   r   rY   r   r   r   r   rM   r   r   	rS   r   r   r   offsetcontentrX   r"   r   ro   r   r   r     s6   
zReplayApiClient.upload_filec           	   
      s   t |tjr'| }| }||tj tdddt	
|dii d}n
tddd|ii d}|  rtzt |||I d H }W n" tyd } zt|jjtd|jjig}|jj|_|d }~ww | |ti t|g |S | |jS r   )r'   r   r   r   r   r   r<   r   r   r   r   r   rw   rj   async_upload_filer   r   rY   r   r   r   r   rM   r   r   r   ro   r   r   r     s<   
z!ReplayApiClient.async_upload_filer$   c              
      s   |    | jd|i |d}|  rEz	t ||}W n" ty< } zt|jjt	
d|jjig}|jj|_|d }~ww | || |S | |jd S Nr>   )r$   Zrequest_dictri   r   r   )ry   _build_requestrw   rj   download_filer   r   rY   r   r   r   r   rM   r   r   r   rS   r$   ri   rX   r"   r   ro   r   r   r     s$   
zReplayApiClient.download_filec              
      s   |    | jd|i |d}|  rIzt ||I d H }W n" ty@ } zt|jjt	
d|jjig}|jj|_|d }~ww | || |S | |jd S r   )ry   r   rw   rj   async_download_filer   r   rY   r   r   r   r   rM   r   r   r   r   ro   r   r   r     s&   
z#ReplayApiClient.async_download_file)NFNNNNN)F),rC   rD   rE   rF   r   r(   r   boolgoogleauthrf   Credentialsr
   rk   rr   ru   rw   rx   ry   rq   rs   r   r   r   r   r   r   rV   r   rW   r   r   r   r   r   r   r   r   rU   r   r   r   r   __classcell__r   r   ro   r   r]      s    	
	
.
$%r]   ),rF   r   r   datetimer0   r   r   r<   r   typingr   r   r   r   Zgoogle.authr   Zrequests.exceptionsr   r   r   Z_api_clientr	   r
   r   r   _commonr   r(   r   r   r    r#   r%   rH   rJ   r+   r/   r8   r?   r@   rK   rW   rZ   r]   r   r   r   r   <module>   s@   	