From 18efe72b2c98e4fbe04a74073dfd0cbe5e8bbab3 Mon Sep 17 00:00:00 2001 From: zqc <835569504@qq.com> Date: Fri, 9 Jan 2026 15:22:43 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=B0=86=E7=9B=91=E7=8B=B1?= =?UTF-8?q?=E5=B8=A6=E5=87=BA=E8=AE=B0=E5=BD=95=E5=86=99=E8=BF=9B=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- models/sur_alert_record.py | 42 ++++ rtsp_service_ws_0108.py | 22 +++ services/sur_alert_record_service.py | 275 +++++++++++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100644 models/sur_alert_record.py create mode 100644 services/sur_alert_record_service.py diff --git a/models/sur_alert_record.py b/models/sur_alert_record.py new file mode 100644 index 0000000..1a7a252 --- /dev/null +++ b/models/sur_alert_record.py @@ -0,0 +1,42 @@ +""" +告警记录表模型 +""" + +from sqlalchemy import Column, Integer, String, DateTime, Text, Float, JSON, func +from sqlalchemy.ext.declarative import declarative_base +from database.base import BaseModel + +Base = declarative_base() + + +# 告警类型常量 +class AlertType: + """告警类型常量类""" + BLACKLIST = 0 # 人脸黑名单 + WHITELIST = 1 # 人脸白名单 + PRISONER_OUT = 5 # 监狱犯人带出 + + +class SurAlertRecord(BaseModel): + """告警记录表""" + __tablename__ = "sur_alert_record" + + alert_type = Column(Integer, nullable=False, comment="类型 0=人脸黑名单,1=人脸白名单,5=监狱犯人带出") + alert_message = Column(Text, comment="消息") + alert_data = Column(JSON, comment="数据") + ori_video_url = Column(Text, comment="原始视频") + ori_img_url = Column(Text, comment="原始图片") + processed_video_url = Column(Text, comment="处理后视频") + processed_img_url = Column(Text, comment="处理后图片") + camera_id = Column(Integer, comment="摄像头") + room_id = Column(Integer, comment="房间") + room_name = Column(Text, comment="房间名称") + person_id = Column(Integer, comment="人员") + confidence = Column(Float, comment="置信度") + handled = Column(Integer, default=0, comment="处理状态:0=未处理,1=已处理") + handler_id = Column(Integer, comment="处理人") + handled_time = Column(DateTime, comment="处理时间") + handle_notes = Column(Text, comment="处理备注") + + def __repr__(self) -> str: + return f"" \ No newline at end of file diff --git a/rtsp_service_ws_0108.py b/rtsp_service_ws_0108.py index 858b9b9..759c902 100644 --- a/rtsp_service_ws_0108.py +++ b/rtsp_service_ws_0108.py @@ -25,6 +25,15 @@ try: except Exception as e: print(f"[WARN] 无法导入人脸识别算法: {e}") +# 导入数据库相关模块 +try: + from services.sur_alert_record_service import SurAlertRecordService + from database.connection import db_manager + from models.sur_alert_record import AlertType + print("[INFO] 成功导入数据库模块") +except Exception as e: + print(f"[WARN] 无法导入数据库模块: {e}") + # -------------------------- Kadian 检测相关导入 -------------------------- from npu_yolo_onnx_person_car_phone import YOLOv8_ONNX # 主检测模型(人/车/后备箱/手机) @@ -602,6 +611,19 @@ class FrameProcessorWorker(threading.Thread): if result['has_passed']: print(f"[INFO] 犯人带出: {result['passed_person_id']}") + # 插入数据库告警记录 + try: + with db_manager.get_session() as db: + alert_service = SurAlertRecordService(db) + alert_service.create_alert_record( + alert_type=AlertType.PRISONER_OUT, + person_id=int(result['passed_person_id']), + camera_id=cam_id + ) + # print(f"[INFO] 告警记录已插入数据库: person_id={result['passed_person_id']}") + except Exception as e: + print(f"[ERROR] 插入告警记录失败: {e}") + # 记录当前帧人脸告警信息 current_face_alert = { "person_name": result['passed_person_id'], diff --git a/services/sur_alert_record_service.py b/services/sur_alert_record_service.py new file mode 100644 index 0000000..08765e0 --- /dev/null +++ b/services/sur_alert_record_service.py @@ -0,0 +1,275 @@ +""" +告警记录业务逻辑服务层 +""" + +import logging +from datetime import datetime +from typing import Optional, List, Dict, Any +from sqlalchemy.orm import Session + +from models.sur_alert_record import SurAlertRecord +from utils.logger import setup_logger + +logger = setup_logger(__name__) + + +class SurAlertRecordService: + """告警记录业务服务""" + + def __init__(self, db: Session): + """ + 初始化服务 + + Args: + db: 数据库会话实例 + """ + self.db = db + + def create_alert_record( + self, + alert_type: int, + person_id: Optional[int] = None, + alert_message: Optional[str] = None, + alert_data: Optional[Dict[str, Any]] = None, + ori_video_url: Optional[str] = None, + ori_img_url: Optional[str] = None, + processed_video_url: Optional[str] = None, + processed_img_url: Optional[str] = None, + camera_id: Optional[int] = None, + room_id: Optional[int] = None, + room_name: Optional[str] = None, + confidence: Optional[float] = None, + handled: Optional[int] = None, + handler_id: Optional[int] = None, + handled_time: Optional[datetime] = None, + handle_notes: Optional[str] = None + ) -> SurAlertRecord: + """ + 创建告警记录 + + Args: + alert_type: 告警类型 + person_id: 人员ID + alert_message: 告警消息 + alert_data: 告警数据 + ori_video_url: 原始视频URL + ori_img_url: 原始图片URL + processed_video_url: 处理后视频URL + processed_img_url: 处理后图片URL + camera_id: 摄像头ID + room_id: 房间ID + room_name: 房间名称 + confidence: 置信度 + handled: 处理状态 + handler_id: 处理人ID + handled_time: 处理时间 + handle_notes: 处理备注 + + Returns: + 创建的告警记录 + """ + logger.info(f"Creating alert record: type={alert_type}, person_id={person_id}") + + # 创建告警记录 + alert_record = SurAlertRecord( + alert_type=alert_type, + person_id=person_id, + alert_message=alert_message, + alert_data=alert_data, + ori_video_url=ori_video_url, + ori_img_url=ori_img_url, + processed_video_url=processed_video_url, + processed_img_url=processed_img_url, + camera_id=camera_id, + room_id=room_id, + room_name=room_name, + confidence=confidence, + handled=handled or 0, + handler_id=handler_id, + handled_time=handled_time, + handle_notes=handle_notes + ) + + try: + self.db.add(alert_record) + self.db.commit() + self.db.refresh(alert_record) + logger.info(f"Alert record created successfully: id={alert_record.id}") + return alert_record + except Exception as e: + self.db.rollback() + logger.error(f"Failed to create alert record: {e}") + raise + + def get_alert_record_by_id(self, alert_id: int) -> Optional[SurAlertRecord]: + """ + 根据ID获取告警记录 + + Args: + alert_id: 告警记录ID + + Returns: + 告警记录或None + """ + return self.db.query(SurAlertRecord).filter(SurAlertRecord.id == alert_id).first() + + def get_alerts_by_person(self, person_id: int, limit: int = 100) -> List[SurAlertRecord]: + """ + 根据人员ID获取告警记录列表 + + Args: + person_id: 人员ID + limit: 返回数量限制 + + Returns: + 告警记录列表 + """ + return ( + self.db.query(SurAlertRecord) + .filter(SurAlertRecord.person_id == person_id) + .order_by(SurAlertRecord.created_time.desc()) + .limit(limit) + .all() + ) + + def get_alerts_by_camera(self, camera_id: int, limit: int = 100) -> List[SurAlertRecord]: + """ + 根据摄像头ID获取告警记录列表 + + Args: + camera_id: 摄像头ID + limit: 返回数量限制 + + Returns: + 告警记录列表 + """ + return ( + self.db.query(SurAlertRecord) + .filter(SurAlertRecord.camera_id == camera_id) + .order_by(SurAlertRecord.created_time.desc()) + .limit(limit) + .all() + ) + + def get_alerts_by_time_range( + self, + start_time: Optional[datetime] = None, + end_time: Optional[datetime] = None, + limit: int = 100, + offset: int = 0 + ) -> List[SurAlertRecord]: + """ + 根据时间范围获取告警记录列表 + + Args: + start_time: 开始时间 + end_time: 结束时间 + limit: 返回数量限制 + offset: 偏移量 + + Returns: + 告警记录列表 + """ + query = self.db.query(SurAlertRecord) + + if start_time: + query = query.filter(SurAlertRecord.created_time >= start_time) + if end_time: + query = query.filter(SurAlertRecord.created_time <= end_time) + + return ( + query.order_by(SurAlertRecord.created_time.desc()) + .offset(offset) + .limit(limit) + .all() + ) + + def update_alert_record( + self, + alert_id: int, + update_data: Dict[str, Any] + ) -> Optional[SurAlertRecord]: + """ + 更新告警记录 + + Args: + alert_id: 告警记录ID + update_data: 更新数据 + + Returns: + 更新后的告警记录或None + """ + logger.info(f"Updating alert record: id={alert_id}") + + alert_record = self.get_alert_record_by_id(alert_id) + if not alert_record: + logger.warning(f"Alert record not found: id={alert_id}") + return None + + try: + for key, value in update_data.items(): + if hasattr(alert_record, key) and key != 'id': + setattr(alert_record, key, value) + + self.db.commit() + self.db.refresh(alert_record) + logger.info(f"Alert record updated successfully: id={alert_record.id}") + return alert_record + except Exception as e: + self.db.rollback() + logger.error(f"Failed to update alert record: {e}") + raise + + def mark_as_handled( + self, + alert_id: int, + handler_id: int, + handle_notes: Optional[str] = None + ) -> Optional[SurAlertRecord]: + """ + 标记告警为已处理 + + Args: + alert_id: 告警记录ID + handler_id: 处理人ID + handle_notes: 处理备注 + + Returns: + 更新后的告警记录或None + """ + return self.update_alert_record( + alert_id, + { + 'handled': 1, + 'handler_id': handler_id, + 'handled_time': datetime.now(), + 'handle_notes': handle_notes + } + ) + + def delete_alert_record(self, alert_id: int) -> bool: + """ + 删除告警记录 + + Args: + alert_id: 告警记录ID + + Returns: + 是否成功删除 + """ + logger.info(f"Deleting alert record: id={alert_id}") + + alert_record = self.get_alert_record_by_id(alert_id) + if not alert_record: + logger.warning(f"Alert record not found: id={alert_id}") + return False + + try: + self.db.delete(alert_record) + self.db.commit() + logger.info(f"Alert record deleted successfully: id={alert_id}") + return True + except Exception as e: + self.db.rollback() + logger.error(f"Failed to delete alert record: {e}") + return False \ No newline at end of file