qualia-sdk 0.1.0__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.
- qualia_sdk-0.1.0/.gitignore +38 -0
- qualia_sdk-0.1.0/PKG-INFO +230 -0
- qualia_sdk-0.1.0/README.md +208 -0
- qualia_sdk-0.1.0/pyproject.toml +102 -0
- qualia_sdk-0.1.0/src/qualia/__init__.py +94 -0
- qualia_sdk-0.1.0/src/qualia/client.py +169 -0
- qualia_sdk-0.1.0/src/qualia/exceptions.py +86 -0
- qualia_sdk-0.1.0/src/qualia/models.py +249 -0
- qualia_sdk-0.1.0/src/qualia/py.typed +0 -0
- qualia_sdk-0.1.0/src/qualia/resources/__init__.py +21 -0
- qualia_sdk-0.1.0/src/qualia/resources/base.py +34 -0
- qualia_sdk-0.1.0/src/qualia/resources/credits.py +32 -0
- qualia_sdk-0.1.0/src/qualia/resources/datasets.py +38 -0
- qualia_sdk-0.1.0/src/qualia/resources/finetune.py +152 -0
- qualia_sdk-0.1.0/src/qualia/resources/instances.py +33 -0
- qualia_sdk-0.1.0/src/qualia/resources/models.py +34 -0
- qualia_sdk-0.1.0/src/qualia/resources/projects.py +87 -0
- qualia_sdk-0.1.0/tests/__init__.py +0 -0
- qualia_sdk-0.1.0/tests/conftest.py +25 -0
- qualia_sdk-0.1.0/tests/integration/__init__.py +0 -0
- qualia_sdk-0.1.0/tests/integration/conftest.py +52 -0
- qualia_sdk-0.1.0/tests/integration/test_api.py +189 -0
- qualia_sdk-0.1.0/tests/integration/test_workflows.py +138 -0
- qualia_sdk-0.1.0/tests/resources/__init__.py +0 -0
- qualia_sdk-0.1.0/tests/resources/test_credits.py +34 -0
- qualia_sdk-0.1.0/tests/resources/test_datasets.py +44 -0
- qualia_sdk-0.1.0/tests/resources/test_finetune.py +184 -0
- qualia_sdk-0.1.0/tests/resources/test_instances.py +79 -0
- qualia_sdk-0.1.0/tests/resources/test_models.py +55 -0
- qualia_sdk-0.1.0/tests/resources/test_projects.py +142 -0
- qualia_sdk-0.1.0/tests/test_client.py +83 -0
- qualia_sdk-0.1.0/tests/test_exceptions.py +126 -0
- qualia_sdk-0.1.0/tests/test_models.py +274 -0
- qualia_sdk-0.1.0/tests/test_workflows.py +357 -0
- qualia_sdk-0.1.0/uv.lock +745 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# qualia
|
|
2
|
+
qcore.config.toml
|
|
3
|
+
.qdev/*
|
|
4
|
+
.env
|
|
5
|
+
|
|
6
|
+
# python-generated
|
|
7
|
+
__pycache__/
|
|
8
|
+
*.py[oc]
|
|
9
|
+
build/
|
|
10
|
+
dist/
|
|
11
|
+
wheels/
|
|
12
|
+
*.egg-info
|
|
13
|
+
.pytest_cache/*
|
|
14
|
+
.coverage
|
|
15
|
+
|
|
16
|
+
# virtual envs
|
|
17
|
+
.venv
|
|
18
|
+
venv/*
|
|
19
|
+
|
|
20
|
+
# ruff stuff:
|
|
21
|
+
.ruff_cache/
|
|
22
|
+
|
|
23
|
+
# mac
|
|
24
|
+
.DS_Store
|
|
25
|
+
|
|
26
|
+
# Jupyter Notebook
|
|
27
|
+
.ipynb_checkpoints
|
|
28
|
+
.ipython
|
|
29
|
+
|
|
30
|
+
# Terraform
|
|
31
|
+
*/*/.terraform/
|
|
32
|
+
*.tfstate
|
|
33
|
+
*.tfstate.backup
|
|
34
|
+
*.tfplan
|
|
35
|
+
|
|
36
|
+
# supabase
|
|
37
|
+
.temp
|
|
38
|
+
reset.sql
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: qualia-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for Qualia Studios VLA fine-tuning platform
|
|
5
|
+
Project-URL: Homepage, https://qualiastudios.dev
|
|
6
|
+
Project-URL: Documentation, https://docs.qualiastudios.dev
|
|
7
|
+
Author: Qualia Studios
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Keywords: fine-tuning,machine-learning,qualia,robotics,vla
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: httpx>=0.25.0
|
|
20
|
+
Requires-Dist: pydantic>=2.0.0
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# Qualia Python SDK
|
|
24
|
+
|
|
25
|
+
The official Python SDK for the [Qualia](https://app.qualiastudios.dev) VLA fine-tuning platform.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install qualia-sdk
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from qualia import Qualia
|
|
37
|
+
|
|
38
|
+
# Initialize the client
|
|
39
|
+
client = Qualia(api_key="your-api-key")
|
|
40
|
+
|
|
41
|
+
# Or use the QUALIA_API_KEY environment variable
|
|
42
|
+
client = Qualia()
|
|
43
|
+
|
|
44
|
+
# List available VLA models
|
|
45
|
+
models = client.models.list()
|
|
46
|
+
for model in models:
|
|
47
|
+
print(f"{model.id}: {model.name}")
|
|
48
|
+
print(f" Camera slots: {model.camera_slots}")
|
|
49
|
+
|
|
50
|
+
# Create a project
|
|
51
|
+
project = client.projects.create(name="My Robot Project")
|
|
52
|
+
print(f"Created project: {project.project_id}")
|
|
53
|
+
|
|
54
|
+
# Get dataset image keys for camera mapping
|
|
55
|
+
image_keys = client.datasets.get_image_keys("lerobot/pusht")
|
|
56
|
+
print(f"Available keys: {image_keys.image_keys}")
|
|
57
|
+
|
|
58
|
+
# Start a finetune job
|
|
59
|
+
job = client.finetune.create(
|
|
60
|
+
project_id=project.project_id,
|
|
61
|
+
model_id="lerobot/smolvla_base",
|
|
62
|
+
vla_type="smolvla",
|
|
63
|
+
dataset_id="lerobot/pusht",
|
|
64
|
+
hours=2.0,
|
|
65
|
+
camera_mappings={"cam_1": "observation.images.top"},
|
|
66
|
+
)
|
|
67
|
+
print(f"Started job: {job.job_id}")
|
|
68
|
+
|
|
69
|
+
# Check job status
|
|
70
|
+
status = client.finetune.get(job.job_id)
|
|
71
|
+
print(f"Status: {status.status.status}")
|
|
72
|
+
print(f"Current phase: {status.status.current_phase}")
|
|
73
|
+
|
|
74
|
+
# Cancel a job if needed
|
|
75
|
+
result = client.finetune.cancel(job.job_id)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Resources
|
|
79
|
+
|
|
80
|
+
### Credits
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
# Get your credit balance
|
|
84
|
+
balance = client.credits.get()
|
|
85
|
+
print(f"Available credits: {balance.balance}")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Datasets
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
# Get image keys from a HuggingFace dataset
|
|
92
|
+
image_keys = client.datasets.get_image_keys("lerobot/pusht")
|
|
93
|
+
# Use these keys as values in camera_mappings
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Finetune
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
# Create a finetune job
|
|
100
|
+
job = client.finetune.create(
|
|
101
|
+
project_id="...",
|
|
102
|
+
model_id="lerobot/smolvla_base", # HuggingFace model ID
|
|
103
|
+
vla_type="smolvla", # smolvla, pi0, or pi0.5
|
|
104
|
+
dataset_id="lerobot/pusht", # HuggingFace dataset ID
|
|
105
|
+
hours=2.0, # Training duration (max 168)
|
|
106
|
+
camera_mappings={ # Map model slots to dataset keys
|
|
107
|
+
"cam_1": "observation.images.top",
|
|
108
|
+
},
|
|
109
|
+
# Optional parameters:
|
|
110
|
+
instance_type="gpu_1x_a100", # From client.instances.list()
|
|
111
|
+
region="us-east-1",
|
|
112
|
+
batch_size=32,
|
|
113
|
+
name="My training run",
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Get job status
|
|
117
|
+
status = client.finetune.get(job.job_id)
|
|
118
|
+
|
|
119
|
+
# Cancel a job
|
|
120
|
+
result = client.finetune.cancel(job.job_id)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Instances
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
# List available GPU instances
|
|
127
|
+
instances = client.instances.list()
|
|
128
|
+
for inst in instances:
|
|
129
|
+
print(f"{inst.id}: {inst.gpu_description} - {inst.credits_per_hour} credits/hr")
|
|
130
|
+
print(f" Specs: {inst.specs.gpu_count}x GPU, {inst.specs.memory_gib}GB RAM")
|
|
131
|
+
print(f" Regions: {[r.name for r in inst.regions]}")
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Models
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
# List available VLA model types
|
|
138
|
+
models = client.models.list()
|
|
139
|
+
for model in models:
|
|
140
|
+
print(f"{model.id}: {model.name}")
|
|
141
|
+
print(f" Base model: {model.base_model_id}")
|
|
142
|
+
print(f" Camera slots: {model.camera_slots}")
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Projects
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
# Create a project
|
|
149
|
+
project = client.projects.create(
|
|
150
|
+
name="My Project",
|
|
151
|
+
description="Optional description",
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
# List all projects
|
|
155
|
+
projects = client.projects.list()
|
|
156
|
+
for p in projects:
|
|
157
|
+
print(f"{p.name}: {len(p.jobs)} jobs")
|
|
158
|
+
|
|
159
|
+
# Delete a project (fails if it has active jobs)
|
|
160
|
+
client.projects.delete(project.project_id)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Configuration
|
|
164
|
+
|
|
165
|
+
### Environment Variables
|
|
166
|
+
|
|
167
|
+
- `QUALIA_API_KEY`: Your API key (used if not passed to constructor)
|
|
168
|
+
- `QUALIA_BASE_URL`: Override the API base URL (default: `https://api.qualiastudios.dev`)
|
|
169
|
+
|
|
170
|
+
### Custom HTTP Client
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
import httpx
|
|
174
|
+
|
|
175
|
+
# Use a custom httpx client for advanced configuration
|
|
176
|
+
custom_client = httpx.Client(
|
|
177
|
+
timeout=60.0,
|
|
178
|
+
limits=httpx.Limits(max_connections=10),
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
client = Qualia(api_key="...", httpx_client=custom_client)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Context Manager
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
# Automatically close the client when done
|
|
188
|
+
with Qualia(api_key="...") as client:
|
|
189
|
+
models = client.models.list()
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Error Handling
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
from qualia import (
|
|
196
|
+
Qualia,
|
|
197
|
+
QualiaError,
|
|
198
|
+
QualiaAPIError,
|
|
199
|
+
AuthenticationError,
|
|
200
|
+
NotFoundError,
|
|
201
|
+
ValidationError,
|
|
202
|
+
RateLimitError,
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
try:
|
|
206
|
+
client = Qualia(api_key="invalid-key")
|
|
207
|
+
client.models.list()
|
|
208
|
+
except AuthenticationError as e:
|
|
209
|
+
print(f"Auth failed: {e}")
|
|
210
|
+
except NotFoundError as e:
|
|
211
|
+
print(f"Not found: {e}")
|
|
212
|
+
except ValidationError as e:
|
|
213
|
+
print(f"Validation error: {e}")
|
|
214
|
+
except RateLimitError as e:
|
|
215
|
+
print(f"Rate limited. Retry after: {e.retry_after}s")
|
|
216
|
+
except QualiaAPIError as e:
|
|
217
|
+
print(f"API error [{e.status_code}]: {e.message}")
|
|
218
|
+
except QualiaError as e:
|
|
219
|
+
print(f"SDK error: {e}")
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Requirements
|
|
223
|
+
|
|
224
|
+
- Python 3.10+
|
|
225
|
+
- httpx
|
|
226
|
+
- pydantic
|
|
227
|
+
|
|
228
|
+
## License
|
|
229
|
+
|
|
230
|
+
MIT
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Qualia Python SDK
|
|
2
|
+
|
|
3
|
+
The official Python SDK for the [Qualia](https://app.qualiastudios.dev) VLA fine-tuning platform.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install qualia-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from qualia import Qualia
|
|
15
|
+
|
|
16
|
+
# Initialize the client
|
|
17
|
+
client = Qualia(api_key="your-api-key")
|
|
18
|
+
|
|
19
|
+
# Or use the QUALIA_API_KEY environment variable
|
|
20
|
+
client = Qualia()
|
|
21
|
+
|
|
22
|
+
# List available VLA models
|
|
23
|
+
models = client.models.list()
|
|
24
|
+
for model in models:
|
|
25
|
+
print(f"{model.id}: {model.name}")
|
|
26
|
+
print(f" Camera slots: {model.camera_slots}")
|
|
27
|
+
|
|
28
|
+
# Create a project
|
|
29
|
+
project = client.projects.create(name="My Robot Project")
|
|
30
|
+
print(f"Created project: {project.project_id}")
|
|
31
|
+
|
|
32
|
+
# Get dataset image keys for camera mapping
|
|
33
|
+
image_keys = client.datasets.get_image_keys("lerobot/pusht")
|
|
34
|
+
print(f"Available keys: {image_keys.image_keys}")
|
|
35
|
+
|
|
36
|
+
# Start a finetune job
|
|
37
|
+
job = client.finetune.create(
|
|
38
|
+
project_id=project.project_id,
|
|
39
|
+
model_id="lerobot/smolvla_base",
|
|
40
|
+
vla_type="smolvla",
|
|
41
|
+
dataset_id="lerobot/pusht",
|
|
42
|
+
hours=2.0,
|
|
43
|
+
camera_mappings={"cam_1": "observation.images.top"},
|
|
44
|
+
)
|
|
45
|
+
print(f"Started job: {job.job_id}")
|
|
46
|
+
|
|
47
|
+
# Check job status
|
|
48
|
+
status = client.finetune.get(job.job_id)
|
|
49
|
+
print(f"Status: {status.status.status}")
|
|
50
|
+
print(f"Current phase: {status.status.current_phase}")
|
|
51
|
+
|
|
52
|
+
# Cancel a job if needed
|
|
53
|
+
result = client.finetune.cancel(job.job_id)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Resources
|
|
57
|
+
|
|
58
|
+
### Credits
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
# Get your credit balance
|
|
62
|
+
balance = client.credits.get()
|
|
63
|
+
print(f"Available credits: {balance.balance}")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Datasets
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
# Get image keys from a HuggingFace dataset
|
|
70
|
+
image_keys = client.datasets.get_image_keys("lerobot/pusht")
|
|
71
|
+
# Use these keys as values in camera_mappings
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Finetune
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
# Create a finetune job
|
|
78
|
+
job = client.finetune.create(
|
|
79
|
+
project_id="...",
|
|
80
|
+
model_id="lerobot/smolvla_base", # HuggingFace model ID
|
|
81
|
+
vla_type="smolvla", # smolvla, pi0, or pi0.5
|
|
82
|
+
dataset_id="lerobot/pusht", # HuggingFace dataset ID
|
|
83
|
+
hours=2.0, # Training duration (max 168)
|
|
84
|
+
camera_mappings={ # Map model slots to dataset keys
|
|
85
|
+
"cam_1": "observation.images.top",
|
|
86
|
+
},
|
|
87
|
+
# Optional parameters:
|
|
88
|
+
instance_type="gpu_1x_a100", # From client.instances.list()
|
|
89
|
+
region="us-east-1",
|
|
90
|
+
batch_size=32,
|
|
91
|
+
name="My training run",
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# Get job status
|
|
95
|
+
status = client.finetune.get(job.job_id)
|
|
96
|
+
|
|
97
|
+
# Cancel a job
|
|
98
|
+
result = client.finetune.cancel(job.job_id)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Instances
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
# List available GPU instances
|
|
105
|
+
instances = client.instances.list()
|
|
106
|
+
for inst in instances:
|
|
107
|
+
print(f"{inst.id}: {inst.gpu_description} - {inst.credits_per_hour} credits/hr")
|
|
108
|
+
print(f" Specs: {inst.specs.gpu_count}x GPU, {inst.specs.memory_gib}GB RAM")
|
|
109
|
+
print(f" Regions: {[r.name for r in inst.regions]}")
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Models
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
# List available VLA model types
|
|
116
|
+
models = client.models.list()
|
|
117
|
+
for model in models:
|
|
118
|
+
print(f"{model.id}: {model.name}")
|
|
119
|
+
print(f" Base model: {model.base_model_id}")
|
|
120
|
+
print(f" Camera slots: {model.camera_slots}")
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Projects
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
# Create a project
|
|
127
|
+
project = client.projects.create(
|
|
128
|
+
name="My Project",
|
|
129
|
+
description="Optional description",
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# List all projects
|
|
133
|
+
projects = client.projects.list()
|
|
134
|
+
for p in projects:
|
|
135
|
+
print(f"{p.name}: {len(p.jobs)} jobs")
|
|
136
|
+
|
|
137
|
+
# Delete a project (fails if it has active jobs)
|
|
138
|
+
client.projects.delete(project.project_id)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Configuration
|
|
142
|
+
|
|
143
|
+
### Environment Variables
|
|
144
|
+
|
|
145
|
+
- `QUALIA_API_KEY`: Your API key (used if not passed to constructor)
|
|
146
|
+
- `QUALIA_BASE_URL`: Override the API base URL (default: `https://api.qualiastudios.dev`)
|
|
147
|
+
|
|
148
|
+
### Custom HTTP Client
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
import httpx
|
|
152
|
+
|
|
153
|
+
# Use a custom httpx client for advanced configuration
|
|
154
|
+
custom_client = httpx.Client(
|
|
155
|
+
timeout=60.0,
|
|
156
|
+
limits=httpx.Limits(max_connections=10),
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
client = Qualia(api_key="...", httpx_client=custom_client)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Context Manager
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
# Automatically close the client when done
|
|
166
|
+
with Qualia(api_key="...") as client:
|
|
167
|
+
models = client.models.list()
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Error Handling
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
from qualia import (
|
|
174
|
+
Qualia,
|
|
175
|
+
QualiaError,
|
|
176
|
+
QualiaAPIError,
|
|
177
|
+
AuthenticationError,
|
|
178
|
+
NotFoundError,
|
|
179
|
+
ValidationError,
|
|
180
|
+
RateLimitError,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
try:
|
|
184
|
+
client = Qualia(api_key="invalid-key")
|
|
185
|
+
client.models.list()
|
|
186
|
+
except AuthenticationError as e:
|
|
187
|
+
print(f"Auth failed: {e}")
|
|
188
|
+
except NotFoundError as e:
|
|
189
|
+
print(f"Not found: {e}")
|
|
190
|
+
except ValidationError as e:
|
|
191
|
+
print(f"Validation error: {e}")
|
|
192
|
+
except RateLimitError as e:
|
|
193
|
+
print(f"Rate limited. Retry after: {e.retry_after}s")
|
|
194
|
+
except QualiaAPIError as e:
|
|
195
|
+
print(f"API error [{e.status_code}]: {e.message}")
|
|
196
|
+
except QualiaError as e:
|
|
197
|
+
print(f"SDK error: {e}")
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Requirements
|
|
201
|
+
|
|
202
|
+
- Python 3.10+
|
|
203
|
+
- httpx
|
|
204
|
+
- pydantic
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
MIT
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "qualia-sdk"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Python SDK for Qualia Studios VLA fine-tuning platform"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
requires-python = ">=3.10"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "Qualia Studios" },
|
|
10
|
+
]
|
|
11
|
+
keywords = ["qualia", "vla", "robotics", "fine-tuning", "machine-learning"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 4 - Beta",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.10",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Typing :: Typed",
|
|
21
|
+
]
|
|
22
|
+
dependencies = [
|
|
23
|
+
"httpx>=0.25.0",
|
|
24
|
+
"pydantic>=2.0.0",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
Homepage = "https://qualiastudios.dev"
|
|
29
|
+
Documentation = "https://docs.qualiastudios.dev"
|
|
30
|
+
|
|
31
|
+
[dependency-groups]
|
|
32
|
+
test = [
|
|
33
|
+
"pytest>=8.0.0",
|
|
34
|
+
"pytest-asyncio>=0.23.0",
|
|
35
|
+
"pytest-cov>=4.0.0",
|
|
36
|
+
"pytest-httpx>=0.30.0",
|
|
37
|
+
"pytest-timeout>=2.0.0",
|
|
38
|
+
"python-dotenv>=1.0.0",
|
|
39
|
+
]
|
|
40
|
+
dev = [
|
|
41
|
+
"ruff>=0.4.0",
|
|
42
|
+
"mypy>=1.10.0",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[tool.uv]
|
|
46
|
+
default-groups = [
|
|
47
|
+
"test",
|
|
48
|
+
"dev",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[build-system]
|
|
52
|
+
requires = ["hatchling"]
|
|
53
|
+
build-backend = "hatchling.build"
|
|
54
|
+
|
|
55
|
+
[tool.hatch.build.targets.wheel]
|
|
56
|
+
packages = ["src/qualia"]
|
|
57
|
+
|
|
58
|
+
[tool.ruff]
|
|
59
|
+
line-length = 89
|
|
60
|
+
target-version = "py310"
|
|
61
|
+
|
|
62
|
+
[tool.ruff.lint]
|
|
63
|
+
select = [
|
|
64
|
+
"I", # isort
|
|
65
|
+
"F", # pyflakes
|
|
66
|
+
"E", # pycodestyle errors
|
|
67
|
+
"W", # pycodestyle warnings
|
|
68
|
+
"B", # flake8-bugbear
|
|
69
|
+
"UP", # pyupgrade
|
|
70
|
+
"SIM", # flake8-simplify
|
|
71
|
+
]
|
|
72
|
+
ignore = [
|
|
73
|
+
"E501", # line too long
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
[tool.mypy]
|
|
77
|
+
python_version = "3.10"
|
|
78
|
+
strict = true
|
|
79
|
+
warn_return_any = true
|
|
80
|
+
warn_unused_ignores = true
|
|
81
|
+
|
|
82
|
+
[tool.pytest.ini_options]
|
|
83
|
+
asyncio_mode = "auto"
|
|
84
|
+
testpaths = ["tests"]
|
|
85
|
+
python_files = ["test_*.py", "*_test.py"]
|
|
86
|
+
addopts = "-v --tb=short"
|
|
87
|
+
markers = [
|
|
88
|
+
"integration: marks tests as integration tests (require API key, hit real dev API)",
|
|
89
|
+
"integration_workflow: marks tests as workflow integration tests (run on merge to master, hit real dev API with real training jobs)",
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
[tool.coverage.run]
|
|
93
|
+
source = ["src/qualia"]
|
|
94
|
+
branch = true
|
|
95
|
+
|
|
96
|
+
[tool.coverage.report]
|
|
97
|
+
show_missing = true
|
|
98
|
+
exclude_lines = [
|
|
99
|
+
"pragma: no cover",
|
|
100
|
+
"if TYPE_CHECKING:",
|
|
101
|
+
"raise NotImplementedError",
|
|
102
|
+
]
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Qualia SDK
|
|
3
|
+
|
|
4
|
+
Python SDK for the Qualia Studios VLA fine-tuning platform.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
```python
|
|
8
|
+
from qualia import Qualia
|
|
9
|
+
|
|
10
|
+
client = Qualia(api_key="your-api-key")
|
|
11
|
+
|
|
12
|
+
# List available models
|
|
13
|
+
models = client.models.list()
|
|
14
|
+
|
|
15
|
+
# Create a project
|
|
16
|
+
project = client.projects.create(name="My Robot Project")
|
|
17
|
+
|
|
18
|
+
# Get dataset image keys for camera mapping
|
|
19
|
+
image_keys = client.datasets.get_image_keys("lerobot/pusht")
|
|
20
|
+
|
|
21
|
+
# Start a finetune job
|
|
22
|
+
job = client.finetune.create(
|
|
23
|
+
project_id=project.project_id,
|
|
24
|
+
model_id="lerobot/smolvla_base",
|
|
25
|
+
vla_type="smolvla",
|
|
26
|
+
dataset_id="lerobot/pusht",
|
|
27
|
+
hours=2.0,
|
|
28
|
+
camera_mappings={"cam_1": "observation.images.top"},
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Check status
|
|
32
|
+
status = client.finetune.get(job.job_id)
|
|
33
|
+
print(f"Status: {status.status}")
|
|
34
|
+
```
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
from .client import Qualia
|
|
38
|
+
from .exceptions import (
|
|
39
|
+
AuthenticationError,
|
|
40
|
+
NotFoundError,
|
|
41
|
+
QualiaAPIError,
|
|
42
|
+
QualiaError,
|
|
43
|
+
RateLimitError,
|
|
44
|
+
ValidationError,
|
|
45
|
+
)
|
|
46
|
+
from .models import (
|
|
47
|
+
CreditBalance,
|
|
48
|
+
DatasetImageKeys,
|
|
49
|
+
FinetuneCancelResult,
|
|
50
|
+
FinetuneJob,
|
|
51
|
+
FinetuneStatus,
|
|
52
|
+
Instance,
|
|
53
|
+
InstanceRegion,
|
|
54
|
+
InstanceSpecs,
|
|
55
|
+
Phase,
|
|
56
|
+
PhaseEvent,
|
|
57
|
+
Project,
|
|
58
|
+
ProjectCreateResult,
|
|
59
|
+
ProjectDeleteResult,
|
|
60
|
+
ProjectJob,
|
|
61
|
+
VLAModel,
|
|
62
|
+
VLAType,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
__version__ = "0.1.0"
|
|
66
|
+
|
|
67
|
+
__all__ = [
|
|
68
|
+
# Client
|
|
69
|
+
"Qualia",
|
|
70
|
+
# Exceptions
|
|
71
|
+
"QualiaError",
|
|
72
|
+
"QualiaAPIError",
|
|
73
|
+
"AuthenticationError",
|
|
74
|
+
"NotFoundError",
|
|
75
|
+
"ValidationError",
|
|
76
|
+
"RateLimitError",
|
|
77
|
+
# Models
|
|
78
|
+
"VLAType",
|
|
79
|
+
"CreditBalance",
|
|
80
|
+
"DatasetImageKeys",
|
|
81
|
+
"FinetuneJob",
|
|
82
|
+
"FinetuneStatus",
|
|
83
|
+
"Phase",
|
|
84
|
+
"PhaseEvent",
|
|
85
|
+
"FinetuneCancelResult",
|
|
86
|
+
"Instance",
|
|
87
|
+
"InstanceRegion",
|
|
88
|
+
"InstanceSpecs",
|
|
89
|
+
"VLAModel",
|
|
90
|
+
"Project",
|
|
91
|
+
"ProjectJob",
|
|
92
|
+
"ProjectCreateResult",
|
|
93
|
+
"ProjectDeleteResult",
|
|
94
|
+
]
|