Files
managed-portal/docs/managed-queue-webhook.md
skye.yue ea618fd674 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.
2026-05-09 11:35:55 +08:00

8.5 KiB
Raw Blame History

Managed Queue Webhook 对接说明

本文档说明 managed/store_dwell_alertmanaged/people_flow_project 两个工程新增的排队统计与 webhook 推送结构,便于接收方按统一协议完成对接。

业务规则

  • 统计窗口固定为每 30 分钟一个窗口。
  • 每个窗口统计两类人数:
    • over_threshold_count:该窗口内累计排队时间大于等于 5 分钟的人数。
    • under_threshold_count:该窗口内累计排队时间小于 5 分钟但大于 0 的人数。
  • 一阶段排队等级规则:
    • crowdedover_threshold_count > 5
    • normal2 <= over_threshold_count <= 5
    • fewover_threshold_count < 2
  • 状态变化规则:
    • queue_increasednormal -> crowdedfew -> crowded
    • queue_decreasednormal -> fewcrowded -> few
    • queue_normalizedcrowded -> normalfew -> normal
    • unchanged:窗口等级未变化
    • initial:首个统计窗口,没有上一个窗口可比较

配置方式

store_dwell_alert

配置文件示例:managed/store_dwell_alert/config/config.example.yaml

thresholds:
  queue_time_threshold_seconds: 300
  crowded_count_threshold: 5
  normal_count_threshold: 2
  pause_timeout_seconds: 300
  alert_cooldown_seconds: 600

webhook:
  url: "https://receiver.example.com/queue-report"
  timeout_seconds: 5.0

people_flow_project

配置文件示例:managed/people_flow_project/config/config.example.yaml

queue:
  enabled: true
  area: [0.0, 0.0, 1.0, 1.0]
  area_mode: "normalized"
  queue_time_threshold_seconds: 300
  crowded_count_threshold: 5
  normal_count_threshold: 2
  pause_timeout_seconds: 5
  source_id: "queue_cam_01"

webhook:
  url: "https://receiver.example.com/queue-report"
  timeout_seconds: 5.0
  event_log_path: "outputs/rtsp_stream/webhook_events.jsonl"

说明:

  • queue.area 用于限定排队区域,默认 [0, 0, 1, 1] 表示全画面。
  • queue.area_mode=normalized 表示区域坐标按画面宽高归一化。
  • 两个工程都会先把 webhook 数据写入本地结果文件,再尝试 HTTP POST。

推送时机

  • 两个工程都会在每个 30 分钟窗口结束时推送一次 half_hour_report
  • store_dwell_alert 仍会继续生成本地事件日志;用于对接的窗口报文以本文档的 half_hour_report 结构为准。

公共字段

两个工程的 webhook 都包含以下公共字段:

字段 类型 说明
event string 固定为 half_hour_report
project_type string 工程类型,值为 store_dwell_alertpeople_flow_project
source_id string 数据源标识。store_dwell_alert 使用 camera_idpeople_flow_project 使用 queue.source_id
window_start string 窗口开始时间ISO 8601
window_end string 窗口结束时间ISO 8601
queue_metrics object 排队统计主体

queue_metrics 结构:

字段 类型 说明
queue_time_threshold_seconds integer 长等待阈值,当前默认 300 秒
over_threshold_count integer 窗口内累计排队时间大于等于阈值的人数
under_threshold_count integer 窗口内累计排队时间小于阈值但大于 0 的人数
queue_level string few / normal / crowded
previous_queue_level string/null 上一个窗口的等级
status_change string initial / unchanged / queue_increased / queue_decreased / queue_normalized
people array 当前窗口内参与统计的人员列表

queue_metrics.people[] 结构:

字段 类型 说明
person_id string 人员标识
queue_seconds integer 该窗口内累计排队秒数
bucket string over_thresholdunder_threshold

store_dwell_alert 完整报文

store_dwell_alert 会额外带上门店停留会话明细:

{
  "event": "half_hour_report",
  "project_type": "store_dwell_alert",
  "camera_id": "store_cam_01",
  "source_id": "store_cam_01",
  "window_start": "2026-05-08T09:00:00+08:00",
  "window_end": "2026-05-08T09:30:00+08:00",
  "active_customer_count": 3,
  "active_customers": [
    {
      "person_id": "cust_101",
      "session_id": "cust_101-s1",
      "role": "customer",
      "status": "active",
      "dwell_seconds": 820,
      "window_queue_seconds": 820
    },
    {
      "person_id": "cust_102",
      "session_id": "cust_102-s1",
      "role": "customer",
      "status": "active",
      "dwell_seconds": 460,
      "window_queue_seconds": 460
    }
  ],
  "closed_customers": [
    {
      "person_id": "cust_103",
      "session_id": "cust_103-s1",
      "final_dwell_seconds": 260,
      "window_queue_seconds": 260
    }
  ],
  "staff_seen_count": 1,
  "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",
    "people": [
      {
        "person_id": "cust_101",
        "queue_seconds": 820,
        "bucket": "over_threshold"
      },
      {
        "person_id": "cust_102",
        "queue_seconds": 460,
        "bucket": "over_threshold"
      },
      {
        "person_id": "cust_103",
        "queue_seconds": 260,
        "bucket": "under_threshold"
      }
    ]
  }
}

people_flow_project 完整报文

people_flow_project 会额外带上过线统计和属性统计结果:

{
  "event": "half_hour_report",
  "project_type": "people_flow_project",
  "source_type": "rtsp",
  "source": "rtsp://user:password@camera-ip:554/h264/ch1/main/av_stream",
  "source_id": "queue_cam_01",
  "window_index": 12,
  "window_start": "2026-05-08T09:00:00+08:00",
  "window_end": "2026-05-08T09:30:00+08:00",
  "window_duration_seconds": 1800,
  "config_path": "/opt/people_flow_project/config/local.yaml",
  "line": {
    "coordinates": [0.1, 0.55, 0.9, 0.55],
    "mode": "normalized"
  },
  "total_people": 7,
  "age_counts": {
    "minor": 1,
    "adult": 5,
    "senior": 1
  },
  "gender_counts": {
    "male": 4,
    "female": 3
  },
  "unknown_attributes": 2,
  "tracks": [
    {
      "track_id": 1,
      "direction": "in",
      "age": 26,
      "age_bucket": "adult",
      "gender": "male",
      "samples_used": 3
    }
  ],
  "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",
    "people": [
      {
        "person_id": "track_12",
        "queue_seconds": 810,
        "bucket": "over_threshold"
      },
      {
        "person_id": "track_21",
        "queue_seconds": 180,
        "bucket": "under_threshold"
      }
    ]
  }
}

接收方建议

  • event + project_type + source_id + window_end 做幂等去重。
  • 业务判断优先读取 queue_metrics.queue_levelqueue_metrics.status_change
  • 如果只关心图片里的需求,最少只需要解析:
    • source_id
    • window_start
    • window_end
    • queue_metrics.over_threshold_count
    • queue_metrics.under_threshold_count
    • queue_metrics.queue_level
    • queue_metrics.status_change