o
    3iLS                     @   s(  d dl Z d dlZd dlmZmZmZmZ d dlmZ zd dl	Z	W n e
y+   edw d dl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 d dlmZ d d	lmZ G d
d de	jZG dd dZG dd dZ G dd dZ!G dd dZ"G dd dZ#G dd dZ$G dd dZ%dS )    N)AnyDictListOptional)
TokenUsagezGPlease install the OpenAI SDK to use this feature: 'pip install openai')call_llm_and_track_usageextract_available_tool_callsmerge_usage_statswith_privacy_mode)extract_openai_usage_from_chunk!extract_openai_content_from_chunk$extract_openai_tool_calls_from_chunkaccumulate_openai_tool_calls)sanitize_openaisanitize_openai_response)Client)setupc                       s6   e Zd ZU dZeed< ddee f fddZ  ZS )OpenAIz_
    A wrapper around the OpenAI SDK that automatically sends LLM usage events to PostHog.
    
_ph_clientNposthog_clientc                    s   t  jdi | |pt | _t| dd| _t| dd| _t| dd| _t| dd| _| jdur7t	| | j| _
| jdurCt| | j| _| jdurOt| | j| _| jdur]t| | j| _dS dS )a  
        Args:
            api_key: OpenAI API key.
            posthog_client: If provided, events will be captured via this client instead of the global `posthog`.
            **openai_config: Any additional keyword args to set on openai (e.g. organization="xxx").
        chatN
embeddingsbeta	responses )super__init__r   r   getattr_original_chat_original_embeddings_original_beta_original_responsesWrappedChatr   WrappedEmbeddingsr   WrappedBetar   WrappedResponsesr   )selfr   kwargs	__class__r   f/lsinfo/ai/hellotax_ai/llm_service/venv_embed/lib/python3.10/site-packages/posthog/ai/openai/openai.pyr   &   s   



zOpenAI.__init__N)	__name__
__module____qualname____doc__PostHogClient__annotations__r   r   __classcell__r   r   r(   r*   r      s   
  r   c                   @   s|  e Zd ZdZdefddZdd Z					dd	ee d
ee dee	ee
f  dedee	ee
f  de
fddZd	ee d
ee dee	ee
f  dedee	ee
f  de
fddZ		dd	ee d
ee dee	ee
f  dedee	ee
f  de	ee
f dedede
deee	ee
f   dee fddZ					dd	ee d
ee dee	ee
f  dedee	ee
f  de
fddZdS )r%   z:Wrapper for OpenAI responses that tracks usage in PostHog.clientc                 C      || _ || _d S r+   _client	_original)r&   r3   original_responsesr   r   r*   r   H      
zWrappedResponses.__init__c                 C      t | j|S )zQFallback to original responses object for any methods we don't explicitly handle.r   r7   r&   namer   r   r*   __getattr__L      zWrappedResponses.__getattr__NFposthog_distinct_idposthog_trace_idposthog_propertiesposthog_privacy_modeposthog_groupsr'   c              
   K   f   |d u r
t t }|ddr| j|||||fi |S t|| jjd||||| jj| j	j
f	i |S NstreamFopenaistruuiduuid4get_create_streamingr   r6   r   base_urlr7   creater&   r@   rA   rB   rC   rD   r'   r   r   r*   rP   P   2   		
zWrappedResponses.createc                    sP   t   
t g  d 	jjdi  	
fdd}| S )Nc                  3   s    zTD ]5} t | dr| jrd u rt | jdr| jjt| d}|r(t| t| d}|d ur6 | | V  qW t }|
 } }	||d  d S t }|
 } }	||d  w )Nresponsemodelr   )	hasattrrS   rT   r   r	   r   appendtime_capture_streaming_event)chunkchunk_usagecontentend_timelatencyoutputfinal_contentr'   model_from_responser@   rD   rC   rB   rA   rS   r&   
start_timeusage_statsr   r*   	generator   s`   




z5WrappedResponses._create_streaming.<locals>.generatorr   rW   r   r7   rP   r&   r@   rA   rB   rC   rD   r'   rd   r   r_   r*   rN   s   s   	".z"WrappedResponses._create_streamingrc   r]   r^   available_tool_callsra   c                 C   s   ddl m} ddlm}m} ddlm} ||d}t|}|dp%|p%d}|d|t	| j
j||||	d|||||||d	}|| j
j| d S )
Nr   StreamingEventDataformat_openai_streaming_inputformat_openai_streaming_outputcapture_streaming_eventr   rT   unknownrH   providerrT   rO   r'   formatted_inputformatted_outputrc   r]   distinct_idtrace_id
propertiesprivacy_modegroups)posthog.ai.typesri   "posthog.ai.openai.openai_converterrk   rl   posthog.ai.utilsrn   r   rM   rJ   r6   rO   r   )r&   r@   rA   rB   rC   rD   r'   rc   r]   r^   rg   ra   ri   rk   rl   rn   rr   sanitized_inputrT   
event_datar   r   r*   rX      s,   

z)WrappedResponses._capture_streaming_eventc              
   K   ,   t || jjd||||| jj| jjf	i |S )a  
        Parse structured output using OpenAI's 'responses.parse' method, but also track usage in PostHog.

        Args:
            posthog_distinct_id: Optional ID to associate with the usage event.
            posthog_trace_id: Optional trace UUID for linking events.
            posthog_properties: Optional dictionary of extra properties to include in the event.
            posthog_privacy_mode: Whether to anonymize the input and output.
            posthog_groups: Optional dictionary of groups to associate with the event.
            **kwargs: Any additional parameters for the OpenAI Responses Parse API.

        Returns:
            The response from OpenAI's responses.parse call.
        rH   r   r6   r   rO   r7   parserQ   r   r   r*   r      s   
zWrappedResponses.parseNNNFN)NN)r,   r-   r.   r/   r   r   r>   r   rJ   r   r   boolrP   rN   r   floatr   rX   r   r   r   r   r*   r%   E   s    
#
J
	

1r%   c                   @   2   e Zd ZdZdefddZdd Zedd Zd	S )
r"   z5Wrapper for OpenAI chat that tracks usage in PostHog.r3   c                 C   r4   r+   r5   )r&   r3   original_chatr   r   r*   r   	  r9   zWrappedChat.__init__c                 C   r:   )zLFallback to original chat object for any methods we don't explicitly handle.r;   r<   r   r   r*   r>     r?   zWrappedChat.__getattr__c                 C      t | j| jjS r+   )WrappedCompletionsr6   r7   completionsr&   r   r   r*   r        zWrappedChat.completionsN	r,   r-   r.   r/   r   r   r>   propertyr   r   r   r   r*   r"         r"   c                   @   sD  e Zd ZdZdefddZdd Z					dd	ee d
ee dee	ee
f  dedee	ee
f  de
fddZd	ee d
ee dee	ee
f  dedee	ee
f  de
fddZ			dd	ee d
ee dee	ee
f  dedee	ee
f  de	ee
f dedede
deee	ee
f   deee	ee
f   dee fddZdS )r   zAWrapper for OpenAI chat completions that tracks usage in PostHog.r3   c                 C   r4   r+   r5   )r&   r3   original_completionsr   r   r*   r     r9   zWrappedCompletions.__init__c                 C   r:   )zSFallback to original completions object for any methods we don't explicitly handle.r;   r<   r   r   r*   r>     r?   zWrappedCompletions.__getattr__NFr@   rA   rB   rC   rD   r'   c              
   K   rE   rF   rI   rQ   r   r   r*   rP   !  rR   zWrappedCompletions.createc                    sr   t   t g  i d dvri d< dd d< 
jjdi 	 	
fdd}| S )Nstream_optionsTinclude_usagec                  3   s   za	D ]6} d u rt | dr| jt| d}|rt| t| d}|d ur, | t| }|r7t| | V  qW t }| }rLt	
 nd }
| |td d S t }| }rst	
 nd }
| |td w )NrT   r   rH   )rU   rT   r   r	   r   rV   r   r   rW   listvaluesrX   r   )rY   rZ   r[   chunk_tool_callsr\   r]   tool_calls_listaccumulated_contentaccumulated_tool_callsr'   ra   r@   rD   rC   rB   rA   rS   r&   rb   rc   r   r*   rd   W  st   



z7WrappedCompletions._create_streaming.<locals>.generatorr   re   rf   r   r   r*   rN   D  s   	$;z$WrappedCompletions._create_streamingrc   r]   r^   
tool_callsrg   ra   c                 C   s   ddl m} ddlm}m} ddlm} ||d}t|}|dp%|p%d}|d|t	| j
j||||	d|
|||||||d	}|| j
j| d S )
Nr   rh   rj   rm   r   rT   ro   rH   rp   )ry   ri   rz   rk   rl   r{   rn   r   rM   rJ   r6   rO   r   )r&   r@   rA   rB   rC   rD   r'   rc   r]   r^   r   rg   ra   ri   rk   rl   rn   rr   r|   rT   r}   r   r   r*   rX     s,   


z+WrappedCompletions._capture_streaming_eventr   )NNN)r,   r-   r.   r/   r   r   r>   r   rJ   r   r   r   rP   rN   r   r   r   rX   r   r   r   r*   r     s~    
#
[
	
r   c                   @   t   e Zd ZdZdefddZdd Z					dd	ee d
ee dee	ee
f  dedee	ee
f  de
fddZdS )r#   z;Wrapper for OpenAI embeddings that tracks usage in PostHog.r3   c                 C   r4   r+   r5   )r&   r3   original_embeddingsr   r   r*   r     r9   zWrappedEmbeddings.__init__c                 C   r:   )zRFallback to original embeddings object for any methods we don't explicitly handle.r;   r<   r   r   r*   r>     r?   zWrappedEmbeddings.__getattr__NFr@   rA   rB   rC   rD   r'   c              	   K   s   |du r
t t }t }| jjdi |}t }	i }
t|dr4|jr4t|jddt|jddd}
|	| }d|	dt
| jj|t|	d	d
|
	dd||t | jjd|p[i }|du red|d< t| jjdry| jjj|ps|d||d |S )a  
        Create an embedding using OpenAI's 'embeddings.create' method, but also track usage in PostHog.

        Args:
            posthog_distinct_id: Optional ID to associate with the usage event.
            posthog_trace_id: Optional trace UUID for linking events.
            posthog_properties: Optional dictionary of extra properties to include in the event.
            posthog_privacy_mode: Whether to anonymize the input and output.
            posthog_groups: Optional dictionary of groups to associate with the event.
            **kwargs: Any additional parameters for the OpenAI Embeddings API.

        Returns:
            The response from OpenAI's embeddings.create call.
        Nusageprompt_tokensr   total_tokens)r   r   rH   rT   input   )z$ai_providerz	$ai_modelz	$ai_inputz$ai_http_statusz$ai_input_tokensz$ai_latencyz$ai_trace_idz$ai_base_urlFz$process_person_profilecapturez$ai_embedding)rt   eventrv   rx   r   )rJ   rK   rL   rW   r7   rP   rU   r   r   rM   r
   r6   r   r   rO   r   )r&   r@   rA   rB   rC   rD   r'   rb   rS   r\   rc   r]   event_propertiesr   r   r*   rP     sH   

zWrappedEmbeddings.creater   )r,   r-   r.   r/   r   r   r>   r   rJ   r   r   r   rP   r   r   r   r*   r#     ,    r#   c                   @   r   )
r$   z>Wrapper for OpenAI beta features that tracks usage in PostHog.r3   c                 C   r4   r+   r5   )r&   r3   original_betar   r   r*   r     r9   zWrappedBeta.__init__c                 C   r:   )zLFallback to original beta object for any methods we don't explicitly handle.r;   r<   r   r   r*   r>      r?   zWrappedBeta.__getattr__c                 C   r   r+   )WrappedBetaChatr6   r7   r   r   r   r   r*   r   $  r   zWrappedBeta.chatN)	r,   r-   r.   r/   r   r   r>   r   r   r   r   r   r*   r$     r   r$   c                   @   r   )
r   z:Wrapper for OpenAI beta chat that tracks usage in PostHog.r3   c                 C   r4   r+   r5   )r&   r3   original_beta_chatr   r   r*   r   ,  r9   zWrappedBetaChat.__init__c                 C   r:   )zQFallback to original beta chat object for any methods we don't explicitly handle.r;   r<   r   r   r*   r>   0  r?   zWrappedBetaChat.__getattr__c                 C   r   r+   )WrappedBetaCompletionsr6   r7   r   r   r   r   r*   r   4  r   zWrappedBetaChat.completionsNr   r   r   r   r*   r   )  r   r   c                   @   r   )r   zFWrapper for OpenAI beta chat completions that tracks usage in PostHog.r3   c                 C   r4   r+   r5   )r&   r3   original_beta_completionsr   r   r*   r   <  r9   zWrappedBetaCompletions.__init__c                 C   r:   )zXFallback to original beta completions object for any methods we don't explicitly handle.r;   r<   r   r   r*   r>   @  r?   z"WrappedBetaCompletions.__getattr__NFr@   rA   rB   rC   rD   r'   c              
   K   r~   )NrH   r   rQ   r   r   r*   r   D  s   	
zWrappedBetaCompletions.parser   )r,   r-   r.   r/   r   r   r>   r   rJ   r   r   r   r   r   r   r   r*   r   9  r   r   )&rW   rK   typingr   r   r   r   ry   r   rH   ImportErrorModuleNotFoundErrorr{   r   r   r	   r
   rz   r   r   r   r   posthog.ai.sanitizationr   r   posthog.clientr   r0   posthogr   r   r%   r"   r   r#   r$   r   r   r   r   r   r*   <module>   s4    & B 0T