Files
Security_AI_integrated/api/alarm.py

148 lines
4.8 KiB
Python

from datetime import datetime
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query, Body
from pydantic import BaseModel
from sqlalchemy.orm import Session
from db.crud import (
create_alarm,
get_alarm_stats,
get_alarms,
update_alarm,
)
from db.models import get_db
from inference.pipeline import get_pipeline
router = APIRouter(prefix="/api/alarms", tags=["告警管理"])
class AlarmUpdateRequest(BaseModel):
llm_checked: Optional[bool] = None
llm_result: Optional[str] = None
processed: Optional[bool] = None
@router.get("", response_model=List[dict])
def list_alarms(
camera_id: Optional[int] = None,
event_type: Optional[str] = None,
limit: int = Query(default=100, le=1000),
offset: int = Query(default=0, ge=0),
db: Session = Depends(get_db),
):
alarms = get_alarms(db, camera_id=camera_id, event_type=event_type, limit=limit, offset=offset)
return [
{
"id": alarm.id,
"camera_id": alarm.camera_id,
"roi_id": alarm.roi_id,
"event_type": alarm.event_type,
"confidence": alarm.confidence,
"snapshot_path": alarm.snapshot_path,
"llm_checked": alarm.llm_checked,
"llm_result": alarm.llm_result,
"processed": alarm.processed,
"created_at": alarm.created_at.isoformat() if alarm.created_at else None,
}
for alarm in alarms
]
@router.get("/stats")
def get_alarm_statistics(db: Session = Depends(get_db)):
stats = get_alarm_stats(db)
return stats
@router.get("/{alarm_id}", response_model=dict)
def get_alarm(alarm_id: int, db: Session = Depends(get_db)):
from db.crud import get_alarms
alarms = get_alarms(db, limit=1)
alarm = next((a for a in alarms if a.id == alarm_id), None)
if not alarm:
raise HTTPException(status_code=404, detail="告警不存在")
return {
"id": alarm.id,
"camera_id": alarm.camera_id,
"roi_id": alarm.roi_id,
"event_type": alarm.event_type,
"confidence": alarm.confidence,
"snapshot_path": alarm.snapshot_path,
"llm_checked": alarm.llm_checked,
"llm_result": alarm.llm_result,
"processed": alarm.processed,
"created_at": alarm.created_at.isoformat() if alarm.created_at else None,
}
@router.put("/{alarm_id}")
def update_alarm_status(
alarm_id: int,
request: AlarmUpdateRequest = Body(...),
db: Session = Depends(get_db),
):
alarm = update_alarm(db, alarm_id, llm_checked=request.llm_checked, llm_result=request.llm_result, processed=request.processed)
if not alarm:
raise HTTPException(status_code=404, detail="告警不存在")
return {"message": "更新成功"}
@router.post("/{alarm_id}/llm-check")
async def trigger_llm_check(alarm_id: int, db: Session = Depends(get_db)):
from db.crud import get_alarms
alarms = get_alarms(db, limit=1)
alarm = next((a for a in alarms if a.id == alarm_id), None)
if not alarm:
raise HTTPException(status_code=404, detail="告警不存在")
if not alarm.snapshot_path or not os.path.exists(alarm.snapshot_path):
raise HTTPException(status_code=400, detail="截图不存在")
try:
from config import get_config
config = get_config()
if not config.llm.enabled:
raise HTTPException(status_code=400, detail="大模型功能未启用")
import base64
with open(alarm.snapshot_path, "rb") as f:
img_base64 = base64.b64encode(f.read()).decode("utf-8")
from openai import OpenAI
client = OpenAI(
api_key=config.llm.api_key,
base_url=config.llm.base_url,
)
prompt = """分析这张监控截图,判断是否存在异常行为。请简要说明:
1. 画面中是否有人
2. 人员位置和行为
3. 是否存在异常"""
response = client.chat.completions.create(
model=config.llm.model,
messages=[
{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{img_base64}"}},
{"type": "text", "text": prompt},
],
}
],
)
result = response.choices[0].message.content
update_alarm(db, alarm_id, llm_checked=True, llm_result=result)
return {"message": "大模型分析完成", "result": result}
except Exception as e:
raise HTTPException(status_code=500, detail=f"大模型调用失败: {str(e)}")
@router.get("/queue/size")
def get_event_queue_size():
pipeline = get_pipeline()
return {"size": len(pipeline.event_queue), "max_size": pipeline.config.inference.event_queue_maxlen}