Skip to content

Repository files navigation

LeRobot Curation Tools

Local fullstack tool for curating LeRobot datasets. Play synchronized camera streams in the browser, assign grades/tags, and edit task instructions — all persisted directly to the dataset's parquet files.

Architecture

┌─────────────────────┐ ┌──────────────┐ ┌─────────────────┐
│ React SPA │────>│ FastAPI │────>│ Local Dataset │
│ Native video player │ │ :8000 │ │ parquet + video │
│ :5173 │ └──────────────┘ └─────────────────┘
└─────────────────────┘
ComponentTechPort
BackendFastAPI + PyArrow8000
FrontendReact + TypeScript + Vite5173
VisualizationBrowser-native synchronized video playbackFrontend

Prerequisites

  • Python 3.12+
  • Node.js 18+
  • uv (recommended) or pip
  • ffmpeg — for serving episode-bounded video clips in the native curation viewer
  • hf-mount — for mounting HF datasets
  • nfs-common (sudo apt install nfs-common -y)

Setup

# Clone with submodule
git clone --recurse-submodules https://github.com/weedmo/robodata.git
cd robodata
# If already cloned without submodules
git submodule update --init --recursive
# The converter flow depends on the bundled rosbag2lerobot-svt submodule# Python environment
uv venv .venv
source .venv/bin/activate
uv pip install -e .# Frontend dependenciescd frontend && npm install &&cd ..

Usage

Quick Start

./start.sh

This starts PostgreSQL in Docker plus the backend and frontend development servers. Open http://localhost:5173 in your browser.

Manual Start

# Terminal 1: Backendsource .venv/bin/activate
uvicorn backend.main:app --host 0.0.0.0 --port 8000 --reload
# Terminal 2: Frontendcd frontend && npm run dev

Production-style Docker Run

docker compose -f docker/compose.yml up --build -d

Open http://localhost:18080.

Notes:

  • nginx serves the frontend bundle and proxies /api/* to the FastAPI app.
  • app runs FastAPI only; it is not exposed directly on the host.
  • The converter and curation-worker containers stay up 24/7. Job lifecycle is decoupled from container lifecycle — see "Operating the converter / curation-worker" below.
  • If 18080 is already in use, run with CURATION_UI_PORT=28080 docker compose -f docker/compose.yml up --build -d.

Operating the converter / curation-worker

컨테이너는 compose 기동 시 1회 up되고 이후 24/7 상주합니다. 작업 라이프사이클은 컨테이너 라이프사이클과 분리됩니다.

  • 변환 시작: UI의 "Convert" 버튼 또는 curl -X POST /api/jobs -H 'Content-Type: application/json' -d '{"type":"convert","payload":{"cell":"<cell_path>"}}'
  • 작업 취소: UI의 "현재 작업 취소" 버튼 또는 curl -X POST /api/jobs/<id>/cancel
  • 워커 일시정지/재개: UI의 Pause/Resume pill 또는 curl -X PATCH /api/workers/converter -H 'Content-Type: application/json' -d '{"desired_state":"paused"}'
  • 코드 배포로 컨테이너 재기동이 필요할 때: docker compose -f docker/compose.yml restart converter (운영자 전용. 일상 흐름에서는 사용하지 않음.)

CURATION_CONVERTER_CONTROL_MODE env 와 convert_runtime.json/convert_stop.flag/ convert_requests.json/convert_events.jsonl 시그널 파일들은 더 이상 사용되지 않습니다. 잔존 파일이 있으면 삭제해도 안전합니다 (NAS 의 lerobot/ 루트).

Workflow

  1. Load Dataset — Enter the local path to a LeRobot v3.0 dataset and click "Load"
  2. Browse Episodes — The episode list appears in the left sidebar with grade badges
  3. Visualize — Click an episode to play its synchronized camera streams in the native viewer (center panel)
  4. Grade — Select a grade (A/B/C/D/F) from the dropdown in the right panel
  5. Tag — Add tags to categorize episodes (e.g., "good_grasp", "collision", "slow")
  6. Edit Task — Modify the task instruction text if needed
  7. Save — Click "Save" to persist changes to the parquet files

All changes are written directly to the dataset's parquet files and survive application restarts.

Dataset Format

This tool works with LeRobot v3.0 datasets:

dataset/
├── meta/
│ ├── info.json # Dataset metadata (fps, features, robot_type)
│ ├── tasks.parquet # Task descriptions (task_index, task)
│ └── episodes/
│ └── chunk-000/
│ └── file-000.parquet # Episode metadata (+ grade, tags after curation)
├── data/
│ └── chunk-000/
│ └── file-000.parquet # Observation/action data
└── videos/
└── observation.images.*/
└── chunk-000/
└── file-000.mp4 # Camera recordings

What Gets Modified

FileChangesHow
meta/episodes/chunk-*/file-*.parquetgrade and tags columns addedNew columns appended, original data untouched
meta/tasks.parquettask column updatedExisting row modified in-place

Original observation/action data in data/ and videos/ is never modified.

API Reference

MethodEndpointDescription
POST/api/datasets/loadLoad dataset from local path
GET/api/datasets/infoGet current dataset metadata
GET/api/episodesList all episodes with grade/tags
GET/api/episodes/{index}Get single episode
PATCH/api/episodes/{index}Update grade and/or tags
GET/api/tasksList all tasks
PATCH/api/tasks/{index}Update task instruction
GET/api/healthHealth check
POST/api/jobsEnqueue a job (type: convert/split/merge/delete/...)
GET/api/jobsList jobs (filter by type/status/dataset_id/since)
GET/api/jobs/{id}Fetch one job (status, payload, progress, result, error)
POST/api/jobs/{id}/cancelCooperative cancel of a queued/running job
GET/api/workersList workers (control + heartbeat join)
GET/api/workers/{id}Fetch one worker
PATCH/api/workers/{id}Change desired_state (running/paused/draining/stopped)

Configuration

Environment variables (prefix CURATION_):

VariableDefaultDescription
CURATION_FASTAPI_PORT8000Backend API port

Development

에이전트와 사람이 GitHub Issue/Project/PR로 작업을 조율하는 방법은 에이전트 GitHub 운영 규칙을 참고하세요.

# Run backend with auto-reloadsource .venv/bin/activate
uvicorn backend.main:app --reload
# Run frontend with HMRcd frontend && npm run dev
# Build frontend for productioncd frontend && npm run build

HuggingFace Dataset Mounting

Auto-mount all HuggingFace repos (models, datasets, spaces) from the Phy-lab organization to the local filesystem.

Mount Location

/tmp/hf-mounts/Phy-lab/
├── model/<model-name>/
├── dataset/<dataset-name>/
└── space/<space-name>/

Manual Run

sudo python3 scripts/hf_auto_mount.py
# For private repos
sudo HF_TOKEN=<token> python3 scripts/hf_auto_mount.py

Already-mounted repos are automatically skipped.

Auto-Mount on Boot (systemd)

sudo cp scripts/hf-auto-mount.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now hf-auto-mount.service

Mount Management

CommandDescription
hf-mount statusCheck current mount status
sudo hf-mount stop <mount-path>Unmount a specific repo
sudo systemctl restart hf-auto-mountRestart service (remount all)

Notes

  • CPU idle at 0%, active only on file access
  • ~20MB memory per mounted repo
  • Auto-remounts on reboot when systemd service is enabled
  • Run the script again to pick up newly added repos

Technical Notes

  • Data integrity: All parquet writes are atomic (temp file + rename). Per-file asyncio locks prevent concurrent write corruption.
  • Episode lookup: O(1) via episode-to-file index built from meta/episodes/ metadata on dataset load.
  • Video playback: FastAPI serves the dataset MP4 files while the React player synchronizes native browser video elements.

License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages