565 lines
23 KiB
Python
565 lines
23 KiB
Python
|
|
# 作者:北小菜
|
|||
|
|
"""业务算法管理 — 小模型/大模型 + 后处理业务逻辑"""
|
|||
|
|
import json
|
|||
|
|
|
|||
|
|
from app.views.ViewsBase import *
|
|||
|
|
from django.shortcuts import render
|
|||
|
|
|
|||
|
|
from app.models import BizAlgorithmModel, AlgorithmModel, LLMModel, ZoneModel
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _parse_labels(raw):
|
|||
|
|
if isinstance(raw, list):
|
|||
|
|
return [str(x).strip() for x in raw if str(x).strip()]
|
|||
|
|
if isinstance(raw, str):
|
|||
|
|
try:
|
|||
|
|
arr = json.loads(raw)
|
|||
|
|
if isinstance(arr, list):
|
|||
|
|
return [str(x).strip() for x in arr if str(x).strip()]
|
|||
|
|
except Exception:
|
|||
|
|
pass
|
|||
|
|
return [s.strip() for s in raw.split(",") if s.strip()]
|
|||
|
|
return []
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _resolve_model_abs_path(model_file):
|
|||
|
|
"""返回模型文件的绝对路径(不存在则返回空串)"""
|
|||
|
|
if not model_file:
|
|||
|
|
return ""
|
|||
|
|
try:
|
|||
|
|
from app.analysis.worker_pool import resolve_model_path
|
|||
|
|
p = resolve_model_path(model_file)
|
|||
|
|
import os as _os
|
|||
|
|
if p and _os.path.exists(p):
|
|||
|
|
return p
|
|||
|
|
except Exception:
|
|||
|
|
pass
|
|||
|
|
return ""
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _check_model_file_exists(model_file):
|
|||
|
|
"""检查模型文件是否存在"""
|
|||
|
|
return bool(_resolve_model_abs_path(model_file))
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _biz_to_dict(b, detail=False):
|
|||
|
|
labels = _parse_labels(b.target_labels or '[]')
|
|||
|
|
d = {
|
|||
|
|
"id": b.id,
|
|||
|
|
"name": b.name,
|
|||
|
|
"flow_type": b.flow_type,
|
|||
|
|
"small_model_id": b.small_model_id,
|
|||
|
|
"small_model_name": b.small_model.name if b.small_model_id and b.small_model else "",
|
|||
|
|
"detector_model_id": b.detector_model_id,
|
|||
|
|
"detector_model_name": b.detector_model.name if b.detector_model_id and b.detector_model else "",
|
|||
|
|
"target_labels": labels,
|
|||
|
|
"llm_id": b.llm_id,
|
|||
|
|
"llm_name": ((b.llm.name or b.llm.model_name) if b.llm_id and b.llm else ""),
|
|||
|
|
"llm_prompt": b.llm_prompt or "",
|
|||
|
|
"llm_validate": b.llm_validate or "",
|
|||
|
|
"post_process": b.post_process or BizAlgorithmModel.POST_AREA,
|
|||
|
|
"ref_angle": float(getattr(b, "ref_angle", 90.0) or 90.0),
|
|||
|
|
"angle_tolerance": float(getattr(b, "angle_tolerance", 45.0) or 45.0),
|
|||
|
|
"forward_count_threshold": int(getattr(b, "forward_count_threshold", 0) or 0),
|
|||
|
|
"reverse_count_threshold": int(getattr(b, "reverse_count_threshold", 0) or 0),
|
|||
|
|
"state": b.state,
|
|||
|
|
"create_time": str(b.create_time),
|
|||
|
|
"zone_count": b.zones.count(),
|
|||
|
|
}
|
|||
|
|
# 小模型文件状态
|
|||
|
|
small = b.small_model if (b.small_model_id and b.small_model) else None
|
|||
|
|
if small:
|
|||
|
|
d["small_model_file"] = small.model_file or ""
|
|||
|
|
d["small_model_engine"] = small.inference_engine or ""
|
|||
|
|
d["small_model_file_exists"] = _check_model_file_exists(small.model_file or "")
|
|||
|
|
d["small_model_file_path"] = _resolve_model_abs_path(small.model_file or "")
|
|||
|
|
else:
|
|||
|
|
d["small_model_file"] = ""
|
|||
|
|
d["small_model_engine"] = ""
|
|||
|
|
d["small_model_file_exists"] = False
|
|||
|
|
d["small_model_file_path"] = ""
|
|||
|
|
detector = b.detector_model if (b.detector_model_id and b.detector_model) else None
|
|||
|
|
if detector:
|
|||
|
|
d["detector_model_file"] = detector.model_file or ""
|
|||
|
|
d["detector_model_engine"] = detector.inference_engine or ""
|
|||
|
|
d["detector_model_file_exists"] = _check_model_file_exists(detector.model_file or "")
|
|||
|
|
else:
|
|||
|
|
d["detector_model_file"] = ""
|
|||
|
|
d["detector_model_engine"] = ""
|
|||
|
|
d["detector_model_file_exists"] = False
|
|||
|
|
flow_names = {
|
|||
|
|
BizAlgorithmModel.FLOW_SMALL: "小模型+后处理",
|
|||
|
|
BizAlgorithmModel.FLOW_LLM: "大模型+后处理",
|
|||
|
|
BizAlgorithmModel.FLOW_BOTH: "小模型+大模型+后处理",
|
|||
|
|
BizAlgorithmModel.FLOW_DETECT_REID: "检测+ReID+后处理",
|
|||
|
|
}
|
|||
|
|
d["flow_type_name"] = flow_names.get(b.flow_type, str(b.flow_type))
|
|||
|
|
post_names = {
|
|||
|
|
BizAlgorithmModel.POST_AREA: "区域入侵",
|
|||
|
|
BizAlgorithmModel.POST_LINE_CROSS: "越线检测",
|
|||
|
|
BizAlgorithmModel.POST_LINE_COUNT: "越线计数",
|
|||
|
|
BizAlgorithmModel.POST_DIRECTION: "方向入侵",
|
|||
|
|
BizAlgorithmModel.POST_DENSITY: "密度报警",
|
|||
|
|
BizAlgorithmModel.POST_DWELL: "滞留报警",
|
|||
|
|
}
|
|||
|
|
d["post_process_name"] = post_names.get(d["post_process"], d["post_process"])
|
|||
|
|
return d
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _validate_biz_fields(params, biz_id=0):
|
|||
|
|
name = (params.get("name") or "").strip()
|
|||
|
|
if not name:
|
|||
|
|
raise ValueError("算法名称不能为空")
|
|||
|
|
try:
|
|||
|
|
flow_type = int(params.get("flow_type", 1))
|
|||
|
|
except Exception:
|
|||
|
|
flow_type = 1
|
|||
|
|
if flow_type not in (1, 2, 3, 4):
|
|||
|
|
raise ValueError("无效的流程类型")
|
|||
|
|
|
|||
|
|
small_model_id = None
|
|||
|
|
detector_model_id = None
|
|||
|
|
llm_id = None
|
|||
|
|
target_labels = []
|
|||
|
|
llm_prompt = (params.get("llm_prompt") or "").strip()
|
|||
|
|
llm_validate = (params.get("llm_validate") or "").strip()
|
|||
|
|
post_process = (params.get("post_process") or BizAlgorithmModel.POST_AREA).strip()
|
|||
|
|
|
|||
|
|
if flow_type in (BizAlgorithmModel.FLOW_SMALL, BizAlgorithmModel.FLOW_BOTH):
|
|||
|
|
try:
|
|||
|
|
small_model_id = int(params.get("small_model_id", 0))
|
|||
|
|
except Exception:
|
|||
|
|
small_model_id = 0
|
|||
|
|
if small_model_id <= 0:
|
|||
|
|
raise ValueError("请选择小模型")
|
|||
|
|
sm = AlgorithmModel.objects.filter(id=small_model_id, state=1).first()
|
|||
|
|
if not sm:
|
|||
|
|
raise ValueError("小模型不存在或已禁用")
|
|||
|
|
if (getattr(sm, "task_type", "") or "detect").lower() == "reid":
|
|||
|
|
raise ValueError("ReID 模型请使用「检测+ReID+后处理」流程,并同时选择 YOLO 检测小模型")
|
|||
|
|
target_labels = _parse_labels(params.get("target_labels"))
|
|||
|
|
if not target_labels:
|
|||
|
|
raise ValueError("请至少选择一个检测目标")
|
|||
|
|
|
|||
|
|
if flow_type == BizAlgorithmModel.FLOW_DETECT_REID:
|
|||
|
|
try:
|
|||
|
|
detector_model_id = int(params.get("detector_model_id", 0))
|
|||
|
|
except Exception:
|
|||
|
|
detector_model_id = 0
|
|||
|
|
try:
|
|||
|
|
small_model_id = int(params.get("small_model_id", 0))
|
|||
|
|
except Exception:
|
|||
|
|
small_model_id = 0
|
|||
|
|
if detector_model_id <= 0:
|
|||
|
|
raise ValueError("请选择检测小模型 (YOLO)")
|
|||
|
|
if small_model_id <= 0:
|
|||
|
|
raise ValueError("请选择 ReID 小模型 (OSNet)")
|
|||
|
|
if detector_model_id == small_model_id:
|
|||
|
|
raise ValueError("检测小模型与 ReID 小模型不能相同")
|
|||
|
|
det = AlgorithmModel.objects.filter(id=detector_model_id, state=1).first()
|
|||
|
|
if not det:
|
|||
|
|
raise ValueError("检测小模型不存在或已禁用")
|
|||
|
|
if (getattr(det, "task_type", "") or "detect").lower() != "detect":
|
|||
|
|
raise ValueError("检测小模型必须是 YOLO 检测模型 (task_type=detect)")
|
|||
|
|
reid = AlgorithmModel.objects.filter(id=small_model_id, state=1).first()
|
|||
|
|
if not reid:
|
|||
|
|
raise ValueError("ReID 小模型不存在或已禁用")
|
|||
|
|
if (getattr(reid, "task_type", "") or "").lower() != "reid":
|
|||
|
|
raise ValueError("ReID 小模型必须是 OSNet ReID 模型 (task_type=reid)")
|
|||
|
|
target_labels = _parse_labels(params.get("target_labels"))
|
|||
|
|
if not target_labels:
|
|||
|
|
raise ValueError("请至少选择一个检测目标")
|
|||
|
|
det_labels = _parse_labels(det.labels or "[]")
|
|||
|
|
invalid = [lb for lb in target_labels if lb not in det_labels]
|
|||
|
|
if invalid:
|
|||
|
|
raise ValueError("检测目标不在检测小模型标签列表中:%s" % "、".join(invalid))
|
|||
|
|
|
|||
|
|
if flow_type in (BizAlgorithmModel.FLOW_LLM, BizAlgorithmModel.FLOW_BOTH):
|
|||
|
|
try:
|
|||
|
|
llm_id = int(params.get("llm_id", 0))
|
|||
|
|
except Exception:
|
|||
|
|
llm_id = 0
|
|||
|
|
if llm_id <= 0:
|
|||
|
|
raise ValueError("请选择大模型")
|
|||
|
|
if not LLMModel.objects.filter(id=llm_id, state=1).exists():
|
|||
|
|
raise ValueError("大模型不存在或已禁用")
|
|||
|
|
if not llm_prompt:
|
|||
|
|
raise ValueError("请输入大模型提示词")
|
|||
|
|
if not llm_validate:
|
|||
|
|
raise ValueError("请输入提示词校验值")
|
|||
|
|
|
|||
|
|
valid_posts = (
|
|||
|
|
BizAlgorithmModel.POST_AREA,
|
|||
|
|
BizAlgorithmModel.POST_LINE_CROSS,
|
|||
|
|
BizAlgorithmModel.POST_LINE_COUNT,
|
|||
|
|
BizAlgorithmModel.POST_DIRECTION,
|
|||
|
|
BizAlgorithmModel.POST_DENSITY,
|
|||
|
|
BizAlgorithmModel.POST_DWELL,
|
|||
|
|
)
|
|||
|
|
if post_process not in valid_posts:
|
|||
|
|
raise ValueError("无效的后处理逻辑")
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
forward_count_threshold = int(params.get("forward_count_threshold", 0) or 0)
|
|||
|
|
except Exception:
|
|||
|
|
forward_count_threshold = 0
|
|||
|
|
try:
|
|||
|
|
reverse_count_threshold = int(params.get("reverse_count_threshold", 0) or 0)
|
|||
|
|
except Exception:
|
|||
|
|
reverse_count_threshold = 0
|
|||
|
|
forward_count_threshold = max(0, forward_count_threshold)
|
|||
|
|
reverse_count_threshold = max(0, reverse_count_threshold)
|
|||
|
|
if post_process == BizAlgorithmModel.POST_LINE_COUNT:
|
|||
|
|
if forward_count_threshold <= 0 and reverse_count_threshold <= 0:
|
|||
|
|
raise ValueError("越线计数至少设置一个方向的报警阈值(大于 0)")
|
|||
|
|
|
|||
|
|
# DIRECTION 后处理参数
|
|||
|
|
try:
|
|||
|
|
ref_angle = float(params.get("ref_angle", 90.0))
|
|||
|
|
except Exception:
|
|||
|
|
ref_angle = 90.0
|
|||
|
|
try:
|
|||
|
|
angle_tolerance = float(params.get("angle_tolerance", 45.0))
|
|||
|
|
except Exception:
|
|||
|
|
angle_tolerance = 45.0
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
"name": name,
|
|||
|
|
"flow_type": flow_type,
|
|||
|
|
"small_model_id": small_model_id,
|
|||
|
|
"detector_model_id": detector_model_id,
|
|||
|
|
"target_labels": json.dumps(target_labels, ensure_ascii=False),
|
|||
|
|
"llm_id": llm_id,
|
|||
|
|
"llm_prompt": llm_prompt,
|
|||
|
|
"llm_validate": llm_validate,
|
|||
|
|
"post_process": post_process,
|
|||
|
|
"ref_angle": ref_angle,
|
|||
|
|
"angle_tolerance": angle_tolerance,
|
|||
|
|
"forward_count_threshold": forward_count_threshold,
|
|||
|
|
"reverse_count_threshold": reverse_count_threshold,
|
|||
|
|
"state": int(params.get("state", 1)),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
def algorithm_index(request):
|
|||
|
|
return render(request, 'app/algorithm/index.html', {})
|
|||
|
|
|
|||
|
|
|
|||
|
|
def algorithm_openIndex(request):
|
|||
|
|
ret = False
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_unknown_error")
|
|||
|
|
data = []
|
|||
|
|
if request.method == 'GET':
|
|||
|
|
__check_ret, __check_msg = f_checkRequestSafe(request)
|
|||
|
|
if __check_ret:
|
|||
|
|
qs = BizAlgorithmModel.objects.select_related('small_model', 'detector_model', 'llm').order_by('-id')
|
|||
|
|
state = request.GET.get('state', '').strip()
|
|||
|
|
if state != '':
|
|||
|
|
qs = qs.filter(state=int(state))
|
|||
|
|
flow = request.GET.get('flow_type', '').strip()
|
|||
|
|
if flow != '':
|
|||
|
|
qs = qs.filter(flow_type=int(flow))
|
|||
|
|
data = [_biz_to_dict(b) for b in qs]
|
|||
|
|
ret = True
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_success")
|
|||
|
|
else:
|
|||
|
|
msg = __check_msg
|
|||
|
|
else:
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_method_not_supported")
|
|||
|
|
return f_responseJson({"code": 1000 if ret else 0, "msg": msg, "data": data})
|
|||
|
|
|
|||
|
|
|
|||
|
|
def algorithm_openCheckModels(request):
|
|||
|
|
"""检查所有小模型的模型文件是否存在,返回就绪列表与缺失列表。
|
|||
|
|
用于前端进入页面时全局告警提示,便于排查具体哪个模型成功/失败。
|
|||
|
|
"""
|
|||
|
|
ret = False
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_unknown_error")
|
|||
|
|
data = {"missing": [], "ok_list": [], "total": 0, "ok_count": 0}
|
|||
|
|
if request.method == 'GET':
|
|||
|
|
__check_ret, __check_msg = f_checkRequestSafe(request)
|
|||
|
|
if __check_ret:
|
|||
|
|
try:
|
|||
|
|
qs = AlgorithmModel.objects.filter(state=1).order_by('id')
|
|||
|
|
total = 0
|
|||
|
|
ok = 0
|
|||
|
|
missing = []
|
|||
|
|
ok_list = []
|
|||
|
|
for a in qs:
|
|||
|
|
total += 1
|
|||
|
|
mf = a.model_file or ""
|
|||
|
|
exists = _check_model_file_exists(mf)
|
|||
|
|
item = {
|
|||
|
|
"id": a.id,
|
|||
|
|
"name": a.name,
|
|||
|
|
"model_file": mf,
|
|||
|
|
"engine": a.inference_engine or "",
|
|||
|
|
}
|
|||
|
|
if exists:
|
|||
|
|
ok += 1
|
|||
|
|
item["hint"] = "模型文件就绪"
|
|||
|
|
ok_list.append(item)
|
|||
|
|
else:
|
|||
|
|
item["hint"] = "模型文件未配置" if not mf else "模型文件不存在"
|
|||
|
|
missing.append(item)
|
|||
|
|
data = {"missing": missing, "ok_list": ok_list, "total": total, "ok_count": ok}
|
|||
|
|
ret = True
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_success")
|
|||
|
|
except Exception as e:
|
|||
|
|
msg = str(e)
|
|||
|
|
else:
|
|||
|
|
msg = __check_msg
|
|||
|
|
else:
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_method_not_supported")
|
|||
|
|
return f_responseJson({"code": 1000 if ret else 0, "msg": msg, "data": data})
|
|||
|
|
|
|||
|
|
|
|||
|
|
def algorithm_openOptions(request):
|
|||
|
|
"""表单下拉:小模型列表、大模型列表、后处理选项"""
|
|||
|
|
ret = False
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_unknown_error")
|
|||
|
|
data = {}
|
|||
|
|
if request.method == 'GET':
|
|||
|
|
__check_ret, __check_msg = f_checkRequestSafe(request)
|
|||
|
|
if __check_ret:
|
|||
|
|
small_models = []
|
|||
|
|
for a in AlgorithmModel.objects.filter(state=1).order_by('-is_default', 'name'):
|
|||
|
|
labels = _parse_labels(a.labels or '[]')
|
|||
|
|
small_models.append({
|
|||
|
|
"id": a.id,
|
|||
|
|
"name": a.name,
|
|||
|
|
"labels": labels,
|
|||
|
|
"algorithm_type": a.algorithm_type,
|
|||
|
|
"task_type": a.task_type,
|
|||
|
|
"model_file": a.model_file or "",
|
|||
|
|
"model_file_exists": _check_model_file_exists(a.model_file or ""),
|
|||
|
|
"engine": a.inference_engine or "",
|
|||
|
|
})
|
|||
|
|
llms = [{"id": x.id, "name": x.name, "model_name": x.model_name}
|
|||
|
|
for x in LLMModel.objects.filter(state=1).order_by('sort', 'id')]
|
|||
|
|
data = {
|
|||
|
|
"small_models": small_models,
|
|||
|
|
"llms": llms,
|
|||
|
|
"post_processes": [
|
|||
|
|
{"value": BizAlgorithmModel.POST_AREA, "label": "区域入侵"},
|
|||
|
|
{"value": BizAlgorithmModel.POST_LINE_CROSS, "label": "越线检测"},
|
|||
|
|
{"value": BizAlgorithmModel.POST_LINE_COUNT, "label": "越线计数"},
|
|||
|
|
{"value": BizAlgorithmModel.POST_DIRECTION, "label": "方向入侵"},
|
|||
|
|
{"value": BizAlgorithmModel.POST_DENSITY, "label": "密度报警"},
|
|||
|
|
{"value": BizAlgorithmModel.POST_DWELL, "label": "滞留报警"},
|
|||
|
|
],
|
|||
|
|
"flow_types": [
|
|||
|
|
{"value": 1, "label": "小模型 + 后处理"},
|
|||
|
|
{"value": 2, "label": "大模型 + 后处理"},
|
|||
|
|
{"value": 3, "label": "小模型 + 大模型 + 后处理"},
|
|||
|
|
{"value": 4, "label": "检测小模型 + ReID小模型 + 后处理"},
|
|||
|
|
],
|
|||
|
|
}
|
|||
|
|
ret = True
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_success")
|
|||
|
|
else:
|
|||
|
|
msg = __check_msg
|
|||
|
|
else:
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_method_not_supported")
|
|||
|
|
return f_responseJson({"code": 1000 if ret else 0, "msg": msg, "data": data})
|
|||
|
|
|
|||
|
|
|
|||
|
|
def algorithm_openAdd(request):
|
|||
|
|
ret = False
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_unknown_error")
|
|||
|
|
if request.method == 'POST':
|
|||
|
|
__check_ret, __check_msg = f_checkRequestSafe(request)
|
|||
|
|
if __check_ret:
|
|||
|
|
params = f_parsePostParams(request)
|
|||
|
|
try:
|
|||
|
|
fields = _validate_biz_fields(params)
|
|||
|
|
BizAlgorithmModel.objects.create(**fields)
|
|||
|
|
ret = True
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_success")
|
|||
|
|
except Exception as e:
|
|||
|
|
msg = str(e)
|
|||
|
|
else:
|
|||
|
|
msg = __check_msg
|
|||
|
|
else:
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_method_not_supported")
|
|||
|
|
return f_responseJson({"code": 1000 if ret else 0, "msg": msg})
|
|||
|
|
|
|||
|
|
|
|||
|
|
def algorithm_openEdit(request):
|
|||
|
|
ret = False
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_unknown_error")
|
|||
|
|
if request.method == 'POST':
|
|||
|
|
__check_ret, __check_msg = f_checkRequestSafe(request)
|
|||
|
|
if __check_ret:
|
|||
|
|
params = f_parsePostParams(request)
|
|||
|
|
try:
|
|||
|
|
bid = int(params.get("id", 0))
|
|||
|
|
b = BizAlgorithmModel.objects.get(id=bid)
|
|||
|
|
fields = _validate_biz_fields(params, biz_id=bid)
|
|||
|
|
for k, v in fields.items():
|
|||
|
|
setattr(b, k, v)
|
|||
|
|
b.save()
|
|||
|
|
_reload_affected_pipelines(b)
|
|||
|
|
ret = True
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_success")
|
|||
|
|
except Exception as e:
|
|||
|
|
msg = str(e)
|
|||
|
|
else:
|
|||
|
|
msg = __check_msg
|
|||
|
|
else:
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_method_not_supported")
|
|||
|
|
return f_responseJson({"code": 1000 if ret else 0, "msg": msg})
|
|||
|
|
|
|||
|
|
|
|||
|
|
def algorithm_openDel(request):
|
|||
|
|
ret = False
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_unknown_error")
|
|||
|
|
data = {"referenced_zones": []}
|
|||
|
|
if request.method == 'POST':
|
|||
|
|
__check_ret, __check_msg = f_checkRequestSafe(request)
|
|||
|
|
if __check_ret:
|
|||
|
|
params = f_parsePostParams(request)
|
|||
|
|
try:
|
|||
|
|
bid = int(params.get("id", 0))
|
|||
|
|
b = BizAlgorithmModel.objects.get(id=bid)
|
|||
|
|
ref_zones = list(
|
|||
|
|
b.zones.select_related('stream').order_by('id')
|
|||
|
|
)
|
|||
|
|
if ref_zones:
|
|||
|
|
# 列出引用该算法的布控名称,便于用户排查并先解除绑定
|
|||
|
|
names = []
|
|||
|
|
for z in ref_zones:
|
|||
|
|
sname = z.stream.nickname if z.stream else ("#%s" % z.stream_id)
|
|||
|
|
names.append("%s/%s" % (sname, z.name))
|
|||
|
|
data["referenced_zones"] = names
|
|||
|
|
raise ValueError("该算法已被 %d 个布控引用,请先解除绑定后再删除(%s)"
|
|||
|
|
% (len(ref_zones), "、".join(names)))
|
|||
|
|
b.delete()
|
|||
|
|
ret = True
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_success")
|
|||
|
|
except Exception as e:
|
|||
|
|
msg = str(e)
|
|||
|
|
else:
|
|||
|
|
msg = __check_msg
|
|||
|
|
else:
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_method_not_supported")
|
|||
|
|
return f_responseJson({"code": 1000 if ret else 0, "msg": msg, "data": data})
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _reload_affected_pipelines(biz):
|
|||
|
|
try:
|
|||
|
|
from app.analysis.manager import AnalysisManager
|
|||
|
|
mgr = AnalysisManager()
|
|||
|
|
stream_ids = set()
|
|||
|
|
for z in biz.zones.select_related('stream').all():
|
|||
|
|
if z.stream_id:
|
|||
|
|
stream_ids.add(z.stream_id)
|
|||
|
|
for sid in stream_ids:
|
|||
|
|
if mgr.is_running(sid):
|
|||
|
|
mgr.reload_zones(sid)
|
|||
|
|
except Exception:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
|
|||
|
|
def algorithm_openAssignContext(request):
|
|||
|
|
"""分配布控:列出全部区域及是否已绑定该算法"""
|
|||
|
|
ret = False
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_unknown_error")
|
|||
|
|
data = {}
|
|||
|
|
if request.method == 'GET':
|
|||
|
|
__check_ret, __check_msg = f_checkRequestSafe(request)
|
|||
|
|
if __check_ret:
|
|||
|
|
params = f_parseGetParams(request)
|
|||
|
|
try:
|
|||
|
|
bid = int(params.get("biz_algorithm_id", 0) or params.get("id", 0))
|
|||
|
|
biz = BizAlgorithmModel.objects.get(id=bid)
|
|||
|
|
zones = []
|
|||
|
|
for z in ZoneModel.objects.select_related('stream').order_by('stream_id', 'id'):
|
|||
|
|
selected = z.algorithms.filter(id=bid).exists()
|
|||
|
|
zones.append({
|
|||
|
|
"id": z.id,
|
|||
|
|
"stream_id": z.stream_id,
|
|||
|
|
"stream_name": z.stream.nickname if z.stream else "",
|
|||
|
|
"zone_name": z.name,
|
|||
|
|
"state": z.state,
|
|||
|
|
"selected": selected,
|
|||
|
|
})
|
|||
|
|
data = {
|
|||
|
|
"biz_algorithm": _biz_to_dict(biz),
|
|||
|
|
"zones": zones,
|
|||
|
|
}
|
|||
|
|
ret = True
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_success")
|
|||
|
|
except Exception as e:
|
|||
|
|
msg = str(e)
|
|||
|
|
else:
|
|||
|
|
msg = __check_msg
|
|||
|
|
else:
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_method_not_supported")
|
|||
|
|
return f_responseJson({"code": 1000 if ret else 0, "msg": msg, "data": data})
|
|||
|
|
|
|||
|
|
|
|||
|
|
def algorithm_openAssignZones(request):
|
|||
|
|
"""将业务算法绑定到布控区域(增删仅影响本算法)"""
|
|||
|
|
ret = False
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_unknown_error")
|
|||
|
|
if request.method == 'POST':
|
|||
|
|
__check_ret, __check_msg = f_checkRequestSafe(request)
|
|||
|
|
if __check_ret:
|
|||
|
|
params = f_parsePostParams(request)
|
|||
|
|
try:
|
|||
|
|
bid = int(params.get("biz_algorithm_id", 0) or params.get("id", 0))
|
|||
|
|
biz = BizAlgorithmModel.objects.get(id=bid)
|
|||
|
|
zone_ids = params.get("zone_ids") or []
|
|||
|
|
if isinstance(zone_ids, str):
|
|||
|
|
try:
|
|||
|
|
zone_ids = json.loads(zone_ids)
|
|||
|
|
except Exception:
|
|||
|
|
zone_ids = [s for s in zone_ids.split(",") if s.strip()]
|
|||
|
|
zone_ids = {int(x) for x in zone_ids if str(x).strip()}
|
|||
|
|
|
|||
|
|
affected_streams = set()
|
|||
|
|
blocked_zones = []
|
|||
|
|
to_remove = [] # 先收集待解绑区域,校验通过后统一执行
|
|||
|
|
# 取消未选中的绑定
|
|||
|
|
for z in ZoneModel.objects.filter(algorithms=biz).prefetch_related('algorithms'):
|
|||
|
|
if z.id not in zone_ids:
|
|||
|
|
if z.algorithms.count() <= 1:
|
|||
|
|
blocked_zones.append(z.name or ("#%s" % z.id))
|
|||
|
|
continue
|
|||
|
|
to_remove.append(z)
|
|||
|
|
affected_streams.add(z.stream_id)
|
|||
|
|
if blocked_zones:
|
|||
|
|
raise ValueError(
|
|||
|
|
LANG_VIEWS_T(request, "zone_algo_required")
|
|||
|
|
+ " (" + "、".join(blocked_zones) + ")"
|
|||
|
|
)
|
|||
|
|
# 校验通过,统一执行解绑
|
|||
|
|
for z in to_remove:
|
|||
|
|
z.algorithms.remove(biz)
|
|||
|
|
# 添加新绑定
|
|||
|
|
if zone_ids:
|
|||
|
|
for z in ZoneModel.objects.filter(id__in=zone_ids):
|
|||
|
|
if not z.algorithms.filter(id=bid).exists():
|
|||
|
|
z.algorithms.add(biz)
|
|||
|
|
affected_streams.add(z.stream_id)
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
from app.analysis.manager import AnalysisManager
|
|||
|
|
mgr = AnalysisManager()
|
|||
|
|
for sid in affected_streams:
|
|||
|
|
if sid and mgr.is_running(sid):
|
|||
|
|
mgr.reload_zones(sid)
|
|||
|
|
except Exception:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
ret = True
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_success")
|
|||
|
|
except Exception as e:
|
|||
|
|
msg = str(e)
|
|||
|
|
else:
|
|||
|
|
msg = __check_msg
|
|||
|
|
else:
|
|||
|
|
msg = LANG_VIEWS_T(request, "msg_method_not_supported")
|
|||
|
|
return f_responseJson({"code": 1000 if ret else 0, "msg": msg})
|