o
    پiW'                     @   sf  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 d dlmZmZ d dlmZ eG dd dZde	d	efd
dZdedee
eef  d	efddZdefddZde	fddZde	fddZde	fddZde	fddZde	fddZe jdefddZe e!de
fdd Z"e e#edee fd!d"Z$d#d$ Z%dS )%    N)	dataclass)AnyCallableDictListOptionalTypecast)EnvironmentStrictUndefined)	BaseModelc                   @   sB   e Zd ZU dZeed< ejed< dd ZdefddZ	d	d
 Z
dS )PromptzRepresents a prompt function.

    We return a `Prompt` class instead of a simple function so the
    template defined in prompt functions can be accessed.

    template	signaturec                 C   s"   t | jj | _t| j| _d S N)listr   
parameterskeyscreate_jinja_templater   jinja_environmentself r   D/home/ubuntu/.local/lib/python3.10/site-packages/outlines/prompts.py__post_init__   s   zPrompt.__post_init__returnc                 O   s.   | j j|i |}|  | jjdi |jS )z}Render and return the template.

        Returns
        -------
        The rendered template as a Python ``str``.

        Nr   )r   bindapply_defaultsr   render	arguments)r   argskwargsbound_argumentsr   r   r   __call__   s   zPrompt.__call__c                 C   s   | j S r   )r   r   r   r   r   __str__)   s   zPrompt.__str__N)__name__
__module____qualname____doc__str__annotations__inspect	Signaturer   r#   r$   r   r   r   r   r      s   
 
r   fnr   c                 C   s4   t | }| j}|du rtdtt|}t||S )a  Decorate a function that contains a prompt template.

    This allows to define prompts in the docstring of a function and simplify their
    manipulation by providing some degree of encapsulation. It uses the `render`
    function internally to render templates.

    >>> import outlines
    >>>
    >>> @outlines.prompt
    >>> def build_prompt(question):
    ...    "I have a ${question}"
    ...
    >>> prompt = build_prompt("How are you?")

    This API can also be helpful in an "agent" context where parts of the prompt
    are set when the agent is initialized and never modified later. In this situation
    we can partially apply the prompt function at initialization.

    >>> import outlines
    >>> import functools as ft
    ...
    >>> @outlines.prompt
    ... def solve_task(name: str, objective: str, task: str):
    ...     '''Your name is {{name}}.
    ..      Your overall objective is to {{objective}}.
    ...     Please solve the following task: {{task}}
    ...     '''
    ...
    >>> hal = ft.partial(solve_task, "HAL", "Travel to Jupiter")

    Returns
    -------
    A `Prompt` callable class which will render the template when called.

    Nz6Could not find a template in the function's docstring.)r+   r   r(   	TypeErrorr	   r)   r   )r-   r   	docstringr   r   r   r   prompt-   s   
%

r0   r   valuesc                 K   s   t | }|jdi |S )a)	  Parse a Jinaj2 template and translate it into an Outlines graph.

    This function removes extra whitespaces and linebreaks from templates to
    allow users to enter prompts more naturally than if they used Python's
    constructs directly. See the examples for a detailed explanation.

    Examples
    --------

    Outlines follow Jinja2's syntax

    >>> import outlines
    >>> outline = outlines.render("I like {{food}} and {{sport}}", food="tomatoes", sport="tennis")
    I like tomatoes and tennis

    If the first line of the template is empty, `render` removes it

    >>> from outlines import render
    >>>
    >>> tpl = '''
    ... A new string'''
    >>> tpl
    ... '\nA new string'
    >>> render(tpl)
    ... 'a new string'

    Similarly, `render` ignores linebreaks introduced by placing the closing quotes
    underneath the text:

    >>> tpl = '''
    ... A new string
    ... '''
    >>> tpl
    ... '\nA new string\n'
    >>> render(tpl)
    ... 'A new string'

    If you want to insert a linebreak at the end of the rendered template, you will
    need to leave an empty line at the end of the template:

    >>> tpl = '''
    ... A new string
    ...
    ... '''
    >>> tpl
    ... '\nA new string\n\n'
    >>> render(tpl)
    ... 'A new string\n'

    `render` removes the identation in docstrings. This is particularly important
    when using prompt functions

    >>> tpl = '''
    ...    a string
    ...    and another string'''
    >>> tpl
    ... '\n   a string\n   and another string'
    >>> render(tpl)
    ... 'a string\nand another string'

    The indentation of the first line is assumed to be the same as the second line's

    >>> tpl = '''a string
    ...     and another'''
    >>> tpl
    ... 'a string\n    and another'
    >>> render(tpl)
    ... 'a string\nand another'

    To get a different indentation for the first and the second line, we can start the
    prompt on the string's second line:

    >>> tpl = '''
    ... First line
    ...   Second line'''
    >>> render(tpl)
    ... 'First Line\n  Second Line'

    Parameters
    ----------
    template
        A string that contains a template written with the Jinja2 syntax.
    **values
        Map from the variables in the template to their value.

    Returns
    -------
    A string that contains the rendered template.

    Nr   )r   r   )r   r1   jinja_templater   r   r   r   _   s   [r   c                 C   s   t | }| ddd}|r|d7 }tdd|}tdddtd}t|j	d< t
|j	d	< t|j	d
< t|j	d< t|j	d< t|j	d< ||}|S )N  z


z(?![\r\n])(\b\s+)T)trim_blockslstrip_blockskeep_trailing_newline	undefinednamedescriptionsourcer   schemar    )r+   cleandocreplaceendswithresubr
   r   get_fn_namefiltersget_fn_descriptionget_fn_sourceget_fn_signature
get_schemaget_fn_argsfrom_string)r   cleaned_templateends_with_linebreakenvr2   r   r   r   r      s&   







r   c                 C   s2   t | stdt| dst| j}|S | j}|S )zReturns the name of a callable.z,The `name` filter only applies to callables.r%   )callabler.   hasattrtyper%   )r-   r:   r   r   r   rC      s   

rC   c                 C   s@   t | stdg }t| }dd |j D }d|}|S )zTReturns the arguments of a function with annotations and default values if provided.z,The `args` filter only applies to callables.c                 S   s   g | ]}t |qS r   )r)   ).0paramr   r   r   
<listcomp>   s    zget_fn_args.<locals>.<listcomp>z, )rN   r.   r+   r   r   r1   join)r-   arg_str_listr   arg_strr   r   r   rI      s   

rI   c                 C   s@   t | stdt| }|du rd}|S |dd  }|S )z1Returns the first line of a callable's docstring.z3The `description` filter only applies to callables.Nr4   r5   r   )rN   r.   r+   getdocsplitstrip)r-   r/   r;   r   r   r   rE      s   
rE   c                 C   sT   t | stdtt| }ttdtj	|}|dur&|
d}|S td)z%Return the source code of a callable..The `source` filter only applies to callables.z(\bdef\b.*)Nr   z)Could not read the function's source code)rN   r.   textwrapdedentr+   	getsourcerA   searchcompileDOTALLgroup)r-   r<   	re_searchr   r   r   rF     s   
rF   c                 C   sP   t | stdtt| }ttd|}|du r!d}|S |	d}|S )z#Return the signature of a callable.rZ   z\(([^)]+)\)Nr4      )
rN   r.   r[   r\   r+   r]   rA   r^   r_   ra   )r-   r<   rb   r   r   r   r   rG     s   
rG   modelc                 C   s   t dt|  d)Nz.No schema rendering function defined for type .)NotImplementedErrorrP   rd   r   r   r   rH   #  s   rH   c                 C   s   t j| ddS )z"Return a pretty-printed dictionary   indent)jsondumpsrg   r   r   r   get_schema_dict*  s   rm   c                 C   s`   t | t tkstdt| drd}|  }nd}|  }||d}t||}tj	|ddS )z&Return the schema of a Pydantic model.z4The `schema` filter only applies to Pydantic models.model_json_schemaz$defsdefinitionsNrh   ri   )
rP   r   r.   rO   rn   r=   getparse_pydantic_schemark   rl   )rd   def_key
raw_schemaro   r=   r   r   r   get_schema_pydantic0  s   


rt   c                 C   sr   i }| d   D ].\}}d|v r|d ||< qd|v r.|d d}t||d  |||< qd| d||< q|S )zParse the output of `Basemodel.[schema|model_json_schema]()`.

    This recursively follows the references to other schemas in case
    of nested models. Other schemas are stored under the "definitions"
    key in the schema of the top-level model.

    
propertiesr;   z$ref/rh   <>)itemsrX   rq   )rs   ro   simple_schemar:   valuerefsr   r   r   rq   C  s   
rq   )&	functoolsr+   rk   rA   r[   dataclassesr   typingr   r   r   r   r   r   r	   jinja2r
   r   pydanticr   r   r0   r)   r   r   rC   rI   rE   rF   rG   singledispatchrH   registerdictrm   rP   rt   rq   r   r   r   r   <module>   s4    $"2_ 