# PRD ④ 控制端配置窗口（GUI）对接方案（templates/instances-only）

> 适用版本：V1（2026-01）
>
> 范围：**仅控制端 GUI/managerd 如何调用设备端 rk3588-agent**。
>
> - 本项目中已在 `agent + media-server` 实现本文档所需能力。
> - **不包含**配置程序（前端/后端）具体 UI 代码实现细节。

---

## 1. 目标

让非技术人员通过 GUI 完成：

1) 新增/删除一路摄像头通道（channel）
2) 选择流程模板（转码/YOLO/报警/人脸检测/人脸识别）并配置参数
3) 一键应用配置（写盘 + reload；失败自动 rollback）
4) 人脸库（SQLite `face_gallery.db`）上传并**无需重启**立即生效

---

## 2. 核心约束（必须遵守）

1) GUI **只支持 `templates/instances` 模式**：
   - 不提供手写 `graphs` 的编辑。
   - 运行态 graphs 只读查看（用于监控/联调）。

2) 人脸数据通过上传整个 SQLite 文件：`face_gallery.db`。

3) 人脸库默认路径：`./models/face_gallery.db`。
   - 要求部署时 **media-server 的工作目录** 与 **agent.models_dir** 关系合理，使该相对路径能找到 agent 上传的 db。
   - 推荐：`media_server_process.work_dir=<rk3588sys 根目录>` 且 `agent.models_dir=<work_dir>/models`。

---

## 3. 鉴权与错误处理

### 3.1 鉴权

- Header：`X-RK-Token: <token>`
- 写接口（会写盘/改状态）必须鉴权。
- 读接口默认可不鉴权；若设备端配置 `agent.require_token_for_read=true`，则读接口也必须鉴权。

### 3.2 统一错误返回

- 成功：`2xx`，一般为 `{"ok":true,...}` 或业务 JSON
- 失败：`4xx/5xx`，返回 `{"error":"..."}`

常见 HTTP：

- `401`：unauthorized
- `400`：validation failed / invalid json
- `404`：not found
- `409`：conflict
- `500`：internal error

---

## 4. GUI 页面与调用流程

### 4.1 设备详情页（只读）

1) 设备信息：`GET /v1/info`
2) 运行态通道摘要：`GET /v1/graphs`
3) 单通道详情（可选）：`GET /v1/graphs/{name}`
4) 日志：`GET /v1/logs/recent?limit=200`

### 4.2 通道配置页（核心：instances）

#### 4.2.1 初始化

1) 获取 schema（渲染表单）：`GET /v1/config/ui/schema`
2) 获取当前 state（回显）：`GET /v1/config/ui/state`

GUI 侧以 `instances[]` 为“通道列表”。

#### 4.2.2 校验/预览（dry-run）

用户编辑完成后：

- `POST /v1/config/ui/plan`

返回：

- `generated_config`：生成出来的 root config（可用于预览/导出）
- `diff`：added/removed/changed（实例级别）

> 说明：plan 的校验是“基础校验”（必填字段/模板名/实例名唯一）。
> 真正的构图/插件/模型加载等校验发生在 apply → media-server reload 阶段。

#### 4.2.3 应用配置

- `POST /v1/config/ui/apply`

行为：

1) agent 生成新的 root config（只包含 `global/queue/templates/instances`）
2) 写盘到 `agent.config_path`
3) 调用 media-server reload
4) reload 失败则自动 rollback 并返回 500

#### 4.2.4 回滚（手动）

- `POST /v1/media-server/rollback`

> 回滚语义：回滚到“上一次成功的**源配置**”（保留 templates/instances，不会被 expanded 覆盖），便于 GUI 二次编辑。

### 4.3 人脸库管理页

#### 4.3.1 上传人脸库

- `PUT /v1/face-gallery`
- Content-Type：`application/octet-stream`
- Body：SQLite 文件二进制（`face_gallery.db`）

保存位置：`<agent.models_dir>/face_gallery.db`

#### 4.3.2 立即生效（无需重启）

- `POST /v1/face-gallery/reload`

行为：

- agent 遍历所有 graphs，找到 `type==ai_face_recog` 的节点
- 对每个节点下发 runtime config patch：bump `gallery.reload_seq`
- 节点收到后会重新加载 SQLite db

---

## 5. Agent 对外 API（控制端对接清单）

> Base：`http://<device_ip>:<agent_port>`（默认 9100）

### 5.1 设备信息

#### `GET /v1/info`

用于设备列表/详情。

### 5.2 运行态（只读代理）

#### `GET /v1/graphs`

#### `GET /v1/graphs/{name}`

#### `GET /v1/logs/recent?limit=200`

### 5.3 配置文件（root config）

#### `GET /v1/config`

返回 `agent.config_path` 对应 JSON（用于导出/高级查看）。

#### `PUT /v1/config`

上传完整 root config JSON（写盘 + reload；失败自动 rollback）。

### 5.4 语义化配置（GUI 推荐使用）

#### `GET /v1/config/ui/schema`

返回：可选模板列表 + 字段 schema（类型/默认/必填）。

#### `GET /v1/config/ui/state`

返回：当前 config 映射到 GUI state（主要是 `instances[]`）+ 内置模板列表。

#### `POST /v1/config/ui/plan`

输入 desired state（instances 列表），返回生成 config 与 diff。

#### `POST /v1/config/ui/apply`

同 plan，但会写盘并 reload（失败自动 rollback）。

### 5.5 模型管理（可选，但建议 GUI 支持）

#### `PUT /v1/models/{name}`

上传模型（.rknn），返回可引用的 `path`。

#### `GET /v1/models`

列出已上传模型（包含 `name/path/sha256/mtime_ms`）。

### 5.6 人脸库

#### `GET /v1/face-gallery`

返回当前 db 文件信息（exists/size/mtime/path）。

#### `PUT /v1/face-gallery`

上传 `face_gallery.db`。

#### `POST /v1/face-gallery/reload`

让所有 `ai_face_recog` 节点热加载新 db。

---

## 6. `config/ui/*` 的数据结构（控制端直接照此传）

### 6.1 `POST /v1/config/ui/plan|apply` Request

```json
{
  "global": { },
  "queue": { },
  "instances": [
    {
      "name": "cam1",
      "template": "face_det_recog_rtsp_hls",
      "params": {
        "url": "rtsp://10.0.0.5:8554/cam",
        "fps": 30,
        "src_w": 1280,
        "src_h": 720,

        "det_model_path": "./models/RetinaFace_mobile320.rknn",
        "recog_model_path": "./models/mobilefacenet_arcface.rknn",
        "gallery_path": "./models/face_gallery.db",

        "gop": 60,
        "bitrate_kbps": 2000,
        "rtsp_port": 8555,
        "hls_path": "./web/hls/cam1/index.m3u8"
      }
    }
  ]
}
```

说明：

- `global/queue` 可省略：agent 会沿用当前 config 中的值。
- `instances` 为全量期望状态：控制端应把当前列表 + 修改后的列表一起提交。
- 当前实现会生成新的 root config（只包含 `global/queue/templates/instances`），不会保留 `graphs`。

### 6.2 `POST /v1/config/ui/plan|apply` Response

```json
{
  "ok": true,
  "generated_config": { "global":{}, "queue":{}, "templates":{}, "instances":[] },
  "diff": { "added": ["cam1"], "removed": [], "changed": [] },
  "warnings": []
}
```

---

## 7. 内置流程模板与必填参数表

> 模板名来自 `GET /v1/config/ui/schema` 的 `templates[]`。

### 7.1 `transcode_rtsp_hls`

- 必填：`url`
- 常用：`fps,src_w,src_h,gop,bitrate_kbps,rtsp_port,hls_path`

### 7.2 `yolo_rtsp_hls`

- 必填：`url, model_path`

### 7.3 `yolo_alarm_minio`

- 必填：`url, model_path, minio_endpoint, minio_bucket, minio_ak, minio_sk`
- 常用：`cooldown_ms`（默认 3000）

### 7.4 `face_det_rtsp_hls`

- 必填：`url, det_model_path`

### 7.5 `face_det_recog_rtsp_hls`

- 必填：`url, det_model_path, recog_model_path`
- 默认：`gallery_path=./models/face_gallery.db`，`thr_accept=0.45`，`thr_margin=0.05`

---

## 8. 人脸库路径对齐建议（避免“上传了但识别不到”）

1) 默认推荐（最省事）：

- media-server work_dir：`/opt/rk3588sys`
- agent.models_dir：`/opt/rk3588sys/models`
- ai_face_recog.gallery.path：`./models/face_gallery.db`

1) 若你们的 work_dir/models_dir 不是这种关系：

- 控制端在 instances params 里把 `gallery_path` 设置为**绝对路径**（例如 `/opt/rk3588sys/models/face_gallery.db`）。

---

## 9. 验收标准

1) GUI 新增通道 → apply 成功后：`GET /v1/graphs` 出现该通道；`GET /v1/graphs/{name}` 能看到节点链路。
2) 删除通道 → apply 成功后 graphs 中消失。
3) 上传 `face_gallery.db` → `POST /v1/face-gallery/reload` 后无需重启即可生效。
4) apply 失败时：自动 rollback，且 rollback 后 config 仍为 templates/instances 源结构。
