# app/main.py from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles import os import time from app.config import get_settings from app.database import engine, Base from app.routers import auth, home_modules, nav_menus, settings as settings_router, upload, images, crawl, wechat_crawl, batch_wechat_crawl, contact_qrcodes, app_downloads, home_experts, home_partners, columns, articles, seo, prerender settings = get_settings() # Create database tables Base.metadata.create_all(bind=engine) app = FastAPI( title=settings.APP_NAME, description="飞点健康官网 CMS 系统 API", version="1.0.0" ) # CORS app.add_middleware( CORSMiddleware, allow_origins=settings.CORS_ORIGINS, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Static files for uploads # Use the actual uploads directory where crawl.py saves images # Resolve relative to backend root to match config.UPLOAD_DIR backend_root = os.path.dirname(os.path.dirname(__file__)) upload_dir = os.path.join(backend_root, settings.UPLOAD_DIR) os.makedirs(upload_dir, exist_ok=True) app.mount("/uploads", StaticFiles(directory=upload_dir), name="uploads") # New unified storage structure storage_admin_dir = os.path.join(backend_root, "..", "storage", "admin") storage_public_dir = os.path.join(backend_root, "..", "storage", "public") storage_tmp_dir = os.path.join(backend_root, "..", "storage", "tmp") os.makedirs(storage_admin_dir, exist_ok=True) os.makedirs(storage_public_dir, exist_ok=True) os.makedirs(storage_tmp_dir, exist_ok=True) app.mount("/storage/admin", StaticFiles(directory=storage_admin_dir), name="storage_admin") app.mount("/storage/public", StaticFiles(directory=storage_public_dir), name="storage_public") app.mount("/storage/tmp", StaticFiles(directory=storage_tmp_dir), name="storage_tmp") def cleanup_old_temp_files(): """启动时清理超过24小时的采集临时文件""" try: if os.name == 'nt': # Windows temp_dir = os.path.join(backend_root, "..", "storage", "tmp", "crawl") else: temp_dir = "/tmp/news_crawl" if not os.path.exists(temp_dir): return now = time.time() max_age = 24 * 3600 # 24小时 count = 0 for root, dirs, files in os.walk(temp_dir): for f in files: filepath = os.path.join(root, f) try: if now - os.path.getmtime(filepath) > max_age: os.remove(filepath) count += 1 except OSError: pass if count > 0: print(f"[cleanup] 已清理 {count} 个过期临时文件") except Exception as e: print(f"[cleanup] 清理临时文件失败: {e}") # 启动时执行清理 cleanup_old_temp_files() # Routers # SEO 路由(无 /api 前缀,直接暴露于根域名) app.include_router(seo.router) app.include_router(prerender.router) app.include_router(auth.router, prefix="/api/auth", tags=["认证"]) app.include_router(home_modules.router, prefix="/api", tags=["首页模块"]) app.include_router(nav_menus.router, prefix="/api", tags=["导航菜单"]) app.include_router(settings_router.router, prefix="/api", tags=["系统设置"]) app.include_router(upload.router, prefix="/api", tags=["文件上传"]) app.include_router(images.router, prefix="/api", tags=["图片管理"]) app.include_router(crawl.router, prefix="/api", tags=["文章采集"]) app.include_router(wechat_crawl.router, prefix="/api", tags=["公众号采集"]) app.include_router(batch_wechat_crawl.router, prefix="/api", tags=["批量公众号采集"]) app.include_router(contact_qrcodes.router, prefix="/api", tags=["咨询二维码"]) app.include_router(app_downloads.router, prefix="/api", tags=["下载应用"]) app.include_router(home_experts.router, prefix="/api", tags=["专家团队"]) app.include_router(home_partners.router, prefix="/api", tags=["合作伙伴"]) app.include_router(columns.router, prefix="/api", tags=["栏目管理"]) app.include_router(articles.router, prefix="/api", tags=["内容管理"]) @app.get("/") def root(): return { "message": f"Welcome to {settings.APP_NAME}", "docs": "/docs", "version": "1.0.0" } @app.get("/health") def health_check(): return {"status": "ok"}