91 lines
3.3 KiB
Python
91 lines
3.3 KiB
Python
"""
|
|
FastAPI application assembly for the AlphaX Agent web surface.
|
|
"""
|
|
|
|
from contextlib import asynccontextmanager
|
|
from pathlib import Path
|
|
|
|
from fastapi import FastAPI, Request
|
|
from fastapi.responses import JSONResponse
|
|
from fastapi.templating import Jinja2Templates
|
|
|
|
from app.db.schema import init_db
|
|
from app.db import auth_db
|
|
from app.db.system_logs import record_exception
|
|
from app.db.analytics import get_all_recommendations, get_cron_run_logs, get_cron_run_summary, get_review_stats, get_stats
|
|
from app.db.recommendation_queries import get_active_recommendations, get_active_recommendations_deduped
|
|
from app.web.routes_admin import build_router as build_admin_router
|
|
from app.web.routes_auth import router as auth_router
|
|
from app.web.routes_content import build_router as build_content_router
|
|
from app.web.routes_market import router as market_router
|
|
from app.web.routes_onchain import router as onchain_router
|
|
from app.web.routes_paper_trading import router as paper_trading_router
|
|
from app.web.routes_pages import build_router as build_pages_router
|
|
from app.web.routes_recommendations import router as recommendations_router
|
|
from app.web.routes_strategy import router as strategy_router
|
|
from app.web.shared import current_request
|
|
from app.web.shared import require_active_subscription as _require_active_subscription
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
|
STOCK_REPORT_TEMPLATE = (REPO_ROOT / "templates" / "stock_report_template.html").read_text(encoding="utf-8")
|
|
HTML_PAGE = (REPO_ROOT / "static" / "app.html").read_text(encoding="utf-8")
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
init_db()
|
|
bootstrap_admin = auth_db.ensure_default_admin()
|
|
if bootstrap_admin.get("created"):
|
|
print(f"默认管理员已创建: {bootstrap_admin.get('email')}")
|
|
yield
|
|
|
|
|
|
app = FastAPI(title="AlphaX Agent", lifespan=lifespan)
|
|
templates = Jinja2Templates(directory=str(REPO_ROOT / "static"))
|
|
|
|
app.include_router(auth_router)
|
|
app.include_router(recommendations_router)
|
|
app.include_router(strategy_router)
|
|
app.include_router(onchain_router)
|
|
app.include_router(paper_trading_router)
|
|
app.include_router(market_router)
|
|
app.include_router(build_admin_router(templates))
|
|
app.include_router(build_content_router(REPO_ROOT))
|
|
app.include_router(build_pages_router(templates, REPO_ROOT, STOCK_REPORT_TEMPLATE))
|
|
|
|
|
|
@app.middleware("http")
|
|
async def bind_current_request(request: Request, call_next):
|
|
token = current_request.set(request)
|
|
try:
|
|
return await call_next(request)
|
|
finally:
|
|
current_request.reset(token)
|
|
|
|
|
|
@app.exception_handler(Exception)
|
|
async def global_exception_handler(request: Request, exc: Exception):
|
|
user = None
|
|
try:
|
|
user = auth_db.get_user_by_session_token(request.cookies.get("altcoin_session", ""))
|
|
except Exception:
|
|
user = None
|
|
log_id = record_exception(
|
|
exc,
|
|
source="web",
|
|
request_method=request.method,
|
|
request_path=request.url.path,
|
|
query_string=request.url.query,
|
|
user_email=(user or {}).get("email", ""),
|
|
user_id=(user or {}).get("id", 0),
|
|
status_code=500,
|
|
context={
|
|
"client": request.client.host if request.client else "",
|
|
"user_agent": request.headers.get("user-agent", ""),
|
|
},
|
|
)
|
|
return JSONResponse(
|
|
status_code=500,
|
|
content={"detail": "系统内部错误", "error_id": log_id},
|
|
)
|