Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions openrag/chainlit_api.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from api.middleware.auth import AuthMiddleware
from api.routers.user.download import router as download_router
from chainlit.utils import mount_chainlit
from fastapi import FastAPI

Expand All @@ -21,4 +22,12 @@ def _get_auth_service(request):
get_auth_service=_get_auth_service,
)

# Ray Serve mode runs the API and Chainlit on separate ports. Source previews
# rewrite their file download links to the browser origin (the Chainlit host),
# so this standalone Chainlit app must also expose the authorized,
# partition-checked source-download route (/static/{extract_id}) or those
# links would 404. In the mounted (/chainlit) deployment the UI shares the
# API's origin, which already serves this route.
app.include_router(download_router)

mount_chainlit(app=app, target="./app_front.py", path="/chainlit")
45 changes: 45 additions & 0 deletions tests/unit/test_chainlit_api_download.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""Regression test for the standalone Chainlit app's source-download route.

In Ray Serve mode the API and Chainlit run on separate ports. Source previews
rewrite their file download links to the browser origin (the Chainlit host),
so the standalone Chainlit app (``chainlit_api.app``) must expose the
authorized ``/static/{extract_id}`` download route — otherwise PDFs/images/audio
from search sources would 404 against the Chainlit service.
"""

from __future__ import annotations

import importlib
import sys
import types

from fastapi import FastAPI
from fastapi.responses import PlainTextResponse


def _import_chainlit_api(monkeypatch):
"""Import ``chainlit_api`` with ``chainlit`` stubbed out."""
chainlit = types.ModuleType("chainlit")
chainlit_utils = types.ModuleType("chainlit.utils")

def mount_chainlit(app: FastAPI, target: str, path: str):
@app.get(f"{path}/")
async def chainlit_page():
return PlainTextResponse("chainlit")

chainlit_utils.mount_chainlit = mount_chainlit
chainlit.utils = chainlit_utils
monkeypatch.setitem(sys.modules, "chainlit", chainlit)
monkeypatch.setitem(sys.modules, "chainlit.utils", chainlit_utils)

sys.modules.pop("chainlit_api", None)
return importlib.import_module("chainlit_api")


def test_standalone_chainlit_exposes_source_download_route(monkeypatch):
monkeypatch.setenv("AUTH_MODE", "token")

module = _import_chainlit_api(monkeypatch)

routes = {getattr(r, "name", None): getattr(r, "path", None) for r in module.app.routes}
assert routes.get("download_source") == "/static/{extract_id}"
Loading