317 lines
7.6 KiB
Markdown
317 lines
7.6 KiB
Markdown
# World Labs 3D 世界生成中转接口兼容要求
|
||
|
||
本文档用于说明我方系统接入 World Labs 3D 世界生成功能时,对第三方中转服务的接口兼容要求。
|
||
|
||
## 核心原则
|
||
|
||
我方系统会按照 World Labs 官方 API 协议发起请求:
|
||
|
||
```text
|
||
{baseUrl} + /marble/v1/...
|
||
```
|
||
|
||
中转服务需要兼容官方路径、请求体、响应体和错误格式。请不要要求我方把 `baseUrl` 配置成某个完整接口地址。
|
||
|
||
正确示例:
|
||
|
||
```text
|
||
http://your-proxy-domain.com
|
||
```
|
||
|
||
错误示例:
|
||
|
||
```text
|
||
http://your-proxy-domain.com/marble/v1/worlds:generate
|
||
```
|
||
|
||
## 我方请求方式
|
||
|
||
我方后台会在请求中携带:
|
||
|
||
```http
|
||
WLT-Api-Key: {配置的 API Key}
|
||
Accept: application/json
|
||
Content-Type: application/json
|
||
```
|
||
|
||
中转服务应支持 `WLT-Api-Key` 请求头。如果中转服务内部自行管理官方 Key,也可以将该字段作为租户标识或鉴权凭据,但不应要求我方改成其他 header。
|
||
|
||
## 必须兼容的接口
|
||
|
||
### 1. 准备上传素材
|
||
|
||
```http
|
||
POST {baseUrl}/marble/v1/media-assets:prepare_upload
|
||
```
|
||
|
||
请求体示例:
|
||
|
||
```json
|
||
{
|
||
"file_name": "input.jpg",
|
||
"extension": "jpg",
|
||
"kind": "image",
|
||
"metadata": {
|
||
"mime_type": "image/jpeg",
|
||
"uploaded_from": "canvas_world_mode"
|
||
}
|
||
}
|
||
```
|
||
|
||
响应必须包含可用的上传信息:
|
||
|
||
```json
|
||
{
|
||
"media_asset": {},
|
||
"upload_info": {
|
||
"upload_url": "https://...",
|
||
"upload_method": "PUT",
|
||
"required_headers": {}
|
||
}
|
||
}
|
||
```
|
||
|
||
要求:
|
||
|
||
- `upload_url` 必须可由我方服务器直接访问。
|
||
- `upload_method` 如为 `PUT`,必须支持 `PUT` 上传文件二进制。
|
||
- `required_headers` 中返回的 header,我方会原样带上。
|
||
- 上传成功时,上传地址必须返回 `2xx`。
|
||
|
||
### 2. 创建世界生成任务
|
||
|
||
```http
|
||
POST {baseUrl}/marble/v1/worlds:generate
|
||
```
|
||
|
||
请求体示例:
|
||
|
||
```json
|
||
{
|
||
"display_name": "",
|
||
"model": "marble-1.1",
|
||
"permission": {
|
||
"public": false
|
||
},
|
||
"world_prompt": {
|
||
"type": "image",
|
||
"image_prompt": {
|
||
"source": "media_asset",
|
||
"media_asset_id": "media_asset_id_here"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
响应需兼容官方 operation 结构,至少包含:
|
||
|
||
```json
|
||
{
|
||
"operation_id": "task-id",
|
||
"done": false,
|
||
"metadata": {
|
||
"progress": {
|
||
"status": "RUNNING"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
要求:
|
||
|
||
- `operation_id` 必须稳定,后续查询状态必须使用同一个 id。
|
||
- 不要在创建成功但任务未完成时返回业务失败。
|
||
- 如果余额不足、Key 无效,应返回明确 HTTP 状态码和错误信息。
|
||
|
||
### 3. 查询任务状态
|
||
|
||
```http
|
||
GET {baseUrl}/marble/v1/operations/{operation_id}
|
||
```
|
||
|
||
运行中响应示例:
|
||
|
||
```json
|
||
{
|
||
"operation_id": "task-id",
|
||
"done": false,
|
||
"metadata": {
|
||
"progress": {
|
||
"status": "RUNNING",
|
||
"description": "World generation in progress"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
成功响应示例:
|
||
|
||
```json
|
||
{
|
||
"operation_id": "task-id",
|
||
"done": true,
|
||
"error": null,
|
||
"metadata": {
|
||
"progress": {
|
||
"status": "SUCCEEDED"
|
||
},
|
||
"world_id": "world-id"
|
||
},
|
||
"response": {
|
||
"world_id": "world-id",
|
||
"world_marble_url": "https://marble.worldlabs.ai/world/...",
|
||
"assets": {
|
||
"mesh": {
|
||
"collider_mesh_url": "https://cdn.marble.worldlabs.ai/.../model.glb"
|
||
},
|
||
"imagery": {
|
||
"pano_url": "https://cdn.marble.worldlabs.ai/.../rgb_0.png"
|
||
},
|
||
"thumbnail_url": "https://cdn.marble.worldlabs.ai/.../thumbnail.webp",
|
||
"splats": {
|
||
"spz_urls": {
|
||
"100k": "https://cdn.marble.worldlabs.ai/...100k.spz",
|
||
"150k": "https://cdn.marble.worldlabs.ai/...150k.spz",
|
||
"500k": "https://cdn.marble.worldlabs.ai/...500k.spz",
|
||
"full_res": "https://cdn.marble.worldlabs.ai/...full.spz"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
失败响应示例:
|
||
|
||
```json
|
||
{
|
||
"operation_id": "task-id",
|
||
"done": true,
|
||
"error": {
|
||
"message": "Insufficient account balance"
|
||
}
|
||
}
|
||
```
|
||
|
||
要求:
|
||
|
||
- `done=false` 表示任务仍在运行。
|
||
- `done=true` 且 `error=null` 表示任务成功。
|
||
- `done=true` 且 `error.message` 存在表示任务失败。
|
||
- 不要把运行中的任务返回为 HTTP 404。
|
||
- 不要因为任务未完成就返回 `Operation not found`。
|
||
|
||
### 4. 查询世界详情
|
||
|
||
```http
|
||
GET {baseUrl}/marble/v1/worlds/{world_id}
|
||
```
|
||
|
||
当 `operations` 成功响应中资产不完整时,我方会调用该接口补充详情。响应应包含与 `response` 内 world 对象兼容的数据结构。
|
||
|
||
## 错误码要求
|
||
|
||
建议按以下语义返回:
|
||
|
||
| 场景 | HTTP 状态码 | message 示例 |
|
||
| --- | --- | --- |
|
||
| API Key 缺失或无效 | `401` | `Unauthorized` |
|
||
| 权限不足 | `403` | `Forbidden` |
|
||
| 余额不足 | `402` 或 `403` | `Insufficient account balance` |
|
||
| 请求体错误 | `400` | `Invalid request body` |
|
||
| 任务不存在 | `404` | `Operation not found` |
|
||
| 上游超时 | `504` | `Upstream timeout` |
|
||
| 上游异常 | `502` | `Upstream error` |
|
||
|
||
响应体建议:
|
||
|
||
```json
|
||
{
|
||
"message": "Insufficient account balance"
|
||
}
|
||
```
|
||
|
||
或:
|
||
|
||
```json
|
||
{
|
||
"error": {
|
||
"message": "Insufficient account balance"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 超时与稳定性要求
|
||
|
||
- `prepare_upload` 建议 30 秒内返回。
|
||
- `worlds:generate` 建议 60 秒内返回 operation,而不是等待生成完成。
|
||
- `operations/{id}` 建议 10 秒内返回当前状态。
|
||
- 生成任务本身可异步运行,前端会轮询状态。
|
||
- 同一个 `operation_id` 多次查询必须返回同一个任务状态,不应随机切换账号或路由。
|
||
|
||
## 上传地址要求
|
||
|
||
`prepare_upload` 返回的 `upload_url` 可以是官方签名地址,也可以是中转服务自己的上传地址,但必须满足:
|
||
|
||
- 我方服务器可直接访问。
|
||
- 支持返回的 `upload_method`。
|
||
- 支持上传原始文件二进制。
|
||
- 上传成功返回 `2xx`。
|
||
- 上传完成后,后续 `worlds:generate` 使用的 `media_asset_id` 必须可用。
|
||
|
||
## 安全要求
|
||
|
||
- 不要在错误信息中返回完整官方 API Key。
|
||
- 日志中建议只记录 Key 前后少量字符,例如 `sk-****abcd`。
|
||
- 中转服务如保存官方 Key,应加密存储。
|
||
- 上传 URL 如有签名,应设置合理过期时间。
|
||
- 不要允许用户通过 `baseUrl` 或 path 注入访问内网地址。
|
||
|
||
## 我方验收用例
|
||
|
||
中转服务上线前,请至少通过以下链路:
|
||
|
||
1. `POST /marble/v1/media-assets:prepare_upload` 返回 `media_asset_id` 和可上传 URL。
|
||
2. 使用返回的 `upload_url` 上传图片,返回 `2xx`。
|
||
3. `POST /marble/v1/worlds:generate` 返回稳定 `operation_id`。
|
||
4. `GET /marble/v1/operations/{operation_id}` 在运行中返回 `done=false`。
|
||
5. 任务完成后返回 `done=true`、`error=null`、`world_id` 和资产 URL。
|
||
6. 资产 URL 中至少应包含 thumbnail、pano、mesh 或 spz 中的一种,最好完整返回。
|
||
7. `GET /marble/v1/worlds/{world_id}` 可返回完整 world 详情。
|
||
|
||
## 配置示例
|
||
|
||
我方系统中的 API 地址应填写中转根地址:
|
||
|
||
```text
|
||
http://23.169.168.133:8080
|
||
```
|
||
|
||
最终我方会请求:
|
||
|
||
```text
|
||
http://23.169.168.133:8080/marble/v1/media-assets:prepare_upload
|
||
http://23.169.168.133:8080/marble/v1/worlds:generate
|
||
http://23.169.168.133:8080/marble/v1/operations/{operation_id}
|
||
http://23.169.168.133:8080/marble/v1/worlds/{world_id}
|
||
```
|
||
|
||
如果切回官方接口,配置为:
|
||
|
||
```text
|
||
https://api.worldlabs.ai
|
||
```
|
||
|
||
最终请求:
|
||
|
||
```text
|
||
https://api.worldlabs.ai/marble/v1/media-assets:prepare_upload
|
||
https://api.worldlabs.ai/marble/v1/worlds:generate
|
||
https://api.worldlabs.ai/marble/v1/operations/{operation_id}
|
||
https://api.worldlabs.ai/marble/v1/worlds/{world_id}
|
||
```
|
||
|
||
## 结论
|
||
|
||
中转服务需要做的是兼容 World Labs 官方 API 协议,而不是要求我方修改接口路径。只要中转根地址完整支持 `/marble/v1/...`,我方系统就可以在官方接口和中转接口之间无缝切换。
|