stouchinglhh
Claude
sync processor from GitLab c697b6e: 版本 1.19.4 / 前端 1.12.4 —— 服务端 i18n(首屏不再闪英文)、推理模块并入模型页、前端抽出 shared/、缓存键改用前端号
bb59211
Raw History Blame Contribute Delete
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"
@register_check
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