
    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j2                  j5                  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"y)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                 v    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      U/var/www/openai/venv/lib/python3.12/site-packages/huggingface_hub/_webhooks_server.pyr   zWebhooksServer.__new__a   sF    "$  $%  ws##    Nui	gr.Blockswebhook_secretc                     || _         |xs t        j                  d      | _        i | _        t        | j                         y )NWEBHOOK_SECRET)_uiosgetenvr!   registered_webhooks_warn_on_empty_secret)selfr   r!   s      r   __init__zWebhooksServer.__init__n   s8    
 ,K		:J0K8: d112r   pathc                      t              r  j                               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xs |j                   j                  d       }|j                  v rt        d| d      |j                  |<   y )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   s`    7D#T%:T]]$A$A#$F#GHH4333 8H:5E!FGG15D$$X.r   )callableadd_webhookr   r   post)r)   r+   r4   s   `` r   r6   zWebhooksServer.add_webhooky   sG    8 D>%4##%d++ 
w||		6 
	6 r   prevent_thread_locklaunch_kwargsc                   	 | j                   xs | j                         }|j                  dt                |j                  dddi|\  | _        }}| j                  j                         D ]I  \  }}| j                  t        || j                        } | j
                  j                  |      |       K t        j                  j                  d      }|d|z   n|j                  xs |j                  		j!                  d      	d	}|d
d
j#                  	fd| j                  D              z   z  }|dz  }t%        |       |s|j'                          yy)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  |   yw)z	  - POST N ).0webhookurls     r   	<genexpr>z(WebhooksServer.launch.<locals>.<genexpr>   s     #gNf7iuWI$>Nfs   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   s9   
 XX/--/
 	  )4!*!Ut!U}!U!Q 2288:JD$"".4T$J]J]^ (D!!$'- ; ZZ^^L1
)3)?j:%bllFbVXVbVbiinD4$))#gdNfNf#gggg]]g"OO #r   c           	         ddl } |j                         5 } |j                  d        |j                  d        |j                  t        | j                         ddz   dj                  d | j                  j                         D              z           |j                  t        rd	nd
       ddd       |S # 1 sw Y   S xY w)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   \   K   | ]$  \  }}d | dt        |j                  |       d & yw)z- [z]()N)_get_webhook_doc_urlr/   )rA   webhook_pathrB   s      r   rD   z1WebhooksServer._get_default_ui.<locals>.<genexpr>   s=      1Q-g ,r*>w?O?OQ]*^)__`a1Qs   *,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   s    RYY[BBKKCDBKKD BKKt//011LM** 151I1I1O1O1Q  BKK qv! 2 	3 2 	s   BB;;C)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   *   sy    3j$ %)(,	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                j                        |        t        j                        dk(  rt	        j
                  j                         t        j                        fd       }|| _        | S )Nr	   c                  d    t        j                   j                          j                          y r`   )atexit
unregisterrH   )apps   r   _launch_nowz5webhook_endpoint.<locals>._inner.<locals>._launch_now.  s      cjj)JJLr   )_get_global_appr6   r^   r'   rj   registerrH   r   )r2   rm   rl   r+   s     @r   _innerz webhook_endpoint.<locals>._inner&  sj    d#s&&'1,OOCJJ'	szz		 
	
 "r   )r5   webhook_endpointr   r   r6   r   )r+   rp   s   ` r   rq   rq      sP    x ~!!$''
>%%&X (  '  Mr   c                  .    t         
t               a t         S r`   )r   r   r@   r   r   rn   rn   :  s    $&r   r!   c                 b    | "t        d       t        d       t        d       y t        d       y )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  s:    jkJ	
 	H	

 	45r   webhook_namerZ   c                 8    d| z   |j                  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LwVVr   r2   c                 f    t        j                         t               dt        f fd       }dj                  vrnj                  t        j                  dt         j                  j                  t              ft        j                  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                   j                  d      }|t        ddid      S |k7  rt        ddid      S dj                  v r| |d<   t	        j
                        r d	i | d {   S  d	i |S 7 w)
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 ... 'F9 &&t,''>&>! (s   A4B7B8B)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(;(;!!yw7H7H7^7^krs K**113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      s   Z   	  ? ? J J (. (,+G+g +/X&' .JJNN:&$.	 x x xv P8C= PH P Pf 6(3- 6D 6Ws W# W# W
- -# -( -r   