a
    dgG                     @   s  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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 d d	l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) d dl*m+Z+ d dl,m-Z- d dl.m/Z/ d dl0m1Z1m2Z2 d dl3m4Z4 dZ5dddddddidgddZ6ede4dZ7eee7f Z8ee9d d!d"Z:eed#d$d%Z;G d&d' d'eZ<ee=d(d)d*Z>ed+d,d-d.G d/d0 d0eZ?dS )1    N)
itemgetter)
AnyCallableDictListOptionalSequenceType	TypedDictTypeVarUnion)
ChatOllama)
deprecated)AsyncCallbackManagerForLLMRunCallbackManagerForLLMRun)LanguageModelInput)	AIMessageBaseMessageToolCall)OutputParserLike)JsonOutputParser)PydanticOutputParser)ChatGeneration
ChatResult)SystemMessagePromptTemplate)RunnableRunnableLambda)RunnableMap)RunnablePassthrough)BaseTool)is_basemodel_instanceis_basemodel_subclass)	BaseModela%  You have access to the following tools:

{tools}

You must always select one of the above tools and respond with only a JSON object matching the following schema:

{{
  "tool": <name of the selected tool>,
  "tool_input": <parameters for the selected tool, matching the tool's JSON schema>
}}
Z__conversational_responsezNRespond conversationally if no other tools should be called for a given query.objectresponsestringz$Conversational response to the user.)typedescription)r&   
propertiesrequired)namer'   
parameters_BM)bound)objreturnc                 C   s   t | tot| pt| jv S N)
isinstancer&   r!   r"   	__bases__)r.    r3   z/var/www/html/cobodadashboardai.evdpl.com/venv/lib/python3.9/site-packages/langchain_experimental/llms/ollama_functions.py_is_pydantic_classL   s    
r5   )toolr/   c                 C   s   d}t | r"|   }|d }nt| trF| j }|  }| j}n\t| rj| 	  }|  }| j}n8t| t
rd| v rd| v r|  S td|  d|  d||d}|r||d	< |S )
z!Convert a tool to an Ollama tool.Ntitler*   r+   zCannot convert z! to an Ollama tool. 
            z0 needs to be a Pydantic class, model, or a dict.)r*   r+   r'   )r5   Zmodel_constructZmodel_json_schemar1   r   Ztool_call_schemaget_namer'   r    Zget_input_schemadictcopy
ValueError)r6   r'   schemar*   Z
definitionr3   r3   r4   convert_to_ollama_toolR   s.    



r=   c                   @   s.   e Zd ZU eed< ee ed< ee ed< dS )_AllReturnTyperawparsedparsing_errorN)__name__
__module____qualname__r   __annotations__r   _DictOrPydanticBaseExceptionr3   r3   r3   r4   r>   n   s   
r>   )messager/   c                 C   s   t | trv| j}| j}t|dkr>|d }|d}t|S d|v rnd|d v r^|d d S td|  ntdtd|  d	S )
z)Extract `function_call` from `AIMessage`.r   argsfunction_call	argumentsz;`arguments` missing from `function_call` within AIMessage: z.`tool_calls` missing from AIMessage: {message}z-`message` is not an instance of `AIMessage`: N)	r1   r   additional_kwargs
tool_callslengetjsondumpsr;   )rH   kwargsrN   Z	tool_callrJ   r3   r3   r4   parse_responset   s    


rT   z0.0.64z1.0zlangchain_ollama.ChatOllama)ZsinceZremovalZalternative_importc                	       s  e Zd ZU dZeZeed< edd fddZ	e
eeeef ee eef  eeeef ddd	Zd
deeee f eeeeeeef f dddZdee eee  ee eed fddZdee eee  ee eed fddZeedddZ  Z S )OllamaFunctionsz)Function chat model that uses Ollama API.tool_system_prompt_templateN)rS   r/   c                    s   t  jf i | d S r0   )super__init__)selfrS   	__class__r3   r4   rX      s    zOllamaFunctions.__init__)toolsrS   r/   c                 K   s   | j f d|i|S )N	functions)bind)rY   r\   rS   r3   r3   r4   
bind_tools   s    zOllamaFunctions.bind_toolsF)include_raw)r<   r`   rS   r/   c                K   s   |rt d| t|}|du r*t d| j|gdd}|rJt|d}nt }tt|B }|rtjt	d|B dd	 d
}tjdd	 d}	|j
|	gdd}
t|d|
B S ||B S dS )a   Model wrapper that returns outputs formatted to match the given schema.

        Args:
            schema: The output schema as a dict or a Pydantic class. If a Pydantic class
                then the model output will be an object of that class. If a dict then
                the model output will be a dict. With a Pydantic class the returned
                attributes will be validated, whereas with a dict they will not be.
            include_raw: If False then only the parsed structured output is returned. If
                an error occurs during model output parsing it will be raised. If True
                then both the raw model response (a BaseMessage) and the parsed model
                response will be returned. If an error occurs during output parsing it
                will be caught and returned as well. The final output is always a dict
                with keys "raw", "parsed", and "parsing_error".

        Returns:
            A Runnable that takes any ChatModel input and returns as output:

                If include_raw is True then a dict with keys:
                    raw: BaseMessage
                    parsed: Optional[_DictOrPydantic]
                    parsing_error: Optional[BaseException]

                If include_raw is False then just _DictOrPydantic is returned,
                where _DictOrPydantic depends on the schema:

                If schema is a Pydantic class then _DictOrPydantic is the Pydantic
                    class.

                If schema is a dict then _DictOrPydantic is a dict.

        Example: Pydantic schema (include_raw=False):
            .. code-block:: python

                from langchain_experimental.llms import OllamaFunctions
                from pydantic import BaseModel

                class AnswerWithJustification(BaseModel):
                    '''An answer to the user question along with justification for the answer.'''
                    answer: str
                    justification: str

                llm = OllamaFunctions(model="phi3", format="json", temperature=0)
                structured_llm = llm.with_structured_output(AnswerWithJustification)

                structured_llm.invoke("What weighs more a pound of bricks or a pound of feathers")

                # -> AnswerWithJustification(
                #     answer='They weigh the same',
                #     justification='Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume or density of the objects may differ.'
                # )

        Example: Pydantic schema (include_raw=True):
            .. code-block:: python

                from langchain_experimental.llms import OllamaFunctions
                from pydantic import BaseModel

                class AnswerWithJustification(BaseModel):
                    '''An answer to the user question along with justification for the answer.'''
                    answer: str
                    justification: str

                llm = OllamaFunctions(model="phi3", format="json", temperature=0)
                structured_llm = llm.with_structured_output(AnswerWithJustification, include_raw=True)

                structured_llm.invoke("What weighs more a pound of bricks or a pound of feathers")
                # -> {
                #     'raw': AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_Ao02pnFYXD6GN1yzc0uXPsvF', 'function': {'arguments': '{"answer":"They weigh the same.","justification":"Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume or density of the objects may differ."}', 'name': 'AnswerWithJustification'}, 'type': 'function'}]}),
                #     'parsed': AnswerWithJustification(answer='They weigh the same.', justification='Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume or density of the objects may differ.'),
                #     'parsing_error': None
                # }

        Example: dict schema (method="include_raw=False):
            .. code-block:: python

                from langchain_experimental.llms import OllamaFunctions, convert_to_ollama_tool
                from pydantic import BaseModel

                class AnswerWithJustification(BaseModel):
                    '''An answer to the user question along with justification for the answer.'''
                    answer: str
                    justification: str

                dict_schema = convert_to_ollama_tool(AnswerWithJustification)
                llm = OllamaFunctions(model="phi3", format="json", temperature=0)
                structured_llm = llm.with_structured_output(dict_schema)

                structured_llm.invoke("What weighs more a pound of bricks or a pound of feathers")
                # -> {
                #     'answer': 'They weigh the same',
                #     'justification': 'Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume and density of the two substances differ.'
                # }


        zReceived unsupported arguments NzJschema must be specified when method is 'function_calling'. Received None.rQ   )r\   format)Zpydantic_objectr?   c                 S   s   d S r0   r3   _r3   r3   r4   <lambda>      z8OllamaFunctions.with_structured_output.<locals>.<lambda>)r@   rA   c                 S   s   d S r0   r3   rb   r3   r3   r4   rd     re   )r@   rA   )Zexception_key)r?   )r;   r5   r_   r   r   r   rT   r   Zassignr   Zwith_fallbacksr   )rY   r<   r`   rS   Zis_pydantic_schemaZllmZoutput_parserZparser_chainZparser_assignZparser_noneZparser_with_fallbackr3   r3   r4   with_structured_output   s0    fz&OllamaFunctions.with_structured_output)messagesstoprun_managerrS   r/   c              
      s
   dg }dv rd= dv rFfdd|D }|s@tdd= dd |D }|t t| j}|jtj	|ddd	}t
 j|g| f||d
}|jd j}	t|	tstdzt|	}
W n* tjy   td| j d|	 Y n0 d|
v r
|
d nd  t fdd|D d }|d u sB|d td krd|
v rhd|
d v rh|
d d }n*d|
v r||
d }ntd| j d|	 ttt|ddgdS d|
v r|
d ni }tdt |r|ni dtt dd dgd}tt|dgdS )Nr]   rK   c                    s$   g | ]}|d   d d  kr|qS r*   rK   r3   .0fnrS   r3   r4   
<listcomp>(  s   z-OllamaFunctions._generate.<locals>.<listcomp>WIf `function_call` is specified, you must also pass a matching function in `functions`.c                 S   s   g | ]}t |qS r3   r=   rk   r3   r3   r4   ro   1  re      indentr\   rh   ri   r   3OllamaFunctions does not support non-string output.'a' did not respond with valid JSON. 
                Please try again. 
                Response: r6   c                 3   s   | ]}|d   kr|V  qdS r*   Nr3   rk   called_tool_namer3   r4   	<genexpr>K  re   z,OllamaFunctions._generate.<locals>.<genexpr>r*   
tool_inputr$   z Failed to parse a response from 	 output: contentrH   generations Zcall_-)r*   rJ   id)r   rN   )rP   r;   appendDEFAULT_RESPONSE_FUNCTIONr   from_templaterV   ra   rQ   rR   rW   	_generater   textr1   strloadsJSONDecodeErrormodelnextr   r   r   r   uuiduuid4replace)rY   rg   rh   ri   rS   r]   system_message_prompt_templatesystem_messageresponse_messagechat_generation_contentparsed_chat_resultcalled_toolr$   called_tool_argumentsresponse_message_with_functionsrZ   r|   rS   r4   r     s    









zOllamaFunctions._generatec                    s   dg }dv rd= dv rHfdd|D }|s@tdd= n|sV|t t|d rpdd |D }t| j}|jt	j
|dd	d
}t j|g| f||dI d H }|jd j}	t|	tstdzt	|	}
W n, t	jy   td| j d|	 Y n0 |
d  |
d }t fdd|D d }|d u rZtd| j d|	 |d td krttt|d ddgdS tdd |rt	
|nddid}tt|dgdS )Nr]   rK   c                    s$   g | ]}|d   d d  kr|qS rj   r3   rk   rn   r3   r4   ro     s   z.OllamaFunctions._agenerate.<locals>.<listcomp>rp   r   c                 S   s   g | ]}t |qS r3   rq   rk   r3   r3   r4   ro     re   rr   rs   ru   rv   rw   rx   ry   r6   r~   c                 3   s   | ]}|d   kr|V  qdS rz   r3   rk   r{   r3   r4   r}     re   z-OllamaFunctions._agenerate.<locals>.<genexpr>z%Failed to parse a function call from r   r*   r$   r   r   r   r   )r*   rL   )r   rM   )rP   r;   r   r   r5   r   r   rV   ra   rQ   rR   rW   
_agenerater   r   r1   r   r   r   r   r   r   r   r   )rY   rg   rh   ri   rS   r]   r   r   r   r   r   r   r   r   rZ   r   r4   r   |  s    








zOllamaFunctions._agenerate)r/   c                 C   s   dS )NZollama_functionsr3   )rY   r3   r3   r4   	_llm_type  s    zOllamaFunctions._llm_type)NN)NN)!rB   rC   rD   __doc__DEFAULT_SYSTEM_TEMPLATErV   r   rE   r   rX   r   r   r   r	   r"   r   r   r   r   r   r_   boolrf   r   r   r   r   r   r   r   propertyr   __classcell__r3   r3   rZ   r4   rU      sF   

   
b  
PrU   )@rQ   r   operatorr   typingr   r   r   r   r   r   r	   r
   r   r   Z&langchain_community.chat_models.ollamar   Zlangchain_core._apir   Zlangchain_core.callbacksr   r   Zlangchain_core.language_modelsr   Zlangchain_core.messagesr   r   r   Z"langchain_core.output_parsers.baser   Z"langchain_core.output_parsers.jsonr   Z&langchain_core.output_parsers.pydanticr   Zlangchain_core.outputsr   r   Zlangchain_core.promptsr   Zlangchain_core.runnablesr   r   Zlangchain_core.runnables.baser   Z$langchain_core.runnables.passthroughr   Zlangchain_core.toolsr   Zlangchain_core.utils.pydanticr    r!   Zpydanticr"   r   r   r,   rF   r   r5   r=   r>   r   rT   rU   r3   r3   r3   r4   <module>   sR   0