|
1 | 1 | import asyncio
|
2 |
| -from typing import Awaitable, Callable |
| 2 | +import os |
| 3 | +from typing import Any, Awaitable, Callable |
3 | 4 |
|
4 | 5 | from fastapi import APIRouter, FastAPI, Request, Response, status
|
| 6 | +from fastapi.responses import RedirectResponse |
| 7 | +from fastapi.staticfiles import StaticFiles |
5 | 8 | from flux0_api.agents import (
|
6 | 9 | mount_create_agent_route,
|
7 | 10 | mount_list_agents_route,
|
|
20 | 23 | from starlette.types import ASGIApp
|
21 | 24 |
|
22 | 25 |
|
| 26 | +class SPAStaticFiles(StaticFiles): |
| 27 | + async def get_response(self, path: str, scope: Any) -> Response: |
| 28 | + assert isinstance(self.directory, str), "Static directory must be a string" |
| 29 | + |
| 30 | + full_path = os.path.join(self.directory, path) |
| 31 | + |
| 32 | + # If the file exists, serve it |
| 33 | + if os.path.isfile(full_path): |
| 34 | + return await super().get_response(path, scope) |
| 35 | + |
| 36 | + # If the file does NOT exist, serve `index.html` |
| 37 | + return await super().get_response("index.html", scope) |
| 38 | + |
| 39 | + |
23 | 40 | async def create_api_app(c: Container) -> ASGIApp:
|
24 | 41 | logger = c[Logger]
|
25 | 42 | correlator = c[ContextualCorrelator]
|
@@ -52,6 +69,16 @@ async def add_correlation_id(
|
52 | 69 | with logger.operation(f"HTTP Request: {request.method} {request.url.path}"):
|
53 | 70 | return await call_next(request)
|
54 | 71 |
|
| 72 | + static_dir = os.path.join( |
| 73 | + os.path.dirname(__file__), os.environ.get("FLUX0_STATIC_DIR", "/app/chat") |
| 74 | + ) |
| 75 | + if os.path.isdir(static_dir): |
| 76 | + api_app.mount("/chat", SPAStaticFiles(directory=static_dir), name="static") |
| 77 | + |
| 78 | + @api_app.get("/", include_in_schema=False) |
| 79 | + async def root() -> Response: |
| 80 | + return RedirectResponse("/chat") |
| 81 | + |
55 | 82 | api_router = APIRouter(prefix="/api")
|
56 | 83 |
|
57 | 84 | api_agents_router = APIRouter(prefix="/agents")
|
|
0 commit comments