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
30.69k stars 2.28k forks source link

Gradio showing Error: NO API Found #8410

Closed yjtan0819 closed 4 weeks ago

yjtan0819 commented 1 month ago

Describe the bug

I'm working with a FastAPI application that has multiple endpoints. The 'login-demo' endpoint presents a Gradio interface with a Login Button. Once the user clicks the button and logs in via Microsoft Entra ID, I aim to show their name, preferred_username, and roles on a separate Gradio interface at the 'gradio' endpoint. This setup works perfectly on localhost. However, when I deploy this on Azure Kubernetes Service using nginx and a custom path, I encounter an issue. I can fetch the user information, but the 'gradio' endpoint returns an 'Error: NO API Found' and does not display the user information.

https://fastapi.example.com/login-demo is accessed by the nginx proxy to http://0.0.0.0:7000/login-demo for example.

I'm seeking assistance to resolve this issue. Can anyone help please?

Have you searched existing issues? 🔎

Reproduction

import gradio as gr
import os
from authlib.integrations.starlette_client import OAuth, OAuthError
from fastapi import FastAPI, Depends, Request, Cookie
from starlette.config import Config
from starlette.responses import RedirectResponse
from starlette.middleware.sessions import SessionMiddleware
import uvicorn
import gradio as gr
import hashlib

app = FastAPI()
AZURE_CLIENT_ID = os.getenv("AZURE_CLIENT_ID")
AZURE_CLIENT_SECRET = os.getenv("AZURE_CLIENT_SECRET")
AZURE_TENANT_ID = os.getenv("AZURE_TENANT_ID")
SECRET_KEY = hashlib.sha256(AZURE_CLIENT_SECRET.encode()).hexdigest()

config_data = {'AZURE_CLIENT_ID': AZURE_CLIENT_ID, 'AZURE_CLIENT_SECRET': AZURE_CLIENT_SECRET}
starlette_config = Config(environ=config_data)
oauth = OAuth(starlette_config)
oauth.register(
    name='azure',
    server_metadata_url='https://login.microsoftonline.com/{tenant_id}/v2.0/.well-known/openid-configuration'.format(tenant_id=AZURE_TENANT_ID),
    client_kwargs={'scope': 'openid email profile'},
)
app.add_middleware(SessionMiddleware, secret_key=SECRET_KEY)

# Dependency to get the current user
def get_user(request: Request):
    user = request.session.get('user')
    print(user)
    if user:
        return user
    return None

@app.get('/')
def public(user: dict = Depends(get_user)):
    if user:
        return RedirectResponse(url='/gradio/')
    else:
        return RedirectResponse(url='/login-demo/')

@app.route('/logout')
async def logout(request: Request):
    request.session.pop('user', None)
    return RedirectResponse(url='/')

@app.route('/login')
async def login(request: Request):
    redirect_uri = request.url_for('auth')
    redirect_uri = str(redirect_uri).replace("http://", "https://")
    return await oauth.azure.authorize_redirect(request, redirect_uri)

@app.route('/auth')
async def auth(request: Request):
    try:
        access_token = await oauth.azure.authorize_access_token(request)
    except OAuthError:
        return RedirectResponse(url='/')
    request.session['user'] = dict(access_token)["userinfo"]
    return RedirectResponse(url='/gradio')

with gr.Blocks() as login_demo:
    gr.Button("Login", link="/login")

app = gr.mount_gradio_app(app, login_demo, path="/login-demo")

def greet(request: gr.Request):
    name = request.username['name']
    preferred_username = request.username['preferred_username']
    roles = request.username['roles']
    return f"Welcome to Gradio, {name}! Your preferred username is {preferred_username} and your roles are {roles}."

with gr.Blocks() as main_demo:
    m = gr.Markdown("Welcome to Gradio!")
    gr.Button("Logout", link="/logout")
    main_demo.load(greet, None, m)

app = gr.mount_gradio_app(app, main_demo, path="/gradio", auth_dependency=get_user)

if __name__ == '__main__':
    uvicorn.run("app:app", host='0.0.0.0', port=7000, forwarded_allow_ips='*')

Screenshot

  1. First screenshot is the wanted result which is displayed on localhost Screenshot 2024-05-29 161821
  2. Second screenshot is the result when launched on AKS with nginx Screenshot 2024-05-29 152737

Logs

No response

System Info

Gradio Environment Information:
------------------------------
Operating System: Linux
gradio version: 4.31.5
gradio_client version: 0.16.4

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

aiofiles: 23.2.1
altair: 5.3.0
fastapi: 0.111.0
ffmpy: 0.3.2
gradio-client==0.16.4 is not installed.
httpx: 0.27.0
huggingface-hub: 0.23.2
importlib-resources: 6.4.0
jinja2: 3.1.4
markupsafe: 2.1.5
matplotlib: 3.9.0
numpy: 1.26.4
orjson: 3.10.3
packaging: 24.0
pandas: 2.2.2
pillow: 10.3.0
pydantic: 2.7.2
pydub: 0.25.1
python-multipart: 0.0.9
pyyaml: 6.0.1
ruff: 0.4.6
semantic-version: 2.10.0
tomlkit==0.12.0 is not installed.
typer: 0.12.3
typing-extensions: 4.12.0
urllib3: 2.2.1
uvicorn: 0.30.0
authlib; extra == 'oauth' is not installed.
itsdangerous; extra == 'oauth' is not installed.

gradio_client dependencies in your environment:

fsspec: 2024.5.0
httpx: 0.27.0
huggingface-hub: 0.23.2
packaging: 24.0
typing-extensions: 4.12.0
websockets: 11.0.3

Severity

Blocking usage of gradio

yjtan0819 commented 1 month ago

Update: I successfully integrated the bar_plot_demo from this GitHub link into a FastAPI path. I achieved this by appending app = gr.mount_gradio_app(app, bar_plot, path="/") at the end of the script. However, on my AKS server, this setup only functions correctly when I mount the bar plot on the root path /. If I attempt to mount it on a different path, let's say /test, I encounter an "Error: No API Found" message.

pievalentin commented 1 month ago

I have the same error trying to deploy my app with azure auth. Seems like mount_gradio_app is not behaving as expected.

yjtan0819 commented 4 weeks ago

This issue has been solved by adding a parameter root_path in gr.mount_gradio_app, which will tell the gradio interface to fetch the required information at the right path.