feat(v2): add annotated evidence and alert dispatch
This commit is contained in:
@@ -57,6 +57,7 @@ V2 对应模块的当前落实与 T-304 目标如下:
|
||||
| 实时视频源 | `v2/internal/source` | 用 FFprobe 获取尺寸/FPS,以 FFmpeg 输出 BGR 帧;有界重连、取消、来源状态和单槽最新帧投递 | ONNX、事件判定、UI 绘制;错误状态不得含 URL |
|
||||
| ONNX Pose | `v2/internal/pose` | 114 letterbox、RGB/CHW、NMS、关键点及坐标还原 | 人员 ID、摔倒结论 |
|
||||
| 事件引擎 | `v2/internal/fall` | 复现 V1 的跟踪、证据、四态状态机和 `FallEvent` | 视频解码、声音、文件 |
|
||||
| 画面与证据 | `v2/internal/render`、`v2/internal/alert` | 叠加人员骨架/状态,红色仅表示 CONFIRMED;按事件 ID 保存一次 PNG 和 JSONL | 读取 RTSP、重跑事件规则、直接操作 Walk 控件 |
|
||||
| Windows UI | `v2/internal/ui` | Walk 顶部“监控/设置”Tab、渲染最新帧和已计算状态 | 直接读 RTSP、执行 ONNX 或事件规则 |
|
||||
| 应用装配 | `v2/cmd/silver-pose`(T-304) | 管理 worker 生命周期、取消、最新帧投递和依赖注入 | 重写领域规则 |
|
||||
|
||||
|
||||
@@ -94,6 +94,12 @@ FallEvent = {
|
||||
|
||||
`event_id` 带每次监控运行的会话前缀(`FALL-<session>-NNNNNN`),跨监控重启全局唯一;因此同一天目录内的截图不会被覆盖,`events.jsonl` 也不会出现同 id 不同内容的记录。
|
||||
|
||||
### V2 本地事件证据
|
||||
|
||||
V2 的 `internal/render` 把 BGR 视频帧与已经完成的 `FrameResult` 合成为 RGBA 图像。它画 person box、17 点骨架、ID、状态和 UTC 时间;`NORMAL` 为绿色、`SUSPECT`/`RECOVERING` 为琥珀色,只有任一人员为 `CONFIRMED` 时才绘制红色骨架和六像素红色画面边框。
|
||||
|
||||
`internal/alert.Dispatcher` 只接收 `CONFIRMED` 的 `FallEvent` 和已叠加的图像。它在写文件前用 `event_id` 去重,写入 `artifacts.event_dir/YYYYMMDD/FALL-*.png` 与同目录 `events.jsonl`;失败会释放该 ID 使后续帧可以重试。JSONL 的字段与下文 `AlertRecord` 一致,且模块从不接收、保存或输出 RTSP URL。
|
||||
|
||||
T-202 的 `alerts` 按 `event_id` 去重,对首次 CONFIRMED 只触发一次副作用(声音、弹窗、截图、JSONL 一行)。JSONL 记录如下,文件名与字段不含 RTSP 地址、凭证或客户姓名:
|
||||
|
||||
```text
|
||||
|
||||
@@ -157,7 +157,7 @@ git commit -m "feat(v2): add reconnecting FFmpeg stream source"
|
||||
- Create: `v2/internal/alert/dispatcher_test.go`
|
||||
- Modify: `docs/api.md`
|
||||
|
||||
- [ ] **Step 1: Write failing rendering and alert tests**
|
||||
- [x] **Step 1: Write failing rendering and alert tests**
|
||||
|
||||
```go
|
||||
func TestRenderUsesRedBorderOnlyForConfirmed(t *testing.T) {
|
||||
@@ -174,12 +174,12 @@ func TestDispatchWritesOnePNGAndRedactedJSONL(t *testing.T) {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Verify tests fail**
|
||||
- [x] **Step 2: Verify tests fail**
|
||||
|
||||
Run: `Set-Location v2; go test ./internal/render ./internal/alert -v`
|
||||
Expected: FAIL because both packages are absent.
|
||||
|
||||
- [ ] **Step 3: Implement deterministic evidence outputs**
|
||||
- [x] **Step 3: Implement deterministic evidence outputs**
|
||||
|
||||
```go
|
||||
func Render(bgr []byte, width, height int, result fall.FrameResult) *image.RGBA
|
||||
@@ -189,12 +189,12 @@ func (d *Dispatcher) Dispatch(event fall.Event, image *image.RGBA) (Record, erro
|
||||
|
||||
Draw a 17-point COCO skeleton, box and ASCII `track/state/time` label in the image. Normal/SUSPECT/RETRYING use green/amber/slate respectively; only `CONFIRMED` draws critical red skeleton and a six-pixel image border. Create `YYYYMMDD/FALL-*.png` and append one UTF-8 JSONL line with the V1-compatible public event fields plus source ID, UTC time and relative screenshot path. The dispatcher holds a seen-event-ID set before writing so retried UI messages cannot overwrite an image or replay an alert. Its notifier interface only reports a one-shot notification request; it does not own UI controls.
|
||||
|
||||
- [ ] **Step 4: Run focused tests**
|
||||
- [x] **Step 4: Run focused tests**
|
||||
|
||||
Run: `Set-Location v2; go test ./internal/render ./internal/alert -v`
|
||||
Expected: PASS, including red-only-confirmed, PNG decodability, one JSONL line and no `rtsp`/credential substring.
|
||||
|
||||
- [ ] **Step 5: Commit the rendering and alert slice**
|
||||
- [x] **Step 5: Commit the rendering and alert slice**
|
||||
|
||||
```powershell
|
||||
git add v2/internal/render v2/internal/alert docs/api.md
|
||||
|
||||
Reference in New Issue
Block a user