
    7|h%                         d 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 ddl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Z& G d de      Z'y)zMLX Chat Wrapper.    )
AnyCallableDictIteratorListLiteralOptionalSequenceTypeUnion)AsyncCallbackManagerForLLMRunCallbackManagerForLLMRun)LanguageModelInput)BaseChatModel)	AIMessageAIMessageChunkBaseMessageHumanMessageSystemMessage)ChatGenerationChatGenerationChunk
ChatResult	LLMResult)Runnable)BaseTool)convert_to_openai_tool)MLXPipelinez4You are a helpful, respectful, and honest assistant.c                       e Zd ZU dZeed<    ee      Zeed<   dZ	e
ed<   de
f 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d	ee   dedee   defdZdedefdZededefd       Zedefd       Z	 	 dd	ee   d
eee      dee   de
dee   f
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* xZ+S )ChatMLXa  MLX chat models.

    Works with `MLXPipeline` LLM.

    To use, you should have the ``mlx-lm`` python package installed.

    Example:
        .. code-block:: python

            from langchain_community.chat_models import chatMLX
            from langchain_community.llms import MLXPipeline

            llm = MLXPipeline.from_model_id(
                model_id="mlx-community/quantized-gemma-2b-it",
            )
            chat = chatMLX(llm=llm)

    llmcontentsystem_messageN	tokenizerkwargsc                 Z    t        |   di | | j                  j                  | _        y )N )super__init__r    r$   )selfr%   	__class__s     b/var/www/html/test/engine/venv/lib/python3.12/site-packages/langchain_community/chat_models/mlx.pyr)   zChatMLX.__init__D   s$    "6"++    messagesstoprun_managerreturnc                     | j                  |      } | j                  j                  d|g||d|}| j                  |      S N)promptsr/   r0   r'   )_to_chat_promptr    	_generate_to_chat_resultr*   r.   r/   r0   r%   	llm_input
llm_results          r,   r6   zChatMLX._generateH   sS     ((2	'TXX'' 
Kd
GM

 ##J//r-   c                    K   | j                  |      } | j                  j                  d|g||d| d {   }| j                  |      S 7 wr3   )r5   r    
_agenerater7   r8   s          r,   r<   zChatMLX._agenerateU   sa      ((2	.488.. 
Kd
GM
 

 ##J//
s   6AAAtokenizereturn_tensorsc                     |st        d      t        |d   t              st        d      |D cg c]  }| j                  |       }}| j                  j                  ||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!T)r=   add_generation_promptr>   )
ValueError
isinstancer   _to_chatml_formatr$   apply_chat_template)r*   r.   r=   r>   mmessages_dictss         r,   r5   zChatMLX._to_chat_promptb   sy     JKK(2,5CDD=EF$003FF~~11"&)	 2 
 	
 Gs   A)messagec                     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.system	assistantuserzUnknown message type: )roler"   )rC   r   r   r   rB   typer"   )r*   rH   rM   s      r,   rD   zChatMLX._to_chatml_formatw   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   r!   )rH   generation_info)generations
llm_output)rQ   r   r   textrP   appendr   rR   )r:   chat_generationsgchat_generations       r,   r7   zChatMLX._to_chat_result   sj    ''* 	5A,!!&&11CTCTO ##O4		5 (Z5J5J
 	
r-   c                      y)Nzmlx-chat-wrapperr'   )r*   s    r,   	_llm_typezChatMLX._llm_type   s    !r-   c              +     K   dd l m} ddlm} 	 dd l m} ddlm}m} ddlm} |j                  d| j                  j                        }	|	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         }| j                  j                  } ||
xs d|||      } |d ||      }t         ||| j                  j                   ||      t#        |            D ]  \  \  }}}d }t%        |t&              s*| j                  j)                  |j+                               }n| j                  j)                  |      }|r/t-        t/        |            }|r|j1                  ||       | ||k(  s|||v s y  y # t        $ r t        d      w xY ww)Nr   )generate_step)make_logits_processorsmake_samplerzTCould not import mlx_lm python package. Please install it with `pip install mlx_lm`.model_kwargstempg        
max_tokensd   repetition_penaltyrepetition_context_sizetop_pg      ?min_pmin_tokens_to_keep   Tnp)r=   r>   )samplerlogits_processorsr!   )rH   )chunk)mlx.corecoremlx_lm.utilsr[   mlx_lm.sample_utilsr\   r]   ImportErrorgetr    pipeline_kwargsr5   arrayr$   eos_token_idzipmodelrangerC   intdecodeitemr   r   on_llm_new_token)r*   r.   r/   r0   r%   mxr[   r\   r]   r^   r_   max_new_tokensrb   rc   rd   re   rf   r9   prompt_tokensrt   ri   rj   tokenprobnrS   rk   s                              r,   _streamzChatMLX._stream   s     	.		!P2 zz.$((2J2JK"&&vs3*..|SA.:.>.> $/
 2>1A1A%t2
 $''5#''5"."2"23G"K((DQU(V	1.~~22t{sE5:LM2$&=
 !$"3	 .!!
 	MUD1 #'DeS)~~,,UZZ\:~~,,U3 +N44PQ00U0C $)9ddl3	=  	? 	s(   HG4 GH+H0H4H		H)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.
        rg   zKWhen specifying `tool_choice`, you must provide exactly one tool. Received z tools.r   functionname)rN   r   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   rC   strbooldictr(   bind)r*   r   r   r%   toolformatted_toolsr+   s         r,   
bind_toolszChatMLX.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)NN)FN),__name__
__module____qualname____doc__r   __annotations__r   DEFAULT_SYSTEM_PROMPTr#   r$   r   r)   r   r   r	   r   r   r   r6   r   r<   r   r5   r   rD   staticmethodr   r7   propertyrY   r   r   r   r
   r   r   r   r   r   r   r   r   r   __classcell__)r+   s   @r,   r   r   ,   s7   & 
$1:O$PNMPIs, , %):>	0{#0 tCy!0 67	0
 0 
0  %)?C	0{#0 tCy!0 ;<	0
 0 
0  (,	
{#
 
 !	

 

*: : : 
I 
* 
 
 "3 " " %):>	F{#F tCy!F 67	F
 F 
%	&FX RV	6=d38ndHhFGH6= eD#w~/F$LMN	6=
 6= 
$k1	26= 6=r-   r   N)(r   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   langchain_core.outputsr   r   r   r   langchain_core.runnablesr   langchain_core.toolsr   %langchain_core.utils.function_callingr   %langchain_community.llms.mlx_pipeliner   r   r   r'   r-   r,   <module>r      sZ       > D   . ) H =R i=m i=r-   