Spaces:
Running
Running
stouchinglhh
Claude
sync processor from GitLab c697b6e: 版本 1.19.4 / 前端 1.12.4 —— 服务端 i18n(首屏不再闪英文)、推理模块并入模型页、前端抽出 shared/、缓存键改用前端号
bb59211 Download processor/app/processing/cleaning/checks/glove/device_status.py from Stouching-Robotics/DataFlowing: direct link, hf CLI and curl.
- Browser
- Download file 4.55 kB
-
https://huggingface.co/spaces/Stouching-Robotics/DataFlowing/resolve/main/processor/app/processing/cleaning/checks/glove/device_status.py
- Command line
-
hf download hf://spaces/Stouching-Robotics/DataFlowing/processor/app/processing/cleaning/checks/glove/device_status.py
-
curl -L -o device_status.py https://huggingface.co/spaces/Stouching-Robotics/DataFlowing/resolve/main/processor/app/processing/cleaning/checks/glove/device_status.py
4.55 kB
| """手套连接状态 —— 录制途中掉线。 | |
| 为什么重要 | |
| ---------- | |
| 手套掉线时阵列读数会**静默保持最后一个值**,看起来完全正常:有列、有 16×16、 | |
| 数值也在合理范围。只有状态列说实话。所以这一项是唯一能看见"设备其实没了" | |
| 的检查。 | |
| 判定口径(分两种,因为状态词表只见过一个值) | |
| ------------------------------------------ | |
| ``connected`` 是实测见到的**唯一**取值(S80C / D435 两个项目、全部集、全部帧)。 | |
| 其余词表未知,所以: | |
| 录制中途**状态发生变化** → **FAIL** | |
| 无论变成什么,从"连着"变成别的就是掉线,这个判断不依赖词表。 | |
| 全程恒定但不是 ``connected`` → **WARN** | |
| 可能是掉线,也可能是我们没见过的正常状态词(如 "ok"/"active")。 | |
| 词表未证实之前不拦批次 —— 拦错了用户会开始无脑点通过,比不拦更糟。 | |
| 空字符串 → **WARN**(这一帧没读到状态) | |
| ★ 阈值不放进 ``default_params``:词表是字符串,而前端设置面板把所有参数都渲染 | |
| 成数字输入框。硬塞会把面板显示成 NaN。真需要可配时先改面板的类型支持。 | |
| """ | |
| from __future__ import annotations | |
| from app.processing.cleaning.checks import ( | |
| CheckContext, CleaningCheck, register_check, | |
| Finding, PASS, WARN, FAIL, | |
| ) | |
| # 实测唯一见过的取值。其余一律按"词表未知"处理,不直接判失败。 | |
| _HEALTHY = "connected" | |
| class GloveDeviceStatusCheck(CleaningCheck): | |
| slug = "glove.device_status" | |
| label = "Glove Connection" | |
| version = "1.0" | |
| description = "Device dropped out mid-recording (from status.*_glove)" | |
| requires_channels = ("device_status",) | |
| device_cards = ("glove_sensor",) | |
| default_params: dict = {} | |
| default_severity = FAIL | |
| def run(self, ctx: CheckContext) -> list[Finding]: | |
| findings: list[Finding] = [] | |
| for stream in ctx.streams_of("device_status"): | |
| values = tuple(stream.series.get("device_status") or ()) | |
| # 流名就是那一列的最后一段(left_glove / right_glove),用它报位置 | |
| hand = stream.key | |
| if not values: | |
| findings.append(self.finding( | |
| ctx, WARN, stream=hand, | |
| message=f"{hand}: no status column data", | |
| metrics={"frames": 0}, | |
| )) | |
| continue | |
| blanks = sum(1 for item in values if not item) | |
| distinct: list[str] = [] | |
| for item in values: | |
| if item and item not in distinct: | |
| distinct.append(item) | |
| # ① 中途变过 —— 与词表无关,见到即掉线 | |
| if len(distinct) > 1: | |
| changes = [i for i in range(1, len(values)) if values[i] != values[i - 1]] | |
| findings.append(self.finding( | |
| ctx, FAIL, stream=hand, | |
| message=(f"{hand}: status changed {len(changes)} times " | |
| f"during recording: {' -> '.join(distinct)}"), | |
| metrics={"frames": len(values), "distinct": distinct, | |
| "first_change_frame": changes[0] if changes else None, | |
| "blank_frames": blanks}, | |
| )) | |
| continue | |
| status = distinct[0] if distinct else "" | |
| # ② 恒定但词表未知 / ③ 全空 | |
| if not status: | |
| findings.append(self.finding( | |
| ctx, WARN, stream=hand, | |
| message=f"{hand}: status column is entirely blank", | |
| metrics={"frames": len(values), "blank_frames": blanks}, | |
| )) | |
| elif status != _HEALTHY: | |
| findings.append(self.finding( | |
| ctx, WARN, stream=hand, | |
| message=(f"{hand}: status is constantly {status!r} (only " | |
| f"{_HEALTHY!r} has ever been observed; vocabulary " | |
| f"unconfirmed - please verify manually)"), | |
| metrics={"frames": len(values), "status": status}, | |
| )) | |
| else: | |
| findings.append(self.finding( | |
| ctx, PASS, stream=hand, | |
| message=f"{hand}: {_HEALTHY} for the whole episode", | |
| metrics={"frames": len(values), "status": status}, | |
| )) | |
| return findings | |