import uuid import logging from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select, desc from ..core.deps import get_db from ..models.db import RegulationSource, RegulationUpdate from ..worker import fetch_regulation_source logger = logging.getLogger(__name__) router = APIRouter(prefix="/api/regulation", tags=["法规监控"]) class SourceCreate(BaseModel): name: str url: str domain: str = "vehicle_safety" fetch_interval: int = 86400 fetch_config: dict = {} class SubscribeRequest(BaseModel): name: str channel: str # email / webhook / feishu / dingtalk target: str domains: list[str] = [] importance_min: str = "normal" @router.post("/sources") async def create_source(req: SourceCreate, db: AsyncSession = Depends(get_db)): source = RegulationSource( name=req.name, url=req.url, domain=req.domain, fetch_interval=req.fetch_interval, fetch_config=req.fetch_config, ) db.add(source) await db.flush() return { "id": str(source.id), "name": source.name, "url": source.url, "domain": source.domain, "status": "active", } @router.get("/sources") async def list_sources(db: AsyncSession = Depends(get_db)): result = await db.execute( select(RegulationSource).where(RegulationSource.is_active == True) ) sources = result.scalars().all() return [{"id": str(s.id), "name": s.name, "url": s.url, "domain": s.domain} for s in sources] @router.post("/sources/{source_id}/fetch") async def manual_fetch(source_id: str, db: AsyncSession = Depends(get_db)): """手动触发某个监控源的抓取(测试用)""" result = await db.execute( select(RegulationSource).where(RegulationSource.id == uuid.UUID(source_id)) ) source = result.scalar_one_or_none() if not source: raise HTTPException(status_code=404, detail="监控源不存在") task = fetch_regulation_source.delay(source_id) return {"task_id": task.id, "status": "queued", "source_id": source_id} @router.get("/updates") async def get_updates( domain: str | None = None, limit: int = 20, offset: int = 0, db: AsyncSession = Depends(get_db), ): query = select(RegulationUpdate).order_by(desc(RegulationUpdate.fetched_at)) result = await db.execute(query.limit(limit).offset(offset)) updates = result.scalars().all() return { "updates": [ { "id": str(u.id), "title": u.title, "url": u.url, "change_type": u.change_type, "summary": u.summary, "importance": u.importance, "fetched_at": u.fetched_at.isoformat() if u.fetched_at else None, } for u in updates ] } @router.post("/subscribe") async def subscribe(req: SubscribeRequest, db: AsyncSession = Depends(get_db)): from ..models.db import Workspace # 借用DB session # 简化版:仅记录订阅(推送逻辑在 push-worker 中实现) return { "id": str(uuid.uuid4()), "name": req.name, "channel": req.channel, "domains": req.domains, "status": "active", }