
    g=                        U d 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 ddlmZmZmZ er
ddlZddlmZ  e            rddlmZmZ dd	lmZ ndxZxZZdaed
         ed<   ej                            d          du Ze G d d
                      Zeddee         de	fd            ZdefdZdee         ddfdZ dededefdZ!de	dede	fdZ"dS )zSContains `WebhooksServer` and `webhook_endpoint` to create a webhook server easily.    N)wraps)TYPE_CHECKINGAnyCallableDictOptional   )experimentalis_fastapi_availableis_gradio_available)Request)FastAPIr   )JSONResponseWebhooksServer_global_appSPACE_IDc                        e Zd ZdZd fdZ	 	 dded         dee         ddfdZdd	ee         defd
Z	dde
deddfdZddZ xZS )r   aB  
    The [`WebhooksServer`] class lets you create an instance of a Gradio app that can receive Huggingface webhooks.
    These webhooks can be registered using the [`~WebhooksServer.add_webhook`] decorator. Webhook endpoints are added to
    the app as a POST endpoint to the FastAPI router. Once all the webhooks are registered, the `launch` method has to be
    called to start the app.

    It is recommended to accept [`WebhookPayload`] as the first argument of the webhook function. It is a Pydantic
    model that contains all the information about the webhook event. The data will be parsed automatically for you.

    Check out the [webhooks guide](../guides/webhooks_server) for a step-by-step tutorial on how to setup your
    WebhooksServer and deploy it on a Space.

    <Tip warning={true}>

    `WebhooksServer` is experimental. Its API is subject to change in the future.

    </Tip>

    <Tip warning={true}>

    You must have `gradio` installed to use `WebhooksServer` (`pip install --upgrade gradio`).

    </Tip>

    Args:
        ui (`gradio.Blocks`, optional):
            A Gradio UI instance to be used as the Space landing page. If `None`, a UI displaying instructions
            about the configured webhooks is created.
        webhook_secret (`str`, optional):
            A secret key to verify incoming webhook requests. You can set this value to any secret you want as long as
            you also configure it in your [webhooks settings panel](https://huggingface.co/settings/webhooks). You
            can also set this value as the `WEBHOOK_SECRET` environment variable. If no secret is provided, the
            webhook endpoints are opened without any security.

    Example:

        ```python
        import gradio as gr
        from huggingface_hub import WebhooksServer, WebhookPayload

        with gr.Blocks() as ui:
            ...

        app = WebhooksServer(ui=ui, webhook_secret="my_secret_key")

        @app.add_webhook("/say_hello")
        async def hello(payload: WebhookPayload):
            return {"message": "hello"}

        app.launch()
        ```
    returnc                     t                      st          d          t                      st          d          t                                          |           S )NzjYou must have `gradio` installed to use `WebhooksServer`. Please run `pip install --upgrade gradio` first.zlYou must have `fastapi` installed to use `WebhooksServer`. Please run `pip install --upgrade fastapi` first.)r   ImportErrorr   super__new__)clsargskwargs	__class__s      \/var/www/html/ai-engine/env/lib/python3.11/site-packages/huggingface_hub/_webhooks_server.pyr   zWebhooksServer.__new__a   sg    "$$ 	   $%% 	   wws###    Nui	gr.Blockswebhook_secretc                     || _         |pt          j        d          | _        i | _        t          | j                   d S )NWEBHOOK_SECRET)_uiosgetenvr!   registered_webhooks_warn_on_empty_secret)selfr   r!   s      r   __init__zWebhooksServer.__init__n   sB    
 ,K	:J0K0K8: d122222r   pathc                      t                    r                                            S t          t          j                   fd            }|S )ax  
        Decorator to add a webhook to the [`WebhooksServer`] server.

        Args:
            path (`str`, optional):
                The URL path to register the webhook function. If not provided, the function name will be used as the
                path. In any case, all webhooks are registered under `/webhooks`.

        Raises:
            ValueError: If the provided path is already registered as a webhook.

        Example:
            ```python
            from huggingface_hub import WebhooksServer, WebhookPayload

            app = WebhooksServer()

            @app.add_webhook
            async def trigger_training(payload: WebhookPayload):
                if payload.repo.type == "dataset" and payload.event.action == "update":
                    # Trigger a training job if a dataset is updated
                    ...

            app.launch()
        ```
        c                      | d         }dp|j                             d           }|j        v rt          d| d          |j        |<   d S )Nr   z
/webhooks//zWebhook z already exists.)__name__stripr'   
ValueError)r   r   funcabs_pathr+   r)   s       r   _inner_postz/WebhooksServer.add_webhook.<locals>._inner_post   si    7DHT%:T]$A$A#$F$FHHH4333 !FH!F!F!FGGG15D$X...r   )callableadd_webhookr   r   post)r)   r+   r4   s   `` r   r6   zWebhooksServer.add_webhooky   sm    8 D>> 	,%4##%%d+++ 
w|			6 	6 	6 	6 	6 
		6 r   Fprevent_thread_locklaunch_kwargsc                   	 | j         p|                                 }|                    dt                      |j        dddi|\  | _        }}| j                                        D ]E\  }}| j        t          || j                  } | j        
                    |          |           Ft          j                            d          }|d|z   n|j        p|j        		                    d          	d	}|d
d
                    	fd| j        D                       z   z  }|dz  }t%          |           |s|                                 dS dS )zLaunch the Gradio app and register webhooks to the underlying FastAPI server.

        Input parameters are forwarded to Gradio when launching the app.
        sharer8   TNr!   
SPACE_HOSTzhttps://r.   z/
Webhooks are correctly setup and ready to use:
c              3   &   K   | ]}d  | V  dS )z	  - POST N ).0webhookurls     r   	<genexpr>z(WebhooksServer.launch.<locals>.<genexpr>   s1      #g#g7$>$>W$>$>#g#g#g#g#g#gr   zG
Go to https://huggingface.co/settings/webhooks to setup your webhooks.r@   )r$   _get_default_ui
setdefault	_is_locallaunchfastapi_appr'   itemsr!   _wrap_webhook_to_check_secretr7   r%   environget	share_url	local_urlr0   joinprintblock_thread)
r)   r8   r9   r   _r+   r2   
space_hostmessagerC   s
            @r   rH   zWebhooksServer.launch   s|   
 X/--//
 	  )444!*!U!Ut!U}!U!U!Q 288:: 	. 	.JD$".4T$J]^^^ (D!!$''---- Z^^L11
)3)?j:%%blFbVXVbiinnD4$))#g#g#g#gdNf#g#g#ggggg]]g" 	OO	 	r   c           	         ddl } |j                    5 } |j        d            |j        d            |j        t          | j                   ddz   d                    d | j                                        D                       z               |j        t          rd	nd
           ddd           n# 1 swxY w Y   |S )zLDefault UI if not provided (lists webhooks and provides basic instructions).r   Nu)   # This is an app to process 🤗 WebhooksaT  Webhooks are a foundation for MLOps-related features. They allow you to listen for new changes on specific repos or to all repos belonging to particular set of users/organizations (not just your repos, but any repo). Check out this [guide](https://huggingface.co/docs/hub/webhooks) to get to know more about webhooks on the Huggingface Hub.z webhook(s) are registered:z

z
 c              3   T   K   | ]#\  }}d | dt          |j        |           dV  $dS )z- [z]()N)_get_webhook_doc_urlr/   )rA   webhook_pathrB   s      r   rD   z1WebhooksServer._get_default_ui.<locals>.<genexpr>   s]        -g b,aa*>w?OQ]*^*^aaa     r   zGo to https://huggingface.co/settings/webhooks to setup your webhooks.
You app is running locally. Please look at the logs to check the full URL you need to set.z
This app is running on a Space. You can find the corresponding URL in the options menu (top-right) > 'Embed the Space'. The URL looks like 'https://{username}-{repo_name}.hf.space'.)gradioBlocksMarkdownlenr'   rP   rJ   rG   )r)   grr   s      r   rE   zWebhooksServer._get_default_ui   sP   RY[[ 	BBKCDDDBKD   BKt/00MMM**  151I1O1O1Q1Q       BK  q qv  !	 	 	 	 	 	 	 	 	 	 	 	 	 	 	2 	s   BB99B= B=)r   r   )NNN)F)r   r    )r/   
__module____qualname____doc__r   r   strr*   r   r6   boolr   rH   rE   __classcell__)r   s   @r   r   r   *   s        3 3j$ $ $ $ $ $ %)(,	3 	3[!	3 !	3 
		3 	3 	3 	3) ) ) ) ) ) )V   $    QU        D       r   r+   r   c                      t                     r t                                 S t          t          j                  dt
          dt
          f fd            }|S )a  Decorator to start a [`WebhooksServer`] and register the decorated function as a webhook endpoint.

    This is a helper to get started quickly. If you need more flexibility (custom landing page or webhook secret),
    you can use [`WebhooksServer`] directly. You can register multiple webhook endpoints (to the same server) by using
    this decorator multiple times.

    Check out the [webhooks guide](../guides/webhooks_server) for a step-by-step tutorial on how to setup your
    server and deploy it on a Space.

    <Tip warning={true}>

    `webhook_endpoint` is experimental. Its API is subject to change in the future.

    </Tip>

    <Tip warning={true}>

    You must have `gradio` installed to use `webhook_endpoint` (`pip install --upgrade gradio`).

    </Tip>

    Args:
        path (`str`, optional):
            The URL path to register the webhook function. If not provided, the function name will be used as the path.
            In any case, all webhooks are registered under `/webhooks`.

    Examples:
        The default usage is to register a function as a webhook endpoint. The function name will be used as the path.
        The server will be started automatically at exit (i.e. at the end of the script).

        ```python
        from huggingface_hub import webhook_endpoint, WebhookPayload

        @webhook_endpoint
        async def trigger_training(payload: WebhookPayload):
            if payload.repo.type == "dataset" and payload.event.action == "update":
                # Trigger a training job if a dataset is updated
                ...

        # Server is automatically started at the end of the script.
        ```

        Advanced usage: register a function as a webhook endpoint and start the server manually. This is useful if you
        are running it in a notebook.

        ```python
        from huggingface_hub import webhook_endpoint, WebhookPayload

        @webhook_endpoint
        async def trigger_training(payload: WebhookPayload):
            if payload.repo.type == "dataset" and payload.event.action == "update":
                # Trigger a training job if a dataset is updated
                ...

        # Start the server manually
        trigger_training.launch()
        ```
    r2   r   c                    t                                                     |            t          j                  dk    rt	          j        j                   t          j                  fd            }|| _        | S )Nr	   c                  b    t          j         j                                                     d S r`   )atexit
unregisterrH   )apps   r   _launch_nowz5webhook_endpoint.<locals>._inner.<locals>._launch_now.  s)     cj)))JJLLLLLr   )_get_global_appr6   r^   r'   rj   registerrH   r   )r2   rm   rl   r+   s     @r   _innerz webhook_endpoint.<locals>._inner&  s    d###s&''1,,OCJ'''	sz			 	 	 	 
		
 "r   )r5   webhook_endpointr   r   r6   r   )r+   rp   s   ` r   rq   rq      st    x ~~ (!!!$'''
>%&&X (      '&  Mr   c                  :    t           t                      a t           S r`   )r   r   r@   r   r   rn   rn   :  s    $&&r   r!   c                     | /t          d           t          d           t          d           d S t          d           d S )NzZWebhook secret is not defined. This means your webhook endpoints will be open to everyone.zTo add a secret, set `WEBHOOK_SECRET` as environment variable or pass it at initialization: 
	`app = WebhooksServer(webhook_secret='my_secret', ...)`zpFor more details about webhook secrets, please refer to https://huggingface.co/docs/hub/webhooks#webhook-secret.z$Webhook secret is correctly defined.)rQ   r<   s    r   r(   r(   A  sj    jkkkJ	
 	
 	
 	H	
 	
 	
 	
 	

 	455555r   webhook_namerZ   c                 @    d| z   |                     dd          z   dz   S )z@Returns the anchor to a given webhook in the docs (experimental)z/docs#/default/r.   rS   _post)replace)rt   rZ   s     r   rY   rY   P  s'    |+l.B.B3.L.LLwVVr   r2   c                 f    t          j                   t                     dt          f fd            }dj        vrl                    t          j        dt           j        j        t                    ft          j        	                                          z             |_
        |S )a  Wraps a webhook function to check the webhook secret before calling the function.

    This is a hacky way to add the `request` parameter to the function signature. Since FastAPI based itself on route
    parameters to inject the values to the function, we need to hack the function signature to retrieve the `Request`
    object (and hence the headers). A far cleaner solution would be to use a middleware. However, since
    `fastapi==0.90.1`, a middleware cannot be added once the app has started. And since the FastAPI app is started by
    Gradio internals (and not by us), we cannot add a middleware.

    This method is called only when a secret has been defined by the user. If a request is sent without the
    "x-webhook-secret", the function will return a 401 error (unauthorized). If the header is sent but is incorrect,
    the function will return a 403 error (forbidden).

    Inspired by https://stackoverflow.com/a/33112180.
    requestc                   K   | j                             d          }|t          ddid          S |k    rt          ddid          S dj        v r| |d<   t	          j                  r d	i | d {V S  d	i |S )
Nzx-webhook-secreterrorz x-webhook-secret header not set.i  )status_codezInvalid webhook secret.i  ry   r@   )headersrM   r   
parametersinspectiscoroutinefunction)ry   r   request_secretr2   initial_sigr!   s      r   _protected_funcz6_wrap_webhook_to_check_secret.<locals>._protected_funcf  s       ,,-?@@!*L M[^____^++*C DRUVVVV ... 'F9 &t,, 	"'''''''4>>&>>!r   )namekind
annotation)r~   )r   	signaturer   r   r~   rw   	ParameterPOSITIONAL_OR_KEYWORDtuplevalues__signature__)r2   r!   r   r   s   `` @r   rK   rK   U  s     #D))K
4[["w " " " " " " " ["$ ...(3(;(;!yw7H7^krsss K*1133445 )< )
 )
% r   r`   )#rc   rj   r   r%   	functoolsr   typingr   r   r   r   r   utilsr
   r   r   r[   r_   fastapir   r   fastapi.responsesr   r   __annotations__rL   rM   rG   r   rd   rq   rn   r(   rY   rK   r@   r   r   <module>r      sM   Z Y Y   				       ? ? ? ? ? ? ? ? ? ? ? ? ? ? J J J J J J J J J J    ,((((((((....... (,+G+g +/X&' . . .JNN:&&$.	 x x x x x x x xv P P8C= PH P P P Pf    6(3- 6D 6 6 6 6Ws W# W# W W W W
- -# -( - - - - - -r   