diff --git a/docling_serve/app.py b/docling_serve/app.py
index 5ef0abf..249ce81 100644
--- a/docling_serve/app.py
+++ b/docling_serve/app.py
@@ -18,7 +18,13 @@ from fastapi import (
WebSocketDisconnect,
)
from fastapi.middleware.cors import CORSMiddleware
+from fastapi.openapi.docs import (
+ get_redoc_html,
+ get_swagger_ui_html,
+ get_swagger_ui_oauth2_redirect_html,
+)
from fastapi.responses import RedirectResponse
+from fastapi.staticfiles import StaticFiles
from docling.datamodel.base_models import DocumentStream
@@ -116,8 +122,18 @@ def create_app(): # noqa: C901
version = "0.0.0"
+ offline_docs_assets = False
+ if (
+ docling_serve_settings.static_path is not None
+ and (docling_serve_settings.static_path).is_dir()
+ ):
+ offline_docs_assets = True
+ _log.info("Found static assets.")
+
app = FastAPI(
title="Docling Serve",
+ docs_url=None if offline_docs_assets else "/docs",
+ redoc_url=None if offline_docs_assets else "/redocs",
lifespan=lifespan,
version=version,
)
@@ -157,6 +173,38 @@ def create_app(): # noqa: C901
"or `pip install gradio`"
)
+ #############################
+ # Offline assets definition #
+ #############################
+ if offline_docs_assets:
+ app.mount(
+ "/static",
+ StaticFiles(directory=docling_serve_settings.static_path),
+ name="static",
+ )
+
+ @app.get("/docs", include_in_schema=False)
+ async def custom_swagger_ui_html():
+ return get_swagger_ui_html(
+ openapi_url=app.openapi_url,
+ title=app.title + " - Swagger UI",
+ oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
+ swagger_js_url="/static/swagger-ui-bundle.js",
+ swagger_css_url="/static/swagger-ui.css",
+ )
+
+ @app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
+ async def swagger_ui_redirect():
+ return get_swagger_ui_oauth2_redirect_html()
+
+ @app.get("/redoc", include_in_schema=False)
+ async def redoc_html():
+ return get_redoc_html(
+ openapi_url=app.openapi_url,
+ title=app.title + " - ReDoc",
+ redoc_js_url="/static/redoc.standalone.js",
+ )
+
#############################
# API Endpoints definitions #
#############################
@@ -164,9 +212,10 @@ def create_app(): # noqa: C901
# Favicon
@app.get("/favicon.ico", include_in_schema=False)
async def favicon():
- response = RedirectResponse(
- url="https://raw.githubusercontent.com/docling-project/docling/refs/heads/main/docs/assets/logo.svg"
- )
+ logo_url = "https://raw.githubusercontent.com/docling-project/docling/refs/heads/main/docs/assets/logo.svg"
+ if offline_docs_assets:
+ logo_url = "/static/logo.svg"
+ response = RedirectResponse(url=logo_url)
return response
@app.get("/health")
diff --git a/docling_serve/gradio_ui.py b/docling_serve/gradio_ui.py
index c96b763..6d222c1 100644
--- a/docling_serve/gradio_ui.py
+++ b/docling_serve/gradio_ui.py
@@ -8,15 +8,29 @@ import gradio as gr
import requests
from docling_serve.helper_functions import _to_list_of_strings
-from docling_serve.settings import uvicorn_settings
+from docling_serve.settings import docling_serve_settings, uvicorn_settings
logger = logging.getLogger(__name__)
+############################
+# Path of static artifacts #
+############################
+
+logo_path = "https://raw.githubusercontent.com/docling-project/docling/refs/heads/main/docs/assets/logo.svg"
+js_components_url = "https://unpkg.com/@docling/docling-components@0.0.3"
+if (
+ docling_serve_settings.static_path is not None
+ and docling_serve_settings.static_path.is_dir()
+):
+ logo_path = str(docling_serve_settings.static_path / "logo.svg")
+ js_components_url = "/static/docling-components.js"
+
+
##############################
# Head JS for web components #
##############################
-head = """
-
+head = f"""
+
"""
#################
@@ -360,7 +374,7 @@ with gr.Blocks(
with gr.Column(scale=1, min_width=90):
try:
gr.Image(
- "https://raw.githubusercontent.com/docling-project/docling/refs/heads/main/docs/assets/logo.svg",
+ logo_path,
height=80,
width=80,
show_download_button=False,
diff --git a/docling_serve/settings.py b/docling_serve/settings.py
index 90676b3..9a48a04 100644
--- a/docling_serve/settings.py
+++ b/docling_serve/settings.py
@@ -30,6 +30,7 @@ class DoclingServeSettings(BaseSettings):
enable_ui: bool = False
artifacts_path: Optional[Path] = None
+ static_path: Optional[Path] = None
options_cache_size: int = 2
allow_external_plugins: bool = False
diff --git a/docs/configuration.md b/docs/configuration.md
index e375794..769fd3d 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -33,6 +33,7 @@ THe following table describes the options to configure the Docling Serve app.
| CLI option | ENV | Default | Description |
| -----------|-----|---------|-------------|
| `--artifacts-path` | `DOCLING_SERVE_ARTIFACTS_PATH` | unset | If set to a valid directory, the model weights will be loaded from this path |
+| | `DOCLING_SERVE_STATIC_PATH` | unset | If set to a valid directory, the static assets for the docs and ui will be loaded from this path |
| `--enable-ui` | `DOCLING_SERVE_ENABLE_UI` | `false` | Enable the demonstrator UI. |
| | `DOCLING_SERVE_OPTIONS_CACHE_SIZE` | `2` | How many DocumentConveter objects (including their loaded models) to keep in the cache. |
| | `DOCLING_SERVE_CORS_ORIGINS` | `["*"]` | A list of origins that should be permitted to make cross-origin requests. |