Python SDK
Official Python SDK for the Aholo Open API.
- Requirements: Python ≥ 3.9
- PyPI: manycore-aholo-sdk-*
- GitHub: manycoretech/aholo-spatial-sdk
Installation
Install only the packages you need:
pip install manycore-aholo-sdk-asset # file upload
pip install manycore-aholo-sdk-world # world recon & generation (v1.3.0+ supports insv)
pip install manycore-aholo-sdk-lux3d # Lux3D 3D generation
Authentication
Recommended: set the environment variable; the SDK reads AHOLO_API_KEY automatically:
export AHOLO_API_KEY=your_api_key_here
Or pass the key explicitly:
from manycore.aholo_sdk_world import create_world_client
from manycore.aholo_sdk_core import AholoClientConfig
world = create_world_client(AholoClientConfig(api_key='your_api_key_here', region='com'))
Never hardcode API keys in source code, packages, or public repositories.
Region
| Value | Description | API endpoint |
|---|---|---|
cn | China | https://api.aholo3d.cn |
com | Global | https://api.aholo3d.com |
Asset upload
from manycore.aholo_sdk_asset import create_asset_client
asset = create_asset_client(region='com')
Upload a file
result = asset.upload_file('video.mp4')
print(result.url) # public URL
Upload bytes
with open('image.jpg', 'rb') as f:
data = f.read()
result = asset.upload_bytes(data, filename='image.jpg')
Progress callback
def on_progress(uploaded: int, total: int) -> None:
pct = round(uploaded / total * 100)
print(f'\rUpload progress: {pct}%', end='', flush=True)
result = asset.upload_file('video.mp4', on_progress=on_progress)
UploadResult fields
| Field | Type | Description |
|---|---|---|
url | str | Public file URL |
md5 | str | File MD5 |
upload_key | str | None | OUS upload key |
obs_task_id | str | None | OUS task ID |
World
from manycore.aholo_sdk_world import create_world_client
world = create_world_client(region='com')
Reconstruction type supports image, video, and insv (manycore-aholo-sdk-world v1.3.0+). Generation resources accept image only (at most one).
3DGS reconstruction (video / images)
op = world.reconstructions.create(
name='Living room',
resources=[{'url': 'https://cdn.example.com/room.mp4', 'type': 'video'}],
task_quality='normal', # 'low' | 'normal' | 'high'
scene='model', # 'model' | 'space'
use_mask=False, # optional: segment uploaded resources when True
)
detail = world.wait_for(op['worldId'])
print(detail.get('assets', {}).get('splats', {}).get('urls', {}).get('plyPath'))
Image reconstruction requires ≥ 20 image resources (type image; extensions .jpg/.jpeg/.png/.webp). Use type=video for .mp4/.mov; Insta360 panoramic video uses type=insv (.insv). URL extension must match type.
Insta360 example:
op = world.reconstructions.create(
name='Panoramic living room',
resources=[{'url': 'https://cdn.example.com/room.insv', 'type': 'insv'}],
task_quality='high',
scene='space',
)
3DGS generation (from prompt)
Generation resources accept images only (type image, at most one) — not video / insv.
op = world.generations.create(
name='Forest cabin',
prompt='A modern cabin in the forest',
# resources=[{'url': 'https://cdn.example.com/ref.jpg', 'type': 'image'}], # optional, at most one
)
detail = world.wait_for(op['worldId'])
Get world detail
detail = world.retrieve(world_id)
print(detail.get('status'))
Task status & polling
| Phase | Status | Description |
|---|---|---|
| In progress | PENDING | Queued |
| In progress | PREPROCESSING | Preprocessing |
| In progress | RUNNING | Running |
| Success | SUCCEEDED | Done |
| Failed | FAILED | Failed |
| Failed | CANCELED | Canceled |
| Failed | TIMEOUT | Timed out |
| Failed | REJECTED | Rejected |
world.wait_for(world_id) returns details on SUCCEEDED; failure terminal states raise PollingFailedError.
WorldDetail fields
| Field | Type | Description |
|---|---|---|
worldId | str | World ID |
status | str | Task status |
assets.splats.urls.plyPath | str | None | PLY download URL |
assets.splats.urls.spzPath | str | None | SPZ download URL |
assets.splats.urls.lodMetaPath | str | None | LOD metadata URL |
assets.imagery.panoUrl | str | None | AI-generated panorama URL |
assets.semanticsMetadata.upAxis | str | None | World up axis (Y / Z) |
Lux3D
The following APIs require manycore-aholo-sdk-lux3d 1.7.0 or later.
from manycore.aholo_sdk_lux3d import create_lux3d_client
lux3d = create_lux3d_client(region='com')
Multimodal to image
Provide at least one of img or prompt.
task_id = lux3d.multimodal_to_image.create(
prompt='A wooden chair product photo, white background',
img='https://example.com/object.jpg',
)
result = lux3d.tasks.wait_for(task_id)
task_id = lux3d.multimodal_to_image.create_from_file(
'./object.jpg',
prompt='A wooden chair product photo, white background',
)
Image to four views
Provide at least one of img or prompt. Prompt-only and image+prompt are both valid.
task_id = lux3d.image_to_four_view.create(
img='https://example.com/object.jpg',
prompt='Product four-view, white background',
)
result = lux3d.tasks.wait_for(task_id)
Image to 3D
task_id = lux3d.img_to_3d.create(
img='https://example.com/object.jpg',
version='G1', # required: G1 or G1-Turbo
face_count=200_000,
output_format=['zip', 'glb', 'ply'],
ai_predict_size=True,
)
# From local file
task_id = lux3d.img_to_3d.create_from_file('./object.jpg', version='G1-Turbo')
result = lux3d.tasks.wait_for(task_id)
print(result['outputs'][0]['content']) # default zip download URL
Text to 3D
task_id = lux3d.text_to_3d.create(
prompt='A wooden chair with carved legs',
version='G1',
style='photorealistic', # see styles below
)
result = lux3d.tasks.wait_for(task_id)
Text-to-3D styles:
photorealistic (default) | cartoon | anime | hand_painted | cyberpunk | fantasy | glass
Multi-format export
task_id = lux3d.multi_format_export.create(
model_url='https://example.com/model.glb',
output_format=['usdz', 'obj_zip', 'stl'], # required for GLB input; also supports fbx_zip, 3mf
)
result = lux3d.tasks.wait_for(task_id)
List task history
page = lux3d.tasks.list(
page=1,
page_size=20,
status=3, # optional filter: 0 init, 1 running, 3 success, 4 failed; results may still include 6 canceled
# start_time / end_time: optional Unix timestamps in milliseconds
)
for task in page['items']:
print(task['taskId'], task['status'])
Material transfer
task_id = lux3d.material_transfer.create(
img='https://example.com/material.jpg',
mesh_url='https://example.com/model.glb',
version='v3.0-standard',
ai_predict_size=True,
)
result = lux3d.tasks.wait_for(task_id)
Generation parameters
versionis required for image/text generation:G1orG1-Turbo.face_countranges from 10,000 to 300,000 and defaults to 200,000; it does not affect PLY.output_formatsupportszip/glb/ply;ai_predict_sizedefaults toTrue.- For G1-Turbo ZIP/GLB output,
enable_pbrcontrols materials. Image generation requires exactly one ofimg/imgs.
Lux3dTaskResult fields
| Field | Type | Description |
|---|---|---|
taskId | int | Task ID |
status | int | 0 init; 1 running; 3 success; 4 failed; 6 canceled |
outputs | list | Output files (outputs[n]['content'] is download URL, valid ~2 hours after success) |
lux3d.tasks.wait_for(task_id) returns when status == 3; raises PollingFailedError on status == 4 or 6. Poll every 10–15 seconds.
Error handling
from manycore.aholo_sdk_core import (
AuthenticationError,
RateLimitError,
BusinessError,
PollingTimeoutError,
PollingFailedError,
)
try:
detail = world.wait_for(world_id)
except AuthenticationError:
print('Invalid or missing API Key')
except RateLimitError:
print('Rate limit exceeded')
except BusinessError as e:
print('Business error:', e.code, e)
except PollingTimeoutError:
print('Polling timed out')
except PollingFailedError as e:
print('Task failed:', e)
| Exception | Description |
|---|---|
AuthenticationError | Invalid or missing API Key |
RateLimitError | Rate limit exceeded |
BusinessError | API business error (includes code) |
PollingTimeoutError | Polling timed out |
PollingFailedError | Task failed |
More examples
See GitHub examples:
| File | Description |
|---|---|
upload_file.py | Upload a local file and print URL |
world_reconstruct.py | Upload video / Insta360 .insv → 3DGS reconstruction → poll to completion |
lux3d_img_to_3d.py | Local image → Lux3D image-to-3D → poll to completion |
lux3d_multi_format_export.py | GLB → Lux3D multi-format export → poll to completion |
After cloning the repo:
export AHOLO_API_KEY=your_api_key_here
# optional: export AHOLO_REGION=com # default cn
pip install -e packages/aholo-sdk-core -e packages/aholo-sdk-asset \
-e packages/aholo-sdk-world -e packages/aholo-sdk-lux3d
python examples/upload_file.py ./photo.jpg
python examples/world_reconstruct.py ./room.mp4 # also .mov, .insv
python examples/lux3d_img_to_3d.py ./chair.png
GitHub README is for installation only. If it conflicts with this page, this page wins. Source and runnable examples: GitHub.