diff --git a/src/phoenix/server/app.py b/src/phoenix/server/app.py index 8c3f422f07..ae18b0885b 100644 --- a/src/phoenix/server/app.py +++ b/src/phoenix/server/app.py @@ -65,6 +65,7 @@ from phoenix.server.api.routers.v1 import V1_ROUTES from phoenix.server.api.schema import schema from phoenix.server.grpc_server import GrpcServer +from phoenix.server.openapi.docs import get_swagger_ui_html from phoenix.server.telemetry import initialize_opentelemetry_tracer_provider from phoenix.trace.schemas import Span @@ -239,6 +240,10 @@ async def openapi_schema(request: Request) -> Response: return schemas.OpenAPIResponse(request=request) +async def api_docs(request: Request) -> Response: + return get_swagger_ui_html(openapi_url="/schema", title="arize-phoenix API") + + def create_app( database_url: str, export_path: Path, @@ -353,6 +358,10 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: {"path": export_path}, ), ), + Route( + "/docs", + api_docs, + ), Route( "/graphql", graphql, diff --git a/src/phoenix/server/openapi/__init__.py b/src/phoenix/server/openapi/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/phoenix/server/openapi/docs.py b/src/phoenix/server/openapi/docs.py new file mode 100644 index 0000000000..78bd6ff93b --- /dev/null +++ b/src/phoenix/server/openapi/docs.py @@ -0,0 +1,218 @@ +import json +from typing import Any, Dict, Optional + +from starlette.responses import HTMLResponse + +swagger_ui_default_parameters: Dict[str, Any] = { + "dom_id": "#swagger-ui", + "layout": "BaseLayout", + "deepLinking": True, + "showExtensions": True, + "showCommonExtensions": True, +} + + +def get_swagger_ui_html( + *, + openapi_url: str = "/schema", + title: str, + swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui-bundle.js", + swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui.css", + swagger_favicon_url: str = "/favicon.ico", + oauth2_redirect_url: Optional[str] = None, + init_oauth: Optional[str] = None, + swagger_ui_parameters: Optional[Dict[str, Any]] = None, +) -> HTMLResponse: + """ + Generate and return the HTML that loads Swagger UI for the interactive API + docs (normally served at `/docs`). + """ + current_swagger_ui_parameters = swagger_ui_default_parameters.copy() + if swagger_ui_parameters: + current_swagger_ui_parameters.update(swagger_ui_parameters) + + html = f""" + + +
+ + +