Spaces:
Running
Running
stouchinglhh
Claude
sync processor from GitLab c697b6e: 版本 1.19.4 / 前端 1.12.4 —— 服务端 i18n(首屏不再闪英文)、推理模块并入模型页、前端抽出 shared/、缓存键改用前端号
bb59211 Download processor/app/processing/modules/data_quality.py from Stouching-Robotics/DataFlowing: direct link, hf CLI and curl.
- Browser
- Download file 6.47 kB
-
https://huggingface.co/spaces/Stouching-Robotics/DataFlowing/resolve/main/processor/app/processing/modules/data_quality.py
- Command line
-
hf download hf://spaces/Stouching-Robotics/DataFlowing/processor/app/processing/modules/data_quality.py
-
curl -L -o data_quality.py https://huggingface.co/spaces/Stouching-Robotics/DataFlowing/resolve/main/processor/app/processing/modules/data_quality.py
6.47 kB
| """Data Cleaning —— 数据清洗(质检):一个节点统管确定性与 AI 两类检查。 | |
| 显示名是 Data Cleaning;slug 仍是 ``data_quality``(持久化契约,改它会让已保存 | |
| 工作流的 nodeType 对不上)。两者不一致是有意的 —— 见下方端口 key 的同类说明。 | |
| 本节点由两个旧节点合并而来,两者功能高度重叠: | |
| ai_quality_review 视频检查(黑屏/冻结/丢帧/解码) + AI 标注覆盖率 | |
| data_cleaning 视频检查 + UMI/手套/EGO 检查(第 2 期接入) | |
| 历史原因:视频检查最早"寄居"在 ``ai_quality_review`` 里,好让纯视频工作流 | |
| 也有质量门禁(见 ``ai_annotation.py`` 的 ``video_quality_review_node_config`` | |
| docstring)。现在合并成一张卡片,语义与配置都归一处。 | |
| **两个旧 slug 都作为别名保留**(``workflow_types.LEGACY_TO_CANONICAL``), | |
| 已保存的工作流打开时自动迁移,连线不受影响 —— 端口的 key 刻意保持不变: | |
| 输入 data 所有旧连线都用它 | |
| 输出 reviewed 旧连线用它接 lerobot_export | |
| 检查分两层,与清洗方案 PDF §4 的两栏一一对应: | |
| 机器可直接判断(确定性、免费、可每集跑) | |
| ├─ 视频:解码 / 黑屏 / 冻结 / 丢帧 | |
| ├─ UMI:帧对齐 / action / 夹爪量程 / SLAM 连续性 | |
| ├─ 手套:全零 / 死点 / 漂移 / 饱和 | |
| └─ EGO:曝光 / 关键点缺失 / 左右手 | |
| 需联合判断或复核(有成本、可选) | |
| └─ AI 标注覆盖率;将来的 VLM 语义复核 | |
| 检查项的算法实现与工作流适配器分开,与 ``app/processing/black_glove`` 同构: | |
| app/processing/cleaning/ ← 契约 + 检查项 + 报告组装 | |
| app/processing/modules/data_quality.py ← 本文件:artifact 契约 + 端口 + 配置 | |
| 新增检查项 = 在 ``app/processing/cleaning/checks/`` 下放一个 .py,本文件不用改。 | |
| **只出结论,不产出数据** —— 原始数据一字不改,也不生成 clean_v1 之类的副本。 | |
| 区间信息完整保留在报告的 ``ranges`` 里,下游按 ``training_use`` 过滤即可。 | |
| 数据不对时**卡在人工审核**:判 FAIL/ERROR 的批次会被推回 ``to_review`` | |
| (就是审核页的入口),并在 ``cleaning_summary.blocking`` 上留一个粘性标记, | |
| 让 AI 标注 / 视频门禁的自动批准路径让路。WARN 只记录、不拦。 | |
| """ | |
| from __future__ import annotations | |
| from app.processing import ProcessingModule, JobContext, ArtifactRef | |
| from app.processing.registry import register | |
| from app.processing.theme import REVIEW_COLOR | |
| class DataQualityModule(ProcessingModule): | |
| slug = "data_quality" | |
| version = "1.0" | |
| category = "review" | |
| label = "Data Cleaning" | |
| # 必须取自 web/static/iconify-preload.js 的白名单 —— 图标是离线预载的, | |
| # 不在表内的名字 iconify-icon 会去 api.iconify.design 拉,调色板一次渲染 | |
| # 全部节点,一个漏网图标就能让整块面板卡住。check-circle 表示"校验", | |
| # 与同组 review 节点的 eye(human) 不冲突。 | |
| # 改图标后请跑 scripts/check_icon_preload.sh。 | |
| icon = "ant-design:check-circle-outlined" | |
| color = REVIEW_COLOR | |
| # 端口 key 是持久化契约 —— 取值必须与合并前的 ai_quality_review 逐字一致, | |
| # 否则已保存工作流的连线会因 sourceHandle/targetHandle 对不上而失效。 | |
| # 详见 workflow_types.py 里前端对 ``out.key === inp.key`` 的校验。 | |
| inputs = ({"key": "data", "label": "Data"},) | |
| outputs = ({"key": "reviewed", "label": "Reviewed Data"},) | |
| # 配置结构(前端设置弹窗按设备卡片写入):: | |
| # | |
| # {"devices": { | |
| # "gripper_device": { | |
| # "checks": { | |
| # "umi.slam_continuity": {"enabled": true, | |
| # "params": {"max_linear_mps": 3.0}}, | |
| # "video.freeze": {"enabled": false} | |
| # }}}} | |
| # | |
| # 引擎侧由 ``cleaning.engine.resolve_config()`` 解析。 | |
| default_config = {"devices": {}} | |
| # ★ 刻意留空 —— 配置全部走专用弹窗(DeviceQualityModal),不走通用 | |
| # config_schema 渲染。 | |
| # | |
| # 通用那套是**平铺字段列表**,表达不了"按设备卡片分组 + 每项带阈值"的 | |
| # 嵌套结构;硬塞会变成一长串 enable_xxx 开关。曾短暂用过那套,结果是 | |
| # 三个阈值在节点里和检查项里各存一份(frame_tolerance 与 | |
| # video.frame_drop.tolerance_ratio 同义),迟早不一致。 | |
| # | |
| # 现在阈值只有一处定义:检查项的 ``default_params``;节点只存"覆盖值"。 | |
| config_schema = () | |
| # 真实检查在 run 完成回调里跑(那时才能读到合并后的 episode 数据), | |
| # 与 human_review / 旧 ai_quality_review 的分工一致。 | |
| # 注:该字段当前无消费方,仅作语义标注(全仓 grep 只见 schema 与文档)。 | |
| execution_target = "server" | |
| capabilities = ("data_quality", "quality_gate", "quality_review") | |
| def run(self, ctx: JobContext) -> dict[str, ArtifactRef] | None: | |
| """透传上游 artifact。上游没连 → skipped。 | |
| **真正的检查不在 ``run()`` 里跑** —— 在 worker 的 run 完成回调里 | |
| (``api/worker.py`` 调 ``cleaning.trigger.spawn_cleaning_for_run``)。 | |
| 为什么不在 ``run()``:DAG 执行期 worker 是在 staging 目录里干活、 | |
| 产物要等 ``_publish_episode_result`` 才合并回批次目录。在这一步读 | |
| 批次目录,拿到的是**上一轮**的数据 —— 尤其 ``action`` 列,它由 | |
| ``umi_slam_action`` 派生产出,读早了会全是采集端的零占位。 | |
| 完成回调时数据已经合并完毕,与 ``human_review`` / 旧 | |
| ``ai_quality_review`` 的分工一致。 | |
| 检查所需的数据**不靠端口传** —— 完成回调手上就有 | |
| ``localstore.get_episode()`` 的记录(``path`` + ``episode_index``), | |
| 检查项直接读批次目录。 | |
| ★ 进来的是 ``episode_index`` 不是可选的:``path`` 是**项目目录**, | |
| 几十集共享,漏传会拿第 0 集的数据去比全部集的视频。 | |
| """ | |
| if not ctx.incoming: | |
| ctx.skip("No upstream data — skipped") | |
| return dict(ctx.incoming) | |