Quickstart
5 分钟上手 Aholo 3D 生成/重建 API
前置准备
获取 API 访问权限
- 注册酷家乐开放平台账号
- 创建应用获取 appuid
- 了解接口鉴权规则(签名认证)
基本概念
appuid: 第三方用户ID,所有接口必传ousToken: 上传凭证,10分钟有效期projectId: 项目唯一标识taskId: 任务唯一标识
API 基础信息
Base URL: https://openapi.kujiale.com/v2/aholo
认证方式: appuid + 签名(详见官方文档)
响应格式: { "c": "0", "d": {...}, "m": null, "f": "" }
c: 状态码,"0"表示成功d: 返回数据m: 消息(错误时)f: 标志位
完整示例:从图片创建 3D 重建项目
python
import requests
import hashlib
import time
# ========== 配置 ==========
APPUID = "your_appuid" # 替换为你的 appuid
BASE_URL = "https://openapi.kujiale.com/v2/aholo"
# ========== Step 1: 获取上传Token ==========
def get_upload_token():
"""获取上传凭证"""
response = requests.get(
f"{BASE_URL}/upload/token",
params={"appuid": APPUID}
# 注意:实际使用需添加签名认证
)
data = response.json()["d"]
return {
"ousToken": data["ousToken"],
"globalDomain": data["globalDomain"],
"blockSize": data["blockSize"]
}
upload_info = get_upload_token()
print(f"✓ 获得 ousToken: {upload_info['ousToken'][:20]}...")
print(f"✓ 上传域名: {upload_info['globalDomain']}")
# ========== Step 2: 上传图片 ==========
def upload_image(file_path, upload_info):
"""上传单个图片文件"""
# 计算 MD5
with open(file_path, "rb") as f:
file_data = f.read()
md5 = hashlib.md5(file_data).hexdigest()
# 上传
response = requests.post(
f"https://{upload_info['globalDomain']}/ous/api/v2/single/upload",
headers={"ous-token-v2": upload_info["ousToken"]},
files={"file": open(file_path, "rb")},
data={"md5": md5}
)
task_id = response.json()["d"]["taskId"]
# 轮询等待上传完成
while True:
status_response = requests.get(
f"https://{upload_info['globalDomain']}/ous/api/v2/upload/status",
headers={"ous-token-v2": upload_info["ousToken"]}
)
status_data = status_response.json()["d"]
status = status_data["status"]
if status == 5: # 上传成功
return status_data["url"]
elif status in [6, 8]: # 失败
raise Exception(f"上传失败: status={status}")
print(f"上传状态: {status}, 等待中...")
time.sleep(0.5)
image_url = upload_image("/path/to/your/image.jpg", upload_info)
print(f"✓ 图片上传成功: {image_url}")
# ========== Step 3: 创建 3D 重建项目 ==========
def create_3d_recon_project(image_url, project_name):
"""创建3D重建项目"""
payload = {
"projectName": project_name,
"cover": image_url,
"scene": "model", # model=物体, space=室内
"taskQuality": "NORMAL", # LOW/NORMAL/HIGH/ULTRA
"accessLevel": 0, # 0=公开, 1=私有
"resources": [
{
"name": "input.jpg",
"type": 0, # 0=图片
"url": image_url,
"meta": {
"width": 1920,
"height": 1080,
"duration": None
}
}
],
"uploadSog": False,
"panorama": False
}
response = requests.post(
f"{BASE_URL}/project/create-3d-recon",
params={"appuid": APPUID},
json=payload
)
return response.json()["d"] # projectId
project_id = create_3d_recon_project(image_url, "我的3D模型")
print(f"✓ 项目创建成功: {project_id}")
# ========== Step 4: 查询任务状态 ==========
def wait_for_task(project_id, timeout=600):
"""等待任务完成"""
start_time = time.time()
while time.time() - start_time < timeout:
response = requests.post(
f"{BASE_URL}/project/task/list/by-ids",
params={"appuid": APPUID},
json=[project_id]
)
tasks = response.json()["d"]
if tasks:
task = tasks[0]
status = task["status"]
if status == 3: # 成功
return task["result"]
elif status in [4, 5, 6, 7]: # 失败/取消/超时/拒绝
raise Exception(f"任务失败: status={status}")
print(f"任务状态: {status}, 等待中...")
time.sleep(5)
raise Exception("超时")
result = wait_for_task(project_id)
print(f"✓ 任务完成!")
# ========== Step 5: 获取结果 ==========
print("\n📦 3D 资产:")
print(f" PLY: {result['plyPath']}")
print(f" SPZ: {result['spzPath']}")
print(f" SOG: {result['sogPath']}")
# 或获取完整项目信息
project_info = requests.get(
f"{BASE_URL}/project/info",
params={"appuid": APPUID, "projectId": project_id}
).json()["d"]
print(f"\n项目名称: {project_info['name']}")
print(f"项目类型: {project_info['projectType']}") # 0=重建, 1=生成
项目类型说明
| 类型 | 接口 | 说明 |
|---|---|---|
| 3D 重建 | create-3d-recon | 从图片/视频重建真实物体/空间 |
| 3D 生成 | create-3d-gen | AI 生成虚拟空间 |
任务状态枚举
| Status | 含义 | 是否终态 |
|---|---|---|
| 0 | 排队中 | 否 |
| 1 | 等待执行 | 否 |
| 2 | 执行中 | 否 |
| 3 | 成功 | ✓ 是 |
| 4 | 失败 | ✓ 是 |
| 5 | 取消 | ✓ 是 |
| 6 | 超时 | ✓ 是 |
| 7 | 被拒绝 | ✓ 是 |
| 8 | 预处理中 | 否 |