robot-data-audit 0.7.2__tar.gz → 0.7.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {robot_data_audit-0.7.2/robot_data_audit.egg-info → robot_data_audit-0.7.3}/PKG-INFO +8 -3
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/README.md +7 -2
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/pyproject.toml +1 -1
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/recommend/formatter.py +6 -2
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/recommend/temporal_metrics.py +36 -5
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/ui_app/components/common.py +616 -548
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/ui_app/i18n.py +96 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/ui_app/pages/3_Health_Overview.py +313 -266
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/ui_app/pages/4_Episode_Explorer.py +1025 -844
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3/robot_data_audit.egg-info}/PKG-INFO +8 -3
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/robot_data_audit.egg-info/SOURCES.txt +2 -0
- robot_data_audit-0.7.3/tests/test_req3b_fps_floor.py +86 -0
- robot_data_audit-0.7.3/tests/test_ui_visual_audit.py +233 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/LICENSE +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/__init__.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/audit/__init__.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/audit/dataset_audit.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/audit/episode_audit.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/audit/rules.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/calibration/__init__.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/calibration/normalization.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/calibration/portable.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/calibration/reference.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/calibration/scorer.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/cli/__init__.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/cli/main.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/export/__init__.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/export/clean_export.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/io/__init__.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/io/lerobot_loader.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/io/schema.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/metrics/__init__.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/metrics/base.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/metrics/distribution.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/metrics/integrity.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/metrics/motion.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/metrics/temporal.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/metrics/video_integrity.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/metrics/visual_integrity.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/metrics/visual_quality.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/recommend/__init__.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/recommend/api_client.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/recommend/engine.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/recommend/local_fallback.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/recommend/preflight.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/recommend/types.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/report/__init__.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/report/aggregation.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/report/audit_history.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/report/json_report.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/report/summary.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/report/top_issues.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/ui_app/__init__.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/ui_app/app.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/ui_app/components/__init__.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/ui_app/pages/1_Upload.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/ui_app/pages/2_Audit.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/ui_app/pages/5_Export.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/ui_app/pages/6_History.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/ui_app/pages/7_Recommend.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/rda/validation.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/robot_data_audit.egg-info/dependency_links.txt +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/robot_data_audit.egg-info/entry_points.txt +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/robot_data_audit.egg-info/requires.txt +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/robot_data_audit.egg-info/top_level.txt +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/setup.cfg +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/tests/test_evidence_levels.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/tests/test_i18n.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/tests/test_lerobot_loader_v30_libero.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/tests/test_lerobot_task_identity.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/tests/test_metrics.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/tests/test_negative_control.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/tests/test_preflight.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/tests/test_rda_render.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/tests/test_recommend_offline.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/tests/test_req10_req11_visual_calibration.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/tests/test_req3_idle_alignment.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/tests/test_req4_visual_integrity.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/tests/test_validation.py +0 -0
- {robot_data_audit-0.7.2 → robot_data_audit-0.7.3}/tests/test_video_frame_integrity.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: robot-data-audit
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.3
|
|
4
4
|
Summary: Robot Data Audit (RDA) - Quality auditing tool for robot datasets
|
|
5
5
|
Author-email: Niu Su Tech <dev@niusutech.com>
|
|
6
6
|
License: MIT License
|
|
@@ -98,7 +98,12 @@ Optional dependency tiers:
|
|
|
98
98
|
|
|
99
99
|
**Visual metrics without PyAV are reported as "not audited", never as
|
|
100
100
|
"pass"**: the JSON report carries a top-level `skipped_by_missing_dep`
|
|
101
|
-
field and the CLI prints a warning listing the skipped checks.
|
|
101
|
+
field and the CLI prints a warning listing the skipped checks. The web
|
|
102
|
+
dashboard shows the same guarantee — a dep-missing dataset renders a
|
|
103
|
+
"not audited ≠ pass" banner, and the Health Overview adds a Visual
|
|
104
|
+
Integrity section (checked / flagged / not-checked episode counts) while
|
|
105
|
+
Episode Explorer gains a per-episode Visual Audit panel (freeze-region
|
|
106
|
+
table, per-camera quality penalties, per-sample quality curves).
|
|
102
107
|
|
|
103
108
|
## Quick start
|
|
104
109
|
|
|
@@ -113,7 +118,7 @@ rda recommend /path/to/dataset --policy temporal # or frame-wise
|
|
|
113
118
|
rda ui
|
|
114
119
|
```
|
|
115
120
|
|
|
116
|
-
`rda audit` is fully offline. `rda recommend` computes all metrics locally and sends only aggregated statistics (<1KB) to the rules API — cached for offline reuse, and `RDA_API_URL` can point to your own server for private deployments.
|
|
121
|
+
`rda audit` is fully offline. `rda recommend` computes all metrics locally and sends only aggregated statistics (<1KB) to the rules API — cached for offline reuse, and `RDA_API_URL` can point to your own server for private deployments. The `usable_retention` statistic is **fps-aware** (v0.7.3): a "usable" run must span ≥16 frames *and* ≥1 second (DROID's `min_non_idle_len=16` encodes 1 s at 15-30 Hz; on 50 Hz data the floor rises to 50 frames so sub-second twitches no longer count).
|
|
117
122
|
|
|
118
123
|
<p align="center">
|
|
119
124
|
<img width="2549" alt="RDA recommendations" src="https://github.com/user-attachments/assets/e366cdf1-b169-46b0-b020-5327493a9124" />
|
|
@@ -35,7 +35,12 @@ Optional dependency tiers:
|
|
|
35
35
|
|
|
36
36
|
**Visual metrics without PyAV are reported as "not audited", never as
|
|
37
37
|
"pass"**: the JSON report carries a top-level `skipped_by_missing_dep`
|
|
38
|
-
field and the CLI prints a warning listing the skipped checks.
|
|
38
|
+
field and the CLI prints a warning listing the skipped checks. The web
|
|
39
|
+
dashboard shows the same guarantee — a dep-missing dataset renders a
|
|
40
|
+
"not audited ≠ pass" banner, and the Health Overview adds a Visual
|
|
41
|
+
Integrity section (checked / flagged / not-checked episode counts) while
|
|
42
|
+
Episode Explorer gains a per-episode Visual Audit panel (freeze-region
|
|
43
|
+
table, per-camera quality penalties, per-sample quality curves).
|
|
39
44
|
|
|
40
45
|
## Quick start
|
|
41
46
|
|
|
@@ -50,7 +55,7 @@ rda recommend /path/to/dataset --policy temporal # or frame-wise
|
|
|
50
55
|
rda ui
|
|
51
56
|
```
|
|
52
57
|
|
|
53
|
-
`rda audit` is fully offline. `rda recommend` computes all metrics locally and sends only aggregated statistics (<1KB) to the rules API — cached for offline reuse, and `RDA_API_URL` can point to your own server for private deployments.
|
|
58
|
+
`rda audit` is fully offline. `rda recommend` computes all metrics locally and sends only aggregated statistics (<1KB) to the rules API — cached for offline reuse, and `RDA_API_URL` can point to your own server for private deployments. The `usable_retention` statistic is **fps-aware** (v0.7.3): a "usable" run must span ≥16 frames *and* ≥1 second (DROID's `min_non_idle_len=16` encodes 1 s at 15-30 Hz; on 50 Hz data the floor rises to 50 frames so sub-second twitches no longer count).
|
|
54
59
|
|
|
55
60
|
<p align="center">
|
|
56
61
|
<img width="2549" alt="RDA recommendations" src="https://github.com/user-attachments/assets/e366cdf1-b169-46b0-b020-5327493a9124" />
|
|
@@ -101,11 +101,15 @@ def format_recommendation_text(result: RecommendationResult, lang: str = "zh") -
|
|
|
101
101
|
# REQ-3 (v0.6.0): DROID-aligned retention metrics
|
|
102
102
|
usable = getattr(ts, "usable_retention_ratio", {}).get("median", 0.0)
|
|
103
103
|
max_idle = getattr(ts, "max_idle_run_frames", {}).get("median", 0.0)
|
|
104
|
+
# REQ-3② (v0.7.3): report the floor actually applied
|
|
105
|
+
# (max(16, 1s-in-frames) when fps is known; 16 otherwise).
|
|
106
|
+
floor = getattr(ts, "usable_run_floor_frames", {}).get("median", 0.0)
|
|
107
|
+
floor = int(round(floor)) if floor else 16
|
|
104
108
|
if lang == "zh":
|
|
105
|
-
lines.append(f" usable_retention: {usable:.1%} (连续 ≥
|
|
109
|
+
lines.append(f" usable_retention: {usable:.1%} (连续 ≥{floor} 帧非静止段帧占比, 对齐 DROID; ≥16 帧且 ≥1s)")
|
|
106
110
|
lines.append(f" max_idle_run: {max_idle:.0f} 帧 (最长连续静止段)")
|
|
107
111
|
else:
|
|
108
|
-
lines.append(f" usable_retention: {usable:.1%} (frames in runs >=
|
|
112
|
+
lines.append(f" usable_retention: {usable:.1%} (frames in runs >= {floor} non-idle, DROID-aligned; >=16 frames and >=1s)")
|
|
109
113
|
lines.append(f" max_idle_run: {max_idle:.0f} frames (longest static stretch)")
|
|
110
114
|
else:
|
|
111
115
|
if lang == "zh":
|
|
@@ -38,6 +38,9 @@ from rda.io.schema import EpisodeData
|
|
|
38
38
|
# REQ-3 (v0.6.0): minimum length of a consecutive non-idle segment for it
|
|
39
39
|
# to count as "usable" in usable_retention_ratio. Aligned with openpi's
|
|
40
40
|
# DROID chunked filter (min_non_idle_len=16 ≈ 1s at typical 15-30Hz).
|
|
41
|
+
# REQ-3② (v0.7.3): this is the *floor*; compute_temporal_sufficiency
|
|
42
|
+
# raises it to max(16, fps) when the episode's fps is known, so the
|
|
43
|
+
# floor always means "at least 1 second" on high-fps (>16 Hz) data.
|
|
41
44
|
USABLE_RUN_MIN_FRAMES = 16
|
|
42
45
|
|
|
43
46
|
|
|
@@ -228,10 +231,14 @@ class TemporalSufficiency:
|
|
|
228
231
|
threshold: float = 0.0
|
|
229
232
|
# REQ-3 (v0.6.0): DROID-aligned retention metrics.
|
|
230
233
|
# usable_retention_ratio: fraction of frames inside "usable" runs —
|
|
231
|
-
# consecutive non-idle segments of at least
|
|
232
|
-
# frames (
|
|
234
|
+
# consecutive non-idle segments of at least usable_run_floor_frames
|
|
235
|
+
# frames (REQ-3②: max(16, 1s-in-frames), DROID-aligned). Directly
|
|
233
236
|
# answers "how much data survives a chunk-aligned prune".
|
|
234
237
|
usable_retention_ratio: float = 0.0
|
|
238
|
+
# REQ-3② (v0.7.3): the actual run-length floor applied for
|
|
239
|
+
# usable_retention_ratio (max(16, 1s-in-frames)); lets the report
|
|
240
|
+
# and server-side consumers know which semantics produced the ratio.
|
|
241
|
+
usable_run_floor_frames: int = USABLE_RUN_MIN_FRAMES
|
|
235
242
|
# Longest run of consecutive all-idle chunks (in chunks). A static
|
|
236
243
|
# stretch longer than chunk_size-1 chunks cannot fit any valid
|
|
237
244
|
# chunk window (DROID min_idle_len semantics).
|
|
@@ -351,12 +358,26 @@ def compute_temporal_sufficiency(
|
|
|
351
358
|
|
|
352
359
|
# --- REQ-3 (v0.6.0): DROID-aligned retention metrics ---
|
|
353
360
|
# usable_retention_ratio: frames inside active runs of at least
|
|
354
|
-
#
|
|
355
|
-
#
|
|
356
|
-
|
|
361
|
+
# MIN_USABLE_RUN frames, where MIN_USABLE_RUN = max(16, 1s in frames)
|
|
362
|
+
# (REQ-3②, v0.7.3): DROID's min_non_idle_len=16 encodes "≈1s at
|
|
363
|
+
# typical 15-30Hz". Above 16 Hz the frame floor alone undercounts
|
|
364
|
+
# the intended duration — at 50 Hz, 16 frames is only 0.32s, which
|
|
365
|
+
# lets sub-second twitches pass as "usable". Taking the max with
|
|
366
|
+
# 1s-in-frames restores the time-based semantics on high-fps data
|
|
367
|
+
# while keeping byte-identical behavior at ≤16 Hz (where 16 ≥ 1s).
|
|
368
|
+
# fps comes from episode.meta ("fps", set by the loader from
|
|
369
|
+
# info.json); fall back to the plain frame floor when unknown.
|
|
370
|
+
fps = episode.meta.get("fps") if episode.meta else None
|
|
371
|
+
try:
|
|
372
|
+
fps = int(fps) if fps else 0
|
|
373
|
+
except (TypeError, ValueError):
|
|
374
|
+
fps = 0
|
|
375
|
+
min_usable_run = max(USABLE_RUN_MIN_FRAMES, fps) if fps > 0 else USABLE_RUN_MIN_FRAMES
|
|
376
|
+
usable_frames = sum(r for r in runs if r >= min_usable_run)
|
|
357
377
|
result.usable_retention_ratio = (
|
|
358
378
|
usable_frames / T_frames if T_frames > 0 else 0.0
|
|
359
379
|
)
|
|
380
|
+
result.usable_run_floor_frames = min_usable_run
|
|
360
381
|
# max_idle_run_frames: longest run of consecutive idle steps, in
|
|
361
382
|
# frames (k idle steps ≈ k+1 consecutive static frames).
|
|
362
383
|
max_idle_steps = 0
|
|
@@ -431,6 +452,11 @@ class DatasetTemporalSufficiency:
|
|
|
431
452
|
# REQ-3 (v0.6.0): DROID-aligned retention metrics (dataset level).
|
|
432
453
|
usable_retention_ratio: Dict[str, float] = field(default_factory=dict)
|
|
433
454
|
max_idle_run_frames: Dict[str, float] = field(default_factory=dict)
|
|
455
|
+
# REQ-3② (v0.7.3): median of the per-episode run-length floors that
|
|
456
|
+
# produced usable_retention_ratio (max(16, 1s-in-frames) when fps
|
|
457
|
+
# is known, else 16). Dataset-level so reports/API consumers can
|
|
458
|
+
# state the semantics; "unknown" floor is reported as 16.
|
|
459
|
+
usable_run_floor_frames: Dict[str, float] = field(default_factory=dict)
|
|
434
460
|
|
|
435
461
|
def to_dict(self) -> Dict[str, Any]:
|
|
436
462
|
"""Serialize to dict."""
|
|
@@ -448,6 +474,7 @@ class DatasetTemporalSufficiency:
|
|
|
448
474
|
"valid_window_ratio_10": self.valid_window_ratio_10,
|
|
449
475
|
"valid_window_ratio_20": self.valid_window_ratio_20,
|
|
450
476
|
"usable_retention_ratio": self.usable_retention_ratio,
|
|
477
|
+
"usable_run_floor_frames": self.usable_run_floor_frames,
|
|
451
478
|
"max_idle_run_frames": self.max_idle_run_frames,
|
|
452
479
|
}
|
|
453
480
|
|
|
@@ -519,6 +546,10 @@ def aggregate_temporal_sufficiency(
|
|
|
519
546
|
result.usable_retention_ratio = _dist(
|
|
520
547
|
np.array([ts.usable_retention_ratio for ts in valid], dtype=np.float64)
|
|
521
548
|
)
|
|
549
|
+
# REQ-3②: dataset-level view of the run-length floor that was applied.
|
|
550
|
+
result.usable_run_floor_frames = _dist(
|
|
551
|
+
np.array([float(ts.usable_run_floor_frames) for ts in valid], dtype=np.float64)
|
|
552
|
+
)
|
|
522
553
|
result.max_idle_run_frames = _dist(
|
|
523
554
|
np.array([float(ts.max_idle_run_frames) for ts in valid], dtype=np.float64)
|
|
524
555
|
)
|