Files
minimap1.1/backend/app/main.py
2026-03-21 21:39:25 +08:00

101 lines
2.8 KiB
Python

import logging
from fastapi import FastAPI, Request
from fastapi.exceptions import RequestValidationError
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from app.config import settings
from app.database import Base, SessionLocal, engine, ensure_database_schema
from app.routers import html
from app.routers.html import cleanup_expired_files
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
)
logger = logging.getLogger(__name__)
settings.html_storage_dir.mkdir(parents=True, exist_ok=True)
Base.metadata.create_all(bind=engine)
ensure_database_schema()
app = FastAPI(
title=settings.app_name,
version="2.0.0",
description=(
"Store agent-generated educational HTML pages and return a direct access URL. "
"The generated OpenAPI document can be imported directly into Tencent Cloud "
"Agent plugins."
),
)
app.add_middleware(
CORSMiddleware,
allow_origins=settings.allowed_origins,
allow_credentials=False,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(html.router, prefix=settings.api_prefix)
def _truncate_for_log(value: str) -> str:
limit = settings.request_log_max_chars
if len(value) <= limit:
return value
return f"{value[:limit]}... [truncated {len(value) - limit} chars]"
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(
request: Request,
exc: RequestValidationError,
) -> JSONResponse:
if settings.enable_request_debug_log:
try:
raw_body = (await request.body()).decode("utf-8", errors="replace")
except Exception as body_error:
raw_body = f"<failed to read body: {body_error}>"
interesting_headers = {
key: value
for key, value in request.headers.items()
if key.lower() in {"content-type", "content-length", "x-api-key", "user-agent"}
}
logger.error(
"422 validation error: method=%s path=%s query=%s headers=%s errors=%s body=%s",
request.method,
request.url.path,
dict(request.query_params),
interesting_headers,
exc.errors(),
_truncate_for_log(raw_body),
)
return JSONResponse(
status_code=422,
content={"detail": exc.errors()},
)
@app.on_event("startup")
def cleanup_on_startup() -> None:
db = SessionLocal()
try:
deleted_count = cleanup_expired_files(db)
if deleted_count > 0:
logger.info("Deleted %s expired HTML files during startup", deleted_count)
finally:
db.close()
@app.get("/", summary="Health check")
def health_check() -> dict[str, str]:
return {
"message": "HTML Knowledge API is running",
"openapi_url": "/openapi.json",
}