Ë
    Q^(h—=  ã                   ó†  — 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      €ú^/var/www/skyplay_api_hub/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´·	±	Ð:JÓ0KˆÔØ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`   ø€ à˜‘7ˆDØ# TÒ%:¨T¯]©]×$AÑ$AÀ#Ó$FÐ#GÐHˆHØ˜4×3Ñ3Ñ3Ü  8¨H¨:Ð5EÐ!FÓGÐGØ15ˆD×$Ñ$ 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                  Š	‰	€t!        d«      ‚‰	j#                  d	«      Š	d
}|ddj%                  ˆ	fd„| j                  D «       «      z   z  }|dz  }t'        |«       |s|j)                  «        yy)z Launch 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://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   ó,   •K  — | ]  }d ‰› |› �–— Œ y­w)z	  - POST N© )Ú.0ÚwebhookÚurls     €r   ú	<genexpr>z(WebhooksServer.launch.<locals>.<genexpr>Á   s   øè ø€ Ò#gÀ7 i°¨u°W°IÔ$>Ñ#gùs   ƒ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_urlr1   r0   ÚjoinÚprintÚblock_thread)
r)   r8   r9   r   Ú_r+   r2   Ú
space_hostÚmessagerC   s
            @r   rH   zWebhooksServer.launch¤   sO  ø€ ð
 �X‰XÒ/˜×-Ñ-Ó/ˆð
 	× Ñ  ¬)Ô4Ø!* §¡Ñ!U¸tÐ!UÀ}Ñ!UÑˆÔ˜!˜Qð ×2Ñ2×8Ñ8Ó:ò 	.‰JˆD�$à×"Ñ"Ð.Ü4°TÈ$×J]ÑJ]Ô^�ð (ˆD×Ñ×!Ñ! $Ó'¨Õ-ð	.ô —Z‘Z—^‘^ LÓ1ˆ
Ø)3Ð)?ˆj˜:Ò%ÀbÇlÁlÒFbÐVX×VbÑVbˆØˆ;ÜÐvÓwÐwØ�i‰i˜‹nˆØDˆØ�4˜$Ÿ)™)Ó#gÈd×NfÑNfÔ#gÓgÑgÑgˆØÐ]Ñ]ˆÜˆgŒá"Ø�O‰OÕð #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<   è ø€ ò á-˜ gð ˜,˜ rÔ*>¸w×?OÑ?OÐQ]Ó*^Ð)_Ð_`Ôañùs   ‚*,z¡Go 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Ð   € ãàˆR�Y‰Y‹[ð 	˜BØˆB�K‰KÐCÔDØˆB�K‰KðDôð ˆB�K‰KÜ�t×/Ñ/Ó0Ð1Ð1LÐMØñà—*‘*ñ à15×1IÑ1I×1OÑ1OÓ1Qôó ñôð ˆB�K‰Kõ ñ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ó "÷H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_now0  s    ø€ ô ×Ñ˜cŸj™jÔ)Ø�J‰J�Lr   )Ú_get_global_appr6   r^   r'   rj   ÚregisterrH   r   )r2   rm   rl   r+   s     @€r   Ú_innerz webhook_endpoint.<locals>._inner(  sj   ù€ äÓˆØˆ�‰˜Ó˜dÔ#Üˆs×&Ñ&Ó'¨1Ò,ä�O‰O˜CŸJ™JÔ'ä	ˆs�z‰zÓ	ó	ó 
ð	ð
 "ˆŒØˆ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.z•To 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(   C  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   R  s$   € à˜|Ñ+¨l×.BÑ.BÀ3ÈÓ.LÑLÈwÑ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_funch  sœ   øè ø€ à Ÿ™×,Ñ,Ð-?Ó@ˆØÐ!Ü Ð*LÐ MÐ[^Ô_Ð_Ø˜^Ò+Ü Ð*CÐ DÐRUÔVÐVð ˜×.Ñ.Ñ.Ø 'ˆF�9Ñô ×&Ñ& 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   W  s¤   ú€ ô ×#Ñ# DÓ)€Kä
ˆ4ƒ[ð"¤wö "ó ð"ð$ ˜×.Ñ.Ñ.Ø(3×(;Ñ(;ä×!Ñ! y´w×7HÑ7H×7^Ñ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Ð&Ñ'Ó .Ø�J‰J�N‰N˜:Ó&¨$Ð.€	ð ÷zð zó ðzðz ñP˜8 C™=ð P°Hò Pó ðPðf˜ó ð6¨(°3©-ð 6¸Dó 6ðW sð W¸#ð WÀ#ó Wð
-¨ð -À#ð -È(ô -r   