Refactor store dwell alert management API and dwell engine
- Updated argument parsing in manage_api.py to include new threshold parameters. - Enhanced _config_payload to include thresholds and webhook configurations. - Modified _build_summary to track queue metrics and adjust alert reporting. - Refactored DwellEngine to utilize queue thresholds for alerting and reporting. - Added queue metrics calculations and status change tracking in dwell_engine.py. - Updated notifier.py to support posting JSON events to webhooks. - Adjusted example configuration to reflect new threshold parameters. - Enhanced Docker entrypoint script for better process management. - Updated tests to cover new queue metrics and thresholds. - Improved ManagedServiceDetail and ManagedServices Vue components to display queue metrics.
This commit is contained in:
@@ -16,7 +16,15 @@ def build_client(project_root: Path):
|
||||
" rtsp_url: rtsp://before-update\n"
|
||||
" output_dir: outputs\n"
|
||||
"rtsp:\n"
|
||||
" output_subdir: rtsp_stream\n",
|
||||
" output_subdir: rtsp_stream\n"
|
||||
"queue:\n"
|
||||
" source_id: queue_cam_01\n"
|
||||
" queue_time_threshold_seconds: 300\n"
|
||||
" crowded_count_threshold: 5\n"
|
||||
" normal_count_threshold: 2\n"
|
||||
"webhook:\n"
|
||||
" url: https://example.test/webhook\n"
|
||||
" event_log_path: outputs/rtsp_stream/webhook_events.jsonl\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
@@ -24,13 +32,23 @@ def build_client(project_root: Path):
|
||||
windows_dir = rtsp_dir / "windows"
|
||||
windows_dir.mkdir(parents=True, exist_ok=True)
|
||||
latest_payload = {
|
||||
"event": "half_hour_report",
|
||||
"source_type": "rtsp",
|
||||
"source_id": "queue_cam_01",
|
||||
"window_start": "2026-04-16T09:30:00+08:00",
|
||||
"window_end": "2026-04-16T10:00:00+08:00",
|
||||
"total_people": 7,
|
||||
"age_counts": {"minor": 1, "adult": 5, "senior": 1},
|
||||
"gender_counts": {"male": 4, "female": 3},
|
||||
"unknown_attributes": 2,
|
||||
"queue_metrics": {
|
||||
"queue_time_threshold_seconds": 300,
|
||||
"over_threshold_count": 6,
|
||||
"under_threshold_count": 2,
|
||||
"queue_level": "crowded",
|
||||
"previous_queue_level": "normal",
|
||||
"status_change": "queue_increased",
|
||||
},
|
||||
"tracks": [
|
||||
{"track_id": 1, "direction": "in"},
|
||||
{"track_id": 2, "direction": "out"},
|
||||
@@ -47,6 +65,14 @@ def build_client(project_root: Path):
|
||||
"window_start": "2026-04-16T09:00:00+08:00",
|
||||
"window_end": "2026-04-16T09:30:00+08:00",
|
||||
"total_people": 5,
|
||||
"queue_metrics": {
|
||||
"queue_time_threshold_seconds": 300,
|
||||
"over_threshold_count": 2,
|
||||
"under_threshold_count": 1,
|
||||
"queue_level": "normal",
|
||||
"previous_queue_level": None,
|
||||
"status_change": "initial",
|
||||
},
|
||||
"age_counts": {"minor": 0, "adult": 4, "senior": 1},
|
||||
"gender_counts": {"male": 2, "female": 3},
|
||||
"unknown_attributes": 1,
|
||||
@@ -58,7 +84,12 @@ def build_client(project_root: Path):
|
||||
json.dumps(latest_payload),
|
||||
encoding="utf-8",
|
||||
)
|
||||
(project_root / "outputs" / "rtsp_run.log").write_text("rtsp ok\n", encoding="utf-8")
|
||||
(project_root / "outputs" / "rtsp_run.log").write_text(
|
||||
"rtsp ok\n", encoding="utf-8"
|
||||
)
|
||||
(rtsp_dir / "webhook_events.jsonl").write_text(
|
||||
json.dumps(latest_payload) + "\n", encoding="utf-8"
|
||||
)
|
||||
|
||||
app = create_app(config_path)
|
||||
app.testing = True
|
||||
@@ -85,6 +116,8 @@ def test_get_manage_config(tmp_path: Path):
|
||||
assert response.json["config_path"] == str(config_path)
|
||||
assert response.json["runtime"]["rtsp_url"] == "rtsp://before-update"
|
||||
assert response.json["rtsp"]["output_subdir"] == "rtsp_stream"
|
||||
assert response.json["queue"]["source_id"] == "queue_cam_01"
|
||||
assert response.json["webhook"]["url"] == "https://example.test/webhook"
|
||||
|
||||
|
||||
def test_put_manage_config_updates_rtsp_url(tmp_path: Path):
|
||||
@@ -111,8 +144,15 @@ def test_get_manage_summary(tmp_path: Path):
|
||||
assert response.json["result_type"] == "people_flow_project"
|
||||
assert response.json["last_result_time"] == "2026-04-16T10:00:00+08:00"
|
||||
assert response.json["metrics"]["total_people"] == 7
|
||||
assert response.json["metrics"]["queue_level"] == "crowded"
|
||||
assert response.json["metrics"]["over_threshold_count"] == 6
|
||||
assert response.json["metrics"]["under_threshold_count"] == 2
|
||||
assert response.json["metrics"]["status_change"] == "queue_increased"
|
||||
assert response.json["metrics"]["direction_counts"] == {"in": 2, "out": 1}
|
||||
assert response.json["metrics"]["recent_window_stats"][0]["window_end"] == "2026-04-16T10:00:00+08:00"
|
||||
assert (
|
||||
response.json["metrics"]["recent_window_stats"][0]["window_end"]
|
||||
== "2026-04-16T10:00:00+08:00"
|
||||
)
|
||||
|
||||
|
||||
def test_get_manage_windows(tmp_path: Path):
|
||||
@@ -126,6 +166,7 @@ def test_get_manage_windows(tmp_path: Path):
|
||||
assert response.json["page_size"] == 1
|
||||
assert response.json["items"][0]["window_end"] == "2026-04-16T10:00:00+08:00"
|
||||
assert response.json["items"][0]["total_people"] == 7
|
||||
assert response.json["items"][0]["queue_level"] == "crowded"
|
||||
|
||||
|
||||
def test_get_manage_files(tmp_path: Path):
|
||||
@@ -137,6 +178,7 @@ def test_get_manage_files(tmp_path: Path):
|
||||
assert {item["path"] for item in response.json["files"]} == {
|
||||
"outputs/rtsp_run.log",
|
||||
"outputs/rtsp_stream/latest.json",
|
||||
"outputs/rtsp_stream/webhook_events.jsonl",
|
||||
"outputs/rtsp_stream/windows/stats_2026-04-16_09-00-00.json",
|
||||
"outputs/rtsp_stream/windows/stats_2026-04-16_09-30-00.json",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user