o
    h=                     @   sD  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r9ddlZddlmZ e rKddlmZmZ dd	lmZ nd Z ZZdaed
 ed< ejddu ZeG dd
 d
Zeddee de	fddZdefddZdee ddfddZ dededefddZ!de	dede	fd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                       s   e Zd ZdZd fddZ		dded dee ddfd	d
Zddee defddZ	dde
deddfddZdddZ  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                    s(   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__ t/var/www/html/construction_image-detection-poc/venv/lib/python3.10/site-packages/huggingface_hub/_webhooks_server.pyr   a   s   zWebhooksServer.__new__Nui	gr.Blockswebhook_secretc                 C   s*   || _ |p	td| _i | _t| j d S )NWEBHOOK_SECRET)_uiosgetenvr   registered_webhooks_warn_on_empty_secret)selfr   r   r   r   r   __init__n   s   zWebhooksServer.__init__pathc                    s0   t  r
  S ttj fd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                     sF   | 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_pathr(   r&   r   r   _inner_post   s
   
z/WebhooksServer.add_webhook.<locals>._inner_post)callableadd_webhookr   r   post)r&   r(   r0   r   r/   r   r2   y   s
   zWebhooksServer.add_webhookFprevent_thread_locklaunch_kwargsc           	         s   | j p|  }|dt |jdddi|\| _}}| j D ]\}}| jdur0t	|| jd}| j
|| q tjd}|durGd| n|jpL|j  du rUtd d	 d
}|dd fdd| jD  7 }|d7 }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.
        sharer4   TNr   
SPACE_HOSTzhttps://zWCannot find the URL of the app. Please provide a valid `ui` or update `gradio` version.r)   z/
Webhooks are correctly setup and ready to use:
c                 3   s    | ]
}d   | V  qdS )z	  - POST Nr   ).0webhookurlr   r   	<genexpr>   s    z(WebhooksServer.launch.<locals>.<genexpr>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_secretr3   r"   environget	share_url	local_urlr,   r+   joinprintblock_thread)	r&   r4   r5   r   _r(   r-   
space_hostmessager   r<   r   rB      s&   

"zWebhooksServer.launchc              	   C   s   ddl }| 6}|d |d |t| j dd ddd	 | j D   |tr3d
nd W d   |S 1 sAw   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                 s   s.    | ]\}}d | dt |j| dV  qdS )z- [z]()N)_get_webhook_doc_urlr*   )r:   webhook_pathr;   r   r   r   r>      s
    
z1WebhooksServer._get_default_ui.<locals>.<genexpr>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$   rJ   rD   rA   )r&   grr   r   r   r   r?      s0   



zWebhooksServer._get_default_ui)r   r   )NNN)F)r   r   )r*   
__module____qualname____doc__r   r   strr'   r   r2   boolr   rB   r?   __classcell__r   r   r   r   r   *   s    5
+$r(   r   c                    s6   t  r	t  S ttjdtdtf fd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()
        ```
    r-   r   c                    sN   t    |  t jdkrt j t j fdd}|| _| S )Nr   c                      s   t  j    d S rX   )atexit
unregisterrB   r   appr   r   _launch_now0  s   z5webhook_endpoint.<locals>._inner.<locals>._launch_now)_get_global_appr2   rV   r$   r_   registerrB   r   )r-   rc   r(   ra   r   _inner(  s   z webhook_endpoint.<locals>._inner)r1   webhook_endpointr   r   r2   r   )r(   rg   r   rf   r   rh      s
   <
rh   c                   C   s   t d u rt a t S rX   )r   r   r   r   r   r   rd   <  s   rd   r   c                 C   s0   | d u r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.)rK   r7   r   r   r   r%   C  s   r%   webhook_namerR   c                 C   s   d|  | dd d S )z@Returns the anchor to a given webhook in the docs (experimental)z/docs#/default/r)   rM   _post)replace)ri   rR   r   r   r   rQ   R  s   rQ   r-   c                    sd   t  t dtf fdd}djvr0jt jdt jjtdftj	  d|_
|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                    s|   | j d}|d u rtddiddS |krtddiddS djv r(| |d< t r7 d	i |I d H S  d	i |S )
Nzx-webhook-secreterrorz x-webhook-secret header not set.i  )status_codezInvalid webhook secret.i  rl   r   )headersrG   r   
parametersinspectiscoroutinefunction)rl   r   request_secretr-   initial_sigr   r   r   _protected_funch  s   

z6_wrap_webhook_to_check_secret.<locals>._protected_func)namekind
annotation)rp   )rq   	signaturer   r   rp   rk   	ParameterPOSITIONAL_OR_KEYWORDtuplevalues__signature__)r-   r   rv   r   rt   r   rE   W  s   

rE   rX   )#r[   r_   rq   r"   	functoolsr   typingr   r   r   r   r   utilsr	   r
   r   rS   rW   fastapir   r   fastapi.responsesr   r   __annotations__rF   rG   rA   r   r\   rh   rd   r%   rQ   rE   r   r   r   r   <module>   s2    >S