free-claude-code/api/app.py

87 lines
2.4 KiB
Python

"""FastAPI application factory and configuration."""
import os
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from loguru import logger
from config.logging_config import configure_logging
from config.settings import get_settings
from providers.exceptions import ProviderError
from .dependencies import cleanup_provider
from .routes import router
from .runtime import AppRuntime, warn_if_process_auth_token
# Opt-in to future behavior for python-telegram-bot
os.environ["PTB_TIMEDELTA"] = "1"
# Configure logging first (before any module logs)
_settings = get_settings()
configure_logging(_settings.log_file)
def _warn_if_process_auth_token(settings) -> None:
"""Compatibility wrapper for tests importing the old app helper."""
warn_if_process_auth_token(settings)
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan manager."""
runtime = AppRuntime.for_app(
app, settings=get_settings(), provider_cleanup=cleanup_provider
)
await runtime.startup()
yield
await runtime.shutdown()
def create_app() -> FastAPI:
"""Create and configure the FastAPI application."""
app = FastAPI(
title="Claude Code Proxy",
version="2.0.0",
lifespan=lifespan,
)
# Register routes
app.include_router(router)
# Exception handlers
@app.exception_handler(ProviderError)
async def provider_error_handler(request: Request, exc: ProviderError):
"""Handle provider-specific errors and return Anthropic format."""
logger.error(f"Provider Error: {exc.error_type} - {exc.message}")
return JSONResponse(
status_code=exc.status_code,
content=exc.to_anthropic_format(),
)
@app.exception_handler(Exception)
async def general_error_handler(request: Request, exc: Exception):
"""Handle general errors and return Anthropic format."""
logger.error(f"General Error: {exc!s}")
import traceback
logger.error(traceback.format_exc())
return JSONResponse(
status_code=500,
content={
"type": "error",
"error": {
"type": "api_error",
"message": "An unexpected error occurred.",
},
},
)
return app
# Default app instance for uvicorn
app = create_app()