gradio-app / gradio

Build and share delightful machine learning apps, all in Python. 🌟 Star to support our work!
http://www.gradio.app
Apache License 2.0
33.48k stars 2.53k forks source link

Application root_path not working as it gets discarded by configure_app #9788

Open amol- opened 5 days ago

amol- commented 5 days ago

Describe the bug

The root_path setting is necessary to serve FastAPI applications under subpaths served via a proxy and the ASGI frameworks are expected to strip it from the request path during the routing process, see https://github.com/django/asgiref/issues/229#issuecomment-765583185

But Gradio currently doesn't handle root_path correctly when set via create_app thus making very hard to serve Gradio applications mounted in subpaths. This is probably related to https://github.com/gradio-app/gradio/issues/8073 https://github.com/gradio-app/gradio/issues/9101 and https://github.com/gradio-app/gradio/issues/9529

When creating a Gradio application, it accepts additional options that are forwarded to the FastAPI application. This happens at https://github.com/gradio-app/gradio/blob/main/gradio/routes.py#L236

and is correctly exposed via the create_app factory https://github.com/gradio-app/gradio/blob/main/gradio/routes.py#L342

But when trying to serve Gradio under subpath, setting the root_path via create_app doesn't seem to do anything:

app = gr.routes.App.create_app(demo, app_kwargs={"root_path": "/proxy"})

The root_path is actually unset independently from the value provided, this is caused by the configure_app method invoked by the create_app factory: https://github.com/gradio-app/gradio/blob/main/gradio/routes.py#L345

The configure_app overwrites the application root_path with whatever root_path the mounted block has (which is empty), thus making the root_path setting pointless: https://github.com/gradio-app/gradio/blob/main/gradio/routes.py#L298

Have you searched existing issues? 🔎

Reproduction

import gradio as gr

def greet(name):
    return "Hello, " + name + "!"

with gr.Blocks() as demo:
    gr.Markdown("Welcome to your Gradio application!")

    name = gr.Textbox(label="Name", elem_id="name")
    greeting = gr.Textbox(label="Greeting", elem_id="greeting")
    button = gr.Button("Greet", elem_id="greet")
    button.click(fn=greet,
                 inputs=name,
                 outputs=greeting,
                 api_name="greet")

app = gr.routes.App.create_app(demo, app_kwargs={"root_path": "/proxy"})

with following NGinx configuration

        location /proxy/ {
              proxy_pass http://127.0.0.1:8000;
              proxy_set_header   Host $host;
              proxy_set_header   X-Real-IP $remote_addr;
              proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
              proxy_set_header   X-Forwarded-Proto $scheme;
        }

(the same configuration works correctly if it's a FastAPI application instead of a Gradio application)

Screenshot

No response

Logs

No response

System Info

Gradio Environment Information:
------------------------------
Operating System: Linux
gradio version: 5.2.1
gradio_client version: 1.4.1

------------------------------------------------
gradio dependencies in your environment:

aiofiles: 23.2.1
anyio: 4.6.2.post1
fastapi: 0.115.2
ffmpy: 0.4.0
gradio-client==1.4.1 is not installed.
httpx: 0.27.2
huggingface-hub: 0.25.2
jinja2: 3.1.4
markupsafe: 2.1.5
numpy: 2.1.2
orjson: 3.10.7
packaging: 24.1
pandas: 2.2.3
pillow: 10.4.0
pydantic: 2.9.2
pydub: 0.25.1
python-multipart: 0.0.12
pyyaml: 6.0.2
ruff: 0.6.9
semantic-version: 2.10.0
starlette: 0.40.0
tomlkit==0.12.0 is not installed.
typer: 0.12.5
typing-extensions: 4.12.2
urllib3: 2.2.3
uvicorn: 0.32.0
authlib; extra == 'oauth' is not installed.
itsdangerous; extra == 'oauth' is not installed.

gradio_client dependencies in your environment:

fsspec: 2024.9.0
httpx: 0.27.2
huggingface-hub: 0.25.2
packaging: 24.1
typing-extensions: 4.12.2
websockets: 12.0

Severity

Blocking usage of gradio

cornzz commented 3 days ago

Hi, does this also happen when you do demo.launch(root_path="/proxy") instead of using gr.routes.App.create_app()?

amol- commented 2 days ago

Hi, does this also happen when you do demo.launch(root_path="/proxy") instead of using gr.routes.App.create_app()?

When using demo.launch it can't happen because you are setting the root_path for the block itself. So while the app gets it overwritten by the block via configure_app it doesn't have any impact as it gets actually overwritten with the expected one.

I think that configure_app should copy the root_path from the block only when it's not empty