
    ;3hlK                        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 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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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) erd dl$m*Z*m+Z+ d dl&m,Z, ejZ                  j]                  d      xs   e/ e
 ej`                               dz        Z1 G d d      Z2y)    N)Sequence)BytesIO)Path)TYPE_CHECKINGAny)types)Server)SseServerTransport)Image)	Starlette)JSONResponseResponse)MountRoute)processing_utilsroute_utilsutils)BlockFunction)State)FileData)BlockContextBlocks)	ComponentGRADIO_TEMP_DIRgradioc                      e Zd ZdZd!dZd"dZdefdZdede	d	e	ddfd
Z
de	ddfdZeded   dedefd       Zeded   dedefd       Z	 d#de	dee	e	f   dz  deee	ef   eee	ez        f   fdZdefdZdee	ef   deee	ef   eee	ez        f   fdZdedeee	ez        defdZede	dej4                  dz  fd       Zedej4                  de	de	fd       Zdedeej<                  ej>                  z     fd Z y)$GradioMCPServerz
    A class for creating an MCP server around a Gradio app.

    Args:
        blocks: The Blocks app to create the MCP server for.
    c                 R   || _         | j                   j                         | _        | j                         | _        d | _        d | _        t        j                         }|r1|j                  d      d   }t        j                  dd|      | _        nd| _        | j                          y )N/z[^a-zA-Z0-9]_ )blocksget_api_infoapi_infocreate_mcp_server
mcp_serverrequestroot_urlr   	get_spacesplitresubtool_prefixwarn_about_state_inputs)selfr#   r.   s      J/var/www/html/audio-gradio/venv/lib/python3.12/site-packages/gradio/mcp.py__init__zGradioMCPServer.__init__+   s    002002oo'%++C04K!vvosKHD!D$$&    returnNc                 <   | j                   r| j                   d   j                         D ]o  \  }}| j                  |j                  d      z   }|d   s*| j	                  |      }|s>t        d |j                  D              s[t        j                  d       q yy)z=
        Warn about tools that have gr.State inputs.
        named_endpointsr   show_apic              3   <   K   | ]  }t        |t                y wN)
isinstancer   ).0inputs     r1   	<genexpr>z:GradioMCPServer.warn_about_state_inputs.<locals>.<genexpr>D   s      (5:
5%0(s   zThis MCP server includes a tool that has a gr.State input, which will not be updated between tool calls. The original, default value of the State will be used each time.N)	r%   itemsr.   lstripget_block_fn_from_tool_nameanyinputswarningswarn)r0   endpoint_nameendpoint_info	tool_nameblock_fns        r1   r/   z'GradioMCPServer.warn_about_state_inputs9   s     ==04!1eg,} !,,}/C/CC/HH	 ,#??	JHC (>Foo( % !. r3   c           	      t    t        t         j                  j                  xs d            }|j	                         dt        dt
        t        t        f   dt        t        j                  t        j                  z     f fd       }|j                         dt        t        j                     f fd       }|S )z
        Create an MCP server for the given Gradio Blocks app.

        Parameters:
            blocks: The Blocks app to create the MCP server for.

        Returns:
            The MCP server.
        z
Gradio Appname	argumentsr4   c                 j  K   
j                  |       \  }}
j                  ||      }
j                  |       }d| j                  
j                         }
j
                  r>|
j
                  d   v r-
j
                  d   |   d   }t        j                  |d|      }ng }|t        d|        
j                  |j                  |      }
j                  j                  ||
j                         d{   }	
j                  |j                  |      }
j                  |	d         S 7 4w)	z
            Call a tool on the Gradio app.

            Args:
                name: The name of the tool to call.
                arguments: The arguments to pass to the tool.
            r   r6   
parameters N"Unknown tool for this Gradio app: )rH   rB   r(   data)get_input_schemaconvert_strings_to_filedatar@   removeprefixr.   r%   client_utilsconstruct_args
ValueErrorinsert_empty_staterB   r#   process_apir(   pop_returned_statepostprocess_output_data)rJ   rK   r!   filedata_positionsprocessed_kwargsrH   rE   parameters_infoprocessed_argsoutputr0   s             r1   	call_toolz4GradioMCPServer.create_mcp_server.<locals>.call_toolY   sH     %)$9$9$$?!A!#??-  77=H 1 1$2B2B CDEM}}$--@Q2R!R"&--0A"B="Q # ".!<!<#$" "$ #EdV!LMM!44X__nUN;;22!% 3  F
 "44X__nUN//v??s   C9D3<D1=5D3c                    K   	j                   sg S g } 	j                   d   j                         D ]  \  }}	j                  |j                  d      z   }|d   s*	j	                  |      }||j
                  Jt        j                  |j
                        \  }}	j                  ||      \  }}| j                  t        j                  |||              | S w)z;
            List all tools on the Gradio app.
            r6   r   r7   )rJ   descriptioninputSchema)r%   r>   r.   r?   r@   fnr   get_function_descriptionrQ   appendr   Tool)
toolsrE   rF   rG   rH   rb   rM   schemar!   r0   s
            r1   
list_toolsz5GradioMCPServer.create_mcp_server.<locals>.list_tools   s     
 ==	E04!1eg,} !,,}/C/CC/HH	 ,#??	JH'8;;+> .3.L.L /+K !% 5 5i LIFALL

!*(3(.& Ls   ACBC)r	   strr#   titler`   dictr   listr   TextContentImageContentrj   rg   )r0   serverr`   rj   s   `   r1   r&   z!GradioMCPServer.create_mcp_serverM   s     DKK--=>?				$	@$	@"&sCx.$	@%##e&8&889$	@ 
$	@L 
				$uzz"2 	 
	: r3   appsubpath	root_pathc                      d}t        |       fd}|j                  |t        t        d j                        t        d|      t        dj                        g             y)	z
        Launch the MCP server on the SSE transport.

        Parameters:
            app: The Gradio app to mount the MCP server on.
            subpath: The subpath to mount the MCP server on. E.g. "/gradio_api/mcp"
        z
/messages/c                   K   | _         t        j                  | d      _        	 j	                  | j
                  | j                  | j                        4 d {   }j                  j                  |d   |d   j                  j                                d {    d d d       d {    t               S 7 a7  7 # 1 d {  7  sw Y   t               S xY w# t        $ r}t        dt        |               d }~ww xY ww)Nz/gradio_api/mcp/sse)r(   
route_pathrt   r      zMCP SSE connection error: )r(   r   get_root_urlr)   connect_ssescopereceive_sendr'   runcreate_initialization_optionsr   	Exceptionprintrk   )r(   streamsert   r0   sses      r1   
handle_ssez5GradioMCPServer.launch_mcp_on_sse.<locals>.handle_sse   s     "DL'440#DM
??MM7??GMM  //--

EEG     z!     z! 23q6(;<s   %D5C$ C C$ "?C!C"C&C$ 1C2C$ ?D C$ CC$ C!CC!C$  D!C$ $	D
-DD

Dz/schema)endpointz/sse)rr   )routesN)r
   mountr   r   get_complete_schemar   handle_post_message)r0   rr   rs   rt   messages_pathr   r   s   `  `  @r1   launch_mcp_on_ssez!GradioMCPServer.launch_mcp_on_sse   sg     % /	* 			!!%!9!9 &:6,C,C,CD		
r3   rG   zBlockFunction | Nonec                 z     t         fd j                  j                  j                         D        d      }|S )a  
        Get the BlockFunction for a given tool name.

        Parameters:
            tool_name: The name of the tool to get the BlockFunction for.

        Returns:
            The BlockFunction for the given tool name, or None if it is not found.
        c              3   r   K   | ].  }|j                   j                  j                        k(  r| 0 y wr9   )api_namerS   r.   )r;   rd   r0   rG   s     r1   r=   z>GradioMCPServer.get_block_fn_from_tool_name.<locals>.<genexpr>   s6      ;;)"8"89I9I"JJ s   47N)nextr#   fnsvalues)r0   rG   rH   s   `` r1   r@   z+GradioMCPServer.get_block_fn_from_tool_name   s9     ++//002
 
 r3   rB   zComponent | BlockContextrP   c                 r    t        |       D ](  \  }}t        |t              s|j                  |d        * |S r9   )	enumerater:   r   insertrB   rP   iinput_component_types       r1   rW   z"GradioMCPServer.insert_empty_state   s>     (1'8 	%#A#.6At$	% r3   c                 p    t        |       D ]'  \  }}t        |t              s|j                  |       ) |S r9   )r   r:   r   popr   s       r1   rY   z"GradioMCPServer.pop_returned_state   s;     (1'8 	#A#.6	 r3   rM   c           
      2   d|j                  | j                         }| j                  d   }|j                  |      }|t	        d|       d|d   D ci c]"  }|d   i |d   |r|d   |v r
d||d      ini $ c}d	}| j                  |      S c c}w )
a  
        Get the input schema of the Gradio app API, appropriately formatted for MCP.

        Parameters:
            tool_name: The name of the tool to get the schema for, e.g. "predict"
            parameters: The description and parameters of the tool to get the schema for.
        Returns:
            - The input schema of the Gradio app API.
            - A list of positions of FileData objects in the input schema.
        r   r6   rO   objectrM   parameter_nametyperb   )r   
properties)rS   r.   r%   getrV   simplify_filedata_schema)r0   rG   rM   rE   r6   rF   pri   s           r1   rQ   z GradioMCPServer.get_input_schema   s     I2243C3CDEF--(9:'++M: A)MNN  '|4
  "# &i& &!,<*=*K '
15E3F(GH& 

 ,,V44
s   'Bc                   K   | j                   st        i       S i }| j                   d   j                         D ]  \  }}| j                  |j	                  d      z   }|d   s*| j                  |      }||j                  Jt        j                  |j                        \  }}| j                  ||      \  }	}
|	||<   |||   d<    t        |      S w)a  
        Get the complete schema of the Gradio app API. (For debugging purposes)

        Parameters:
            request: The Starlette request object.

        Returns:
            A JSONResponse containing a dictionary mapping tool names to their input schemas.
        r6   r   r7   rb   )
r%   r   r>   r.   r?   r@   rd   r   re   rQ   )r0   r(   schemasrE   rF   rG   rH   rb   rM   ri   r!   s              r1   r   z#GradioMCPServer.get_complete_schema  s      }}##,0MM:K,L,R,R,T 		@(M=((=+?+?+DDIZ(;;IF#x{{':*/*H*H*U'Z 11)ZH	%+	"4?	"=1		@ G$$s   A C#A1Cri   c           	          dt         dt        t        t         f   dt        fd	 	 d	dt         dt        t        t
        z     dz  dt        t        t         f   dz  dt         ffdg  |      }|fS )
a  
        Parses a schema of a Gradio app API to identify positions of FileData objects. Replaces them with base64
        strings while keeping track of their positions so that they can be converted back to FileData objects
        later.

        Parameters:
            schema: The original schema of the Gradio app API.

        Returns:
            A tuple containing the simplified schema and the positions of the FileData objects.
        objdefsr4   c                 0   t        | t              syd| v r>| d   }|j                  d      r'|j                  d      d   }|j	                  |i       } ny| j	                  di       }|j	                  di       }d|v r>|d   }|j                  d      r'|j                  d      d   }|j	                  |i       }ny|j	                  di       j	                  di       }|j	                  d	i       j	                  d      }|j	                  d
      dk(  xs |dk(  S )NFz$refz#/$defs/r   r    r   meta_typedefaultconstzgradio.FileData)r:   rm   
startswithr+   r   )r   r   refkeypropsr   
type_fielddefault_types           r1   is_gradio_filedatazDGradioMCPServer.simplify_filedata_schema.<locals>.is_gradio_filedataD  s   c4(}&k>>*-))C.,C((3+C GGL"-E99VR(D~6l>>*-))C.,C88C,D ,377DJ88Ir266w?Lw'+<< 5#44r3   Nnodepathc                    |g }|i }t        | t              rd| v r|j                  | d           
| |      rB	j                  |j	                                dD ]  }| j                  |d         d| d<   d| d<   i }d| v xr d| v }| j                         D ]H  \  }}|r|dk(  r |||      ||<   |j                  |        |||      ||<   |j                          J |S t        | t              rQg }t        |       D ]?  \  }}|j                  |       |j                   |||             |j                          A |S | S )N$defs)r   additional_descriptionr   stringr   za http or https url to a fileformatr   )	r:   rm   updaterf   copyr   r>   rn   r   )r   r   r   r   resultis_schema_rootvaluer   itemr[   r   traverses            r1   r   z:GradioMCPServer.simplify_filedata_schema.<locals>.traverseb  s]   
 ||$%d?KKW.%dD1&--diik:P ,d+,#+DL%DDN!'4!HLD4H"&**, #JC%#*=&.udD&AsC(&.udD&As
# D$'( GAtKKNMM(4t"<=HHJ Kr3   )NN)r   rm   rk   boolrn   int)r0   ri   simplified_schemar[   r   r   s      @@@r1   r   z(GradioMCPServer.simplify_filedata_schema5  s    	C 	tCH~ 	$ 	@ ,0*.(	(	sSy/D((	 sCx.4'(	 	(	T 57$V, "444r3   r   r[   c                 l    ddt         dt        t        t        z     dz  dt         ffd |      S )a'  
        Convert specific string values back to FileData objects based on their positions.
        This is used to convert string values (as base64 encoded strings) to FileData
        dictionaries so that they can be passed into .preprocess() logic of a Gradio app.

        Parameters:
            value: The input data to process, which can be an arbitrary nested data structure
                that may or may not contain strings that should be converted to FileData objects.
            filedata_positions: List of paths to positions in the input data that should be converted to FileData objects.

        Returns:
            The processed data with strings converted to FileData objects where appropriate. Base64
            encoded strings are first saved to a temporary file and then converted to a FileData object.

        Example:
            >>> convert_strings_to_filedata(
                {"image": "data:image/jpeg;base64,..."},
                [["image"]]
            )
            >>> {'image': FileData(path='<temporary file path>')},
        Nr   r   r4   c           
          |g }t        | t              r/| j                         D ci c]  \  }}| |||gz          c}}S t        | t              r)t	        |       D cg c]  \  }} |||gz          c}}S t        | t
              rd|v r`| j                  d      r$t        t        j                  | t                    S | j                  d      rt        |       S t        d|        | S c c}}w c c}}w )Nzdata:)r   )zhttp://zhttps://zSInvalid file data format, provide a url ('http://...' or 'https://...'). Received: )r:   rm   r>   rn   r   rk   r   r   r   save_base64_to_cacheDEFAULT_TEMP_DIRrV   )r   r   r   r   r   r   r[   r   s         r1   r   z=GradioMCPServer.convert_strings_to_filedata.<locals>.traverse  s   |$%IM;E3C%66  D$'BKD/Rwq$tqcz2RRD#&43E+E??7+ $-BB "2 
 __%<=#..$mnrmst  K) Ss   C4#C:r9   )r   rn   rk   r   )r0   r   r[   r   s     `@r1   rR   z+GradioMCPServer.convert_strings_to_filedata  s6    2	3 	d39o&< 	 	6 r3   	file_pathc                    t         j                  j                  |       syt         j                  j                  | j	                               d   }|t        j                         vry	 t        j                  |       S # t        $ r Y yw xY w)ze
        If a filepath is a valid image, returns a PIL Image object. Otherwise returns None.
        Nrx   )	osr   existssplitextlowerr   registered_extensionsopenr   )r   exts     r1   	get_imagezGradioMCPServer.get_image  sq    
 ww~~i(ggy01!4e1133	::i(( 		s   )A> >	B
	B
imager   c                     t               }| j                  ||       t        j                  |j	                               j                  d      S )z?
        Returns a base64 encoded string of the image.
        )r   zutf-8)r   savebase64	b64encodegetvaluedecode)r   r   buffers      r1   get_base64_datazGradioMCPServer.get_base64_data  s>    
 

6&
) 1299'BBr3   c                 h   g }| j                   r!t        j                  || j                   d      }|D ]  }t        j                  |      r| j                  |d         x}rr|j                  xs d}| j                  ||      }d|j                          }t        j                  d||      t        j                  dd|d	   xs |d    
      g}nMt        j                  dt        |d	   xs |d         
      g}n!t        j                  dt        |      
      g}|j                  |        |S )z
        Postprocess the output data from the Gradio app to convert FileData objects back to base64 encoded strings.

        Parameters:
            data: The output data to postprocess.
        Nr   pngzimage/r   )r   rP   mimeTypetextzImage URL: url)r   r   )r)   r   add_root_urlrT   is_file_obj_with_metar   r   r   r   r   rp   ro   rk   extend)	r0   rP   return_valuesr_   r   image_formatbase64_datamimetypereturn_values	            r1   rZ   z'GradioMCPServer.postprocess_output_data  s9    ==#00t}}dKD 	/F11&9 NN6&>::5:#(<<#85L"&"6"6ul"KK!'(:(:(<'=>H**!({X ))!'#.ve}/Nv.O!P	$L ))!'c&-2Q6&>.R$L !& 1 1vCK PQ  ./	/0 r3   )r#   r   )r4   Nr9   )!__name__
__module____qualname____doc__r2   r/   r	   r&   r   rk   r   r@   staticmethodr   rn   rW   rY   rm   tupler   r   rQ   r   r   r   rR   r   r   r   r   ro   rp   rZ   rN   r3   r1   r   r   #   s   '(Q6 Qf,
Y ,
 ,
 ,
QU ,
\S =S ( 34<@	  34<@	  -1$5$5 cNT)$5 
tCH~tDsO44	5	$5L%L %6Y538nY5	tCH~tDsO44	5Y5v44.24c	?.C4	4l S U[[4%7   Cu{{ CC CC C C$$	e%"4"44	5$r3   r   )3r   r   r,   tempfilerC   collections.abcr   ior   pathlibr   typingr   r   gradio_client.utilsr   rT   mcpr   
mcp.serverr	   mcp.server.sser
   PILr   starlette.applicationsr   starlette.responsesr   r   starlette.routingr   r   r   r   r   gradio.blocksr   gradio.componentsr   gradio.data_classesr   r   r   r   environr   rk   
gettempdirr   r   rN   r3   r1   <module>r     s     	 	   $   % *   -  , 6 * 7 7 ' # (2+ ::>>"34 				(*9 
_ _r3   