
    +#hgL                        d 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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mZmZmZmZ ddl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+ ddl,m-Z- dZ.e G d d             Z/e G d d             Z0dedefdZ1de0defdZ2dede3fdZ4dede3fdZ5dede3fdZ6dede3fdZ7 G d d e      Z8y!)"zHugging Face Chat Wrapper.    )	dataclass)
AnyCallableDictListLiteralOptionalSequenceTypeUnioncast)AsyncCallbackManagerForLLMRunCallbackManagerForLLMRun)LanguageModelInput)BaseChatModel)	AIMessageBaseMessageChatMessageHumanMessageSystemMessageToolMessage)ChatGeneration
ChatResult	LLMResult)Runnable)BaseTool)convert_to_openai_tool)model_validator)Self)HuggingFaceEndpoint)HuggingFacePipelinez4You are a helpful, respectful, and honest assistant.c                   ,    e Zd ZU dZee   ed<   eed<   y)TGI_RESPONSEz'Response from the TextGenInference API.choicesusageN)__name__
__module____qualname____doc__r   r   __annotations__r        j/var/www/html/sandstorm/venv/lib/python3.12/site-packages/langchain_huggingface/chat_models/huggingface.pyr#   r#   ,   s    1#YKr,   r#   c                   6    e Zd ZU dZeed<   eed<   ee   ed<   y)TGI_MESSAGEz,Message to send to the TextGenInference API.rolecontent
tool_callsN)r&   r'   r(   r)   strr*   r   r   r+   r,   r-   r/   r/   4   s    6
ILT
r,   r/   messagereturnc                 6   t        | t              r!t        | j                  | j                        S t        | t
              rt        d| j                        S t        | t              rNd| j                  v r.| j                  d   D cg c]  }d|d   d   |d   d   di }}nd }d| j                  |d	S t        | t              rt        d
| j                        S t        | t              rd| j                  | j                  dS t        d|        c c}w )Nr0   r1   userr2   functionname	arguments)r:   r;   	assistant)r0   r1   r2   systemtool)r0   r1   r:   zGot unknown type )
isinstancer   dictr0   r1   r   r   additional_kwargsr   r   r:   
ValueError)r4   tcr2   s      r-    _convert_message_to_chat_messagerD   =   s    ';'w??	G\	*99	GY	'7444 "33LA   ":v 6%'
^K%@!J  J$
 	

 
G]	+7??;;	G[	)LL
 	
 ,WI6773s   D_messagec                 F   | j                   }|dk(  s
J d|        t        t        | j                        }|d}i }| j                  x}rLd|d   d   v r=t        |d   d   j                  d            }|j                  dd      }||d   d   d<   ||d	<   t        ||
      S )Nr<   z%Expected role to be 'assistant', got  r;   r   r9   '"r2   )r1   rA   )r0   r   r3   r1   r2   popreplacer   )rE   r0   r1   rA   r2   functions_stringcorrected_functionss          r-   "_convert_TGI_message_to_LC_messagerN   b   s     ==D;N"Gv NN3(()G (((z(*Q-
33":a=#<#@#@#MN"2":":3"D5HJqM*%k2*4,'W8IJJr,   llmc                 F    	 ddl m} t        | |      S # t        $ r Y yw xY w)Nr   )HuggingFaceHubF)(langchain_community.llms.huggingface_hubrQ   r?   ImportError)rO   rQ   s     r-   _is_huggingface_hubrT   t   s-    	
 #~..     	  c                 F    	 ddl m} t        | |      S # t        $ r Y yw xY w)Nr   )HuggingFaceTextGenInferenceF)7langchain_community.llms.huggingface_text_gen_inferencerW   r?   rS   )rO   rW   s     r-   !_is_huggingface_textgen_inferencerY      s.    	
 #:;; rU   c                 "    t        | t              S N)r?   r    rO   s    r-   _is_huggingface_endpointr]          c.//r,   c                 "    t        | t              S r[   )r?   r!   r\   s    r-   _is_huggingface_pipeliner`      r^   r,   c                       e Zd ZU dZeed<   	  ee      Zeed<   dZ	eed<   dZ
ee   ed<   def fd	Z ed
      defd       ZdedefdZ	 	 d"dee   deee      dee   dedef
dZ	 	 d"dee   deee      dee   dedef
dZdee   defdZdedefdZededefd       Zd#dZ ddde!e"e#eef   e$e%e&f      dee"eee'd   e(f      dede)e*ef   f fdZ+dee   deee      dee#eef      fd Z,e-defd!       Z. xZ/S )$ChatHuggingFaceu  Hugging Face LLM's as ChatModels.

    Works with `HuggingFaceTextGenInference`, `HuggingFaceEndpoint`,
    `HuggingFaceHub`, and `HuggingFacePipeline` LLMs.

    Upon instantiating this class, the model_id is resolved from the url
    provided to the LLM, and the appropriate tokenizer is loaded from
    the HuggingFace Hub.

    Setup:
        Install ``langchain-huggingface`` and ensure your Hugging Face token
        is saved.

        .. code-block:: bash

            pip install langchain-huggingface

        .. code-block:: python

            from huggingface_hub import login
            login() # You will be prompted for your HF key, which will then be saved locally

    Key init args — completion params:
        llm: `HuggingFaceTextGenInference`, `HuggingFaceEndpoint`, `HuggingFaceHub`, or
            'HuggingFacePipeline' LLM to be used.

    Key init args — client params:
        custom_get_token_ids: Optional[Callable[[str], List[int]]]
            Optional encoder to use for counting tokens.
        metadata: Optional[Dict[str, Any]]
            Metadata to add to the run trace.
        tags: Optional[List[str]]
            Tags to add to the run trace.
        tokenizer: Any
        verbose: bool
            Whether to print out response text.

    See full list of supported init args and their descriptions in the params
    section.

    Instantiate:
        .. code-block:: python

            from langchain_huggingface import HuggingFaceEndpoint,
            ChatHuggingFace

            llm = HuggingFaceEndpoint(
                repo_id="microsoft/Phi-3-mini-4k-instruct",
                task="text-generation",
                max_new_tokens=512,
                do_sample=False,
                repetition_penalty=1.03,
            )

            chat = ChatHuggingFace(llm=llm, verbose=True)

    Invoke:
        .. code-block:: python

            messages = [
                ("system", "You are a helpful translator. Translate the user
                sentence to French."),
                ("human", "I love programming."),
            ]

            chat(...).invoke(messages)

        .. code-block:: python

            AIMessage(content='Je ai une passion pour le programme.

In
            French, we use "ai" for masculine subjects and "a" for feminine
            subjects. Since "programming" is gender-neutral in English, we
            will go with the masculine "programme".

Confirmation: "J'aime
            le programme." is more commonly used. The sentence above is
            technically accurate, but less commonly used in spoken French as
            "ai" is used less frequently in everyday speech.',
            response_metadata={'token_usage': ChatCompletionOutputUsage
            (completion_tokens=100, prompt_tokens=55, total_tokens=155),
            'model': '', 'finish_reason': 'length'},
            id='run-874c24b7-0272-4c99-b259-5d6d7facbc56-0')

    Stream:
        .. code-block:: python

            for chunk in chat.stream(messages):
                print(chunk)

        .. code-block:: python

            content='Je ai une passion pour le programme.

In French, we use
            "ai" for masculine subjects and "a" for feminine subjects.
            Since "programming" is gender-neutral in English,
            we will go with the masculine "programme".

Confirmation:
            "J'aime le programme." is more commonly used. The sentence
            above is technically accurate, but less commonly used in spoken
            French as "ai" is used less frequently in everyday speech.'
            response_metadata={'token_usage': ChatCompletionOutputUsage
            (completion_tokens=100, prompt_tokens=55, total_tokens=155),
            'model': '', 'finish_reason': 'length'}
            id='run-7d7b1967-9612-4f9a-911a-b2b5ca85046a-0'

    Async:
        .. code-block:: python

            await chat.ainvoke(messages)

        .. code-block:: python

            AIMessage(content='Je déaime le programming.

Littérale : Je
            (j'aime) déaime (le) programming.

Note: "Programming" in
            French is "programmation". But here, I used "programming" instead
            of "programmation" because the user said "I love programming"
            instead of "I love programming (in French)", which would be
            "J'aime la programmation". By translating the sentence
            literally, I preserved the original meaning of the user's
            sentence.', id='run-fd850318-e299-4735-b4c6-3496dc930b1d-0')

    Tool calling:
        .. code-block:: python

            from pydantic import BaseModel, Field

            class GetWeather(BaseModel):
                '''Get the current weather in a given location'''

                location: str = Field(..., description="The city and state,
                e.g. San Francisco, CA")

            class GetPopulation(BaseModel):
                '''Get the current population in a given location'''

                location: str = Field(..., description="The city and state,
                e.g. San Francisco, CA")

            chat_with_tools = chat.bind_tools([GetWeather, GetPopulation])
            ai_msg = chat_with_tools.invoke("Which city is hotter today and
            which is bigger: LA or NY?")
            ai_msg.tool_calls

        .. code-block:: python

            [{'name': 'GetPopulation',
              'args': {'location': 'Los Angeles, CA'},
              'id': '0'}]

    Response metadata
        .. code-block:: python

            ai_msg = chat.invoke(messages)
            ai_msg.response_metadata

        .. code-block:: python
            {'token_usage': ChatCompletionOutputUsage(completion_tokens=100,
            prompt_tokens=8, total_tokens=108),
             'model': '',
             'finish_reason': 'length'}

    rO   r1   system_messageN	tokenizermodel_idkwargsc                     t        |   di | ddlm} | j	                          | j
                  !|j                  | j                        | _        y | j
                  | _        y )Nr   )AutoTokenizerr+   )super__init__transformersri   _resolve_model_idre   from_pretrainedrf   )selfrg   ri   	__class__s      r-   rk   zChatHuggingFace.__init__<  sY    "6".  ~~% ))$--8 	  	r,   after)moder5   c                     t        | j                        s`t        | j                        sKt        | j                        s6t	        | j                        s!t        dt        | j                               | S )NzyExpected llm to be one of HuggingFaceTextGenInference, HuggingFaceEndpoint, HuggingFaceHub, HuggingFacePipeline received )rT   rO   rY   r]   r`   	TypeErrortypero   s    r-   validate_llmzChatHuggingFace.validate_llmI  s`     $DHH-5dhh?,TXX6,TXX6 N+- 
 r,   responsec                     g }|j                   d   j                  }t        t        |j                   d   j                        d|i      }|j                  |       |j                  }| j                  j                  }||d}t        ||      S )Nr   finish_reasonr4   generation_info)token_usagemodelgenerations
llm_output)
r$   rz   r   rN   r4   appendr%   rO   inference_server_urlr   )ro   rx   r   rz   genr}   model_objectr   s           r-   _create_chat_resultz#ChatHuggingFace._create_chat_resultX  s     ((+996x7G7G7J7R7RS,m<
 	3nnxx44%0<H
kjIIr,   messagesstoprun_managerc                    t        | j                        rK| j                  ||      } | j                  j                  j                  dd|i|}| j                  |      S t        | j                        rK| j                  ||      } | j                  j                  j                  dd|i|}| j                  |      S | j                  |      } | j                  j                  d|g||d|}| j                  |      S Nr   )promptsr   r   r+   )rY   rO   _create_message_dictsclientchatr   r]   chat_completion_to_chat_prompt	_generate_to_chat_result	ro   r   r   r   rg   message_dictsanswer	llm_input
llm_results	            r-   r   zChatHuggingFace._generatee  s     -TXX6 66xFM)TXX__))K=KFKF++F33%dhh/ 66xFM4TXX__44VmVvVF++F33,,X6I+++ "$KKQJ ''
33r,   c                 x  K   t        | j                        rS| j                  ||      } | j                  j                  j                  dd|i| d {   }| j                  |      S | j                  |      } | j                  j                  d|g||d| d {   }| j                  |      S 7 `7 wr   )	rY   rO   r   async_clientr   r   r   
_agenerater   r   s	            r-   r   zChatHuggingFace._agenerate{  s      -TXX6 66xFM54880055W}WPVWWF++F33,,X6I2txx22  "$K KQ  J ''
33 Xs%   AB:B6A
B: B8!B:8B:c                     |st        d      t        |d   t              st        d      |D cg c]  }| j                  |       }}| j                  j                  |dd      S c c}w )zHConvert a list of messages into a prompt format expected by wrapped LLM.z+At least one HumanMessage must be provided!z$Last message must be a HumanMessage!FT)tokenizeadd_generation_prompt)rB   r?   r   _to_chatml_formatre   apply_chat_template)ro   r   mmessages_dictss       r-   r   zChatHuggingFace._to_chat_prompt  st    
 JKK(2,5CDD=EF$003FF~~11U$ 2 
 	
 Gs   A(r4   c                     t        |t              rd}n=t        |t              rd}n*t        |t              rd}nt	        dt        |             ||j                  dS )z+Convert LangChain message to ChatML format.r=   r<   r8   zUnknown message type: r7   )r?   r   r   r   rB   ru   r1   )ro   r4   r0   s      r-   r   z!ChatHuggingFace._to_chatml_format  sW     g}-D+D.D5d7m_EFF99r,   r   c                     g }| j                   d   D ]>  }t        t        |j                        |j                        }|j                  |       @ t        || j                        S )Nr   rc   r{   r   )r   r   r   textr|   r   r   r   )r   chat_generationsgchat_generations       r-   r   zChatHuggingFace._to_chat_result  sj    ''* 	5A,!!&&11CTCTO ##O4		5 (Z5J5J
 	
r,   c                 F   ddl m} t        | j                        s,t	        | j                  d      r2| j                  j
                  r| j                  j
                  | _        yt        | j                        r| j                  j                  }nGt        | j                        r| j                  j                  | _        y| j                  j                  } |d      }|D ]#  }|j                  |k(  s|j                  | _        % | j                  st        d| d      y)z8Resolve the model_id from the LLM's inference_server_urlr   )list_inference_endpointsrepo_idN*zIFailed to resolve model_id:Could not find model id for inference server: zBMake sure that your Hugging Face token has access to the endpoint.)huggingface_hubr   rT   rO   hasattrr   rf   rY   r   r`   endpoint_urlurl
repositoryrB   )ro   r   r   available_endpointsendpoints        r-   rm   z!ChatHuggingFace._resolve_model_id  s     	=txx(DHHi(TXX-=-= HH,,DM.txx8*.((*G*GL%dhh/ HH--DM8800L6s;+ 	4H|||+ ( 3 3	4 }}AAMTU  r,   )tool_choicetoolsr   autononec                   |D cg c]  }t        |       }}||rt        |      dk7  rt        dt        |       d      t        |t              r|dvrkdd|id}nct        |t
              r|d   }nMt        |t              r/|d   d   d   |d   d   k7  r)t        d	| d
|d   d   d    d      t        d|       ||d<   t        |    dd|i|S c c}w )a*  Bind tool-like objects to this chat model.

        Assumes model is compatible with OpenAI tool-calling API.

        Args:
            tools: A list of tool definitions to bind to this chat model.
                Supports any tool definition handled by
                :meth:`langchain_core.utils.function_calling.convert_to_openai_tool`.
            tool_choice: Which tool to require the model to call.
                Must be the name of the single provided function or
                "auto" to automatically determine which function to call
                (if any), or a dict of the form:
                {"type": "function", "function": {"name": <<tool_name>>}}.
            **kwargs: Any additional parameters to pass to the
                :class:`~langchain.runnable.Runnable` constructor.
           zKWhen specifying `tool_choice`, you must provide exactly one tool. Received z tools.r   r9   r:   )ru   r9   r   zTool choice z/ was specified, but the only provided tool was .zEUnrecognized tool_choice type. Expected str, bool or dict. Received: r   r   r+   )	r   lenrB   r?   r3   boolr@   rj   bind)ro   r   r   rg   r>   formatted_toolsrp   s         r-   
bind_toolszChatHuggingFace.bind_tools  sE   0 EJJD1$7JJ"{?#q( &&)/&:%;7D  +s+&66 *%+[$9#K K.-a0K.#A&z26:":.v67 %&{m 4--<Q-?
-KF-S,TTUW 
 !!!,/  %0F=!w|</<V<<= Ks   Cc                 @    |D cg c]  }t        |       }}|S c c}w r[   )rD   )ro   r   r   r   r   s        r-   r   z%ChatHuggingFace._create_message_dicts  s+     GOO9!<OO Ps   c                      y)Nzhuggingface-chat-wrapperr+   rv   s    r-   	_llm_typezChatHuggingFace._llm_type  s    )r,   )NN)r5   N)0r&   r'   r(   r)   r   r*   r   DEFAULT_SYSTEM_PROMPTrd   re   rf   r	   r3   rk   r   r   rw   r#   r   r   r   r   r   r   r   r   r   r@   r   staticmethodr   r   rm   r
   r   r   r   r   r   r   r   r   r   r   r   propertyr   __classcell__)rp   s   @r-   rb   rb      s?   ]~ 
H3 %2:O$PNMPIs"Hhsm"
 
 '"d  #JL JZ J  %):>	4{#4 tCy!4 67	4
 4 
42 %)?C	4{#4 tCy!4 ;<	4
 4 
4$
{#
 

": : : 
I 
* 
 
B RV	6=d38ndHhFGH6= eD#w~/F$LMN	6=
 6= 
$k1	26=p[)19$s)1D	d38n	 *3 * *r,   rb   N)9r)   dataclassesr   typingr   r   r   r   r   r	   r
   r   r   r    langchain_core.callbacks.managerr   r   langchain_core.language_modelsr   *langchain_core.language_models.chat_modelsr   langchain_core.messagesr   r   r   r   r   r   langchain_core.outputsr   r   r   langchain_core.runnablesr   langchain_core.toolsr   %langchain_core.utils.function_callingr   pydanticr   typing_extensionsr   /langchain_huggingface.llms.huggingface_endpointr    /langchain_huggingface.llms.huggingface_pipeliner!   r   r#   r/   rD   rN   r   rT   rY   r]   r`   rb   r+   r,   r-   <module>r      s     !   > D  I H - ) H $ " O OR       "8"8	"8JKKK$	S 	T 		3 	4 	0# 0$ 00# 0$ 0C*m C*r,   