o
    5ti0G                     @   s  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 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 d dlmZ d dlmZ d d	lmZ eeZG d
d deZdeddfddZ eddde	e!e!f fddZ"edG dd deZ#dS )    N)	lru_cache)AnyDictList
NamedTupleOptionalTupleTypecast)tqdm)Instance)LM)register_model)JsonChatStr)simple_parse_args_stringc                   @   s   e Zd ZU eed< eed< dS )LogLikelihoodResultlog_likelihood	is_greedyN)__name__
__module____qualname__float__annotations__bool r   r   Q/home/ubuntu/.local/lib/python3.10/site-packages/lm_eval/models/ibm_watsonx_ai.pyr      s   
 r   credsreturnc                    s   dddddddd}t  fd	d
dD p d}d v o! d }t fdd
dD }|r3|r3|srg }|sB|d|d  d |sO|d|d  d |sa|d|d  d|d  d dd| d}|d7 }t|dS )z
    Validate credentials for APIClient authentication.

    Required conditions:
    - Either ("username" and "password") or "apikey" must be present.
    - "url" is mandatory.
    - Either "project_id" or "space_id" must be present.
    WATSONX_API_KEYWATSONX_TOKENWATSONX_URLWATSONX_PROJECT_IDWATSONX_SPACE_IDWATSONX_USERNAMEWATSONX_PASSWORD)apikeytokenurl
project_idspace_idusernamepasswordc                 3       | ]}  |V  qd S Nget.0keyr   r   r   	<genexpr>.       z&_verify_credentials.<locals>.<genexpr>)r*   r+   r%   r'   c                 3   r,   r-   r.   r0   r3   r   r   r4   4   r5   )r(   r)   z0either ('username' and 'password') or 'apikey' ()zurl (zeither 'project_id' (r(   z) or 'space_id' (r)   zMissing required credentials: z, z. z>Please set the environment variables indicated in parentheses.N)allr/   anyappendjoin
ValueError)r   env_var_maphas_authhas_urlhas_project_or_space_idmissing_keys	error_msgr   r3   r   _verify_credentials   s:   
rB   )maxsizec               
      s   zddl m}  W n ty   tdw |   tddtddtddtddtd	dtd
dtddd d d vrGd d< t fdddD rWtd t   S )a  
    Retrieves Watsonx API credentials from environmental variables.
    Returns:
        Dict[str, str]: A dictionary containing the credentials necessary for authentication, including
                        keys such as `apikey` or `token`, `url`, and `project_id`.
    Raises:
        AssertionError: If the credentials format is invalid or any of the necessary credentials are missing.
    r   load_dotenvzHCould not import dotenv: Please install lm_eval[ibm_watsonx_ai] package.r#   Nr$   r   r   r    r!   r"   )r*   r+   r%   r&   r'   r(   r)   zcloud.ibm.comr'   	openshiftinstance_idc                 3   r,   r-   r.   r0   credentialsr   r   r4   i   r5   z*get_watsonx_credentials.<locals>.<genexpr>)r*   r+   r%   zYou're passing `username`, `password`, and `apikey` at the same time, which might cause issues. More info on authentication in different scenarios can be found in the docs: https://ibm.github.io/watsonx-ai-python-sdk/setup_cpd.html)	dotenvrE   ImportErrorosgetenvr7   warningswarnrB   rD   r   rH   r   get_watsonx_credentialsH   s0   







	rP   watsonx_llmc                
       sR  e Zd ZdZe	d"ded  dedee dd fddZ		d"d	ed
eee
e
f  ddf fddZedee dee defddZdd Zdeeeef  deeeef  defddZdee dee fddZdee deeeef  fddZdeeeef  fddZedefddZdeeeef  deeeef  fd d!Z  ZS )#
WatsonxLLMz
    Implementation of LM model interface for evaluating Watsonx model with the lm_eval framework.
    See https://github.com/EleutherAI/lm-evaluation-harness/blob/main/docs/model_guide.md for reference.
    Ncls
arg_stringadditional_configr   c                 C   s~  zddl m} W n ty   tdw t|}|| |dd}|dd}|du r5|du r5td|ddsKd|d	< d|d
< d|d< d|d< |j|ddsUdnd|j	|dd|j
|d	d|j|d
d|j|dd|j|dd|j|dd|j|dd|j|dd|j|dd|j|dd|j|dd|jdddddi}dd | D }| t |||dS )zi
        Allow the user to specify model parameters (TextGenerationParameters) in CLI arguments.
        r   GenTextParamsMetaNamesPCould not import ibm_watsonx_ai: Please install lm_eval[ibm_watsonx_ai] package.model_idNdeployment_idzI'model_id' or 'deployment_id' is required, please pass it in 'model_args'	do_sampletemperaturetop_ptop_kseedgreedysamplelength_penaltyrepetition_penaltymin_new_tokensmax_new_tokens   stop_sequences
time_limittruncate_input_tokensT)generated_tokensinput_tokenstoken_logprobstoken_ranksc                 S   s   i | ]\}}|d ur||qS r-   r   )r1   kvr   r   r   
<dictcomp>   s    z5WatsonxLLM.create_from_arg_string.<locals>.<dictcomp>)watsonx_credentialsrY   rZ   generate_params)ibm_watsonx_ai.metanamesrW   rK   r   updatepopr;   r/   DECODING_METHODLENGTH_PENALTYTEMPERATURETOP_PTOP_KRANDOM_SEEDREPETITION_PENALTYMIN_NEW_TOKENSMAX_NEW_TOKENSSTOP_SEQUENCES
TIME_LIMITTRUNCATE_INPUT_TOKENSRETURN_OPTIONSitemsrP   )rS   rT   rU   	GenParamsargsrY   rZ   rr   r   r   r   create_from_arg_stringz   s^   	
z!WatsonxLLM.create_from_arg_stringrq   rr   c           	         s   zddl m} ddlm} W n ty   tdw t   ||}|dd }|j	| || _
|||||d| _|| _d S )Nr   )	APIClient)ModelInferencerX   r(   )rY   rZ   
api_clientr(   )ibm_watsonx_air    ibm_watsonx_ai.foundation_modelsr   rK   super__init__r/   setdefault_projectrr   model	_model_id)	selfrq   rY   rZ   rr   r   r   clientr(   	__class__r   r   r      s(   

zWatsonxLLM.__init__response_tokenscontext_tokensc                 C   sP   t |}| d|d  |dd kr| d |d kS td| d| d|  )a7  
        Determines whether a stop token has been generated in the `response_tokens` compared to the `context_tokens`.
        If the tokens do not match as expected, the function raises a RuntimeError, indicating a possible
        misalignment between the tokens generated by the tokenizer and the model.
        Args:
            response_tokens (List[str]): The List of tokens generated as a response by the model.
            context_tokens (List[str]): The List of tokens representing the input context.
        Returns:
            bool: True if the `response_tokens` likely contain a stop token that terminates the sequence,
                  otherwise raises an exception.
        Raises:
            RuntimeError: If there is an unexpected mismatch between the `response_tokens` and the `context_tokens`.
        N   zUThere is an unexpected difference between tokenizer and model tokens:
context_tokens=z
response_tokens=)lenRuntimeError)r   r   context_lengthr   r   r   _has_stop_token   s   
zWatsonxLLM._has_stop_tokenc                 C   sN   | j jdg| jddd d d }tdd |d D r%td	| j d
dS )a  
        Verifies if the model supports returning log probabilities for input tokens.
        This function sends a prompt to the model and checks whether the model's response
        includes log probabilities for the input tokens. If log probabilities are not present,
        it raises a `RuntimeError`, indicating that the model is not supported.
        Raises:
            RuntimeError: If the model does not return log probabilities for input tokens.
        zThe best ice cream flavor is:Tpromptparamsraw_responser   resultsc                 s   s     | ]}| d ddu V  qdS )logprobNr.   r1   r&   r   r   r   r4      s    z;WatsonxLLM._check_model_logprobs_support.<locals>.<genexpr>rk   zModel z< is not supported: does not return logprobs for input tokensN)r   generate_textrr   r7   r   r   )r   tokensr   r   r   _check_model_logprobs_support   s    	z(WatsonxLLM._check_model_logprobs_supportrk   c                 C   sb   dd |D }t |}| ||r|d8 }ttdd ||d D tdd ||d D dS )	aK  
        Calculates the log likelihood of the generated tokens compared to the context tokens.
        Args:
            input_tokens (List[Dict[str, float]]): A List of token dictionaries, each containing
                token information like `text` and `logprob`.
            context_tokens (List[Dict[str, float]]): A List of token dictionaries representing
                the input context.
        Returns:
            LogLikelihoodResult: An object containing the calculated log likelihood and a boolean
            flag indicating if the tokens were generated greedily.
        c                 S   s   g | ]}|d  qS )textr   r   r   r   r   
<listcomp>  s    z2WatsonxLLM._get_log_likelihood.<locals>.<listcomp>r   c                 s   s    | ]	}| d dV  qdS )r   r   Nr.   r   r   r   r   r4         
z1WatsonxLLM._get_log_likelihood.<locals>.<genexpr>Nc                 s   s    | ]	}|d  dkV  qdS )rankr   Nr   r   r   r   r   r4     r   )r   r   )r   r   r   sumr7   )r   rk   r   r   r   r   r   r   _get_log_likelihood  s   

zWatsonxLLM._get_log_likelihoodrequestsc                 C   s   dd |D }g }t |ddD ]Q}|\}}z(t|tr4t|j}| j|| j}|d d d d }n| j	|| j}W n t
yP } ztd	 |d
}~ww || | jd||f| q|S )a%  
        Generates text responses for a List of requests, with progress tracking and caching.
        Args:
            requests (List[Instance]): A List of instances, each containing a text input to be processed.
        Returns:
            List[str]: A List of generated responses.
        c                 S      g | ]}|j qS r   r   r1   requestr   r   r   r   *      z-WatsonxLLM.generate_until.<locals>.<listcomp>z#Running generate_until function ...descchoicesr   messagecontentzError while generating text.Ngenerate_until)r   
isinstancer   jsonloadsr   r   chatrr   r   	Exceptioneval_loggererrorr9   
cache_hookadd_partial)r   r   r   r   contextcontinuationresponseexpr   r   r   r   "  s0   




zWatsonxLLM.generate_untilc                 C   sP  zddl m} W n ty   tdw |   t| j}d||j< dd |D }g }t|ddD ]j}|\}}z| jj	|d	d
d d }W n t
yY }	 ztd |	d}	~	ww || }
z| jj|
|d	d}W n t
y| }	 ztd |	d}	~	ww | |d d d |}|| | jd||f|j|jf q2tttttf  |S )a  
        Args:
            requests: Each request contains Instance.args : Tuple[str, str] containing:
                1. an input string to the LM and
                2. a target string on which the loglikelihood of the LM producing this target,
                   conditioned on the input, will be returned.
        Returns:
            Tuple (loglikelihood, is_greedy) for each request according to the input order:
                loglikelihood: probability of generating the target string conditioned on the input
                is_greedy: True if and only if the target string would be generated by greedy sampling from the LM
        r   rV   rX   r   c                 S   r   r   r   r   r   r   r   r   Z  r   z,WatsonxLLM.loglikelihood.<locals>.<listcomp>z"Running loglikelihood function ...r   T)r   return_tokensresultr   zError while model tokenize.Nr    Error while model generate text.r   rk   loglikelihood)rs   rW   rK   r   copyrr   r~   r   r   tokenizer   r   r   r   r   r9   r   r   r   r   r
   r   r   r   r   )r   r   r   rr   r   r   r   r   tokenized_contextr   input_promptr   log_likelihood_responser   r   r   r   D  sh   





	zWatsonxLLM.loglikelihoodc                 C   s   zddl m} W n ty   tdw |   t| j}d||j< dd |D }g }t|ddD ]A}|\}}z| j	j
||d	d
}W n tyV }	 ztd |	d}	~	ww | |d d d g }
||
 | jd||f|
j q2tttttf  |S )a  
        Used to evaluate perplexity on a data distribution.
        Args:
            requests: Each request contains Instance.args : Tuple[str] containing an input string to the model whose
                entire loglikelihood, conditioned on purely the EOT token, will be calculated.
        Returns:
            Tuple (loglikelihood,) for each request according to the input order:
                loglikelihood: solely the probability of producing each piece of text given no starting input.
        r   rV   rX   r   c                 S   r   r   r   r   r   r   r   r     r   z4WatsonxLLM.loglikelihood_rolling.<locals>.<listcomp>z*Running loglikelihood_rolling function ...r   Tr   r   Nr   rk   loglikelihood_rolling)rs   rW   rK   r   r   deepcopyrr   r~   r   r   r   r   r   r   r   r9   r   r   r   r
   r   r   r   r   )r   r   r   rr   r   r   r   r   r   r   r   r   r   r   r     sH   





z WatsonxLLM.loglikelihood_rollingc                 C   s   dS )N r   )r   r   r   r   tokenizer_name  s   zWatsonxLLM.tokenizer_namechat_historyc                 C   s   t t|S r-   )r   r   dumps)r   r   r   r   r   apply_chat_template  s   zWatsonxLLM.apply_chat_templater-   )r   r   r   __doc__classmethodr	   strr   r   r   r   r   staticmethodr   r   r   r   r   r   r   r   r   r   r   r   propertyr   r   __classcell__r   r   r   r   rR   s   sR    D 
 ""@1rR   )$r   r   loggingrL   rN   	functoolsr   typingr   r   r   r   r   r   r	   r
   r   lm_eval.api.instancer   lm_eval.api.modelr   lm_eval.api.registryr   lm_eval.models.api_modelsr   lm_eval.utilsr   	getLoggerr   r   r   dictrB   r   rP   rR   r   r   r   r   <module>   s(    (
.*