feat(aiot): 告警三表结构升级 + 腾讯云COS对象存储集成
1. 新增三表结构: alarm_event(主表), alarm_event_ext(算法扩展), alarm_llm_analysis(大模型分析) 2. 新增 AlarmEventService 服务,支持 MQTT/HTTP 双路创建告警 3. MQTT handler 双写新旧表,平滑过渡 4. 重写 yudao_aiot_alarm 路由,对接新告警服务 5. 集成腾讯云 COS 对象存储:上传、预签名URL、STS临时凭证 6. 新增 storage 路由:upload/presign/upload-url/sts 四个接口 7. COS 未启用时自动降级本地 uploads/ 目录存储 8. 新增数据迁移脚本 migrate_to_alarm_event.py 9. 删除根目录 main.py(非项目入口) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
114
app/models.py
114
app/models.py
@@ -6,7 +6,7 @@ import os
|
||||
from datetime import datetime, timezone
|
||||
from typing import Optional
|
||||
from sqlalchemy import (
|
||||
Column, String, Integer, BigInteger, DateTime, Text, Enum, JSON,
|
||||
Column, String, Integer, SmallInteger, BigInteger, Boolean, Float, DateTime, Text, Enum, JSON,
|
||||
ForeignKey, create_engine, Index
|
||||
)
|
||||
from sqlalchemy.orm import declarative_base, sessionmaker, relationship
|
||||
@@ -254,6 +254,118 @@ class EdgeDevice(Base):
|
||||
}
|
||||
|
||||
|
||||
# ==================== 新告警三表结构 ====================
|
||||
|
||||
class AlarmEvent(Base):
|
||||
"""告警事件主表"""
|
||||
__tablename__ = "alarm_event"
|
||||
|
||||
alarm_id = Column(String(64), primary_key=True, comment="分布式告警ID")
|
||||
alarm_type = Column(String(32), nullable=False, comment="告警类型")
|
||||
algorithm_code = Column(String(64), comment="算法编码")
|
||||
device_id = Column(String(64), nullable=False, comment="摄像头/设备ID")
|
||||
scene_id = Column(String(64), comment="场景/ROI ID")
|
||||
event_time = Column(DateTime, nullable=False, comment="事件发生时间")
|
||||
first_frame_time = Column(DateTime, comment="首帧时间")
|
||||
last_frame_time = Column(DateTime, comment="末帧时间")
|
||||
duration_ms = Column(Integer, comment="持续时长(毫秒)")
|
||||
alarm_level = Column(SmallInteger, comment="告警级别: 1提醒 2一般 3严重 4紧急")
|
||||
confidence_score = Column(Float, comment="置信度 0-1")
|
||||
alarm_status = Column(String(20), default="NEW", comment="告警状态: NEW/CONFIRMED/FALSE/CLOSED")
|
||||
handle_status = Column(String(20), default="UNHANDLED", comment="处理状态: UNHANDLED/HANDLING/DONE")
|
||||
snapshot_url = Column(String(512), comment="截图URL")
|
||||
video_url = Column(String(512), comment="视频URL")
|
||||
edge_node_id = Column(String(64), comment="边缘节点ID")
|
||||
handler = Column(String(64), comment="处理人")
|
||||
handle_remark = Column(Text, comment="处理备注")
|
||||
handled_at = Column(DateTime, comment="处理时间")
|
||||
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
|
||||
updated_at = Column(DateTime, default=lambda: datetime.now(timezone.utc),
|
||||
onupdate=lambda: datetime.now(timezone.utc))
|
||||
|
||||
__table_args__ = (
|
||||
Index('idx_alarm_event_time', 'event_time'),
|
||||
Index('idx_alarm_device_type', 'device_id', 'alarm_type'),
|
||||
)
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"alarm_id": self.alarm_id,
|
||||
"alarm_type": self.alarm_type,
|
||||
"algorithm_code": self.algorithm_code,
|
||||
"device_id": self.device_id,
|
||||
"scene_id": self.scene_id,
|
||||
"event_time": self.event_time.isoformat() if self.event_time else None,
|
||||
"first_frame_time": self.first_frame_time.isoformat() if self.first_frame_time else None,
|
||||
"last_frame_time": self.last_frame_time.isoformat() if self.last_frame_time else None,
|
||||
"duration_ms": self.duration_ms,
|
||||
"alarm_level": self.alarm_level,
|
||||
"confidence_score": self.confidence_score,
|
||||
"alarm_status": self.alarm_status,
|
||||
"handle_status": self.handle_status,
|
||||
"snapshot_url": self.snapshot_url,
|
||||
"video_url": self.video_url,
|
||||
"edge_node_id": self.edge_node_id,
|
||||
"handler": self.handler,
|
||||
"handle_remark": self.handle_remark,
|
||||
"handled_at": self.handled_at.isoformat() if self.handled_at else None,
|
||||
"created_at": self.created_at.isoformat() if self.created_at else None,
|
||||
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
||||
}
|
||||
|
||||
|
||||
class AlarmEventExt(Base):
|
||||
"""告警事件扩展表(算法结果详情)"""
|
||||
__tablename__ = "alarm_event_ext"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
alarm_id = Column(String(64), nullable=False, index=True, comment="关联告警ID")
|
||||
ext_type = Column(String(32), comment="扩展类型: EDGE/POST/MANUAL")
|
||||
ext_data = Column(JSON, comment="扩展数据")
|
||||
roi_config = Column(JSON, comment="ROI配置快照")
|
||||
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"id": self.id,
|
||||
"alarm_id": self.alarm_id,
|
||||
"ext_type": self.ext_type,
|
||||
"ext_data": self.ext_data,
|
||||
"roi_config": self.roi_config,
|
||||
"created_at": self.created_at.isoformat() if self.created_at else None,
|
||||
}
|
||||
|
||||
|
||||
class AlarmLlmAnalysis(Base):
|
||||
"""告警大模型分析表"""
|
||||
__tablename__ = "alarm_llm_analysis"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
alarm_id = Column(String(64), nullable=False, index=True, comment="关联告警ID")
|
||||
llm_model = Column(String(32), comment="模型名称")
|
||||
analysis_type = Column(String(20), comment="分析类型: REVIEW/EXPLAIN/RISK")
|
||||
summary = Column(Text, comment="分析摘要")
|
||||
is_false_alarm = Column(Boolean, comment="是否误报")
|
||||
risk_score = Column(Integer, comment="风险评分 0-100")
|
||||
confidence_score = Column(Float, comment="分析置信度")
|
||||
suggestion = Column(Text, comment="处置建议")
|
||||
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"id": self.id,
|
||||
"alarm_id": self.alarm_id,
|
||||
"llm_model": self.llm_model,
|
||||
"analysis_type": self.analysis_type,
|
||||
"summary": self.summary,
|
||||
"is_false_alarm": self.is_false_alarm,
|
||||
"risk_score": self.risk_score,
|
||||
"confidence_score": self.confidence_score,
|
||||
"suggestion": self.suggestion,
|
||||
"created_at": self.created_at.isoformat() if self.created_at else None,
|
||||
}
|
||||
|
||||
|
||||
# ==================== 数据库管理 ====================
|
||||
|
||||
_engine = None
|
||||
|
||||
Reference in New Issue
Block a user