55 lines
1.7 KiB
Python
55 lines
1.7 KiB
Python
from collections.abc import AsyncGenerator
|
|
from contextlib import asynccontextmanager
|
|
|
|
from fastapi import FastAPI
|
|
from openai import AsyncOpenAI
|
|
|
|
from auth import ApiKeyAuthenticator
|
|
from config import Settings
|
|
from routes import router
|
|
from service import ChatService
|
|
from storage import JsonSessionStorage
|
|
from tools import ToolRegistry
|
|
|
|
|
|
def create_app(
|
|
settings: Settings | None = None,
|
|
client: AsyncOpenAI | None = None,
|
|
) -> FastAPI:
|
|
resolved_settings = settings or Settings.from_env()
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
|
|
resolved_client = client
|
|
if resolved_client is None:
|
|
if not resolved_settings.api_key:
|
|
raise RuntimeError("DEEPSEEK_API_KEY is required")
|
|
resolved_client = AsyncOpenAI(
|
|
api_key=resolved_settings.api_key,
|
|
base_url=resolved_settings.base_url,
|
|
)
|
|
|
|
app.state.chat_service = ChatService(
|
|
storage=JsonSessionStorage(resolved_settings.data_dir),
|
|
client=resolved_client,
|
|
model=resolved_settings.model,
|
|
default_system_prompt=resolved_settings.default_system_prompt,
|
|
tool_registry=ToolRegistry(resolved_settings.tool_timeout_seconds),
|
|
max_tool_rounds=resolved_settings.max_tool_rounds,
|
|
max_tool_calls_per_turn=resolved_settings.max_tool_calls_per_turn,
|
|
)
|
|
app.state.authenticator = ApiKeyAuthenticator(
|
|
resolved_settings.api_key_whitelist
|
|
)
|
|
yield
|
|
|
|
if client is None:
|
|
await resolved_client.close()
|
|
|
|
app = FastAPI(title="Simple Chat API", version="0.1.0", lifespan=lifespan)
|
|
app.include_router(router)
|
|
return app
|
|
|
|
|
|
app = create_app()
|