Files
AIRegulation-Deployment/services/compliance-backend/app/api/regulation.py
2026-04-23 09:58:47 +08:00

112 lines
3.3 KiB
Python

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",
}