Metadata-Version: 2.4
Name: ldp-common-dataset-sdk
Version: 0.1.0
Summary: Standalone Python SDK for uploading common video datasets to LDP.
License-Expression: Apache-2.0
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.31
Requires-Dist: cos-python-sdk-v5>=1.9.30
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"

# LDP Common Dataset SDK

独立、可发布的 Python SDK，用于把符合 LDP 通用视频规范的 LeRobot v3.0 数据集上传到 LDP。

- PyPI 项目名：`ldp-common-dataset-sdk`
- Python import 名：`ldp_common_dataset`
- 不依赖 LDP 仓库内的 `app`、`backend` 或其他目录
- 支持账号登录、多租户账号选择、采集项目/任务查询、数据校验、COS 上传和任务状态等待

## 安装

在本目录开发安装：

```bash
python -m pip install -e /home/ls/workspace/ldp/backend/dataset_sdk
```

构建公开发布包：

```bash
cd /home/ls/workspace/ldp/backend/dataset_sdk
python -m pip install build twine
python -m build
twine check dist/*
```

发布前请按组织流程确认包名、版本、许可证和 PyPI 仓库。

完整发行步骤见 [SDK_RELEASE_GUIDE.md](SDK_RELEASE_GUIDE.md)。

## 数据采集与上传流程

通用数据应按以下归属链路上传：

```text
采集项目 → 采集任务 → 采集员 + 采集设备 → 通用视频数据集
```

1. 采集员账号通过 `/api/auth/login/password` 登录。
2. 查询采集项目和开放的采集任务。
3. 选择一个属于该项目、状态为 `open`、且唯一绑定一个设备的采集任务。
4. SDK 校验本地数据集目录和 `meta/info.json`。
5. 创建带有 `collectionTaskId`、`collectorAccountId`、`deviceId` 的上传任务。
6. SDK 获取临时 STS 凭证，将文件直接上传 COS。
7. 服务端导入、校验、标准化并注册数据集；SDK 轮询到成功或失败。

如果当前租户没有采集项目或指定项目下没有开放的采集任务，SDK 会停止上传，并提示用户先在 LDP 创建对应的采集项目和采集任务。没有归因信息的数据不会进入上传阶段。

通用数据集对象存储上传允许 `admin`、`manager` 和 `collector`。采集员登录后，SDK 默认把登录响应的 `userId` 作为实际采集员 ID，因此同一个登录会话可以完成项目、任务、采集元归因和上传全流程。服务器目录导入涉及服务器文件系统，仍只允许管理员或经理操作。

## 数据集目录规范

首版仅接受 1～10 路 H.264/H.265 MP4：

```text
my_dataset/
├── meta/info.json
└── videos/
    ├── observation.images.camera_01/chunk-000/file-000.mp4
    └── observation.images.camera_02/chunk-000/file-000.mp4
```

关键要求：

- 根目录名只包含字母、数字、`_`、`-`，长度不超过 128。
- `codebase_version` 为 `v3.0`。
- `chunks_size` 为 `1000`。
- `features` 只声明视频。
- camera key 从 `observation.images.camera_01` 连续编号。
- 每个 episode、每路 camera 必须恰好存在一个 MP4。
- 目录不能包含规范之外的额外文件。

## 快速使用

```python
from ldp_common_dataset import CommonDatasetUploader, LdpClient

client = LdpClient.from_env()
session = client.login()
context = client.resolve_collection_context()

result = CommonDatasetUploader(client).upload(
    "/data/my_dataset",
    context=context,
    on_progress=lambda current, total, stage: print(current, total, stage),
)
print(result.task.result_dataset_id)
```

参数会覆盖同名环境变量：

```python
client = LdpClient.from_env(
    base_url="https://ldp.example.com",
    phone="13800000000",
    password="password",
    collection_project_id="12",
    collection_task_id="34",
    collector_account_id="56",
    device_id="78",
)
```

完整代码见 [examples/upload_dataset.py](examples/upload_dataset.py)，样例目录说明见 [examples/README.md](examples/README.md)，分步说明见 [usage/project_task_upload.md](usage/project_task_upload.md)。

## 环境变量

| 环境变量 | 说明 | 默认值 |
|---|---|---|
| `LDP_BASE_URL` | LDP 平台地址 | `https://ldp.lingrobotics.com/` |
| `LDP_PHONE` | 登录手机号 | 无 |
| `LDP_PASSWORD` | 登录密码 | 无 |
| `LDP_ACCESS_TOKEN` | 已有 token；当前上传流程仍建议调用 `login()`取得用户信息 | 无 |
| `LDP_MEMBERSHIP_ID` | 同手机号多租户时选择的 membership ID | 无 |
| `LDP_CUSTOMER_ID` | 同手机号多租户时按租户选择 | 无 |
| `LDP_COLLECTION_PROJECT_ID` | 采集项目 ID | 无 |
| `LDP_COLLECTION_TASK_ID` | 采集任务 ID | 无 |
| `LDP_COLLECTOR_ACCOUNT_ID` | 实际采集员账号 ID | 登录用户 ID |
| `LDP_DEVICE_ID` | 采集设备数据库 ID | 任务唯一设备 |
| `LDP_ROBOT_TYPE` | 数据集 robot type | `Other` |
| `LDP_DATASET_DESCRIPTION` | 上传说明 | 空 |
| `LDP_HTTP_TIMEOUT` | HTTP 超时秒数 | `120` |
| `LDP_UPLOAD_WORKERS` | 并发上传文件数 | `4` |
| `LDP_POLL_INTERVAL` | 任务轮询间隔秒数 | `2.5` |
| `LDP_POLL_TIMEOUT` | 等待服务端完成的超时秒数 | `3600` |
| `LDP_VERIFY_TLS` | 是否校验 HTTPS 证书 | `1` |

不要把密码或 access token 写入代码、README 或提交到 Git。

## 测试

```bash
cd /home/ls/workspace/ldp/backend/dataset_sdk
python -m pip install -e ".[dev]"
python -m pytest -q
```

测试覆盖：

- 配置参数、环境变量、默认平台域名和 TLS 开关。
- 登录、多租户 membership 选择和异常响应。
- 采集项目、开放任务、采集员和设备归因。
- 项目/任务缺失时阻止上传并给出创建提示。
- LeRobot v3.0 元数据、camera 连续编号、episode/chunk 文件映射和空文件检查。
- STS/COS 参数映射、并发上传、进度上报、完成清单、轮询成功、失败和超时。
- 本地模拟 LDP HTTP 服务的采集员登录到数据集注册端到端流程。
