from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from .database import create_tables, AsyncSessionLocal from .scheduler import start_scheduler, shutdown_scheduler from .api import news, admin from .config import settings from .models.news import LLMConfig, NewsSource @asynccontextmanager async def lifespan(app: FastAPI): await create_tables() await seed_initial_llm_config() await seed_default_sources() start_scheduler() yield shutdown_scheduler() async def seed_default_sources(): """Insert default news sources on first run if the table is empty.""" from .crawler.rss_fetcher import DEFAULT_SOURCES from sqlalchemy import select async with AsyncSessionLocal() as db: result = await db.execute(select(NewsSource).limit(1)) if result.scalar_one_or_none(): return for src in DEFAULT_SOURCES: db.add(NewsSource( name=src["name"], url=src["url"], source_type="rss", language=src["language"], category=src["category"], )) await db.commit() async def seed_initial_llm_config(): """Insert default LLM config on first run if none exists.""" from sqlalchemy import select async with AsyncSessionLocal() as db: result = await db.execute(select(LLMConfig).limit(1)) if result.scalar_one_or_none(): return if not settings.initial_llm_api_key: return config = LLMConfig( name="默认配置", provider=settings.initial_llm_provider, api_key=settings.initial_llm_api_key, base_url=settings.initial_llm_base_url, model_name=settings.initial_llm_model, is_active=True, ) db.add(config) await db.commit() app = FastAPI(title="医药情报 API", version="1.0.0", lifespan=lifespan) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], ) app.include_router(news.router, prefix="/api/news", tags=["news"]) app.include_router(admin.router, prefix="/api/admin", tags=["admin"]) @app.get("/api/health") async def health(): return {"status": "ok"}