U
    h9                     @   st   d dl 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
 d dlmZ d dlmZ d dlmZ G dd deZdS )	    N)AnyDictListOptionalcast)AgentActionAgentFinish)BaseCallbackHandler)	LLMResult)parsec                       s  e Zd ZU dZdZeed< e dZeed< dZeed< dZ	eed	< d3ee
e e
e e
e d
d fddZeeef ee ed
dddZeed
dddZeed
dddZeed
dddZeeef eeef ed
dddZeeef ed
dddZeed
dd d!Zeeef eed
d"d#d$Zeeed%d&d'Zd4ee
e e
e ed
d(d)d*Zeed
dd+d,Zeed
d-d.d/Zeed
d0d1d2Z  Z S )5ArgillaCallbackHandlera  Callback Handler that logs into Argilla.

    Args:
        dataset_name: name of the `FeedbackDataset` in Argilla. Note that it must
            exist in advance. If you need help on how to create a `FeedbackDataset` in
            Argilla, please visit
            https://docs.argilla.io/en/latest/tutorials_and_integrations/integrations/use_argilla_callback_in_langchain.html.
        workspace_name: name of the workspace in Argilla where the specified
            `FeedbackDataset` lives in. Defaults to `None`, which means that the
            default workspace will be used.
        api_url: URL of the Argilla Server that we want to use, and where the
            `FeedbackDataset` lives in. Defaults to `None`, which means that either
            `ARGILLA_API_URL` environment variable or the default will be used.
        api_key: API Key to connect to the Argilla Server. Defaults to `None`, which
            means that either `ARGILLA_API_KEY` environment variable or the default
            will be used.

    Raises:
        ImportError: if the `argilla` package is not installed.
        ConnectionError: if the connection to Argilla fails.
        FileNotFoundError: if the `FeedbackDataset` retrieval from Argilla fails.

    Examples:
        >>> from langchain_community.llms import OpenAI
        >>> from langchain_community.callbacks import ArgillaCallbackHandler
        >>> argilla_callback = ArgillaCallbackHandler(
        ...     dataset_name="my-dataset",
        ...     workspace_name="my-workspace",
        ...     api_url="http://localhost:6900",
        ...     api_key="argilla.apikey",
        ... )
        >>> llm = OpenAI(
        ...     temperature=0,
        ...     callbacks=[argilla_callback],
        ...     verbose=True,
        ...     openai_api_key="API_KEY_HERE",
        ... )
        >>> llm.generate([
        ...     "What is the best NLP-annotation tool out there? (no bias at all)",
        ... ])
        "Argilla, no doubt about it."
    z%https://github.com/argilla-io/argillaREPO_URLz/issues
ISSUES_URLzphttps://docs.argilla.io/en/latest/tutorials_and_integrations/integrations/use_argilla_callback_in_langchain.htmlBLOG_URLzhttp://localhost:6900DEFAULT_API_URLN)dataset_nameworkspace_nameapi_urlapi_keyreturnc           	         sn  t    zddl}|j| _W n tk
r:   tdY nX t| jtdk r`td| j d|dkrtddkrt	
d| j d	 | j}|dkrtd
dkrt| jtdk rdnd| _t	
d| j d | j}z|j||d W n> tk
r, } ztd| d| j d|W 5 d}~X Y nX || _|p@| | _zXi }t| jtdk r|t	
d| j dt ddi}|jjf | j| jd|| _W nV tk
r } z6td| d| j d| j d| j d| j d|W 5 d}~X Y nX dd g}|d!d" | jjD krPtd#| j d| j d$| d%d&d" | jjD  d'| j d(i | _t	
d)| j d dS )*a)  Initializes the `ArgillaCallbackHandler`.

        Args:
            dataset_name: name of the `FeedbackDataset` in Argilla. Note that it must
                exist in advance. If you need help on how to create a `FeedbackDataset`
                in Argilla, please visit
                https://docs.argilla.io/en/latest/tutorials_and_integrations/integrations/use_argilla_callback_in_langchain.html.
            workspace_name: name of the workspace in Argilla where the specified
                `FeedbackDataset` lives in. Defaults to `None`, which means that the
                default workspace will be used.
            api_url: URL of the Argilla Server that we want to use, and where the
                `FeedbackDataset` lives in. Defaults to `None`, which means that either
                `ARGILLA_API_URL` environment variable or the default will be used.
            api_key: API Key to connect to the Argilla Server. Defaults to `None`, which
                means that either `ARGILLA_API_KEY` environment variable or the default
                will be used.

        Raises:
            ImportError: if the `argilla` package is not installed.
            ConnectionError: if the connection to Argilla fails.
            FileNotFoundError: if the `FeedbackDataset` retrieval from Argilla fails.
        r   NzTo use the Argilla callback manager you need to have the `argilla` Python package installed. Please install it with `pip install argilla`z1.8.0z#The installed `argilla` version is z} but `ArgillaCallbackHandler` requires at least version 1.8.0. Please upgrade `argilla` with `pip install --upgrade argilla`.ZARGILLA_API_URLz[Since `api_url` is None, and the env var `ARGILLA_API_URL` is not set, it will default to `z6`, which is the default API URL in Argilla Quickstart.ZARGILLA_API_KEYz1.11.0zadmin.apikeyzowner.apikeyz[Since `api_key` is None, and the env var `ARGILLA_API_KEY` is not set, it will default to `z6`, which is the default API key in Argilla Quickstart.)r   r   z.Could not connect to Argilla with exception: 'z'.
Please check your `api_key` and `api_url`, and make sure that the Argilla server is up and running. If the problem persists please report it to z as an `integration` issue.1.14.0zYou have Argilla z., but Argilla 1.14.0 or higher is recommended.Zwith_recordsF)nameZ	workspacez@`FeedbackDataset` retrieval from Argilla failed with exception `z+`.
Please check that the dataset with name=z in the workspace=zz exists in advance. If you need help on how to create a `langchain`-compatible `FeedbackDataset` in Argilla, please visit z.. If the problem persists please report it to promptresponsec                 S   s   g | ]
}|j qS  r   .0fieldr   r   R/tmp/pip-unpacked-wheel-9gdii04g/langchain_community/callbacks/argilla_callback.py
<listcomp>   s     z3ArgillaCallbackHandler.__init__.<locals>.<listcomp>z`FeedbackDataset` with name=z] had fields that are not supported yet for the`langchain` integration. Supported fields are: z/, and the current `FeedbackDataset` fields are c                 S   s   g | ]
}|j qS r   r   r   r   r   r   r       s     zl. For more information on how to create a `langchain`-compatible `FeedbackDataset` in Argilla, please visit .zThe `ArgillaCallbackHandler` is currently in beta and is subject to change based on updates to `langchain`. Please report any issues to )super__init__Zargilla__version__ARGILLA_VERSIONImportErrorr   osgetenvwarningswarnr   ZDEFAULT_API_KEYinit	ExceptionConnectionErrorr   r   Zget_workspacer   UserWarningZFeedbackDatasetZfrom_argilladatasetFileNotFoundErrorr   fields
ValueErrorprompts)	selfr   r   r   r   Zrge
extra_argsZsupported_fields	__class__r   r   r#   =   s    

*	6	zArgillaCallbackHandler.__init__)
serializedr3   kwargsr   c                 K   s$   | j t|d p|d |i dS )z.Save the prompts in memory when an LLM starts.parent_run_idrun_idN)r3   updatestr)r4   r9   r3   r:   r   r   r   on_llm_start   s    z#ArgillaCallbackHandler.on_llm_start)tokenr:   r   c                 K   s   dS )z)Do nothing when a new token is generated.Nr   )r4   r@   r:   r   r   r   on_llm_new_token   s    z'ArgillaCallbackHandler.on_llm_new_token)r   r:   r   c                    s   |d rdS | j t|d  }t||jD ]$\ }| jj fdd|D d q*| j t|d  t| jtdk r| j	  dS )z(Log records to Argilla when an LLM ends.r;   Nr<   c                    s    g | ]}d  |j  diqS )r1   r   r   )textstrip)r   Z
generationr   r   r   r       s   z5ArgillaCallbackHandler.on_llm_end.<locals>.<listcomp>recordsr   )
r3   r>   zipgenerationsr/   add_recordspopr   r%   push_to_argilla)r4   r   r:   r3   rI   r   rE   r   
on_llm_end   s    
z!ArgillaCallbackHandler.on_llm_end)errorr:   r   c                 K   s   dS )z%Do nothing when LLM outputs an error.Nr   r4   rN   r:   r   r   r   on_llm_error   s    z#ArgillaCallbackHandler.on_llm_error)r9   inputsr:   r   c                 K   sH   d|krD| j t|d p|d t|d tr6|d n|d gi dS )a  If the key `input` is in `inputs`, then save it in `self.prompts` using
        either the `parent_run_id` or the `run_id` as the key. This is done so that
        we don't log the same input prompt twice, once when the LLM starts and once
        when the chain starts.
        inputr;   r<   N)r3   r=   r>   
isinstancelist)r4   r9   rQ   r:   r   r   r   on_chain_start   s    
z%ArgillaCallbackHandler.on_chain_start)outputsr:   r   c                    s.  t  fddt|d t|d fD s.dS  jt|d p\tt jt|d g }| D ]V\}}t|tr j	j
dd t||D d qf j	j
d	d
|| digd qft|d  jkr jt|d  t|d  jkr jt|d  t jtdk r* j	  dS )zIf either the `parent_run_id` or the `run_id` is in `self.prompts`, then
        log the outputs to Argilla, and pop the run from `self.prompts`. The behavior
        differs if the output is a list or not.
        c                 3   s   | ]}| j kV  qd S )N)r3   )r   keyr4   r   r   	<genexpr>  s   z6ArgillaCallbackHandler.on_chain_end.<locals>.<genexpr>r;   r<   Nc                 S   s&   g | ]\}}d ||d   diqS )r1   rC   rB   )rD   )r   r   outputr   r   r   r      s   
z7ArgillaCallbackHandler.on_chain_end.<locals>.<listcomp>rF   r1    rB   r   )anyr>   r3   getr   r   itemsrS   rT   r/   rJ   rH   joinrD   rK   r   r%   rL   )r4   rV   r:   r3   Zchain_output_keyZchain_output_valr   rX   r   on_chain_end  s:     
z#ArgillaCallbackHandler.on_chain_endc                 K   s   dS )z+Do nothing when LLM chain outputs an error.Nr   rO   r   r   r   on_chain_error8  s    z%ArgillaCallbackHandler.on_chain_error)r9   	input_strr:   r   c                 K   s   dS )zDo nothing when tool starts.Nr   )r4   r9   rb   r:   r   r   r   on_tool_start<  s    z$ArgillaCallbackHandler.on_tool_start)actionr:   r   c                 K   s   dS )z.Do nothing when agent takes a specific action.Nr   )r4   rd   r:   r   r   r   on_agent_actionE  s    z&ArgillaCallbackHandler.on_agent_action)rZ   observation_prefix
llm_prefixr:   r   c                 K   s   dS )zDo nothing when tool ends.Nr   )r4   rZ   rf   rg   r:   r   r   r   on_tool_endI  s    z"ArgillaCallbackHandler.on_tool_endc                 K   s   dS )z&Do nothing when tool outputs an error.Nr   rO   r   r   r   on_tool_errorS  s    z$ArgillaCallbackHandler.on_tool_error)rC   r:   r   c                 K   s   dS z
Do nothingNr   )r4   rC   r:   r   r   r   on_textW  s    zArgillaCallbackHandler.on_text)finishr:   r   c                 K   s   dS rj   r   )r4   rl   r:   r   r   r   on_agent_finish[  s    z&ArgillaCallbackHandler.on_agent_finish)NNN)NN)!__name__
__module____qualname____doc__r   r>   __annotations__r   r   r   r   r#   r   r   r   r?   rA   r
   rM   BaseExceptionrP   rU   r`   ra   rc   r   re   rh   ri   rk   r   rm   __classcell__r   r   r7   r   r      sb   
+    
  
 
 2
	  
r   )r'   r)   typingr   r   r   r   r   Zlangchain_core.agentsr   r   Zlangchain_core.callbacksr	   Zlangchain_core.outputsr
   Zpackaging.versionr   r   r   r   r   r   <module>   s   