# processor
[中文](README.zh-CN.md) | [English](README.md)
> 文档版本:2026-09-28 · 后端版本:`1.19.4` · 前端版本:`1.12.3`
processor 是 EgoData 的数据采集、处理、审核和导出服务,面向具身智能与机器人
操作数据。系统由 FastAPI 后端、异步 Worker、Web 审核页面和 Workflow Studio 组成。
> 项目文档:[项目文档介绍](docs/README.md)。
```text
采集端上传 → 项目匹配 → 工作流处理 → AI/人工审核 → LeRobot/HDF5 导出
```
## 文档导航
- [系统组成](#1-系统组成)
- [安装与启动](#7-安装与启动)
- [代码目录](#2-代码目录)
- [项目数据结构](#3-项目数据结构)
- [视频数据规范](#4-视频数据规范)
- [工作流模块](#5-工作流模块)
- [Web Workflow Studio 前端模块说明](#web-workflow-studio-前端模块说明)
- [处理结果保存](#6-处理结果保存)
- [配置](#8-配置)
- [API](#9-api)
- [测试与排障](#10-测试与排障)
## 1. 系统组成
```text
采集端
│
▼
FastAPI 后端
├── 项目、Episode、工作流和审核 API
├── 上传接收、解压、规范化和数据校验
└── 调度 Worker 处理任务
│
▼
Worker
├── MediaPipe 手部关键点
├── RGB-D metric 3D 手部关键点
├── 通过 API 进行 AI 标注
└── 视频与标注质量审核
│
▼
Web 审核页面
├── 原始 RGB 视频
├── 浏览器 SVG/Canvas 关键点叠加
└── 深度视频伪彩色预览
│
▼
LeRobot v2.1 / v3.0 或 HDF5
```
本机 `processor/` 目录是前端和后端代码的唯一来源。远端服务器只提供数据目录
或 SFTP 存储,不作为本项目的前端、后端代码来源;服务器中的旧代码已废弃。
## 2. 代码目录
点击展开:代码目录
```text
processor/
├── app/ # FastAPI、存储、工作流、处理和导出逻辑
├── worker/ # 异步处理 Worker
├── scripts/ # 部署、启动、检查和数据维护脚本
├── web/
│ ├── templates/ # Web 页面模板
│ ├── static/ # CSS、JavaScript 和前端构建产物
│ └── workflow-studio/ # React + Vite 工作流编辑器源码
├── tests/ # 自动化测试
├── requirements*.txt # Python 依赖清单
├── deploy.py # 跨平台部署入口
├── deploy.sh # Linux 部署入口
├── deploy.bat # Windows 部署入口
└── .env.example # 配置模板
```
运行数据默认存储在 `STORAGE_DIR`:
```text
data/
├── sessions/ # 项目数据集
├── state/ # 系统状态、队列、运行记录和导出任务
└── tmp/ # 上传和 Worker 临时文件
```
运行数据、模型权重、压缩包、凭据和虚拟环境不应提交到 Git。`requirements*.txt` 和
`package.json` 等依赖清单应保留在仓库中。
## 3. 项目数据结构
点击展开:项目数据结构、Episode、Chunk 和 Meta
一个项目就是一个数据集根目录。规范的项目根目录固定只有 `data/`、`meta/`、`videos/`
三个目录,不在项目下创建额外的批次级数据目录:
```text
data/sessions//
├── data/
│ └── chunk-000/
│ ├── episode_000000.parquet
│ └── episode_000001.parquet
├── meta/
│ ├── info.json
│ ├── stats.json
│ ├── tasks.json
│ └── episodes/
│ └── chunk-000/
│ ├── episode_000000.parquet
│ └── episode_000001.parquet
└── videos/
└── chunk-000/
├── observation.images.head_rgb/
│ └── episode_000000.mp4
└── observation.images.head_depth/
└── episode_000000.mp4
```
### Episode 和 Chunk
- Episode 编号从 `000000` 开始;
- `episode_000000` 至 `episode_000999` 存储在 `chunk-000`;
- `episode_001000` 开始使用 `chunk-001`;
- 每个 chunk 最多包含 1000 个 Episode;
- `data`、`meta/episodes` 和 `videos` 使用相同的 Episode/Chunk 对应关系;
- 采集批次名称用于业务追踪,不替代数据集的 `episode_index`。
### Meta 目录
规范的 `meta/` 目录包含:
- `info.json`:数据集版本、FPS、帧数、feature 和路径模板;
- `stats.json`:数据字段统计信息;
- `tasks.json`:任务 ID 和任务描述;
- `episodes/chunk-XXX/episode_XXXXXX.parquet`:单个 Episode 的时间戳、设备信息、视频
信息、采集元数据、校准信息和处理状态。
时间戳、设备信息和校准信息写入对应的 Episode。审核页和标注页只使用当前 Episode 的
真实视频、深度流和元数据。
## 4. 视频数据规范
点击展开:视频源、深度存储和前端伪彩色预览
### 视频源
| 类型 | 源名称示例 | 说明 |
| --- | --- | --- |
| 单目 RGB | `head_rgb` | 普通 RGB 视频 |
| Metric 深度 | `head_depth` | 独立的真实深度视频 |
| 双目 RGB | `stereo_left_rgb`、`stereo_right_rgb` | 左、右 RGB 视频 |
| 双目深度 | `stereo_depth` | 独立深度视频 |
RGB 和 Depth 始终作为独立数据流保存。纯 Depth 流不会被当作 RGB,也不会与 RGB 流重复
保存。
### 深度存储
新的真实深度视频统一使用:
```text
HEVC (H.265) in MP4 / hvc1 / gray12le / qp=6 / range=full
```
深度视频保存的是 12-bit 对数深度码,不是伪彩色图像:
```text
100–5000 mm 对数深度 → 0..4095 gray12le 码值
```
`meta/info.json` 中对应的 feature 使用 `video.is_depth_map=true` 标记,并记录深度编码
参数。读取端将码值反量化为毫米。原始深度视频在处理和导出时保持不变。
### 前端深度预览
深度伪彩色只用于浏览器预览,不写回数据集:
```text
HEVC gray12le
│
└── 浏览器 Canvas:深度码 → JET 伪彩色
```
预览颜色规范:
- 无效深度:黑色;
- 近距离:蓝紫色;
- 中距离:绿色、黄色;
- 远距离:橙色、红色。
打开 Episode 时会预加载深度预览数据。RGB 视频、双目 RGB 视频和导出数据不经过伪彩色
转换,也不会生成额外的伪彩色视频。
## 5. 工作流模块
点击展开:输入、处理、审核、导出模块和节点状态
工作流由 Input、Process、Review 和 Export 四类模块组成。端口具有明确的数据类型,
每个分支只处理连接到对应端口的数据。没有输入连接的分支标记为
`Skipped · Missing Input`,不会阻塞其他已连接分支。
### 输入模块
- `RGB Camera`:单路 RGB 视频;
- `RGB-D Camera`:RGB 视频和 Depth;
- `Stereo RGB Camera`:Left RGB Video 和 Right RGB Video;
- `Stereo RGB-D Camera`:左右 RGB 视频和 Depth;
- `Glove Sensor`:手套压力、关节或传感器数据。
### 处理模块
- `MediaPipe Hand`:从 RGB 视频提取 2D 手部关键点;
- `Human Annotation`:人工标注;
- `AI Annotation`:通过配置的 API 进行视频/片段标注;
- `RGB_TO_2D_BareHand`:裸手 2D 手部关键点;
- `RGB_TO_2D_BlackGlove`:黑手套 2D 手部关键点;
- `RGB-D_3D_BareHand`:使用 RGB 视频和 Depth 计算真实 metric 3D 裸手关键点;
- `RGB-D_3D_BlackGlove`:使用 RGB 视频和 Depth 计算真实 metric 3D 黑手套关键点。
`RGB_TO_2D_*` 的 `Spatial` 按钮只控制浏览器中的空间预览,不生成虚假 3D 数据,也不会
向导出数据写入 3D 值。`RGB-D_3D_*` 的 `RGB Video` 和 `Depth` 是独立输入端,应分别连接
对应的采集端输出。
### Web Workflow Studio 前端模块说明
以下模块是当前前端调色板和画布实际注册的模块。模块名称、端口名称和连接类型由前端
注册表统一维护,不会被陈旧工作流或废弃后端目录覆盖。旧类型
`rgb_hand_3d`、`black_hand_rgb_3d`、`stereo_triangulate` 和 `black_glove_hand` 仅在加载
旧工作流时做映射,新工作流调色板不显示这些类型。
#### 采集端模块(Input)
| 前端模块 | 输入端 | 输出端 | 用途与规则 |
| --- | --- | --- | --- |
| `RGB Camera` | 无 | `RGB Video` | 单目 RGB 视频。设备从当前项目数据中选择;留空时自动匹配。 |
| `RGB-D Camera` | 无 | `RGB Video`、`Depth` | 输出同一设备的 RGB 和真实深度流;Depth 只能连接到深度输入端。 |
| `Stereo RGB Camera` | 无 | `Left RGB Video`、`Right RGB Video` | 双目 RGB 输入;连接一侧时建立对应的左右关系。 |
| `Stereo RGB-D Camera` | 无 | `Left RGB Video`、`Right RGB Video`、`Depth` | 双目 RGB 加真实深度;Depth 用于 RGB-D 3D 处理。 |
| `Glove Sensor` | 无 | `Glove Sensor Data` | 压力、关节或手套传感器数据,不输出视频;可直接连接质量审核。 |
#### 视频和关键点处理模块(Process)
| 前端模块 | 输入端 | 输出端 | 用途与规则 |
| --- | --- | --- | --- |
| `Human Annotation` | `RGB Video` | `Annotation` | 在 RGB 视频上进行帧级人工标注。 |
| `AI Annotation` | `RGB Video` | `Annotation` | 通过本地或 API VLM 进行视频/片段标注;部署时推荐使用 API。 |
| `RGB_TO_2D_BareHand` | `RGB Video` | `Hand 2D` | 裸手 2D 关键点;`Spatial` 仅用于显示,不导出 metric 3D。 |
| `RGB_TO_2D_BlackGlove` | `RGB Video` | `Hand 2D` | 黑手套 2D 关键点;没有 Depth 时不计算 metric 3D。 |
| `RGB-D_3D_BareHand` | `RGB Video`、`Depth` | `Hand 3D` | 使用 RGB 和真实 Depth 计算 metric 3D 裸手关键点;缺少分支时跳过。 |
| `RGB-D_3D_BlackGlove` | `RGB Video`、`Depth` | `Hand 3D` | 使用 RGB 和真实 Depth 计算 metric 3D 黑手套关键点;不会从磁盘寻找或回退到 RGB 估计。 |
`MediaPipe Hand` 保留用于历史工作流和后端兼容,但新工作流调色板不显示。所有节点都
支持鼠标悬停说明,提示模块用途和允许连接的数据类型。
#### 审核模块(Review)
| 前端模块 | 输入端 | 输出端 | 用途与规则 |
| --- | --- | --- | --- |
| `Human Review` | `Review Target` | `Reviewed Data` | 人工检查视频、关键点或标注结果,再进入后续流程。 |
| `AI Quality Review` | `Quality Review Target` | `Reviewed Data` | 检查视频解码、帧连续性、黑屏、冻结、标注覆盖率和传感器数据。 |
#### 导出模块(Export)
| 前端模块 | 输入端 | 输出端 | 用途与规则 |
| --- | --- | --- | --- |
| `LeRobot Export` | `Exportable Data` | `Dataset` | 导出 LeRobot v2.1 或 v3.0;版本在节点上选择。 |
| `HDF5 Export` | `Exportable Data` | `Dataset` | 使用配置的压缩参数导出 HDF5 数据集。 |
#### Workflow Studio 界面功能
点击展开:前端界面组件说明
| 界面组件 | 功能 |
| --- | --- |
| `NodePalette` | 按 Input、Process、Review、Export 分类显示节点;支持搜索、分类折叠和悬停说明。 |
| `WorkflowCanvas` | 支持拖拽创建节点、端口连线、移动、选择、缩放、网格对齐和小地图导航。 |
| `WorkflowNode` | 渲染卡片标题、输入输出端口、项目设备选择/输入框、`Spatial` 和 API 设置按钮。 |
| `WorkflowDrawer` | 查看工作流列表、创建和加载工作流,并刷新当前项目的输入源。 |
| `PipelineToolbar` | 提供新建、保存、另存为、导出工作流 JSON 和运行操作;黄色圆点表示有未保存修改。 |
| `NodeSettingsModal` | 配置 AI Annotation 的 API 厂商、模型、地址和密钥字段。 |
| `DeletableEdge` | 显示数据连接线;选中后可以删除。 |
设备选择始终绑定当前项目。新的空工作流不会显示其他项目的设备;数据上传后,每个卡片
的选择框只显示与该卡片 RGB、RGB-D、双目或手套类型匹配的真实数据源。
### 审核与执行规则
输入端和输出端必须按照端口名称连接。没有输入连接的处理分支直接跳过,不影响其他分支。
只有在 RGB Video 和 Depth 都可用时,RGB-D 3D 才会产生真实 metric 3D 数据。
节点状态限制为:
```text
Connected
Processing
Completed
Skipped · Missing Input
Completed with Warning
```
## 6. 处理结果保存
点击展开:处理结果、上传解压和清理规则
Worker 完成处理后,结果合并到对应 Episode:
```text
data/chunk-000/episode_000000.parquet
└── 2D 关键点、metric 3D、传感器和标注字段
meta/episodes/chunk-000/episode_000000.parquet
└── processing_*、run_id、节点状态和输出索引
```
原始 RGB/Depth 视频不会被覆盖。手部关键点预览在浏览器中叠加到原始 RGB 视频上,不保存
第二份骨骼视频。系统级运行记录位于 `data/state/runs/`,导出临时产品位于
`data/state/exports/`;两者都不属于项目数据集目录。
上传压缩包的流程为:接收 → 解压 → 规范化 → 写入项目 → 校验 → 更新状态。只有完整解压、
原子提交和校验全部成功后,上传临时文件和解压临时目录才会清理;失败时保留暂存内容供
重试和诊断。
## 7. 安装与启动
### Linux
```bash
cd "processor"
cp .env.example .env
# 编辑 .env,设置 API_KEY、WORKER_API_KEY、JWT_SECRET 和存储配置。
chmod +x deploy.sh
./deploy.sh
```
常用参数:
```bash
python deploy.py --check-only # 只检查,不安装、不修改配置、不启动服务。
python deploy.py --skip-vllm # 不启动本地 VLM,AI 标注使用 API。
python deploy.py --no-services # 前台运行,不安装自启动服务。
```
当前 AI 标注部署使用 API。使用 `--skip-vllm`,然后在 Workflow Studio 的
`AI Annotation` 设置中配置 API 厂商、模型和地址。
### Windows
```bat
cd /d "processor"
copy .env.example .env && deploy.bat
```
### 手动启动后端
```bash
cd "processor"
source .venv-linux/bin/activate
export PYTHONPATH="$PWD"
./scripts/run_backend_linux.sh
```
也可以直接运行:
```bash
uvicorn app.main:app --host 0.0.0.0 --port 8000
```
### 启动 Worker
```bash
cd "processor"
export EGODATA_SERVER_URL=http://127.0.0.1:8000
export EGODATA_WORKER_API_KEY='与服务端一致的 Worker API Key'
./scripts/run_worker_linux.sh
```
Windows 使用 `scripts/run_worker_windows.ps1`。Linux 和 Windows 的虚拟环境相互独立,
不能跨系统复制。
### Workflow Studio
```bash
cd "processor/web/workflow-studio"
npm ci
npm run dev
```
生产构建:
```bash
npm run build
```
构建产物写入 `web/static/workflow-studio/`,由 FastAPI 页面服务加载。
## 8. 配置
点击展开:环境变量和安全配置
配置写入 `processor/.env` 或环境变量,不提交到仓库:
| 配置 | 作用 |
| --- | --- |
| `STORAGE_DIR` | 数据和系统状态根目录 |
| `STORAGE_BACKEND` | `local` 或 `sftp` |
| `SFTP_*` | 远端数据目录和 SSH 连接配置 |
| `API_KEY` | 采集端和受保护接口的 API Key |
| `WORKER_API_KEY` | Worker 领取和回传任务使用的 API Key |
| `JWT_SECRET` | Web 登录态签名密钥 |
| `UPLOAD_STAGING_DIR` | 上传压缩包的本地暂存目录 |
| `HOST` / `PORT` | Web/API 监听地址和端口 |
| `PUBLIC_BASE_URL` | 对外访问地址 |
完整模板见 [`.env.example`](.env.example)。生产环境必须使用随机密钥并限制 `.env` 权限。
不要在日志、工作流 JSON、前端代码或文档中写入密码、Token、API Key 和数据库凭据。
## 9. API
点击展开:主要 API 和 OpenAPI 文档
服务启动后可访问:
```text
GET /health
GET /docs
GET /openapi.json
```
主要 API 分组:
```text
/api/v1/auth/* 登录和认证
/api/v1/projects/* 项目和 Episode
/api/v1/workflows/* 工作流定义
/api/v1/session/* 采集端上传
/api/v1/video/* 视频、深度和关键点预览
/api/v1/annotations/* 标注和审核
/api/v1/export/* 数据导出
/api/v1/worker/* Worker 任务领取与回传
```
完整接口契约以运行中的 FastAPI OpenAPI 文档为准。
## 10. 测试与排障
点击展开:测试命令和常见排障步骤
后端和 Worker 基础检查:
```bash
cd "processor"
python -m compileall app worker
python deploy.py --check-only
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python -m pytest -q tests/test_depth_codec.py
```
前端检查:
```bash
cd "processor/web/workflow-studio"
npm run build
```
排障顺序:
1. 访问 `/health`,确认服务和存储可用;
2. 检查 `STORAGE_DIR` 是否指向实际数据目录;
3. 检查上传状态和当前 Episode 的实际文件;
4. 检查 Worker 是否在线、能领取任务并发送心跳;
5. 检查 `data`、`meta/episodes`、`videos` 的 Episode 编号是否一致;
6. RGB-D 3D 节点检查 `RGB Video` 和 `Depth` 是否分别接线;
7. 深度预览异常时检查视频是否为 `gray12le`,不要把伪彩色预览当作原始深度数据。
## 11. 版本约定
点击展开:版本维护规则
- 后端版本在 `app/version.py` 中维护,**只管后端**;
- **前端版本在 `web/VERSION` 中维护**。它覆盖 `processor/web/` 下的全部前端代码
(`templates/`、`static/`、`workflow-studio/`),**不只是那个 React SPA**。
`web/workflow-studio/package.json` 里的 version 只代表 SPA 自己,三者互相独立、不必同步。
- **改了前端就只 bump `web/VERSION` 这一个文件**。它一个号管两件事:
① 模板里的 `?v={{ asset_version }}` 缓存键(读了它浏览器才会重新拉 JS/CSS)
② 提交信息里的「前端 X」。
两个用途共用一个数,不会出现"提交信息写 1.12.3、浏览器却拿 1.12.2"这种对不上的情况。
改前端**不需要**动后端版本号。
- 改完 `web/VERSION` 要**重启服务**才生效(`app/web_version.py` 启动时读一次就缓存)。
- 修复和小调整增加修订号;新增功能增加次版本号;重大架构变更增加主版本号;
- 发布前应同步记录软件版本、数据格式和 API 变化。
当前版本:后端 `1.19.4`,前端 `1.12.3`。