ROI选区01
This commit is contained in:
314
db/crud.py
Normal file
314
db/crud.py
Normal file
@@ -0,0 +1,314 @@
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from db.models import Camera, CameraStatus, ROI, Alarm
|
||||
|
||||
|
||||
def get_all_cameras(db: Session, enabled_only: bool = True) -> List[Camera]:
|
||||
query = db.query(Camera)
|
||||
if enabled_only:
|
||||
query = query.filter(Camera.enabled == True)
|
||||
return query.all()
|
||||
|
||||
|
||||
def get_camera_by_id(db: Session, camera_id: int) -> Optional[Camera]:
|
||||
return db.query(Camera).filter(Camera.id == camera_id).first()
|
||||
|
||||
|
||||
def create_camera(
|
||||
db: Session,
|
||||
name: str,
|
||||
rtsp_url: str,
|
||||
fps_limit: int = 30,
|
||||
process_every_n_frames: int = 3,
|
||||
) -> Camera:
|
||||
camera = Camera(
|
||||
name=name,
|
||||
rtsp_url=rtsp_url,
|
||||
fps_limit=fps_limit,
|
||||
process_every_n_frames=process_every_n_frames,
|
||||
)
|
||||
db.add(camera)
|
||||
db.commit()
|
||||
db.refresh(camera)
|
||||
return camera
|
||||
|
||||
|
||||
def update_camera(
|
||||
db: Session,
|
||||
camera_id: int,
|
||||
name: Optional[str] = None,
|
||||
rtsp_url: Optional[str] = None,
|
||||
fps_limit: Optional[int] = None,
|
||||
process_every_n_frames: Optional[int] = None,
|
||||
enabled: Optional[bool] = None,
|
||||
) -> Optional[Camera]:
|
||||
camera = get_camera_by_id(db, camera_id)
|
||||
if not camera:
|
||||
return None
|
||||
|
||||
if name is not None:
|
||||
camera.name = name
|
||||
if rtsp_url is not None:
|
||||
camera.rtsp_url = rtsp_url
|
||||
if fps_limit is not None:
|
||||
camera.fps_limit = fps_limit
|
||||
if process_every_n_frames is not None:
|
||||
camera.process_every_n_frames = process_every_n_frames
|
||||
if enabled is not None:
|
||||
camera.enabled = enabled
|
||||
|
||||
db.commit()
|
||||
db.refresh(camera)
|
||||
return camera
|
||||
|
||||
|
||||
def delete_camera(db: Session, camera_id: int) -> bool:
|
||||
camera = get_camera_by_id(db, camera_id)
|
||||
if not camera:
|
||||
return False
|
||||
|
||||
db.delete(camera)
|
||||
db.commit()
|
||||
return True
|
||||
|
||||
|
||||
def get_camera_status(db: Session, camera_id: int) -> Optional[CameraStatus]:
|
||||
return (
|
||||
db.query(CameraStatus).filter(CameraStatus.camera_id == camera_id).first()
|
||||
)
|
||||
|
||||
|
||||
def update_camera_status(
|
||||
db: Session,
|
||||
camera_id: int,
|
||||
is_running: Optional[bool] = None,
|
||||
fps: Optional[float] = None,
|
||||
error_message: Optional[str] = None,
|
||||
) -> Optional[CameraStatus]:
|
||||
status = get_camera_status(db, camera_id)
|
||||
if not status:
|
||||
status = CameraStatus(camera_id=camera_id)
|
||||
db.add(status)
|
||||
|
||||
if is_running is not None:
|
||||
status.is_running = is_running
|
||||
if fps is not None:
|
||||
status.fps = fps
|
||||
if error_message is not None:
|
||||
status.error_message = error_message
|
||||
|
||||
status.last_check_time = datetime.utcnow()
|
||||
|
||||
db.commit()
|
||||
db.refresh(status)
|
||||
return status
|
||||
|
||||
|
||||
def get_all_rois(db: Session, camera_id: Optional[int] = None) -> List[ROI]:
|
||||
query = db.query(ROI)
|
||||
if camera_id is not None:
|
||||
query = query.filter(ROI.camera_id == camera_id)
|
||||
return query.filter(ROI.enabled == True).all()
|
||||
|
||||
|
||||
def get_roi_by_id(db: Session, roi_id: int) -> Optional[ROI]:
|
||||
return db.query(ROI).filter(ROI.id == roi_id).first()
|
||||
|
||||
|
||||
def get_roi_by_roi_id(db: Session, camera_id: int, roi_id: str) -> Optional[ROI]:
|
||||
return (
|
||||
db.query(ROI)
|
||||
.filter(ROI.camera_id == camera_id, ROI.roi_id == roi_id)
|
||||
.first()
|
||||
)
|
||||
|
||||
|
||||
def create_roi(
|
||||
db: Session,
|
||||
camera_id: int,
|
||||
roi_id: str,
|
||||
name: str,
|
||||
roi_type: str,
|
||||
points: List[List[float]],
|
||||
rule_type: str,
|
||||
direction: Optional[str] = None,
|
||||
stay_time: Optional[int] = None,
|
||||
threshold_sec: int = 360,
|
||||
confirm_sec: int = 30,
|
||||
return_sec: int = 5,
|
||||
) -> ROI:
|
||||
import json
|
||||
|
||||
roi = ROI(
|
||||
camera_id=camera_id,
|
||||
roi_id=roi_id,
|
||||
name=name,
|
||||
roi_type=roi_type,
|
||||
points=json.dumps(points),
|
||||
rule_type=rule_type,
|
||||
direction=direction,
|
||||
stay_time=stay_time,
|
||||
threshold_sec=threshold_sec,
|
||||
confirm_sec=confirm_sec,
|
||||
return_sec=return_sec,
|
||||
)
|
||||
db.add(roi)
|
||||
db.commit()
|
||||
db.refresh(roi)
|
||||
return roi
|
||||
|
||||
|
||||
def update_roi(
|
||||
db: Session,
|
||||
roi_id: int,
|
||||
name: Optional[str] = None,
|
||||
points: Optional[List[List[float]]] = None,
|
||||
rule_type: Optional[str] = None,
|
||||
direction: Optional[str] = None,
|
||||
stay_time: Optional[int] = None,
|
||||
enabled: Optional[bool] = None,
|
||||
threshold_sec: Optional[int] = None,
|
||||
confirm_sec: Optional[int] = None,
|
||||
return_sec: Optional[int] = None,
|
||||
) -> Optional[ROI]:
|
||||
import json
|
||||
|
||||
roi = get_roi_by_id(db, roi_id)
|
||||
if not roi:
|
||||
return None
|
||||
|
||||
if name is not None:
|
||||
roi.name = name
|
||||
if points is not None:
|
||||
roi.points = json.dumps(points)
|
||||
if rule_type is not None:
|
||||
roi.rule_type = rule_type
|
||||
if direction is not None:
|
||||
roi.direction = direction
|
||||
if stay_time is not None:
|
||||
roi.stay_time = stay_time
|
||||
if enabled is not None:
|
||||
roi.enabled = enabled
|
||||
if threshold_sec is not None:
|
||||
roi.threshold_sec = threshold_sec
|
||||
if confirm_sec is not None:
|
||||
roi.confirm_sec = confirm_sec
|
||||
if return_sec is not None:
|
||||
roi.return_sec = return_sec
|
||||
|
||||
db.commit()
|
||||
db.refresh(roi)
|
||||
return roi
|
||||
|
||||
|
||||
def delete_roi(db: Session, roi_id: int) -> bool:
|
||||
roi = get_roi_by_id(db, roi_id)
|
||||
if not roi:
|
||||
return False
|
||||
|
||||
db.delete(roi)
|
||||
db.commit()
|
||||
return True
|
||||
|
||||
|
||||
def get_roi_points(db: Session, camera_id: int) -> List[dict]:
|
||||
import json
|
||||
|
||||
rois = get_all_rois(db, camera_id)
|
||||
return [
|
||||
{
|
||||
"id": roi.id,
|
||||
"roi_id": roi.roi_id,
|
||||
"name": roi.name,
|
||||
"type": roi.roi_type,
|
||||
"points": json.loads(roi.points),
|
||||
"rule": roi.rule_type,
|
||||
"direction": roi.direction,
|
||||
"stay_time": roi.stay_time,
|
||||
"enabled": roi.enabled,
|
||||
"threshold_sec": roi.threshold_sec,
|
||||
"confirm_sec": roi.confirm_sec,
|
||||
"return_sec": roi.return_sec,
|
||||
}
|
||||
for roi in rois
|
||||
]
|
||||
|
||||
|
||||
def create_alarm(
|
||||
db: Session,
|
||||
camera_id: int,
|
||||
event_type: str,
|
||||
confidence: float = 0.0,
|
||||
snapshot_path: Optional[str] = None,
|
||||
roi_id: Optional[str] = None,
|
||||
llm_checked: bool = False,
|
||||
llm_result: Optional[str] = None,
|
||||
) -> Alarm:
|
||||
alarm = Alarm(
|
||||
camera_id=camera_id,
|
||||
roi_id=roi_id,
|
||||
event_type=event_type,
|
||||
confidence=confidence,
|
||||
snapshot_path=snapshot_path,
|
||||
llm_checked=llm_checked,
|
||||
llm_result=llm_result,
|
||||
)
|
||||
db.add(alarm)
|
||||
db.commit()
|
||||
db.refresh(alarm)
|
||||
return alarm
|
||||
|
||||
|
||||
def get_alarms(
|
||||
db: Session,
|
||||
camera_id: Optional[int] = None,
|
||||
event_type: Optional[str] = None,
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
) -> List[Alarm]:
|
||||
query = db.query(Alarm)
|
||||
if camera_id is not None:
|
||||
query = query.filter(Alarm.camera_id == camera_id)
|
||||
if event_type is not None:
|
||||
query = query.filter(Alarm.event_type == event_type)
|
||||
return query.order_by(Alarm.created_at.desc()).offset(offset).limit(limit).all()
|
||||
|
||||
|
||||
def update_alarm(
|
||||
db: Session,
|
||||
alarm_id: int,
|
||||
llm_checked: Optional[bool] = None,
|
||||
llm_result: Optional[str] = None,
|
||||
processed: Optional[bool] = None,
|
||||
) -> Optional[Alarm]:
|
||||
alarm = db.query(Alarm).filter(Alarm.id == alarm_id).first()
|
||||
if not alarm:
|
||||
return None
|
||||
|
||||
if llm_checked is not None:
|
||||
alarm.llm_checked = llm_checked
|
||||
if llm_result is not None:
|
||||
alarm.llm_result = llm_result
|
||||
if processed is not None:
|
||||
alarm.processed = processed
|
||||
|
||||
db.commit()
|
||||
db.refresh(alarm)
|
||||
return alarm
|
||||
|
||||
|
||||
def get_alarm_stats(db: Session) -> dict:
|
||||
total = db.query(Alarm).count()
|
||||
unprocessed = db.query(Alarm).filter(Alarm.processed == False).count()
|
||||
llm_pending = db.query(Alarm).filter(
|
||||
Alarm.llm_checked == False, Alarm.processed == False
|
||||
).count()
|
||||
|
||||
return {
|
||||
"total": total,
|
||||
"unprocessed": unprocessed,
|
||||
"llm_pending": llm_pending,
|
||||
}
|
||||
167
db/models.py
Normal file
167
db/models.py
Normal file
@@ -0,0 +1,167 @@
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
from sqlalchemy import (
|
||||
Boolean,
|
||||
DateTime,
|
||||
Float,
|
||||
ForeignKey,
|
||||
Integer,
|
||||
String,
|
||||
Text,
|
||||
create_engine,
|
||||
event,
|
||||
)
|
||||
from sqlalchemy.orm import (
|
||||
DeclarativeBase,
|
||||
Mapped,
|
||||
mapped_column,
|
||||
relationship,
|
||||
sessionmaker,
|
||||
)
|
||||
|
||||
from config import get_config
|
||||
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
pass
|
||||
|
||||
|
||||
class Camera(Base):
|
||||
__tablename__ = "cameras"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
name: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
rtsp_url: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
enabled: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
fps_limit: Mapped[int] = mapped_column(Integer, default=30)
|
||||
process_every_n_frames: Mapped[int] = mapped_column(Integer, default=3)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
|
||||
)
|
||||
|
||||
rois: Mapped[List["ROI"]] = relationship(
|
||||
"ROI", back_populates="camera", cascade="all, delete-orphan"
|
||||
)
|
||||
status: Mapped[Optional["CameraStatus"]] = relationship(
|
||||
"CameraStatus", back_populates="camera", uselist=False
|
||||
)
|
||||
alarms: Mapped[List["Alarm"]] = relationship(
|
||||
"Alarm", back_populates="camera", cascade="all, delete-orphan"
|
||||
)
|
||||
|
||||
|
||||
class CameraStatus(Base):
|
||||
__tablename__ = "camera_status"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
camera_id: Mapped[int] = mapped_column(
|
||||
Integer, ForeignKey("cameras.id"), unique=True, nullable=False
|
||||
)
|
||||
is_running: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
last_frame_time: Mapped[Optional[datetime]] = mapped_column(DateTime)
|
||||
fps: Mapped[float] = mapped_column(Float, default=0.0)
|
||||
error_message: Mapped[Optional[str]] = mapped_column(Text)
|
||||
last_check_time: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
|
||||
camera: Mapped["Camera"] = relationship("Camera", back_populates="status")
|
||||
|
||||
|
||||
class ROI(Base):
|
||||
__tablename__ = "rois"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
camera_id: Mapped[int] = mapped_column(
|
||||
Integer, ForeignKey("cameras.id"), nullable=False
|
||||
)
|
||||
roi_id: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||
roi_type: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
points: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
rule_type: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
direction: Mapped[Optional[str]] = mapped_column(String(32))
|
||||
stay_time: Mapped[Optional[int]] = mapped_column(Integer)
|
||||
enabled: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
threshold_sec: Mapped[int] = mapped_column(Integer, default=360)
|
||||
confirm_sec: Mapped[int] = mapped_column(Integer, default=30)
|
||||
return_sec: Mapped[int] = mapped_column(Integer, default=5)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
|
||||
)
|
||||
|
||||
camera: Mapped["Camera"] = relationship("Camera", back_populates="rois")
|
||||
|
||||
|
||||
class Alarm(Base):
|
||||
__tablename__ = "alarms"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
camera_id: Mapped[int] = mapped_column(
|
||||
Integer, ForeignKey("cameras.id"), nullable=False
|
||||
)
|
||||
roi_id: Mapped[Optional[str]] = mapped_column(String(64))
|
||||
event_type: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
confidence: Mapped[float] = mapped_column(Float, default=0.0)
|
||||
snapshot_path: Mapped[Optional[str]] = mapped_column(Text)
|
||||
llm_checked: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
llm_result: Mapped[Optional[str]] = mapped_column(Text)
|
||||
processed: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
|
||||
camera: Mapped["Camera"] = relationship("Camera", back_populates="alarms")
|
||||
|
||||
|
||||
_engine = None
|
||||
_SessionLocal = None
|
||||
|
||||
|
||||
def get_engine():
|
||||
global _engine
|
||||
if _engine is None:
|
||||
config = get_config()
|
||||
_engine = create_engine(
|
||||
config.database.url,
|
||||
echo=config.database.echo,
|
||||
pool_pre_ping=True,
|
||||
pool_recycle=3600,
|
||||
)
|
||||
return _engine
|
||||
|
||||
|
||||
def get_session_factory():
|
||||
global _SessionLocal
|
||||
if _SessionLocal is None:
|
||||
_SessionLocal = sessionmaker(
|
||||
autocommit=False, autoflush=False, bind=get_engine()
|
||||
)
|
||||
return _SessionLocal
|
||||
|
||||
|
||||
def get_db():
|
||||
SessionLocal = get_session_factory()
|
||||
db = SessionLocal()
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def init_db():
|
||||
config = get_config()
|
||||
engine = get_engine()
|
||||
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
if config.database.dialect == "sqlite":
|
||||
for table in [Camera, ROI, Alarm]:
|
||||
table.__table__.create(engine, checkfirst=True)
|
||||
|
||||
|
||||
def reset_engine():
|
||||
global _engine, _SessionLocal
|
||||
_engine = None
|
||||
_SessionLocal = None
|
||||
Reference in New Issue
Block a user