o
    hT[                     @  s  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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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!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/Z0 d dl.m1Z2 d dl3m4Z4 d dl5m6Z6 d dl7m8Z8 d dl9m:Z:m;Z;m<Z<m=Z= d dl>m?Z?m@Z@ d dlAmBZBmCZC erd dlDmEZE eG dd deeFef Z/G dd deFe	ZGd/d#d$ZHd0d(d)ZIeG d*d+ d+ZJG d,d- d-ZKd.S )1    )annotations)IteratorMutableMappingSequence)	dataclass)Enum)TYPE_CHECKINGAnyLiteralcastoverload)configruntime)get_dg_singleton_instance)enforce_filename_restrictionnormalize_upload_file_type)
is_in_form)AtomicImageWidthBehaviorimage_to_url)check_widget_policies)Keycompute_and_register_element_id&get_chat_input_accept_file_proto_valuesave_for_app_testingto_key)StreamlitAPIException)Block)	ChatInput)ChatInputValue)FileUploaderState)RootContainer)gather_metrics)get_script_run_ctx)
WidgetArgsWidgetCallbackWidgetKwargsregister_widget)DeletedFileUploadedFile)is_emojivalidate_material_icon)DeltaGeneratorc                   @  sZ   e Zd ZU ded< ded< dddZdd
dZdddZdddZd ddZd!ddZ	dS )"r   strtextlist[UploadedFile]filesreturnintc                 C     t t| S N)lenvarsself r9   S/var/www/vscode/kcb/lib/python3.10/site-packages/streamlit/elements/widgets/chat.py__len__F      zChatInputValue.__len__Iterator[str]c                 C  r3   r4   )iterr6   r7   r9   r9   r:   __iter__I   r<   zChatInputValue.__iter__itemstr | list[UploadedFile]c                 C  s,   zt | |W S  ty   td| d w NzInvalid key: )getattrAttributeErrorKeyError)r8   r@   r9   r9   r:   __getitem__L   s
   zChatInputValue.__getitem__keyvaluer	   Nonec                 C  s   t | || d S r4   )setattr)r8   rG   rH   r9   r9   r:   __setitem__R   s   zChatInputValue.__setitem__c                 C  s0   zt | | W d S  ty   td| d w rB   )delattrrD   rE   )r8   rG   r9   r9   r:   __delitem__U   s
   zChatInputValue.__delitem__#dict[str, str | list[UploadedFile]]c                 C  s   t | S r4   )r6   r7   r9   r9   r:   to_dict[   s   zChatInputValue.to_dictN)r1   r2   )r1   r=   )r@   r-   r1   rA   )rG   r-   rH   r	   r1   rI   )rG   r-   r1   rI   )r1   rN   )
__name__
__module____qualname____annotations__r;   r?   rF   rK   rM   rO   r9   r9   r9   r:   r   A   s   
 




r   c                   @  s   e Zd ZdZdZdZdZdS )PresetNamesuser	assistantaihumanN)rP   rQ   rR   USER	ASSISTANTAIHUMANr9   r9   r9   r:   rT   _   s
    rT   avatarstr | AtomicImage | None
delta_pathr-   r1   7tuple[BlockProto.ChatMessage.AvatarType.ValueType, str]c              
   C  s   t jj}| du r|jdfS t| tr+| dd tD v r+|j| tjtjfv r(dfS dfS t| tr9t	| r9|j
| fS t| trJ| drJ|jt| fS z|jt| tjdd	d
|dfW S  tyj } ztd|d}~ww )a  Detects the avatar type and prepares the avatar data for the frontend.

    Parameters
    ----------
    avatar :
        The avatar that was provided by the user.
    delta_path : str
        The delta path is used as media ID when a local image is served via the media
        file manager.

    Returns
    -------
    Tuple[AvatarType, str]
        The detected avatar type and the prepared avatar data.
    N c                 S     h | ]}|j qS r9   rH   .0r@   r9   r9   r:   	<setcomp>|       z(_process_avatar_input.<locals>.<setcomp>rV   rU   z	:materialFRGBauto)widthclampchannelsoutput_formatimage_idz5Failed to load the provided avatar value as an image.)
BlockProtoChatMessage
AvatarTypeICON
isinstancer-   rT   r[   rZ   r*   EMOJI
startswithr+   IMAGEr   r   ORIGINAL	Exceptionr   )r]   r_   rq   exr9   r9   r:   _process_avatar_inputf   s>   


rz   files_valueFileUploaderStateProto | Noner/   c           	      C  s   | d u rg S t  }|d u rg S | j}t|dkrg S |jj|jdd |D d}dd |D }g }|D ]'}||j}|d urZt||j	}|
| t|jdrZ|jj|j|jd q3|S )	Nr   c                 S  s   g | ]}|j qS r9   file_idre   fr9   r9   r:   
<listcomp>   rg   z%_pop_upload_files.<locals>.<listcomp>)
session_idfile_idsc                 S  s   i | ]}|j |qS r9   r}   r   r9   r9   r:   
<dictcomp>   s    z%_pop_upload_files.<locals>.<dictcomp>remove_file)r   r~   )r#   uploaded_file_infor5   uploaded_file_mgr	get_filesr   getr~   r)   	file_urlsappendhasattrr   )	r{   ctxr   file_recs_list	file_recscollected_filesr   maybe_file_recuploaded_filer9   r9   r:   _pop_upload_files   s4   
r   c                   @  s>   e Zd ZU dZded< dZded< 	ddddZdddZdS )ChatInputSerdeFboolaccept_filesNzSequence[str] | Noneallowed_typesra   ui_valueChatInputValueProto | None	widget_idr-   r1   str | ChatInputValue | Nonec                 C  sb   |d u s	| dsd S | js|jS t|j}|D ]}| jr)t|ts)t|j	| j qt
|j|dS )Ndata)r.   r0   )HasFieldr   r   r   file_uploader_stater   rs   r(   r   namer   )r8   r   r   uploaded_filesfiler9   r9   r:   deserialize   s   
zChatInputSerde.deserializev
str | NoneChatInputValueProtoc                 C  s
   t |dS )N)r   )r   )r8   r   r9   r9   r:   	serialize   s   
zChatInputSerde.serialize)ra   )r   r   r   r-   r1   r   )r   r   r1   r   )rP   rQ   rR   r   rS   r   r   r   r9   r9   r9   r:   r      s   
 r   c                   @  s   e Zd Zedddd.d
dZe	d/dddddddddd0d"d#Ze	d/dddddddd$d1d'd#Zed(	d/dddddddddd2d+d#Zed3d,d-ZdS )4	ChatMixinchat_messageN)r]   r   1Literal['user', 'assistant', 'ai', 'human'] | strr]   7Literal['user', 'assistant'] | str | AtomicImage | Noner1   r,   c                C  s   |du rt d|du r| dd tD v st|r| }t|| j \}}t }||_	||_
||_t }d|_|j| | jj|dS )u  Insert a chat message container.

        To add elements to the returned container, you can use ``with`` notation
        (preferred) or just call methods directly on the returned object. See the
        examples below.

        Parameters
        ----------
        name : "user", "assistant", "ai", "human", or str
            The name of the message author. Can be "human"/"user" or
            "ai"/"assistant" to enable preset styling and avatars.

            Currently, the name is not shown in the UI but is only set as an
            accessibility label. For accessibility reasons, you should not use
            an empty string.

        avatar : Anything supported by st.image (except list), str, or None
            The avatar shown next to the message.

            If ``avatar`` is ``None`` (default), the icon will be determined
            from ``name`` as follows:

            - If ``name`` is ``"user"`` or ``"human"``, the message will have a
              default user icon.

            - If ``name`` is ``"ai"`` or ``"assistant"``, the message will have
              a default bot icon.

            - For all other values of ``name``, the message will show the first
              letter of the name.

            In addition to the types supported by |st.image|_ (except list),
            the following strings are valid:

            - A single-character emoji. For example, you can set ``avatar="🧑‍💻"``
              or ``avatar="🦖"``. Emoji short codes are not supported.

            - An icon from the Material Symbols library (rounded style) in the
              format ``":material/icon_name:"`` where "icon_name" is the name
              of the icon in snake case.

              For example, ``icon=":material/thumb_up:"`` will display the
              Thumb Up icon. Find additional icons in the `Material Symbols               <https://fonts.google.com/icons?icon.set=Material+Symbols&icon.style=Rounded>`_
              font library.

            .. |st.image| replace:: ``st.image``
            .. _st.image: https://docs.streamlit.io/develop/api-reference/media/st.image

        Returns
        -------
        Container
            A single container that can hold multiple elements.

        Examples
        --------
        You can use ``with`` notation to insert any element into an expander

        >>> import streamlit as st
        >>> import numpy as np
        >>>
        >>> with st.chat_message("user"):
        ...     st.write("Hello 👋")
        ...     st.line_chart(np.random.randn(30, 3))

        .. output ::
            https://doc-chat-message-user.streamlit.app/
            height: 450px

        Or you can just call methods directly in the returned objects:

        >>> import streamlit as st
        >>> import numpy as np
        >>>
        >>> message = st.chat_message("assistant")
        >>> message.write("Hello human")
        >>> message.bar_chart(np.random.randn(30, 3))

        .. output ::
            https://doc-chat-message-user1.streamlit.app/
            height: 450px

        NzWThe author name is required for a chat message, please set it via the parameter `name`.c                 S  rb   r9   rc   rd   r9   r9   r:   rf   ?  rg   z)ChatMixin.chat_message.<locals>.<setcomp>T)block_proto)r   lowerrT   r*   rz   dg_get_delta_path_strro   rp   r   r]   avatar_typeallow_emptyr   CopyFrom_block)r8   r   r]   r   converted_avatarmessage_container_protor   r9   r9   r:   r      s$   Z
zChatMixin.chat_messageYour messageF)rG   	max_charsaccept_file	file_typedisabled	on_submitargskwargsplaceholderr-   rG   
Key | Noner   
int | Noner   Literal[False]r   str | Sequence[str] | Noner   r   r   WidgetCallback | Noner   WidgetArgs | Noner   WidgetKwargs | Noner   c          
      C     d S r4   r9   
r8   r   rG   r   r   r   r   r   r   r   r9   r9   r:   
chat_inputQ     zChatMixin.chat_input)rG   r   r   r   r   r   r   Literal[True, 'multiple']ChatInputValue | Nonec          
      C  r   r4   r9   r   r9   r9   r:   r   `  r   r   bool | Literal['multiple']r   c             
   C  s  d}
t |}t| j|||
dd |dvrtdt }td|d||||d}|r,t|}t r9t	| jr9td	t
| jjj}| jjjtjkrM|sMd
}nd}t }||_t||_|dura||_|
|_t||_|duro|ng |jdd< td|_tt||d}t|j|||	|j|j |dd}||_!|j"r|j#dur|j#|_#d|_$|rt%|||j# |d
krt& j'(d| n| j(d| |j"s|j#S dS )a  Display a chat input widget.

        Parameters
        ----------
        placeholder : str
            A placeholder text shown when the chat input is empty. This
            defaults to ``"Your message"``. For accessibility reasons, you
            should not use an empty string.

        key : str or int
            An optional string or integer to use as the unique key for the widget.
            If this is omitted, a key will be generated for the widget based on
            its content. No two widgets may have the same key.

        max_chars : int or None
            The maximum number of characters that can be entered. If this is
            ``None`` (default), there will be no maximum.

        accept_file : bool or str
            Whether the chat input should accept files. This can be one of the
            following values:

            - ``False`` (default): No files are accepted and the user can only
              submit a message.
            - ``True``: The user can add a single file to their submission.
            - ``"multiple"``: The user can add multiple files to their
              submission.

            When the widget is configured to accept files, the accepted file
            types can be configured with the ``file_type`` parameter.

            By default, uploaded files are limited to 200 MB each. You can
            configure this using the ``server.maxUploadSize`` config option.
            For more information on how to set config options, see
            |config.toml|_.

            .. |config.toml| replace:: ``config.toml``
            .. _config.toml: https://docs.streamlit.io/develop/api-reference/configuration/config.toml

        file_type : str, Sequence[str], or None
            The allowed file extension(s) for uploaded files. This can be one
            of the following types:

            - ``None`` (default): All file extensions are allowed.
            - A string: A single file extension is allowed. For example, to
              only accept CSV files, use ``"csv"``.
            - A sequence of strings: Multiple file extensions are allowed. For
              example, to only accept JPG/JPEG and PNG files, use
              ``["jpg", "jpeg", "png"]``.

        disabled : bool
            Whether the chat input should be disabled. This defaults to
            ``False``.

        on_submit : callable
            An optional callback invoked when the chat input's value is submitted.

        args : tuple
            An optional tuple of args to pass to the callback.

        kwargs : dict
            An optional dict of kwargs to pass to the callback.

        Returns
        -------
        None, str, or dict-like
            The user's submission. This is one of the following types:

            - ``None``: If the user didn't submit a message or file in the last
              rerun, the widget returns ``None``.
            - A string: When the widget is not configured to accept files and
              the user submitted a message in the last rerun, the widget
              returns the user's message as a string.
            - A dict-like object: When the widget is configured to accept files
              and the user submitted a message and/or file(s) in the last
              rerun, the widget returns a dict-like object with two attributes,
              ``text`` and ``files``.

            When the widget is configured to accept files and the user submits
            something in the last rerun, you can access the user's submission
            with key or attribute notation from the dict-like object. This is
            shown in Example 3 below.

            The ``text`` attribute holds a string, which is the user's message.
            This is an empty string if the user only submitted one or more
            files.

            The ``files`` attribute holds a list of UploadedFile objects.
            The list is empty if the user only submitted a message. Unlike
            ``st.file_uploader``, this attribute always returns a list, even
            when the widget is configured to accept only one file at a time.

            The UploadedFile class is a subclass of BytesIO, and therefore is
            "file-like". This means you can pass an instance of it anywhere a
            file is expected.

        Examples
        --------
        **Example 1: Pin the the chat input widget to the bottom of your app**

        When ``st.chat_input`` is used in the main body of an app, it will be
        pinned to the bottom of the page.

        >>> import streamlit as st
        >>>
        >>> prompt = st.chat_input("Say something")
        >>> if prompt:
        ...     st.write(f"User has sent the following prompt: {prompt}")

        .. output ::
            https://doc-chat-input.streamlit.app/
            height: 350px

        **Example 2: Use the chat input widget inline**

        The chat input can also be used inline by nesting it inside any layout
        container (container, columns, tabs, sidebar, etc) or fragment. Create
        chat interfaces embedded next to other content, or have multiple
        chatbots!

        >>> import streamlit as st
        >>>
        >>> with st.sidebar:
        >>>     messages = st.container(height=300)
        >>>     if prompt := st.chat_input("Say something"):
        >>>         messages.chat_message("user").write(prompt)
        >>>         messages.chat_message("assistant").write(f"Echo: {prompt}")

        .. output ::
            https://doc-chat-input-inline.streamlit.app/
            height: 350px

        **Example 3: Let users upload files**

        When you configure your chat input widget to allow file attachments, it
        will return a dict-like object when the user sends a submission. You
        can access the user's message through the ``text`` attribute of this
        dictionary. You can access a list of the user's submitted file(s)
        through the ``files`` attribute. Similar to ``st.session_state``, you
        can use key or attribute notation.

        >>> import streamlit as st
        >>>
        >>> prompt = st.chat_input(
        >>>     "Say something and/or attach an image",
        >>>     accept_file=True,
        >>>     file_type=["jpg", "jpeg", "png"],
        >>> )
        >>> if prompt and prompt.text:
        >>>     st.markdown(prompt.text)
        >>> if prompt and prompt["files"]:
        >>>     st.image(prompt["files"][0])

        .. output ::
            https://doc-chat-input-file-uploader.streamlit.app/
            height: 350px

        ra   F)default_valuewrites_allowed>   FTmultiplez<The `accept_file` parameter must be a boolean or 'multiple'.r   N)user_keyform_idr   r   r   r   z1`st.chat_input()` can't be used in a `st.form()`.bottominlinezserver.maxUploadSize)r   r   chat_input_value)on_change_handlerr   r   deserializer
serializerr   
value_typeT))r   r   r   r   r#   r   r   r   existsr   set
_active_dg_ancestor_block_types_root_containerr!   MAINChatInputProtoidr-   r   r   defaultr   r   r   r   
get_optionmax_upload_size_mbr   r   r'   r   r   r   value_changedrH   	set_valuer   r   	bottom_dg_enqueue)r8   r   rG   r   r   r   r   r   r   r   r   r   
element_idancestor_block_typespositionchat_input_protoserdewidget_stater9   r9   r:   r   o  s    .

c                 C  s
   t d| S )zGet our DeltaGenerator.r,   )r   r7   r9   r9   r:   r     s   
zChatMixin.dg)r   r   r]   r   r1   r,   )r   )r   r-   rG   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r1   r   )r   r-   rG   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r1   r   )r   r-   rG   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r1   r   )r1   r,   )	rP   rQ   rR   r"   r   r   r   propertyr   r9   r9   r9   r:   r      sV    q  r   N)r]   r^   r_   r-   r1   r`   )r{   r|   r1   r/   )L
__future__r   collections.abcr   r   r   dataclassesr   enumr   typingr   r	   r
   r   r   	streamlitr   r   $streamlit.delta_generator_singletonsr   *streamlit.elements.lib.file_uploader_utilsr   r   !streamlit.elements.lib.form_utilsr   "streamlit.elements.lib.image_utilsr   r   r   streamlit.elements.lib.policiesr   streamlit.elements.lib.utilsr   r   r   r   r   streamlit.errorsr   streamlit.proto.Block_pb2r   ro   streamlit.proto.ChatInput_pb2r   r   streamlit.proto.Common_pb2r   r   r    FileUploaderStateProto!streamlit.proto.RootContainer_pb2r!   streamlit.runtime.metrics_utilr"   7streamlit.runtime.scriptrunner_utils.script_run_contextr#   streamlit.runtime.stater$   r%   r&   r'   'streamlit.runtime.uploaded_file_managerr(   r)   streamlit.string_utilr*   r+   streamlit.delta_generatorr,   r-   rT   rz   r   r   r   r9   r9   r9   r:   <module>   sB   

5&