o
    i
W                     @   sv  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 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ZG d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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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#G d.d/ d/e"Z$G d0d1 d1eZ%G d2d3 d3e%Z&G d4d5 d5e%Z'G d6d7 d7e%Z(G d8d9 d9eZ)G d:d; d;e)Z*G d<d= d=e)Z+G d>d? d?eZ,G d@dA dAeZ-G dBdC dCe-Z.G dDdE dEe-Z/G dFdG dGeZ0G dHdI dIe0Z1dJS )K    )VERSION)OpenAIAsyncStreamHandler)OpenAIStreamHandler)_is_async_generator)_is_generator)_loop_handler)_process_finished_stream)parse_version)OAI_HANDOFF_TOOL_ARG)make_traced_stream)	_get_attr)safe_load_jsonv1c                   @   sD   e Zd ZdZdZdZdZdZdZdZ	dZ
dd Zdd	 Zd
d ZdS )_EndpointHooka  
    Base class for all OpenAI endpoint hooks.
    Each new endpoint hook should declare `_request_arg_params` and `_request_kwarg_params`,
    which will be tagged automatically by _EndpointHook._record_request().
    For endpoint-specific request/response parameters that requires special casing, add that logic to
    the endpoint hook's `_record_request()` after a super call to the base `_EndpointHook._record_request()`.
     )api_baseapi_typeapi_versionopenai c                 C   s8  | j }|du rdt|dd }|ddt|f  |d| j | jrXt| jdkrXt| jD ](\}}	|t|kr; n|	du sE|| du rFq/|	| jv rW|d	|	 t	||  q/| j
D ]>}
|
|vrbq[t||
 tr||
  D ]\}}|d
|
|f t	| qoq[|
dks|
dkr||
 dur|dt	||
  q[dS )z
        Set base-level openai tags, as well as request params from args and kwargs.
        All inherited EndpointHook classes should include a super call to this method before performing
        endpoint-specific request tagging logic.
        Nz%sOBJECT_NAMEr   openai.request.endpointz/%s/%szopenai.request.method   z	openai.%szopenai.request.%s.%senginemodelopenai.request.model)ENDPOINT_NAMEgetattr_set_tag_strAPI_VERSIONHTTP_METHOD_TYPE_request_arg_paramslen	enumerate_base_level_tag_argsstr_request_kwarg_params
isinstancedictitems)selfpinintegrationinstancespanargskwargsendpointidxargkw_attrkvr   r   c/home/ubuntu/.local/lib/python3.10/site-packages/ddtrace/contrib/internal/openai/_endpoint_hooks.py_record_request*   s:   

z_EndpointHook._record_requestc           	   	   c   s^    |  |||||| d V \}}t|dr$| |||||| | |S | |||||||S )Nparse)r8   hasattr_record_responser9   )	r*   r+   r,   r-   r.   r/   r0   resperrorr   r   r7   handle_requestJ   s   

z_EndpointHook.handle_requestc           	   	   C   s6   | j D ]}t||r|d| tt||d q|S )Nzopenai.response.%sr   )_response_attrsr:   r   r%   r   )	r*   r+   r,   r.   r/   r0   r<   r=   	resp_attrr   r   r7   r;   T   s
   

z_EndpointHook._record_responseN)__name__
__module____qualname____doc__r!   r&   r?   r$   r   r    OPERATION_IDr8   r>   r;   r   r   r   r7   r      s    
 
r   c                   @   s   e Zd ZdddZdS )_BaseCompletionHookr   c              	      s   t tdkr&trtt ddS tr&tt ddS  fddtr@fdd}| S trQfdd}| S S )	zHandle streamed response objects returned from completions/chat/response endpoint calls.

        This method returns a wrapped version of the OpenAIStream/OpenAIAsyncStream objects
        to trace the response while it is read by the user.
        )r      r   Noperation_typec                  3   s4    zd V } t  | d W   d S   w )NrH   )r   finish)streamed_chunks)r,   r0   rI   r.   r   r7   
shared_genm   s
   zA_BaseCompletionHook._handle_streamed_response.<locals>.shared_genc                    s    } |  d   ddpd}dkr- dd}t|tr-t|d ts-|t|9 }dd t|D }z'2 z3 d H W }t|| |V  q96 W z|  | W d S  ty]   Y d S w z|  | W w  tyn   Y w w )	Nnr   
completionpromptr   r   c                 S      g | ]}g qS r   r   .0_r   r   r7   
<listcomp>~       c_BaseCompletionHook._handle_streamed_response.<locals>.traced_streamed_response.<locals>.<listcomp>	sendgetr'   listintr"   ranger   StopIterationgrM   promptsrK   chunkr0   rI   r<   rL   r.   r   r7   traced_streamed_responsev   s0   
zO_BaseCompletionHook._handle_streamed_response.<locals>.traced_streamed_responsec                  3   s     } |  d   ddpd}dkr- dd}t|tr-t|d ts-|t|9 }dd t|D }z"D ]}t|| |V  q9W z|  | W d S  tyX   Y d S w z|  | W w  tyi   Y w w )	NrM   r   rN   rO   r   r   c                 S   rP   r   r   rQ   r   r   r7   rT      rU   rV   rW   r^   rb   r   r7   rc      s0   
)r	   OPENAI_VERSIONr   r   r   r   r   )r*   r,   r.   r0   r<   rI   rc   r   )r,   r0   rI   r<   rL   r.   r7   _handle_streamed_response\   s$   z-_BaseCompletionHook._handle_streamed_responseN)r   )rA   rB   rC   re   r   r   r   r7   rF   [   s    rF   c                       0   e Zd ZdZdZdZdZdZ fddZ  Z	S )_CompletionHook)r   r   suffixr   completionsPOSTcreateCompletionc              	      r   t  |||||||}|s|j|g ||dd d S |dr-|d u r-| j||||ddS |j|g ||dd |S )NrN   r/   r0   response	operationstreamrH   superr;   llmobs_set_tagsrY   re   r*   r+   r,   r.   r/   r0   r<   r=   	__class__r   r7   r;         z _CompletionHook._record_response
rA   rB   rC   r&   r?   r   r    rE   r;   __classcell__r   r   rv   r7   rg      s    rg   c                   @      e Zd ZdS )_CompletionWithRawResponseHookNrA   rB   rC   r   r   r   r7   r|          r|   c                       <   e Zd ZdZdZdZdZdZ fddZ fdd	Z	  Z
S )
_ChatCompletionHookr   r   ri   zchat/completionsrk   createChatCompletionc                    s   t  |||||| ttdkr=|dr?|di }t|ts#i }|dd d ur-d S |dd d|d< ||d< d S d S d S )N)r      rq   stream_optionsinclude_usagez_dd.auto_extract_token_chunkT)rs   r8   r	   rd   rY   r'   r(   _set_ctx_item)r*   r+   r,   r-   r.   r/   r0   r   rv   r   r7   r8      s   
z#_ChatCompletionHook._record_requestc              	      rm   )Nchatrn   rq   rH   rr   ru   rv   r   r7   r;      rx   z$_ChatCompletionHook._record_response)rA   rB   rC   r&   r?   r   r    rE   r8   r;   rz   r   r   rv   r7   r      s    r   c                   @   r{   )"_ChatCompletionWithRawResponseHookNr}   r   r   r   r7   r      r~   r   c                   @      e Zd ZdZdS )_ChatCompletionParseHookparseChatCompletionNrA   rB   rC   rE   r   r   r   r7   r          r   c                       rf   )_EmbeddingHookr   ri   
embeddingsrk   createEmbeddingc              	      s0   t  |||||||}|j|g ||dd |S )N	embeddingrn   )rs   r;   rt   ru   rv   r   r7   r;      s   z_EmbeddingHook._record_responsery   r   r   rv   r7   r      s    r   c                       @   e Zd ZdZdZdZdZdZdZ fddZ	 fd	d
Z
  ZS )	_ListHookzi
    Hook for openai.ListableAPIResource, which is used by Model.list, File.list, and FineTune.list.
    )r   r   userNGETrZ   c                    sL   t  |||||| |d}|drd|_d S |dr$d|_d S d S )Nr   /models
listModels/files	listFiles)rs   r8   get_tagendswithresourcer*   r+   r,   r-   r.   r/   r0   r1   rv   r   r7   r8      s   




z_ListHook._record_requestc              	      sD   t  |||||||}|sd S t|dr |dt|jpg  |S )Ndatazopenai.response.count)rs   r;   r:   
set_metricr"   r   ru   rv   r   r7   r;     s   
z_ListHook._record_responserA   rB   rC   rD   r!   r&   r   r    rE   r8   r;   rz   r   r   rv   r7   r      s    r   c                   @      e Zd ZdZdZdZdS )_ModelListHookz;
    Hook for openai.resources.models.Models.list (v1)
    modelsr   NrA   rB   rC   rD   r   rE   r   r   r   r7   r         r   c                   @   r   )_FileListHookz9
    Hook for openai.resources.files.Files.list (v1)
    filesr   Nr   r   r   r   r7   r     r   r   c                       sD   e Zd ZdZdZdZdZdZdZdZ	 fdd	Z
 fd
dZ  ZS )_RetrieveHookzcHook for openai.APIResource, which is used by Model.retrieve, File.retrieve, and FineTune.retrieve.)N
request_idrequest_timeoutr   )idowned_byr   parentrootbytescreated
created_atpurposefilenamefine_tuned_modelstatusstatus_details
updated_atNr   retrievec              
         t  |||||| |d}|dr6d|_t|dkr'|d|d  n4|d|d|dd	 n%|d
r[d|_t|dkrM|d|d  n|d|d|dd	 |dd|  d S )Nr   r   retrieveModelr   r   r   r   r   r   r   retrieveFileopenai.request.file_idfile_id%s/*rs   r8   r   r   r   r"   r   rY   r   rv   r   r7   r8   <     


z_RetrieveHook._record_requestc              	         t  |||||||}|S Nrs   r;   ru   rv   r   r7   r;   M     z_RetrieveHook._record_response)rA   rB   rC   rD   r!   r&   r?   r   r    rE   r8   r;   rz   r   r   rv   r7   r   #  s    r   c                   @   r   )_ModelRetrieveHookz:
    Hook for openai.resources.models.Models.retrieve
    r   r   Nr   r   r   r   r7   r   R  r   r   c                   @   r   )_FileRetrieveHookz8
    Hook for openai.resources.files.Files.retrieve
    r   r   Nr   r   r   r   r7   r   [  r   r   c                       r   )_DeleteHookzUHook for openai.DeletableAPIResource, which is used by File.delete, and Model.delete.)Nr   r   r   NDELETEdeletec              
      r   )Nr   r   deleteModelr   r   r   r   sidr   r   
deleteFiler   r   r   r   r   rv   r   r7   r8   m  r   z_DeleteHook._record_requestc              	      s   t  |||||||}|sd S t|dr?|jdr%|d|jd |d|jdd |dt|jdd |S |dt|j |dt|j	 |S )	Nr   zopenai-organizationzopenai.organization.namezopenai.response.idr   r   zopenai.response.deleteddeleted)
rs   r;   r:   _headersrY   r   r   r%   r   r   ru   rv   r   r7   r;   ~  s   
z_DeleteHook._record_responser   r   r   rv   r7   r   d  s    r   c                   @      e Zd ZdZdZdS )_FileDeleteHookz6
    Hook for openai.resources.files.Files.delete
    r   NrA   rB   rC   rD   r   r   r   r   r7   r         r   c                   @   r   )_ModelDeleteHookz8
    Hook for openai.resources.models.Models.delete
    r   Nr   r   r   r   r7   r     r   r   c                       s(   e Zd ZdZdZdZ fddZ  ZS )
_ImageHook)r   imagesrk   c                    s&   t  |||||| |dd d S )Nr   zdall-e)rs   r8   r   r*   r+   r,   r-   r.   r/   r0   rv   r   r7   r8     s   z_ImageHook._record_request)rA   rB   rC   r?   r   r    r8   rz   r   r   rv   r7   r     s
    r   c                   @   r   )_ImageCreateHookzimages/generationscreateImageNrA   rB   rC   r   rE   r   r   r   r7   r         r   c                   @   r   )_ImageEditHookzimages/editscreateImageEditNr   r   r   r   r7   r     r   r   c                   @   r   )_ImageVariationHookzimages/variationscreateImageVariationNr   r   r   r   r7   r     r   r   c                   @   r   )_BaseAudioHookri   audiork   N)rA   rB   rC   r!   r   r    r   r   r   r7   r     s    r   c                   @   r   )_AudioTranscriptionHookzaudio/transcriptionscreateTranscriptionNr   r   r   r   r7   r     r   r   c                   @   r   )_AudioTranslationHookzaudio/translationscreateTranslationNr   r   r   r   r7   r     r   r   c                   @   s$   e Zd ZdZdZdZdZdZdZdS )_ModerationHookri   )r   r   moderationsrk   createModerationN)	rA   rB   rC   r!   r&   r?   r   r    rE   r   r   r   r7   r     s    r   c                   @   r   )_BaseFileHookr   N)rA   rB   rC   r   r   r   r   r7   r     r   r   c                       r   )
_FileCreateHook)	Nr   r   api_keyr   r   r   organizationuser_provided_filename)r   r   )r   r   r   r   r   r   r   rk   
createFilec                    sp   t  |||||| t|dkr|d n|dd}|r0t|dr0|d|jdd  d S |dd d S )	Nr   r   filer   namezopenai.request.filename/)rs   r8   r"   rY   r:   r   r   split)r*   r+   r,   r-   r.   r/   r0   fprv   r   r7   r8     s
    z_FileCreateHook._record_requestc              	      r   r   r   ru   rv   r   r7   r;     r   z _FileCreateHook._record_response)rA   rB   rC   r!   r&   r?   r    rE   r8   r;   rz   r   r   rv   r7   r     s    r   c                       s8   e Zd ZdZdZdZdZ fddZ fddZ  Z	S )	_FileDownloadHook)Nr   r   r   r   r   r   downloadFilezfiles/*/contentc                    sH   t  |||||| |dt|dkr|d  d S |dd d S )Nr   r   r   r   r   )rs   r8   r   r"   rY   r   rv   r   r7   r8     s   2z!_FileDownloadHook._record_requestc              	      s`   t  |||||||}|sd S t|tst|tr$|dt| |S |dt|dd |S )Nzopenai.response.total_bytestotal_bytesr   )rs   r;   r'   r   r%   r   r"   r   ru   rv   r   r7   r;     s   z"_FileDownloadHook._record_response)
rA   rB   rC   r!   r    rE   r   r8   r;   rz   r   r   rv   r7   r     s    r   c                       s@   e Zd ZdZdZdZdZdZ fddZdd Z	d	d
 Z
  ZS )_ResponseHookri   	responsesrk   createResponsec              	      s   t  |||||||}| ||| |s!|j|g ||dd |S |dr4|d u r4| j||||ddS |j|g ||dd |S )Nro   rn   rq   rH   )rs   r;   _trace_mcp_tool_usagert   rY   re   ru   rv   r   r7   r;     s   z_ResponseHook._record_responsec                 C   sZ   |sdS t |dg }|r't|tr)|D ]}t |dd}|dkr&| ||| qdS dS dS )z<Detect and trace server-side MCP tool usage in the response.Noutputtyper   mcp_call)r   r'   rZ   _create_mcp_tool_span)r*   r+   r,   r<   messagesitemmessage_typer   r   r7   r     s   z#_ResponseHook._trace_mcp_tool_usagec           
      C   s   |j dddd;}tt|dd}tt|dd}t|dt}tt|}tt|d	d}	|j|g |||d
|	dd W d   dS 1 sFw   Y  dS )zSCreates and submits a tool span to LLMObs to represent a server-side MCP tool call.client_tool_callTtool)submit_to_llmobskindr   r   r   	argumentsr   )r   r  tool_idrn   N)tracer%   r   r
   r   rt   )
r*   r  r,   r+   r.   r  	tool_nameraw_argumentstool_argumentstool_outputr   r   r7   r   &  s   
"z#_ResponseHook._create_mcp_tool_span)rA   rB   rC   r&   r?   r   r    rE   r;   r   r   rz   r   r   rv   r7   r     s    r   c                   @   r   )_ResponseParseHookparseResponseNr   r   r   r   r7   r  7  r   r  N)2openai.versionr   rd   %ddtrace.contrib.internal.openai.utilsr   r   r   r   r   r   ddtrace.internal.utils.versionr	   ddtrace.llmobs._constantsr
   0ddtrace.llmobs._integrations.base_stream_handlerr   ddtrace.llmobs._utilsr   r   r   r   rF   rg   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   r7   <module>   sV    HI"		/		)
	1