2026-01-16 13:22:26 +08:00
|
|
|
import logging
|
|
|
|
|
from collections.abc import AsyncGenerator
|
|
|
|
|
from contextlib import asynccontextmanager
|
|
|
|
|
|
|
|
|
|
from fastapi import FastAPI
|
|
|
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
|
|
|
|
|
|
|
|
from src.gateway.config import get_gateway_config
|
2026-01-16 23:04:38 +08:00
|
|
|
from src.gateway.routers import artifacts, models, proxy
|
2026-01-16 13:22:26 +08:00
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@asynccontextmanager
|
|
|
|
|
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
|
|
|
|
|
"""Application lifespan handler."""
|
|
|
|
|
config = get_gateway_config()
|
|
|
|
|
logger.info(f"Starting API Gateway on {config.host}:{config.port}")
|
|
|
|
|
logger.info(f"Proxying to LangGraph server at {config.langgraph_url}")
|
|
|
|
|
yield
|
|
|
|
|
logger.info("Shutting down API Gateway")
|
2026-01-19 16:52:30 +08:00
|
|
|
# Close the shared HTTP client
|
|
|
|
|
await proxy.close_http_client()
|
2026-01-16 13:22:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_app() -> FastAPI:
|
|
|
|
|
"""Create and configure the FastAPI application.
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
Configured FastAPI application instance.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
app = FastAPI(
|
|
|
|
|
title="DeerFlow API Gateway",
|
|
|
|
|
description="API Gateway for DeerFlow - proxies to LangGraph Server and provides custom endpoints",
|
|
|
|
|
version="0.1.0",
|
|
|
|
|
lifespan=lifespan,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Add CORS middleware
|
|
|
|
|
app.add_middleware(
|
|
|
|
|
CORSMiddleware,
|
2026-01-17 15:09:44 +08:00
|
|
|
allow_origins=["*"],
|
2026-01-16 13:22:26 +08:00
|
|
|
allow_credentials=True,
|
|
|
|
|
allow_methods=["*"],
|
|
|
|
|
allow_headers=["*"],
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Include routers
|
|
|
|
|
# Models API is mounted at /api/models
|
|
|
|
|
app.include_router(models.router)
|
|
|
|
|
|
2026-01-16 23:04:38 +08:00
|
|
|
# Artifacts API is mounted at /api/threads/{thread_id}/artifacts
|
|
|
|
|
app.include_router(artifacts.router)
|
|
|
|
|
|
2026-01-16 13:22:26 +08:00
|
|
|
# Proxy router handles all LangGraph paths (must be last due to catch-all)
|
|
|
|
|
app.include_router(proxy.router)
|
|
|
|
|
|
|
|
|
|
@app.get("/health")
|
|
|
|
|
async def health_check() -> dict:
|
|
|
|
|
"""Health check endpoint."""
|
|
|
|
|
return {"status": "healthy", "service": "deer-flow-gateway"}
|
|
|
|
|
|
|
|
|
|
return app
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Create app instance for uvicorn
|
|
|
|
|
app = create_app()
|