adf0d17497
publish / version_or_publish (push) Has been cancelled
storybook-build / changes (push) Has been cancelled
storybook-build / :storybook-build (push) Has been cancelled
Sync Gradio Skills to Hugging Face / sync-skills (push) Has been cancelled
functional / changes (push) Has been cancelled
functional / build-frontend (push) Has been cancelled
functional / functional-test-SSR=false (push) Has been cancelled
functional / functional-reload (push) Has been cancelled
js / changes (push) Has been cancelled
js / js-test (push) Has been cancelled
docs-build / changes (push) Has been cancelled
docs-build / docs-build (push) Has been cancelled
docs-build / website-build (push) Has been cancelled
functional / functional-test-SSR=true (push) Has been cancelled
hygiene / hygiene-test (push) Has been cancelled
python / changes (push) Has been cancelled
python / build (push) Has been cancelled
python / test-ubuntu-latest-flaky (push) Has been cancelled
python / test-ubuntu-latest-not-flaky (push) Has been cancelled
python / test-windows-latest-flaky (push) Has been cancelled
python / test-windows-latest-not-flaky (push) Has been cancelled
339 lines
13 KiB
Python
339 lines
13 KiB
Python
"""Gradio Server mode — a FastAPI-based server with Gradio's API engine."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from collections.abc import Callable, Sequence
|
|
from pathlib import Path
|
|
from typing import Any, Literal
|
|
|
|
import fastapi
|
|
from gradio_client.documentation import document
|
|
|
|
from gradio import mcp
|
|
from gradio.i18n import I18n
|
|
from gradio.routes import App
|
|
from gradio.themes import ThemeClass as Theme
|
|
|
|
|
|
class _MCPNamespace:
|
|
"""Namespace for MCP decorators: server.mcp.tool(), server.mcp.resource(), server.mcp.prompt()."""
|
|
|
|
tool = staticmethod(mcp.tool)
|
|
resource = staticmethod(mcp.resource)
|
|
prompt = staticmethod(mcp.prompt)
|
|
|
|
|
|
@document("api", "launch")
|
|
class Server(App):
|
|
"""
|
|
Server is the Gradio API engine exposed on a FastAPI application (Server mode).
|
|
It inherits from FastAPI, so all standard FastAPI methods (.get(), .post(),
|
|
.add_middleware(), .include_router(), etc.) work directly on this instance.
|
|
|
|
New methods added on top of FastAPI:
|
|
api(): Decorator to register a Gradio API endpoint with queue,
|
|
SSE streaming, and concurrency control.
|
|
mcp: Namespace with .tool(), .resource(), and .prompt() decorators
|
|
to tag functions with MCP metadata.
|
|
launch(): Creates an internal Blocks, registers deferred API
|
|
endpoints, and starts the server.
|
|
|
|
Example:
|
|
from gradio import Server
|
|
|
|
server = Server()
|
|
|
|
@server.api(name="hello")
|
|
def hello(name: str) -> str:
|
|
return f"Hello {name}"
|
|
|
|
@server.get("/")
|
|
def root():
|
|
return {"message": "Hello World"}
|
|
|
|
server.launch()
|
|
Demos: server_app
|
|
Guides: server-mode
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
*,
|
|
debug: bool = False,
|
|
title: str = "FastAPI",
|
|
summary: str | None = None,
|
|
description: str = "",
|
|
version: str = "0.1.0",
|
|
openapi_url: str | None = "/openapi.json",
|
|
openapi_tags: list[dict[str, Any]] | None = None,
|
|
servers: list[dict[str, Any]] | None = None,
|
|
dependencies: Any = None,
|
|
default_response_class: Any = None,
|
|
redirect_slashes: bool = True,
|
|
docs_url: str | None = "/docs",
|
|
redoc_url: str | None = "/redoc",
|
|
middleware: Any = None,
|
|
exception_handlers: Any = None,
|
|
on_startup: Any = None,
|
|
on_shutdown: Any = None,
|
|
lifespan: Any = None,
|
|
terms_of_service: str | None = None,
|
|
contact: dict[str, Any] | None = None,
|
|
license_info: dict[str, Any] | None = None,
|
|
root_path: str = "",
|
|
root_path_in_servers: bool = True,
|
|
responses: dict[int | str, dict[str, Any]] | None = None,
|
|
callbacks: Any = None,
|
|
webhooks: Any = None,
|
|
deprecated: bool | None = None,
|
|
include_in_schema: bool = True,
|
|
generate_unique_id_function: Any = None,
|
|
separate_input_output_schemas: bool = True,
|
|
**extra: Any,
|
|
):
|
|
"""
|
|
Parameters:
|
|
debug: Enable debug mode for detailed error tracebacks.
|
|
title: The title of the API, shown in the OpenAPI docs.
|
|
summary: A short summary of the API.
|
|
description: A longer description of the API. Supports Markdown.
|
|
version: The version of the API.
|
|
openapi_url: The URL path for the OpenAPI schema. Set to None to disable.
|
|
openapi_tags: Tags for organizing endpoints in the OpenAPI docs.
|
|
servers: Server URLs for the OpenAPI schema.
|
|
dependencies: Global dependencies applied to all routes.
|
|
default_response_class: The default response class for routes.
|
|
redirect_slashes: Whether to redirect trailing slashes.
|
|
docs_url: The URL path for the Swagger UI docs. Set to None to disable.
|
|
redoc_url: The URL path for the ReDoc docs. Set to None to disable.
|
|
middleware: List of middleware to add to the server.
|
|
exception_handlers: Custom exception handlers.
|
|
on_startup: List of startup event handlers. Prefer lifespan instead.
|
|
on_shutdown: List of shutdown event handlers. Prefer lifespan instead.
|
|
lifespan: An async context manager for startup/shutdown lifecycle.
|
|
terms_of_service: URL to the terms of service.
|
|
contact: Contact information dict for the API.
|
|
license_info: License information dict for the API.
|
|
root_path: A path prefix for the app when behind a proxy.
|
|
root_path_in_servers: Whether to include root_path in the OpenAPI servers field.
|
|
responses: Additional responses for the OpenAPI schema.
|
|
callbacks: OpenAPI callback definitions.
|
|
webhooks: OpenAPI webhook definitions.
|
|
deprecated: Mark all routes as deprecated.
|
|
include_in_schema: Whether to include all routes in the OpenAPI schema.
|
|
generate_unique_id_function: Custom function to generate unique operation IDs.
|
|
separate_input_output_schemas: Whether to generate separate input/output schemas.
|
|
"""
|
|
init_kwargs: dict[str, Any] = {
|
|
"debug": debug,
|
|
"title": title,
|
|
"summary": summary,
|
|
"description": description,
|
|
"version": version,
|
|
"openapi_url": openapi_url,
|
|
"openapi_tags": openapi_tags,
|
|
"servers": servers,
|
|
"redirect_slashes": redirect_slashes,
|
|
"docs_url": docs_url,
|
|
"redoc_url": redoc_url,
|
|
"terms_of_service": terms_of_service,
|
|
"contact": contact,
|
|
"license_info": license_info,
|
|
"root_path": root_path,
|
|
"root_path_in_servers": root_path_in_servers,
|
|
"responses": responses,
|
|
"deprecated": deprecated,
|
|
"include_in_schema": include_in_schema,
|
|
"separate_input_output_schemas": separate_input_output_schemas,
|
|
**extra,
|
|
}
|
|
if dependencies is not None:
|
|
init_kwargs["dependencies"] = dependencies
|
|
if default_response_class is not None:
|
|
init_kwargs["default_response_class"] = default_response_class
|
|
if middleware is not None:
|
|
init_kwargs["middleware"] = middleware
|
|
if exception_handlers is not None:
|
|
init_kwargs["exception_handlers"] = exception_handlers
|
|
if on_startup is not None:
|
|
init_kwargs["on_startup"] = on_startup
|
|
if on_shutdown is not None:
|
|
init_kwargs["on_shutdown"] = on_shutdown
|
|
if lifespan is not None:
|
|
init_kwargs["lifespan"] = lifespan
|
|
if callbacks is not None:
|
|
init_kwargs["callbacks"] = callbacks
|
|
if webhooks is not None:
|
|
init_kwargs["webhooks"] = webhooks
|
|
if generate_unique_id_function is not None:
|
|
init_kwargs["generate_unique_id_function"] = generate_unique_id_function
|
|
super().__init__(**init_kwargs)
|
|
self._deferred_apis: list[tuple[Callable, dict[str, Any]]] = []
|
|
self._mcp = _MCPNamespace()
|
|
|
|
@property
|
|
def mcp(self) -> _MCPNamespace:
|
|
"""MCP decorator namespace: server.mcp.tool(), server.mcp.resource(), server.mcp.prompt()."""
|
|
return self._mcp
|
|
|
|
def api(
|
|
self,
|
|
fn: Callable | None = None,
|
|
*,
|
|
name: str | None = None,
|
|
description: str | None = None,
|
|
concurrency_limit: int | None | Literal["default"] = "default",
|
|
concurrency_id: str | None = None,
|
|
queue: bool = True,
|
|
batch: bool = False,
|
|
max_batch_size: int = 4,
|
|
api_visibility: Literal["public", "private", "undocumented"] = "public",
|
|
time_limit: int | None = None,
|
|
stream_every: float = 0.5,
|
|
):
|
|
"""Decorator to register a function as a Gradio API endpoint.
|
|
|
|
Goes through Gradio's queue with concurrency control and SSE streaming.
|
|
"""
|
|
kwargs = {
|
|
"api_name": name,
|
|
"api_description": description,
|
|
"concurrency_limit": concurrency_limit,
|
|
"concurrency_id": concurrency_id,
|
|
"queue": queue,
|
|
"batch": batch,
|
|
"max_batch_size": max_batch_size,
|
|
"api_visibility": api_visibility,
|
|
"time_limit": time_limit,
|
|
"stream_every": stream_every,
|
|
}
|
|
if fn is not None:
|
|
self._deferred_apis.append((fn, kwargs))
|
|
return fn
|
|
|
|
def wrapper(func):
|
|
self._deferred_apis.append((func, kwargs))
|
|
return func
|
|
|
|
return wrapper
|
|
|
|
def launch(
|
|
self,
|
|
inline: bool | None = None,
|
|
inbrowser: bool = False,
|
|
share: bool | None = None,
|
|
debug: bool = False,
|
|
max_threads: int = 40,
|
|
auth: (
|
|
Callable[[str, str], bool] | tuple[str, str] | list[tuple[str, str]] | None
|
|
) = None,
|
|
auth_message: str | None = None,
|
|
prevent_thread_lock: bool = False,
|
|
show_error: bool = False,
|
|
server_name: str | None = None,
|
|
server_port: int | None = None,
|
|
*,
|
|
height: int = 500,
|
|
width: int | str = "100%",
|
|
favicon_path: str | Path | None = None,
|
|
ssl_keyfile: str | None = None,
|
|
ssl_certfile: str | None = None,
|
|
ssl_keyfile_password: str | None = None,
|
|
ssl_verify: bool = True,
|
|
quiet: bool = False,
|
|
footer_links: list[Literal["api", "gradio", "settings"] | dict[str, str]]
|
|
| None = None,
|
|
allowed_paths: list[str] | None = None,
|
|
blocked_paths: list[str] | None = None,
|
|
root_path: str | None = None,
|
|
app_kwargs: dict[str, Any] | None = None,
|
|
state_session_capacity: int = 10000,
|
|
share_server_address: str | None = None,
|
|
share_server_protocol: Literal["http", "https"] | None = None,
|
|
share_server_tls_certificate: str | None = None,
|
|
auth_dependency: Callable[[fastapi.Request], str | None] | None = None,
|
|
max_file_size: str | int | None = None,
|
|
enable_monitoring: bool | None = None,
|
|
strict_cors: bool = True,
|
|
node_server_name: str | None = None,
|
|
node_port: int | None = None,
|
|
ssr_mode: bool | None = None,
|
|
pwa: bool | None = None,
|
|
mcp_server: bool | None = None,
|
|
_frontend: bool = True,
|
|
i18n: I18n | None = None,
|
|
theme: Theme | str | None = None,
|
|
css: str | None = None,
|
|
css_paths: str | Path | Sequence[str | Path] | None = None,
|
|
js: str | Literal[True] | None = None,
|
|
head: str | None = None,
|
|
head_paths: str | Path | Sequence[str | Path] | None = None,
|
|
num_workers: int | None = None,
|
|
) -> tuple[App, str, str]:
|
|
"""Launch the Gradio API server (Server mode).
|
|
|
|
Parameters match ``Blocks.launch()``; see that method for full descriptions.
|
|
|
|
Returns:
|
|
Tuple of (fastapi_app, local_url, share_url).
|
|
"""
|
|
from gradio.blocks import Blocks
|
|
from gradio.events import api as gr_api
|
|
|
|
with Blocks(mode="server") as blocks:
|
|
for fn, api_kwargs in self._deferred_apis:
|
|
gr_api(fn=fn, **api_kwargs)
|
|
|
|
os.environ["GRADIO_SERVER_MODE_ENABLED"] = "1"
|
|
|
|
return blocks.launch(
|
|
_app=self,
|
|
inline=inline,
|
|
inbrowser=inbrowser,
|
|
share=share,
|
|
debug=debug,
|
|
max_threads=max_threads,
|
|
auth=auth,
|
|
auth_message=auth_message,
|
|
prevent_thread_lock=prevent_thread_lock,
|
|
show_error=show_error,
|
|
server_name=server_name,
|
|
server_port=server_port,
|
|
height=height,
|
|
width=width,
|
|
favicon_path=favicon_path,
|
|
ssl_keyfile=ssl_keyfile,
|
|
ssl_certfile=ssl_certfile,
|
|
ssl_keyfile_password=ssl_keyfile_password,
|
|
ssl_verify=ssl_verify,
|
|
quiet=quiet,
|
|
footer_links=footer_links,
|
|
allowed_paths=allowed_paths,
|
|
blocked_paths=blocked_paths,
|
|
root_path=root_path,
|
|
app_kwargs=app_kwargs,
|
|
state_session_capacity=state_session_capacity,
|
|
share_server_address=share_server_address,
|
|
share_server_protocol=share_server_protocol,
|
|
share_server_tls_certificate=share_server_tls_certificate,
|
|
auth_dependency=auth_dependency,
|
|
max_file_size=max_file_size,
|
|
enable_monitoring=enable_monitoring,
|
|
strict_cors=strict_cors,
|
|
node_server_name=node_server_name,
|
|
node_port=node_port,
|
|
ssr_mode=ssr_mode,
|
|
pwa=pwa,
|
|
mcp_server=mcp_server,
|
|
_frontend=_frontend,
|
|
i18n=i18n,
|
|
theme=theme,
|
|
css=css,
|
|
css_paths=css_paths,
|
|
js=js,
|
|
head=head,
|
|
head_paths=head_paths,
|
|
num_workers=num_workers,
|
|
)
|