feat(v1): add demo runbook and release package
This commit is contained in:
+1
-1
@@ -29,7 +29,7 @@
|
||||
| T-202 | 实现本地报警、弹窗、截图和 JSONL 日志 | T-201 | CONFIRMED 产生一次声音、一次弹窗、一张带标注截图和一条事件日志。 | DONE |
|
||||
| T-203 | 接入海康 RTSP 与断流恢复 | T-202 | 现场有效流可预览;断流状态明确、可重连且不报警。 | DONE |
|
||||
| T-204 | 建立正反例录像回归与现场验收记录 | T-203 | 摔倒、行走、坐下、弯腰、捡物和持续倒地都有预期结果;报警延迟记录在 1–3 秒。 | DONE |
|
||||
| T-205 | 固化客户演示脚本与 V1 发布包 | T-204 | 可按文档完成演示脚本,所有证据可复查,适用边界显示给操作员。 | DOING |
|
||||
| T-205 | 固化客户演示脚本与 V1 发布包 | T-204 | 可按文档完成演示脚本,所有证据可复查,适用边界显示给操作员。 | DONE |
|
||||
| T-206 | 结构化摄像头配置、连接测试与设置页预览 | T-201 | 配置支持 host/端口/通道/账号/密码 结构化来源并拼出 RTSP(凭证百分号编码);公开示例保持无凭证、`config_version` 不含凭证;设置页可掩码输入、点击测试连接,连通后抓拍一帧显示在预览区。 | DONE |
|
||||
| T-207 | 抓流低延迟参数进配置与设置页 | T-206 | 配置支持 transport(tcp/udp)/连接超时/低延迟,程序拼 `OPENCV_FFMPEG_CAPTURE_OPTIONS` 并在开流前注入;设置页用下拉/数字/勾选而非原始字符串;启动可不依赖 run 脚本设环境变量。 | DONE |
|
||||
| T-208 | 每帧摔倒判定诊断叠加 | T-201 | 管线暴露每人策略证据;实时画面角落叠加每人 `accepted/horizontal/角度/rapid/candidate/state`(拒绝时显示原因),便于定位真实摔倒未确认卡在哪一步;诊断字符串构建 Qt-free 可测。 | DONE |
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
## 当前快照
|
||||
|
||||
- 日期:2026-07-22
|
||||
- 阶段:V1 事件管线、PyQt 双 Tab 界面、本地报警工件、结构化摄像头配置/连接测试、抓流低延迟参数与每帧判定诊断叠加已建立;T-204 已验收,T-205(客户演示脚本与 V1 发布包)进行中。判定灵敏度默认已放宽(低位俯视:持续水平即可疑,膝踝可缺,水平阈值 45°),确认窗为主防误报闸。
|
||||
- 阶段:V1 客户演示闭环已验收;T-205 已完成,V2 只能在 T-301 的 ONNX 一致性门槛后开始。判定灵敏度默认已放宽(低位俯视:持续水平即可疑,膝踝可缺,水平阈值 45°),确认窗为主防误报闸。
|
||||
- 已验证环境:Windows PowerShell;Python 3.8.10;Ultralytics 8.3.205;PyQt5 可导入。注意:当前 WSL/Linux 环境未安装 PyQt5,且其 ultralytics/torch 版本与该基线不兼容(模型前向不可用),故 GUI 可视化与真实模型端到端渲染只在 Windows 验证;本环境用 Qt-free 的 `view_model.py` 单元测试与假适配器管线冒烟覆盖视图逻辑。
|
||||
- 旧生产基线:`demo/main.py`、`demo/fall_detection_gui.py`、`demo/detect_fall.py`、`demo/best.pt`。
|
||||
- V1 代码:已建立安全配置、显式 Replay/Stream 视频源、Pose、轻量跟踪、质量/几何证据、倒地领域规则、按 ID 四态事件机及 `v1/pipeline.py` 事件管线;运行事件带非敏感 `config_version`,缺帧/低质量/断流会中断证据确认。新增 `v1/view_model.py`(Qt-free 监控视图状态与设置草稿三份隔离)、`v1/gui.py` 薄 PyQt5 双 Tab 外壳与 `v1/app.py` 装配(`FrameWorker` 只发出已判定的 `FrameAnalysis`,窗口只渲染)。新增 `v1/alerts.py`:按 `event_id` 去重,对首次 CONFIRMED 保存带标注截图、追加 JSONL 事件行,并经可注入 `AlertSink`(Windows 侧 `QtAlertSink` 提供声音与一次性弹窗)触发一次声音/弹窗。新增 `v1/camera.py`(RTSP URL 构建 + 有界连接测试抓帧)与 `config.py` 的结构化来源(host/端口/通道/账号/密码,凭证百分号编码)、`write_local_camera_source`;设置页新增摄像头连接分组、测试连接与预览,以及传输协议/连接超时/低延迟三项抓流调优(由 `config` 存值、`app` 开流前写入 `OPENCV_FFMPEG_CAPTURE_OPTIONS`)。真实海康流已用 `VideoSource(STREAM)` 连通(1920×1080)。
|
||||
@@ -15,7 +15,7 @@
|
||||
- 模型:`demo/best.pt` 可加载为 YOLO Pose,类别 `person`,`kpt_shape=[17, 3]`;与 `D:\PythonP\fall_detection\best.pt` 哈希一致。
|
||||
- 当前标准启动:`./init.ps1`。
|
||||
- 当前标准验证:`python -m compileall -q demo`。
|
||||
- 当前 blocker:T-205 尚未完成客户演示脚本、启动预检与发布包说明。T-204 已记录两条现场确认事件(1.84s、1.86s,均在目标区间)和走动、坐下、弯腰、蹲下捡物、站立停留均不报警的反例结果;现场录像和事件工件保留本机,不提交仓库。GUI 可视化、声音、弹窗与设置页测试连接的像素级观感仍应在 Windows 目视复核。
|
||||
- 当前 blocker:V2 尚未达到 T-301 的模型导出与一致性门槛;现场录像和事件工件保留本机,不提交仓库。GUI 可视化、声音、弹窗与设置页测试连接的像素级观感仍应在 Windows 目视复核。
|
||||
|
||||
全局环境的 `pip check` 存在其他项目的包冲突,因此它不是 Silver Pose 的验收命令。`init.ps1` 只检查本项目实际导入的 OpenCV、NumPy、Ultralytics 与 PyQt5,并在命令非零退出时失败。
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
## 任务状态
|
||||
|
||||
- 已完成:T-000、T-101~T-106(V1 地基与事件管线)、T-201(PyQt 双 Tab)、T-202(本地报警/截图/JSONL)、T-203(海康 RTSP 与断流恢复)、T-204(正反例录像与现场验收)、T-206(结构化摄像头配置与连接测试)、T-207(抓流低延迟参数)、T-208(每帧诊断叠加)、T-209(放宽俯视灵敏度)、T-210(截图 ASCII 标注)、T-211(灵敏度设置页)、T-212(实时流最新帧)、T-213(截图中文标注)。
|
||||
- 正在进行:T-205(客户演示脚本与 V1 发布包)。
|
||||
- 下一个可领取:无;完成 T-205 后才可开始 V2 模型导出门槛 T-301。
|
||||
- 正在进行:无。
|
||||
- 下一个可领取:T-301(锁定 V1 模型并导出 ONNX 一致性工件)。
|
||||
|
||||
## 当前可运行内容
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Silver Pose V1 客户演示手册
|
||||
|
||||
## 启动前检查
|
||||
|
||||
1. 使用 Windows PowerShell 进入发布包根目录,运行 `./init.ps1`;依赖检查、旧基线编译和 V1 测试必须通过。
|
||||
2. 运行 `python -m v1.release verify --package .`,确认发布清单和 `v1/models/best.pt` 的 SHA-256 未被替换。
|
||||
3. 将 `v1/config.release.example.json` 复制为未跟踪的 `v1/config.local.json`,只在本机配置摄像头来源;不得将账号、密码、地址、客户录像或事件工件提交、发送或投屏。
|
||||
4. 在设置页确认摄像头连接测试可抓取预览帧;确认低延迟、确认窗口和灵敏度参数与本次现场记录一致。
|
||||
5. 确认演示区为固定俯视的单路大厅或走廊,人员头、躯干、膝盖和脚踝大部分可见;安全模拟必须由经同意成年人按现场安全措施完成。
|
||||
|
||||
## 现场演示步骤
|
||||
|
||||
1. 运行 `python -m v1.app`,在设置页确认来源已就绪后开始监控。
|
||||
2. 先演示走动、坐下、弯腰、蹲下捡物和站立停留;这些动作不应出现确认摔倒的红色状态、声音或弹窗。
|
||||
3. 由现场负责人安排安全模拟从站立或行走到持续倒地;观察同一人员的骨架、ID、疑似状态和确认后的红色画面。
|
||||
4. 确认事件发生后,向客户展示一次声音、一次弹窗、带姿态标注的截图和一条本地事件记录。
|
||||
5. 可选演示断流:停止来源后界面显示重连状态且不报警;恢复来源后继续预览与检测。
|
||||
|
||||
## 证据复查
|
||||
|
||||
1. 在演示结束后运行 `python -m v1.report artifacts/events`。
|
||||
2. 核对每个确认事件的人员 ID、确认时间、`latency_seconds` 和相对截图路径;本项目的现场目标为 1–3 秒。
|
||||
3. 每个事件仅应有一条 JSONL 记录和一张事件截图;正常活动期间不应产生新的确认事件。
|
||||
4. 截图和 JSONL 只保留在本机约定的工件目录,按客户现场的数据管理要求处理。
|
||||
|
||||
## 适用边界
|
||||
|
||||
- 本演示只覆盖固定俯视、单路、全身大部分可见的大厅或走廊。
|
||||
- `best.pt` 是人体姿态模型,不是摔倒分类器;系统结论来自姿态质量、人员连续性和时间状态机。
|
||||
- 系统不是医疗诊断产品,不承诺所有公共场所、所有视角、严重遮挡、半身人员或多人密集交叉时的可靠性。
|
||||
- 客户应以现场批准的正反例和事件记录评估本机位表现,不应将本演示结果外推为通用准确率承诺。
|
||||
@@ -0,0 +1,173 @@
|
||||
# T-205 V1 Demo Release Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 生成不含客户数据的 V1 演示包,并让现场操作员能按固定脚本完成预检、演示、证据复查和适用边界说明。
|
||||
|
||||
**Architecture:** `v1/release.py` 负责可测试的发布包构建与校验;它只复制 V1 运行代码、公开示例、依赖、运行手册和经 SHA-256 校验的模型。`v1/scripts/build-v1-release.ps1` 只是 Windows 命令行入口。运行手册定义现场步骤,不保存或输出 RTSP 凭证。
|
||||
|
||||
**Tech Stack:** CPython 3.8、PowerShell、`hashlib`、`json`、`shutil`、pytest、PyQt5 V1 应用。
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 可测试的发布包构建器
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `v1/release.py`
|
||||
- Create: `v1/tests/test_release.py`
|
||||
|
||||
- [ ] **Step 1: 写失败测试,定义受控模型和非敏感清单**
|
||||
|
||||
```python
|
||||
def test_build_release_copies_locked_model_and_excludes_local_credentials(tmp_path):
|
||||
model = tmp_path / "best.pt"
|
||||
model.write_bytes(b"locked-model")
|
||||
output = tmp_path / "SilverPose-V1"
|
||||
|
||||
manifest = build_release_package(ROOT, model, sha256_file(model), output)
|
||||
|
||||
assert (output / "v1" / "models" / "best.pt").read_bytes() == b"locked-model"
|
||||
assert manifest["model_sha256"] == sha256_file(model)
|
||||
assert not list(output.rglob("config.local.json"))
|
||||
assert not list(output.rglob("events.jsonl"))
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行测试确认失败**
|
||||
|
||||
Run: `python -m pytest v1/tests/test_release.py -v`
|
||||
|
||||
Expected: 因 `v1.release` 或 `build_release_package` 不存在而失败。
|
||||
|
||||
- [ ] **Step 3: 实现最小构建器**
|
||||
|
||||
```python
|
||||
def build_release_package(project_root, model_path, expected_sha256, output_dir):
|
||||
_validate_model(model_path, expected_sha256)
|
||||
_copy_tree(project_root / "v1", output_dir / "v1", ignored={"config.local.json", "__pycache__"})
|
||||
_copy_file(project_root / "README.md", output_dir / "README.md")
|
||||
_copy_file(project_root / "docs" / "demo-runbook.md", output_dir / "docs" / "demo-runbook.md")
|
||||
_copy_model(model_path, output_dir / "v1" / "models" / "best.pt")
|
||||
return _write_manifest(output_dir, expected_sha256)
|
||||
```
|
||||
|
||||
清单只包含格式版本、生成时间、模型 SHA-256、包内相对文件路径和文件 SHA-256;不得写入 RTSP URL、账号、密码、客户视频路径或事件工件路径。
|
||||
|
||||
- [ ] **Step 4: 运行测试确认通过**
|
||||
|
||||
Run: `python -m pytest v1/tests/test_release.py -v`
|
||||
|
||||
Expected: PASS。
|
||||
|
||||
### Task 2: Windows 发布入口和启动命令
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `v1/scripts/build-v1-release.ps1`
|
||||
- Modify: `init.ps1`
|
||||
- Modify: `README.md`
|
||||
|
||||
- [ ] **Step 1: 写失败测试,定义发布清单校验**
|
||||
|
||||
```python
|
||||
def test_verify_release_rejects_a_tampered_model(tmp_path):
|
||||
output = _build_test_release(tmp_path)
|
||||
(output / "v1" / "models" / "best.pt").write_bytes(b"changed")
|
||||
|
||||
with pytest.raises(ReleaseError, match="model SHA-256"):
|
||||
verify_release_package(output)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行测试确认失败**
|
||||
|
||||
Run: `python -m pytest v1/tests/test_release.py::test_verify_release_rejects_a_tampered_model -v`
|
||||
|
||||
Expected: `verify_release_package` 尚未定义而失败。
|
||||
|
||||
- [ ] **Step 3: 实现清单校验和 PowerShell 入口**
|
||||
|
||||
```powershell
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$ModelPath,
|
||||
[Parameter(Mandatory = $true)][string]$ModelSha256,
|
||||
[string]$Output = "dist/SilverPose-V1"
|
||||
)
|
||||
python -m v1.release build --model-path $ModelPath --model-sha256 $ModelSha256 --output $Output
|
||||
```
|
||||
|
||||
`verify_release_package` 必须重新计算包内模型和清单列出的每个文件 SHA-256。`init.ps1` 的 GUI 启动提示改为 `python -m v1.app`,但继续执行旧 `demo/` 的只读编译基线。README 列出依赖安装、无凭证配置方式、V1 启动命令和发布脚本命令。
|
||||
|
||||
- [ ] **Step 4: 运行针对性测试**
|
||||
|
||||
Run: `python -m pytest v1/tests/test_release.py -v`
|
||||
|
||||
Expected: PASS。
|
||||
|
||||
### Task 3: 客户演示与证据复查手册
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `docs/demo-runbook.md`
|
||||
- Modify: `README.md`
|
||||
|
||||
- [ ] **Step 1: 写手册静态守卫测试**
|
||||
|
||||
```python
|
||||
def test_demo_runbook_covers_preflight_evidence_and_scope():
|
||||
text = (ROOT / "docs" / "demo-runbook.md").read_text(encoding="utf-8")
|
||||
for heading in ("启动前检查", "现场演示步骤", "证据复查", "适用边界"):
|
||||
assert heading in text
|
||||
assert "rtsp://" not in text
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行测试确认失败**
|
||||
|
||||
Run: `python -m pytest v1/tests/test_release.py::test_demo_runbook_covers_preflight_evidence_and_scope -v`
|
||||
|
||||
Expected: 手册不存在而失败。
|
||||
|
||||
- [ ] **Step 3: 编写手册**
|
||||
|
||||
手册必须给出:Windows/依赖/模型哈希/本地配置/摄像头连接测试的预检;演示正常活动和安全模拟摔倒的顺序;确认红色姿态、声音、弹窗和截图的观察点;`python -m v1.report artifacts/events` 的证据复查;断流不报警的观察;固定俯视、全身大部分可见、单路大厅或走廊的范围限制;以及不作医疗级、全场景或 Pose 模型即摔倒分类器的表述。
|
||||
|
||||
- [ ] **Step 4: 运行手册守卫测试**
|
||||
|
||||
Run: `python -m pytest v1/tests/test_release.py -v`
|
||||
|
||||
Expected: PASS。
|
||||
|
||||
### Task 4: 构建并复查无敏感工件的演示包
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `docs/06-tasks.md`
|
||||
- Modify: `docs/current-state.md`
|
||||
- Modify: `progress.md`
|
||||
|
||||
- [ ] **Step 1: 使用锁定模型构建临时发布包**
|
||||
|
||||
Run: `$releaseRoot = Join-Path $env:TEMP "SilverPose-V1-Release"; $modelSha = (Get-FileHash -Algorithm SHA256 demo/best.pt).Hash.ToLower(); pwsh -File v1/scripts/build-v1-release.ps1 -ModelPath demo/best.pt -ModelSha256 $modelSha -Output $releaseRoot`
|
||||
|
||||
Expected: 输出 `release-manifest.json`,模型、代码、公开示例和手册存在,且构建目录中无 `config.local.json`、`events.jsonl`、`artifacts/` 或 RTSP 地址。
|
||||
|
||||
- [ ] **Step 2: 校验发布包**
|
||||
|
||||
Run: `$releaseRoot = Join-Path $env:TEMP "SilverPose-V1-Release"; $modelSha = (Get-FileHash -Algorithm SHA256 demo/best.pt).Hash.ToLower(); pwsh -File v1/scripts/build-v1-release.ps1 -ModelPath demo/best.pt -ModelSha256 $modelSha -Output $releaseRoot; python -m v1.release verify --package $releaseRoot`
|
||||
|
||||
Expected: `release package verified`。
|
||||
|
||||
- [ ] **Step 3: 运行全量验证**
|
||||
|
||||
Run: `./init.ps1`, `python -m pytest v1/tests -v`, `python -m compileall -q v1 demo`, `git diff --check`。
|
||||
|
||||
Expected: 所有测试通过,编译退出码 0,差异检查无输出。
|
||||
|
||||
- [ ] **Step 4: 更新任务与执行记录并提交**
|
||||
|
||||
将 T-205 标为 DONE,记录实际构建/校验命令和“不包含客户工件”的结果;提交代码、测试、手册和任务文档。临时发布目录保持在忽略目录内,不提交。
|
||||
|
||||
## 自检
|
||||
|
||||
- 覆盖:发布包、模型哈希、篡改检测、Windows 入口、演示步骤、证据复查、适用边界和无敏感工件。
|
||||
- 任务没有未定义的函数或占位步骤;每项生产行为均先有失败测试。
|
||||
- 发布包验证不依赖真实 RTSP,也不打印或写入凭证。
|
||||
Reference in New Issue
Block a user