fix(edge): 配置更新时保留算法状态,避免重复告警
- 新增 update_algorithm_params() 方法,仅更新参数不重置状态机 - 修改 reload_all_algorithms() 支持 preserve_state 参数 - preserve_state=True: 保留状态机,仅更新参数(配置更新) - preserve_state=False: 完全重置(手动重启) - 修改 main.py 配置更新回调使用 preserve_state=True 修复问题:配置更新导致算法状态机重置,周界入侵CONFIRMING_CLEAR状态丢失,重新生成新告警 现在配置更新时保留告警状态,不会产生重复告警 支持算法: - leave_post: 更新 leave_countdown_sec, working_hours 等参数 - intrusion: 更新 confirm_intrusion_seconds, confirm_clear_seconds 等参数 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
105
algorithms.py
105
algorithms.py
@@ -908,22 +908,111 @@ class AlgorithmManager:
|
||||
logger.error(f"重新加载ROI算法配置失败: {e}")
|
||||
return False
|
||||
|
||||
def reload_all_algorithms(self) -> int:
|
||||
"""重新加载所有算法配置"""
|
||||
def update_algorithm_params(self, roi_id: str, bind_id: str, bind_config: dict) -> bool:
|
||||
"""仅更新算法参数,保留状态机
|
||||
|
||||
Args:
|
||||
roi_id: ROI ID
|
||||
bind_id: 绑定ID
|
||||
bind_config: 绑定配置字典(包含algo_code和params)
|
||||
|
||||
Returns:
|
||||
是否成功更新
|
||||
"""
|
||||
try:
|
||||
import json
|
||||
key = f"{roi_id}_{bind_id}"
|
||||
|
||||
# 算法实例不存在,创建新的
|
||||
if roi_id not in self.algorithms or key not in self.algorithms[roi_id]:
|
||||
return self.load_bind_from_redis(bind_id)
|
||||
|
||||
# 提取参数
|
||||
params_str = bind_config.get("params", "{}")
|
||||
params = json.loads(params_str) if isinstance(params_str, str) else params_str
|
||||
algo_code = bind_config.get("algo_code")
|
||||
|
||||
# 获取现有算法实例
|
||||
existing_algo = self.algorithms[roi_id][key].get(algo_code)
|
||||
|
||||
if existing_algo is None:
|
||||
# 算法类型不匹配,重新创建
|
||||
return self.load_bind_from_redis(bind_id)
|
||||
|
||||
# 更新参数(根据算法类型调用不同的更新方法)
|
||||
if algo_code == "leave_post":
|
||||
# 更新离岗检测参数
|
||||
leave_countdown_sec = params.get("leave_countdown_sec", 300)
|
||||
working_hours = params.get("working_hours", [])
|
||||
confirm_on_duty_sec = params.get("confirm_on_duty_sec", 10)
|
||||
confirm_leave_sec = params.get("confirm_leave_sec", 30)
|
||||
cooldown_sec = params.get("cooldown_sec", 600)
|
||||
target_class = params.get("target_class", "person")
|
||||
|
||||
existing_algo.leave_countdown_sec = leave_countdown_sec
|
||||
existing_algo.working_hours = working_hours
|
||||
existing_algo.confirm_on_duty_sec = confirm_on_duty_sec
|
||||
existing_algo.confirm_leave_sec = confirm_leave_sec
|
||||
existing_algo.cooldown_sec = cooldown_sec
|
||||
existing_algo.target_class = target_class
|
||||
|
||||
logger.info(f"[{roi_id}_{bind_id}] 更新离岗检测参数: countdown={leave_countdown_sec}s, hours={len(working_hours)}")
|
||||
|
||||
elif algo_code == "intrusion":
|
||||
# 更新周界入侵参数
|
||||
confirm_intrusion_sec = params.get("confirm_intrusion_seconds") or params.get("confirm_seconds", 5)
|
||||
confirm_clear_sec = params.get("confirm_clear_seconds", 180)
|
||||
cooldown_sec = params.get("cooldown_seconds", 300)
|
||||
target_class = params.get("target_class")
|
||||
|
||||
existing_algo.confirm_intrusion_seconds = confirm_intrusion_sec
|
||||
existing_algo.confirm_clear_seconds = confirm_clear_sec
|
||||
existing_algo.cooldown_seconds = cooldown_sec
|
||||
if target_class is not None:
|
||||
existing_algo.target_class = target_class
|
||||
|
||||
logger.info(f"[{roi_id}_{bind_id}] 更新周界入侵参数: intrusion={confirm_intrusion_sec}s, clear={confirm_clear_sec}s")
|
||||
|
||||
# 其他算法类型可以在此添加
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"更新算法参数失败 {roi_id}_{bind_id}: {e}")
|
||||
return False
|
||||
|
||||
def reload_all_algorithms(self, preserve_state: bool = True) -> int:
|
||||
"""重新加载所有算法配置
|
||||
|
||||
Args:
|
||||
preserve_state: 是否保留算法状态(默认True)
|
||||
True - 仅更新参数,保留状态机(用于配置更新)
|
||||
False - 完全重置(用于手动重启)
|
||||
|
||||
Returns:
|
||||
成功加载的算法数量
|
||||
"""
|
||||
count = 0
|
||||
try:
|
||||
from core.config_sync import get_config_sync_manager
|
||||
config_manager = get_config_sync_manager()
|
||||
bindings = config_manager.get_bindings_from_redis("")
|
||||
|
||||
|
||||
for bind in bindings:
|
||||
bind_id = bind.get("bind_id")
|
||||
roi_id = bind.get("roi_id")
|
||||
self.reset_algorithm(roi_id, bind_id)
|
||||
if self.load_bind_from_redis(bind_id):
|
||||
count += 1
|
||||
|
||||
logger.info(f"已重新加载 {count} 个算法配置")
|
||||
|
||||
if preserve_state:
|
||||
# 仅更新参数,不重置状态
|
||||
if self.update_algorithm_params(roi_id, bind_id, bind):
|
||||
count += 1
|
||||
else:
|
||||
# 完全重置
|
||||
self.reset_algorithm(roi_id, bind_id)
|
||||
if self.load_bind_from_redis(bind_id):
|
||||
count += 1
|
||||
|
||||
logger.info(f"已重新加载 {count} 个算法配置 (preserve_state={preserve_state})")
|
||||
return count
|
||||
except Exception as e:
|
||||
logger.error(f"重新加载所有算法配置失败: {e}")
|
||||
|
||||
3
main.py
3
main.py
@@ -97,7 +97,8 @@ class EdgeInferenceService:
|
||||
if self._settings.config_sync_mode == "LOCAL" and self._config_manager:
|
||||
def _on_config_update(topic, data):
|
||||
if self._algorithm_manager:
|
||||
self._algorithm_manager.reload_all_algorithms()
|
||||
# 保留状态地更新参数,避免告警重复
|
||||
self._algorithm_manager.reload_all_algorithms(preserve_state=True)
|
||||
# 配置更新后清理无ROI的摄像头流
|
||||
self._cleanup_cameras_without_roi()
|
||||
# 配置更新后动态加载新摄像头流(异步执行,不阻塞HTTP响应)
|
||||
|
||||
Reference in New Issue
Block a user