You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

126 lines
3.3 KiB

"""
数据缓冲平台 - FastAPI 主入口
"""
import logging
from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from app.database import engine, Base
from app.config import HOST, PORT, LOG_LEVEL
from app.api import data, tasks, config, futures_analysis, ai_config
from app.services.scheduler import start_scheduler, stop_scheduler
# 配置日志
logging.basicConfig(
level=getattr(logging, LOG_LEVEL.upper(), logging.INFO),
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
)
logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI):
"""应用生命周期管理"""
# 启动时:建表 + 启动调度器
logger.info("创建数据库表...")
Base.metadata.create_all(bind=engine)
from app.analysis_db import init_analysis_db
init_analysis_db()
logger.info("期货智析数据库初始化完成")
logger.info("启动定时调度器...")
start_scheduler()
# 恢复已启用的任务
from app.database import SessionLocal
from app.services.cache import list_tasks
from app.services.scheduler import add_job
db = SessionLocal()
try:
enabled_tasks = [t for t in list_tasks(db) if t.enabled]
for t in enabled_tasks:
add_job(t.id, t.interval_seconds)
logger.info(f"恢复定时任务: {t.symbol} (每 {t.interval_seconds}s)")
finally:
db.close()
logger.info(f"数据缓冲平台已启动 http://{HOST}:{PORT}")
yield
# 关闭时
logger.info("停止调度器...")
stop_scheduler()
app = FastAPI(
title="数据缓冲平台",
description="期货/股票行情数据缓存与定时采集平台",
version="1.0.0",
lifespan=lifespan,
)
# CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 静态文件服务
STATIC_DIR = Path(__file__).resolve().parent / "static"
STATIC_DIR.mkdir(parents=True, exist_ok=True)
app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
@app.get("/ui")
def ui_page():
"""品种配置管理页面"""
return FileResponse(str(STATIC_DIR / "index.html"))
# 注册路由
app.include_router(data.router, prefix="/api/v1")
app.include_router(tasks.router, prefix="/api/v1")
app.include_router(config.router, prefix="/api/v1")
app.include_router(futures_analysis.router, prefix="/api/v1")
app.include_router(ai_config.router, prefix="/api/v1")
@app.get("/futures-analysis")
def futures_analysis_page():
"""期货智析页面"""
return FileResponse(str(STATIC_DIR / "futures_analysis.html"))
@app.get("/ai-config")
def ai_config_page():
"""AI模型配置页面"""
return FileResponse(str(STATIC_DIR / "ai_config.html"))
@app.get("/api/v1/health")
def health():
return {"status": "ok", "service": "market-data-buffer"}
@app.get("/")
def root():
return {
"message": "数据缓冲平台 API",
"docs": "/docs",
"health": "/api/v1/health",
}
if __name__ == "__main__":
import uvicorn
uvicorn.run("app.main:app", host=HOST, port=PORT, reload=True)