o
    3Ih7i                     @   s  zd dl Z W n ey   edw d dlZd dlZd dlmZ d dlmZm	Z	m
Z
mZmZmZmZmZ d dlmZ d dlmZ d dlmZmZ d dlmZ d d	lmZmZ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& d dl'm(Z(m)Z) d dl*m+Z+ e,dZ-eG dd dZ.eG dd de.Z/ee.e/f Z0e	ee0f Z1G dd deZ2dd Z3dede	e4ef fddZ5dee$e	f deee6df ee6df f fddZ7de"fd d!Z8d"e9de6fd#d$Z:d%ee	e4ef  d&edee4 fd'd(Z;d)e9de4fd*d+Z<dS ),    NzEPlease install LangChain to use this feature: 'pip install langchain')	dataclass)AnyDictListOptionalSequenceTupleUnioncast)UUID)BaseCallbackHandler)AgentActionAgentFinish)Document)	AIMessageBaseMessageFunctionMessageHumanMessageSystemMessageToolMessage)ChatGeneration	LLMResult)	BaseModel)default_client)get_model_paramswith_privacy_mode)Clientposthogc                   @   sP   e Zd ZU eed< 	 eed< 	 ee ed< 	 ee ed< 	 edefddZ	dS )	SpanMetadataname
start_timeend_timeinputreturnc                 C   s   | j sdS | j | j S )Nr   )r!   r    )self r%   ^/home/air/sanwanet/gpt-api/venv/lib/python3.10/site-packages/posthog/ai/langchain/callbacks.pylatency7   s   zSpanMetadata.latencyN)
__name__
__module____qualname__str__annotations__floatr   r   propertyr'   r%   r%   r%   r&   r   ,   s   
 r   c                   @   sz   e Zd ZU dZee ed< 	 dZee ed< 	 dZee	ee
f  ed< 	 dZee ed< 	 dZeee	ee
f   ed< dS )GenerationMetadataNprovidermodelmodel_paramsbase_urltools)r(   r)   r*   r0   r   r+   r,   r1   r2   r   r   r3   r4   r   r%   r%   r%   r&   r/   >   s   
 r/   c                   @   s  e Zd ZU dZeed< 	 eeee	e
ef  ed< 	 eeee	e
ef  ed< 	 ee ed< 	 ee ed< 	 eeeef  ed< 	 eed< 	 eeef ed	< 	 	
djd
d
d
dd
ddee deeee	e
ef  deeee	e
ef  deeeef  dedeeeef  fddZd
d
ddeeef deeef dedee deeeef  f
ddZd
ddeeef dedee defd d!Zd
dd"ededee defd#d$Zd
ddeeef d%eee  dedee fd&d'Zd
ddeeef d(ee dedee def
d)d*Zd
dd+ededee ded,ef
d-d.Zd
dd/ededee defd0d1Zd
dd"ededee defd2d3Zd
d
ddeeeef  d4ededee deeeef  ded,efd5d6Zd
dd7ededee ded,ef
d8d9Zd
d
d:d"ededee d;eee  ded,efd<d=Z d
d
ddeeeef  d>ededee deeeef  ded,efd?d@Z!d
ddAe"e# dedee defdBdCZ$d
d
d:d"ededee d;eee  ded,efdDdEZ%d
ddFe&dedee ded,ef
dGdHZ'd
ddIe(dedee ded,ef
dJdKZ)djdedee fdLdMZ*defdNdOZ+ded,efdPdQZ,	
djdeeeef  dRededee fdSdTZ-	
	
dkdeeef ded%eeeeef  ee f deeeef  dUeeeef  f
dVdWZ.ded,ee/ fdXdYZ0defdZd[Z1dededee fd\d]Z2dedee defd^d_Z3deded`e4dedee f
dadbZ5dedee d/eeef fdcddZ6	
djdeded`e7d7eeef dee f
dedfZ8	
djdgededee fdhdiZ9d
S )lCallbackHandlerzG
    The PostHog LLM observability callback handler for LangChain.
    _client_distinct_id	_trace_id_trace_input_trace_name_properties_runs_parent_treeNF)distinct_idtrace_id
propertiesprivacy_modegroupsclientr>   r?   r@   rA   rB   c                C   sT   |pt }|du rtd|| _|| _|| _|pi | _|| _|p i | _i | _i | _	dS )a  
        Args:
            client: PostHog client instance.
            distinct_id: Optional distinct ID of the user to associate the trace with.
            trace_id: Optional trace ID to use for the event.
            properties: Optional additional metadata to use for the trace.
            privacy_mode: Whether to redact the input and output of the trace.
            groups: Optional additional PostHog groups to use for the trace.
        NzPostHog client is required)
r   
ValueErrorr6   r7   r8   r;   _privacy_mode_groupsr<   r=   )r$   rC   r>   r?   r@   rA   rB   posthog_clientr%   r%   r&   __init__p   s   


zCallbackHandler.__init__)parent_run_idmetadata
serializedinputsrun_idrI   rJ   c                K   :   | j d|||d | || | j||||fi | d S )Non_chain_start)rL   _log_debug_event_set_parent_of_run_set_trace_or_span_metadata)r$   rK   rL   rM   rI   rJ   kwargsr%   r%   r&   rO         

zCallbackHandler.on_chain_start)rI   outputsrT   c                K   $   | j d|||d | ||| d S )Non_chain_end)rV   rQ   "_pop_run_and_capture_trace_or_span)r$   rV   rM   rI   rT   r%   r%   r&   rX         zCallbackHandler.on_chain_enderrorc                K   rW   )Non_chain_errorr\   rY   r$   r\   rM   rI   rT   r%   r%   r&   r]      r[   zCallbackHandler.on_chain_errormessagesc                K   sF   | j d|||d | || dd |D }| j|||fi | d S )Non_chat_model_start)r`   c                 S   s   g | ]}|D ]}t |qqS r%   )_convert_message_to_dict).0rowmessager%   r%   r&   
<listcomp>   s
    z7CallbackHandler.on_chat_model_start.<locals>.<listcomp>rQ   rR   _set_llm_metadata)r$   rK   r`   rM   rI   rT   r"   r%   r%   r&   ra      s   	z#CallbackHandler.on_chat_model_startpromptsc                K   s8   | j d|||d | || | j|||fi | d S )Non_llm_start)ri   rg   )r$   rK   ri   rM   rI   rT   r%   r%   r&   rj      s   	zCallbackHandler.on_llm_starttokenr#   c                K   s   | j d|||d dS )z?Run on new LLM token. Only available when streaming is enabled.on_llm_new_token)rk   N)rQ   )r$   rk   rM   rI   rT   r%   r%   r&   rl      s   	z CallbackHandler.on_llm_new_tokenresponsec                K   s&   | j d||||d | ||| dS )z
        The callback works for both streaming and non-streaming runs. For streaming runs, the chain must set `stream_usage=True` in the LLM.
        
on_llm_end)rm   rT   NrQ   _pop_run_and_capture_generation)r$   rm   rM   rI   rT   r%   r%   r&   rn      s   
zCallbackHandler.on_llm_endc                K   rW   )Non_llm_errorr^   ro   r_   r%   r%   r&   rq      r[   zCallbackHandler.on_llm_error	input_strc                K   rN   )Non_tool_start)rr   rP   )r$   rK   rr   rM   rI   rJ   rT   r%   r%   r&   rs      s   

zCallbackHandler.on_tool_startoutputc                K   rW   )Non_tool_end)rt   rY   )r$   rt   rM   rI   rT   r%   r%   r&   ru     r[   zCallbackHandler.on_tool_end)rI   tagsrv   c                K   rW   )Non_tool_errorr^   rY   r$   r\   rM   rI   rv   rT   r%   r%   r&   rw     s   	zCallbackHandler.on_tool_errorqueryc                K   rN   )Non_retriever_start)ry   rP   )r$   rK   ry   rM   rI   rJ   rT   r%   r%   r&   rz   #  rU   z"CallbackHandler.on_retriever_start	documentsc                K   rW   )Non_retriever_end)r{   rY   )r$   r{   rM   rI   rT   r%   r%   r&   r|   3  s   z CallbackHandler.on_retriever_endc                K   s$   | j d|||d | ||| dS )zRun when Retriever errors.on_retriever_errorr^   NrY   rx   r%   r%   r&   r}   @  s   
z"CallbackHandler.on_retriever_erroractionc                K   s:   | j d|||d | || | jd|||fi | dS )zRun on agent action.on_agent_action)r~   NrP   )r$   r~   rM   rI   rT   r%   r%   r&   r   M  s   	zCallbackHandler.on_agent_actionfinishc                K   rW   )Non_agent_finish)r   rY   )r$   r   rM   rI   rT   r%   r%   r&   r   Z  r[   zCallbackHandler.on_agent_finishc                 C   s   |dur|| j |< dS dS )zd
        Set the parent run ID for a chain run. If there is no parent, the run is the root.
        Nr=   )r$   rM   rI   r%   r%   r&   rR   e  s   z"CallbackHandler._set_parent_of_runc                 C   s(   z	| j | W dS  ty   Y dS w )z;
        Remove the parent run ID for a chain run.
        N)r=   popKeyError)r$   rM   r%   r%   r&   _pop_parent_of_runl  s
   z"CallbackHandler._pop_parent_of_runc                 C   s&   |}|| j v r| j | }|| j v s|S )z3
        Finds the root ID of a chain run.
        r   )r$   rM   idr%   r%   r&   _find_root_runu  s
   


zCallbackHandler._find_root_runr"   c                 K   sB   |d u rdnd}t |fi |p|}t||t d d| j|< d S )Ntracespanr   r"   r    r!   )_get_langchain_run_namer   timer<   )r$   rK   r"   rM   rI   rT   default_namerun_namer%   r%   r&   rS   ~  s
   z+CallbackHandler._set_trace_or_span_metadatainvocation_paramsc                 K   s   t |fi |p	d}t||t d d}t|tr(t||_|d }	r(|	|_t|trA|d }
r7|
|_	|d }rA||_
z|d d }|d urO||_W n	 tyY   Y nw || j|< d S )N
generationr   r4   ls_model_namels_providerrT   openai_api_base)r   r/   r   
isinstancedictr   r2   getr4   r1   r0   r3   r   r<   )r$   rK   rM   r`   rJ   r   rT   r   r   r4   r1   r0   r3   r%   r%   r&   rh     s,   	


z!CallbackHandler._set_llm_metadatac                 C   sH   t   }z| j|}W n ty   td|  Y d S w ||_|S )NzNo run metadata found for run )r   r<   r   r   logwarningr!   )r$   rM   r!   runr%   r%   r&   _pop_run_metadata  s   z!CallbackHandler._pop_run_metadatac                 C   s   | j p| |}|s|S |S N)r8   r   )r$   rM   r?   r%   r%   r&   _get_trace_id  s   zCallbackHandler._get_trace_idc                 C   s   |dur|| j vr|S |S )zr
        Replace the parent run ID with the trace ID for second level runs when a custom trace ID is set.
        Nr   )r$   r?   rM   rI   r%   r%   r&   _get_parent_run_id  s   z"CallbackHandler._get_parent_run_idc                 C   sf   |  |}| | | |}|sd S t|tr#td| d d S | ||||| ||| d S )NRun zB is a generation, but attempted to be captured as a trace or span.)	r   r   r   r   r/   r   r   _capture_trace_or_spanr   )r$   rM   rI   rV   r?   r   r%   r%   r&   rZ     s"   




z2CallbackHandler._pop_run_and_capture_trace_or_spanr   c                 C   s   |d u rdnd}|t | j| j|j|j|j|d}|d ur!||d< | jr*|| j t|t	r:t
||d< d|d< n|d urHt | j| j||d< | jd u rQd	|d
< | jj| jpX|||| jd d S )Nz	$ai_tracez$ai_span)$ai_trace_idz$ai_input_state$ai_latency$ai_span_name$ai_span_id$ai_parent_id	$ai_errorT$ai_is_errorz$ai_output_stateF$process_person_profiler>   eventr@   rB   )r   r6   rE   r"   r'   r   r;   updater   BaseException_stringify_exceptionr7   capturerF   )r$   r?   rM   r   rV   rI   
event_nameevent_propertiesr%   r%   r&   r     s8   	




z&CallbackHandler._capture_trace_or_spanc                 C   sf   |  |}| | | |}|sd S t|ts#td| d d S | ||||| ||| d S )Nr   zC is not a generation, but attempted to be captured as a generation.)	r   r   r   r   r/   r   r   _capture_generationr   )r$   rM   rI   rm   r?   r   r%   r%   r&   rp     s"   




z/CallbackHandler._pop_run_and_capture_generationc                 C   s(  |||j ||j|j|jt| j| j|jd|j|j	d}|j
r)t| j| j|j
|d< t|tr?t||d< t||d< d|d< n3t|\}}||d< ||d	< |jd
 }	t|	d
 tradd |	D }
ndd |	D }
t| j| j|
|d< | jr{|| j | jd u rd|d< | jj| jp|d|| jd d S )N   )r   r   r   r   z$ai_providerz	$ai_modelz$ai_model_parametersz	$ai_input$ai_http_statusr   z$ai_base_urlz	$ai_toolsr   r   Tr   z$ai_input_tokensz$ai_output_tokensc                 S   s   g | ]
}t tt|jqS r%   )rb   r
   r   re   rc   r   r%   r%   r&   rf   C  s    z7CallbackHandler._capture_generation.<locals>.<listcomp>c                 S   s   g | ]}t |qS r%   )_extract_raw_esponser   r%   r%   r&   rf   H  s    z$ai_output_choicesFr   z$ai_generationr   )r   r0   r1   r2   r   r6   rE   r"   r'   r3   r4   r   r   _get_http_statusr   _parse_usagegenerationsr   r;   r   r7   r   rF   )r$   r?   rM   r   rt   rI   r   input_tokensoutput_tokensgeneration_resultcompletionsr%   r%   r&   r     s\   	





z#CallbackHandler._capture_generationr   c              
   K   s>   t d| dt|d d  dt|d d  d|  d S )NzEvent: z
, run_id:    z, parent_run_id: z
, kwargs: )r   debugr+   )r$   r   rM   rI   rT   r%   r%   r&   rQ   \  s   2z CallbackHandler._log_debug_eventr   NN):r(   r)   r*   __doc__r   r,   r   r	   r+   intr-   r   r   r   RunMetadataStorageboolrH   rO   rX   r   r]   r   r   ra   rj   rl   r   rn   rq   rs   ru   listrw   rz   r   r   r|   r}   r   r   r   r   rR   r   r   rS   rh   RunMetadatar   r   r   rZ   r   r   rp   r/   r   rQ   r%   r%   r%   r&   r5   P   sv  
 
%













	



	





	







)



Fr5   c                 C   s8   | j dur| j  dkr| j  S t| dr| jjS dS )z<Extract the response from the last response of the LLM call.N re   )textstriphasattrre   additional_kwargs)last_responser%   r%   r&   r   h  s
   

r   re   r#   c                 C   s   t | trd| jd}n9t | trd| jd}n-t | tr$d| jd}n!t | tr0d| jd}nt | tr<d| jd}n	| jt| jd}| j	rN|
| j	 |S )Nuser)rolecontent	assistantsystemtoolfunction)r   r   r   r   r   r   r   typer+   r   r   )re   message_dictr%   r%   r&   rb   u  s   




rb   usagec                 C   sl   t | tr| j} g d}i }|D ]\}}|| v r+| | }t |tr%t|n|}|||< q|d|dfS )N)
)r   r"   )r   rt   )prompt_token_countr"   )candidates_token_countrt   )inputTokenCountr"   )outputTokenCountrt   )prompt_tokensr"   )completion_tokensrt   )input_token_countr"   )generated_token_countrt   r"   rt   )r   r   __dict__r   sumr   )r   conversion_listparsed_usage	model_keytype_keycaptured_countfinal_countr%   r%   r&   _parse_usage_model  s   

r   rm   c                 C   s  ddg}d}| j d ur|D ]}| j |rt| j | } nqt| dr| jD ]_}d|v r6t|d } |S |D ]M}|jrKd|jv rKt|jd } n;t|di }t|di }t|trb|dd nd }t|tro|dd nd }	t|dd }
|p||	p||
}|rt|} nq8q'|S )	Ntoken_usager   r   r   usage_metadatare   response_metadataz amazon-bedrock-invocationMetrics)	
llm_outputr   r   r   r   generation_infogetattrr   r   )rm   llm_usage_keys	llm_usagekeyr   generation_chunkmessage_chunkr   bedrock_anthropic_usagebedrock_titan_usageollama_usagechunk_usager%   r%   r&   r     sX   


%
	
r   r\   c                 C   s   t | dt | dd}|S )Nstatus_codecoder   )r   )r\   r   r%   r%   r&   r     s   r   rK   rT   c              	   K   sr   d|v r|d dur|d S | du rdS z| d W S  t tfy$   Y nw z| d d W S  t tfy8   Y dS w )aw  Retrieve the name of a serialized LangChain runnable.

    The prioritization for the determination of the run name is as follows:
    - The value assigned to the "name" key in `kwargs`.
    - The value assigned to the "name" key in `serialized`.
    - The last entry of the value assigned to the "id" key in `serialized`.
    - "<unknown>".

    Args:
        serialized (Optional[Dict[str, Any]]): A dictionary containing the runnable's serialized data.
        **kwargs (Any): Additional keyword arguments, potentially including the 'name' override.

    Returns:
        str: The determined name of the Langchain runnable.
    r   Nr   r   )r   	TypeError)rK   rT   r%   r%   r&   r     s   
r   	exceptionc                 C   s&   t | }|r| jj d| S | jjS )Nz: )r+   	__class__r(   )r   descriptionr%   r%   r&   r     s   r   )=	langchainImportErrorModuleNotFoundErrorloggingr   dataclassesr   typingr   r   r   r   r   r   r	   r
   uuidr   langchain.callbacks.baser   langchain.schema.agentr   r   langchain_core.documentsr   langchain_core.messagesr   r   r   r   r   r   langchain_core.outputsr   r   pydanticr   r   r   posthog.ai.utilsr   r   posthog.clientr   	getLoggerr   r   r/   r   r   r5   r   r+   rb   r   r   r   r   r   r   r   r%   r%   r%   r&   <module>   sd    (
 
    

'6
!