feat: add queue level and status change labels in metrics for better readability

This commit is contained in:
2026-05-12 18:55:42 +08:00
parent e2409d4ebe
commit 330373b8f1
5 changed files with 155 additions and 19 deletions

View File

@@ -217,7 +217,7 @@ def _build_summary(ctx: ManageContext) -> dict:
"result_type": PROJECT_TYPE,
"headline": (
"Latest report shows "
f"{_string_value(queue_metrics.get('queue_level')) or 'few'} queue, "
f"{_queue_metric_label(queue_metrics, 'queue_level_label') or _string_value(queue_metrics.get('queue_level')) or 'few'} queue, "
f"{_int_value(queue_metrics.get('over_threshold_count'))} over 5 min and "
f"{_int_value(queue_metrics.get('under_threshold_count'))} under 5 min"
),
@@ -228,6 +228,19 @@ def _build_summary(ctx: ManageContext) -> dict:
"window_end": window_end,
"total_people": total_people,
"queue_level": _string_value(queue_metrics.get("queue_level")),
"queue_level_label": _queue_metric_label(
queue_metrics,
"queue_level_label",
fallback_level=_string_value(queue_metrics.get("queue_level")),
),
"previous_queue_level": _string_value(
queue_metrics.get("previous_queue_level")
),
"previous_queue_level_label": _queue_metric_label(
queue_metrics,
"previous_queue_level_label",
fallback_level=_string_value(queue_metrics.get("previous_queue_level")),
),
"over_threshold_count": _int_value(
queue_metrics.get("over_threshold_count")
),
@@ -235,6 +248,11 @@ def _build_summary(ctx: ManageContext) -> dict:
queue_metrics.get("under_threshold_count")
),
"status_change": _string_value(queue_metrics.get("status_change")),
"status_change_label": _queue_metric_label(
queue_metrics,
"status_change_label",
fallback_status=_string_value(queue_metrics.get("status_change")),
),
"direction_counts": direction_counts,
"age_counts": _map_string_int(payload.get("age_counts")),
"gender_counts": _map_string_int(payload.get("gender_counts")),
@@ -282,6 +300,19 @@ def _load_window_stats(ctx: ManageContext) -> list[dict]:
"window_end": _string_value(payload.get("window_end")),
"total_people": _int_value(payload.get("total_people")),
"queue_level": _queue_metric_value(payload, "queue_level"),
"queue_level_label": _queue_metric_label(
payload.get("queue_metrics"),
"queue_level_label",
fallback_level=_queue_metric_value(payload, "queue_level"),
),
"previous_queue_level": _queue_metric_value(
payload, "previous_queue_level"
),
"previous_queue_level_label": _queue_metric_label(
payload.get("queue_metrics"),
"previous_queue_level_label",
fallback_level=_queue_metric_value(payload, "previous_queue_level"),
),
"over_threshold_count": _queue_metric_int(
payload, "over_threshold_count"
),
@@ -289,6 +320,11 @@ def _load_window_stats(ctx: ManageContext) -> list[dict]:
payload, "under_threshold_count"
),
"status_change": _queue_metric_value(payload, "status_change"),
"status_change_label": _queue_metric_label(
payload.get("queue_metrics"),
"status_change_label",
fallback_status=_queue_metric_value(payload, "status_change"),
),
"age_counts": _map_string_int(payload.get("age_counts")),
"gender_counts": _map_string_int(payload.get("gender_counts")),
"unknown_attributes": _int_value(payload.get("unknown_attributes")),
@@ -448,5 +484,46 @@ def _queue_metric_int(payload: dict, field: str) -> int:
return _int_value(queue_metrics.get(field))
def _queue_metric_label(
queue_metrics,
field: str,
fallback_level: str = "",
fallback_status: str = "",
) -> str:
if isinstance(queue_metrics, dict):
direct = _string_value(queue_metrics.get(field))
if direct:
return direct
if fallback_level:
return _queue_level_label(fallback_level)
if fallback_status:
return _queue_status_change_label(fallback_status)
return ""
def _queue_level_label(level: str) -> str:
if level == "crowded":
return "人多"
if level == "normal":
return "人数正常"
if level == "few":
return "人少"
return ""
def _queue_status_change_label(status_change: str) -> str:
if status_change == "queue_increased":
return "人数变多"
if status_change == "queue_decreased":
return "人数变少"
if status_change == "queue_normalized":
return "人数变正常"
if status_change == "unchanged":
return "没变化"
if status_change == "initial":
return "初始"
return "其他变化"
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -126,8 +126,11 @@ class QueueWindowTracker:
"over_threshold_count": over_threshold_count,
"under_threshold_count": under_threshold_count,
"queue_level": queue_level,
"queue_level_label": _queue_level_label(queue_level),
"previous_queue_level": previous_queue_level,
"previous_queue_level_label": _queue_level_label(previous_queue_level),
"status_change": status_change,
"status_change_label": _queue_status_change_label(status_change),
"people": [
{
"person_id": f"track_{track_id}",
@@ -199,3 +202,27 @@ def _queue_status_change(previous_level: str | None, current_level: str) -> str:
if current_level == "normal" and previous_level in {"crowded", "few"}:
return "queue_normalized"
return "changed"
def _queue_level_label(level: str | None) -> str:
if level == "crowded":
return "人多"
if level == "normal":
return "人数正常"
if level == "few":
return "人少"
return ""
def _queue_status_change_label(status_change: str) -> str:
if status_change == "queue_increased":
return "人数变多"
if status_change == "queue_decreased":
return "人数变少"
if status_change == "queue_normalized":
return "人数变正常"
if status_change == "unchanged":
return "没变化"
if status_change == "initial":
return "初始"
return "其他变化"

View File

@@ -46,8 +46,11 @@ def build_client(project_root: Path):
"over_threshold_count": 6,
"under_threshold_count": 2,
"queue_level": "crowded",
"queue_level_label": "人多",
"previous_queue_level": "normal",
"previous_queue_level_label": "人数正常",
"status_change": "queue_increased",
"status_change_label": "人数变多",
},
"tracks": [
{"track_id": 1, "direction": "in"},
@@ -70,8 +73,11 @@ def build_client(project_root: Path):
"over_threshold_count": 2,
"under_threshold_count": 1,
"queue_level": "normal",
"queue_level_label": "人数正常",
"previous_queue_level": None,
"previous_queue_level_label": "",
"status_change": "initial",
"status_change_label": "初始",
},
"age_counts": {"minor": 0, "adult": 4, "senior": 1},
"gender_counts": {"male": 2, "female": 3},
@@ -145,9 +151,13 @@ def test_get_manage_summary(tmp_path: Path):
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"]["queue_level_label"] == "人多"
assert response.json["metrics"]["previous_queue_level"] == "normal"
assert response.json["metrics"]["previous_queue_level_label"] == "人数正常"
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"]["status_change_label"] == "人数变多"
assert response.json["metrics"]["direction_counts"] == {"in": 2, "out": 1}
assert (
response.json["metrics"]["recent_window_stats"][0]["window_end"]
@@ -167,6 +177,11 @@ def test_get_manage_windows(tmp_path: Path):
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"
assert response.json["items"][0]["queue_level_label"] == "人多"
assert response.json["items"][0]["previous_queue_level"] == "normal"
assert response.json["items"][0]["previous_queue_level_label"] == "人数正常"
assert response.json["items"][0]["status_change"] == "queue_increased"
assert response.json["items"][0]["status_change_label"] == "人数变多"
def test_get_manage_files(tmp_path: Path):

View File

@@ -41,3 +41,8 @@ def test_queue_window_tracker_builds_crowded_report():
assert queue_metrics["over_threshold_count"] == 6
assert queue_metrics["under_threshold_count"] == 2
assert queue_metrics["queue_level"] == "crowded"
assert queue_metrics["queue_level_label"] == "人多"
assert queue_metrics["previous_queue_level"] is None
assert queue_metrics["previous_queue_level_label"] == ""
assert queue_metrics["status_change"] == "initial"
assert queue_metrics["status_change_label"] == "初始"