tripocli v2.0.0:Tripo AI 3D 生成与加工 CLI(面向 Agent 与开发者,纯 Python 标准库、零第三方依赖)

覆盖文生 3D、图生 3D、多视图、批量生成,以及重拓扑、绑定、动画、智能分割、
纹理、PBR、智能 UV、部件补全、格式导出与下载。

代码组织:一个功能一个模块(tripo/features/),入口薄壳 tripocli.py。
This commit is contained in:
Mrpzx committed 2026-10-13 19:22:54 +08:00
commit 977f97995a
60 files changed
+5622

No files matched your search

+280
View File
@@ -0,0 +1,280 @@
# Tripo API 规范(实测契约)
本文档记录 `tripocli` 在真实生产环境(studio.tripo3d.ai / api.tripo3d.ai)**实测验证过**的接口契约,
供接入方与其它 Agent 参考。带 ⚠️ 的都是踩过的坑,按实测结果书写,不是推测。
---
## 一、鉴权
### 1. 请求头(业务接口必带)
```http
Accept: application/json
Content-Type: application/json
Origin: https://studio.tripo3d.ai
Referer: https://studio.tripo3d.ai/
Authorization: Bearer <JWT>
x-tripo-device-id: <device_id>
```
⚠️ **缺少 `Origin`/`Referer` 会返回 `403 code=1017 Access denied: invalid domain`**(实测)。
### 2. Cookie 换 JWT
```
GET /v2/studio/studio/whoami?tokenizeAs=default_jwt
```
- 鉴权:**必须用 Cookie**(`ory_kratos_session`)。⚠️ 实测**用 Bearer JWT 调这个接口会 401**。
- 响应关键字段:`tokenized`(即后续使用的 JWT,**有效期约 15 分钟**)、`expires_at`(会话到期)、`id`、`identity.traits.email`。
- Cookie `ory_kratos_session` 有效期约 **30 天**。
- ⚠️ 短时间内高频调用该接口偶发瞬时 `401`,需重试。
---
## 二、账户
| 功能 | 方法与路径 | 说明 |
|---|---|---|
| 积分/会员 | `GET /v2/studio/user/profile/payment` | `data.wallet.total_credit`、`expiring_credit`、`expiring_date`;`data.member.type`、`valid_until` |
| 试用额度 | `POST /v2/studio/operation/quota`(body `{}`) | `data.quota.generation.*`、`data.quota.uv_edit.*` |
| 资产列表 | `GET /v2/studio/assets/v2` | ⚠️ 需要 `asset_type=mine`(实测 `model`/`personal`/`team` 等都报 `invalid asset type`)+ `type=model` |
---
## 三、生成接口
三者返回结构一致:`data.{task_id, project_id, operator_id, is_nsfw}`。
### 1. 文生 3D
```
POST /v2/studio/operation/text_to_model
```
| 字段 | 类型 | 说明 |
|---|---|---|
| `prompt` | string | 必填 |
| `model_version` | string | 高精度 `v3.1-20260211` / `v3.0-20250812` / `v2.5-20250123`;智能网格 `Nexus-v2.0-20260801`(P2.0,实测可用)/ `Nexus-v1.0-20260214` |
| `face_limit` | int | 高精度默认 2000000;智能网格常用 25000 |
| `quad` | bool | 智能网格一般 true |
| `texture` / `pbr` / `delight` | bool | 默认 true |
| `texture_quality` | string | `standard` / `detailed` |
| `texture_alignment` | string | `original_image` |
| `geometry_quality` | string | `detailed` |
| `smart_poly` | bool | 智能网格模式 true |
| `t_pose` | bool | 人形角色 T-Pose |
| `visibility` | string | `shareable` / `private` |
| `model_count` | int | 1 / 2 / 4(⚠️ 多候选时 `project.model_url` 只给一个) |
### 2. 图生 3D(⚠️ 必须带审核结果)
```
POST /v2/studio/storage/temporary_token # body: {"client":"aws","format":"png|jpg|webp"}
→ sts_ak / sts_sk / session_token / host / resource_bucket / resource_uri
PUT https://{bucket}.{host}/{resource_uri} # AWS SigV4 直传(region us-west-2)
POST /v2/studio/audit/image # body: {"image": {"bucket","key"}} → {"data":{"result":"pass"}}
POST /v2/studio/operation/image_to_model
```
`image` 对象**必须**包含审核结果与来源,否则一律返回 `11002 Image audit result not found`:
```json
{
"image": {
"bucket": "tripo-data",
"key": "tripo-studio/<date>/<uuid>/input.webp",
"image_audit_result": "pass",
"image_source": "upload"
},
"model_version": "v3.1-20260211",
"face_limit": 2000000,
"quad": false,
"texture": true,
"pbr": true,
"delight": true,
"texture_alignment": "original_image",
"texture_quality": "detailed",
"geometry_quality": "detailed",
"smart_poly": false,
"visibility": "shareable"
}
```
### 3. 多视角图生 3D
```
POST /v2/studio/operation/multiview_to_model
```
⚠️ `image` 必须是**恰好 4 个**已审核图片对象的数组(前/左/右/后);少于 4 个返回 `1004 Invalid parameter(s)`,未审核返回 `11002`。
### 4. 导入自己的模型(上传 glb/obj/fbx/stl)
```
POST /v2/studio/storage/temporary_token # body: {"client":"aws","format":"glb|obj|fbx|stl"}
PUT https://{bucket}.{host}/{resource_uri} # AWS SigV4 直传(同图片)
POST /v2/studio/operation/import_user_model
```
⚠️ body 是**嵌套**的,`model` 里放 S3 对象(实测):
```json
{
"format": "glb",
"model": {"bucket": "tripo-data", "key": "tripo-studio/<date>/<uuid>/input.glb"},
"name": "my_model.glb",
"transform_matrix": [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1],
"use_original_uv": true
}
```
→ `data.{project_id, operator_id}`(随后可用 progress 轮询;实测导入成功后可下载)。
⚠️ **`transform_matrix`** 是 4x4 矩阵(前端在导入对话框里让用户转模型用的「找到最佳角度」),CLI 用单位矩阵即可。
⚠️ 导入会**丢弃自定义材质与多层节点层级**(界面明确提示);个别模型(如 Tripo 自己导出的带材质 glb)服务端处理会失败(`9104` / `Internal algorithm error`),换标准 obj/glb 即可。
### 5. 部件名(`part_name_list`)来自模型文件,不在接口里
`remesh` / `pbr` / `texture_model` 的 `part_name_list` 取的是**模型里的节点名**:
未拆分为单个 `tripo_node_<operator_id>`,智能分割后为每个部件一个 `tripo_part_<n>`。
⚠️ 项目详情接口**不返回**部件名,前端是**下载 GLB 后解析 `nodes[].name`** 得到的;
`tripocli` 用同样办法(纯标准库解析 GLB 的 JSON chunk),读不到时回退到 `tripo_node_<operator_id>`。
### 6. 批量图生 3D
```
POST /v2/studio/operation/batch_image_to_model
```
⚠️ 字段名是 **`image`**(数组,不是 `images`,写错返回 `type mismatch for field "image"`);响应 `data` 是**数组**,每项 `{project_id, operator_id}`。
---
## 四、任务与项目
| 功能 | 方法与路径 |
|---|---|
| 进度轮询 | `POST /v2/studio/progress`,body `{"ids":["<operator_id>"]}` → `[{status, progress, left_time, point_cloud_model_url}]`,`status ∈ running/success/failed` |
| 项目详情 | `GET /v2/studio/project/detail/v3/<project_id>?locale=zh-CN` → `data.model_url`、`cover_image`、`operator.{operator_id, status, model_version, is_textured, ...}` |
⚠️ 轮询偶发裸 `502`,需重试而非中断。
---
## 四、文生图(参考图生成)
```
POST /v2/studio/image/gen_image_v2
{
"if_upload": true, "sketch_to_render": false, "t_pose": false,
"amount": 4, // 1-4
"model_version": "gemini_3.1_flash_image_preview",
"prompt": "a cute cartoon wooden barrel",
"resolution": "1K", // 实测 1K/2K/4K 有效,8K 报 400
"scale": "1:1" // 1:1 16:9 9:16 4:3 3:4
}
→ {"task_id": ..., "asset_id": ..., "remaining_free_count": 96}
POST /v2/studio/image/get_image_asset {"asset_id": "..."}
→ {status, type:"generate_image", output:{data:[{bucket,key,url}]}}
```
图片模型 `model_version`(在页面逐个选中并抓包确认):
| 界面名 | model_version |
|---|---|
| Nano Banana 2(默认) | `gemini_3.1_flash_image_preview` |
| Nano Banana Pro | `gemini_3_pro_image_preview` |
| GPT Image 2 | `gpt_image_2` |
| GPT Image 2.5 | `gpt_image_2.5_sunburst` |
| Midjourney v8.2 | `midjourney` |
> 异步:先 `gen_image_v2` 拿 `asset_id`,再轮询 `get_image_asset` 直到 `status=success`。
### 图片侧其它接口(实测)
| 功能 | 方法与路径 | 说明 |
|---|---|---|
| 模板清单 | `GET /v2/studio/image/available_templates` | 返回 `{templates:[{template_id,title,description,category,secondary_tag,tag}]}`。**模板是客户端的提示词+参数预设**,请求体里没有 `template_id`(实测),CLI 只用来列清单 |
| 单图→多视角图 | `POST /v2/studio/image/gen_multiview` | body `{image, model_version, amount, resolution, scale}`(`image` 需先上传+审核)。结果 `get_image_asset` 的 `type="multiview_images"`,`output.data` 为 4 张(实测出图 4 张) |
| 图片资产 | `POST /v2/studio/image/image_assets` | body `{page_num,page_size}` |
| 图片放大 | `POST /v2/studio/image/upscale` | 需 `asset_id`(实测:只给 image 报 `field "asset_id" is not set`) |
| 图片拆分 | `POST /v2/studio/image/split` | — |
| 重新生成 | `POST /v2/studio/image/re_gen_image` / `re_gen_multiview` | — |
| 批量删除 | `POST /v2/studio/image/batch_delete` | — |
---
## 五、后处理算子
⚠️ **通用规则**:每个算子都会为项目新建一个 operator;**必须等上一个算子 `success` 之后**才能对同一项目再提交,
否则返回 `2021 the status of task is not success`。
⚠️ **`part_name_list`**:`remesh` / `pbr_generate` / `texture_model` 都需要它,值为
`["tripo_node_<项目当前 operator_id>"]`。缺它时请求会被接受,但任务在 **100% 处失败**(实测)。
| 功能 | 路径 | 关键字段 |
|---|---|---|
| 重拓扑 | `POST /v2/studio/operation/remesh` | `bake:true`、`face_limit`、`quad`、`smart_poly:false`、`model_version:"default"`、`part_name_list` |
| 绑定前检查 | `POST /v2/studio/operation/pre_rig_check` | `project_id`(`model_version` 可选)→ `{check_success, riggable, rig_type}` |
| 骨骼绑定 | `POST /v2/studio/operation/rigging_model` | `project_id`、`rig_type:"biped"`、`spec`、`model_version`。⚠️ **spec 有 5 个值**(取自前端数据表 + 实测核对):`mixamo` / `actorcore`(界面对应 ActorCore)/ `unreal`(UE5 Mannequin)/ `unity`(Unity Humanoid Compatible)/ `vrm`(VRM 1.0 Humanoid) |
| 动画重定向 | `POST /v2/studio/operation/retarget_model` | ⚠️ 动作用 `animations` **数组**:`["preset:biped:afraid"]`;+ `project_id`、`rig_type:"biped"`、`model_version:"default"`。⚠️ **动画结果不在顶层 `project.model_url`**(那是 `rigging` 算子的带网格绑骨模型),而在 `project.operator.retarget[]` 数组中(按 `operator_id` 匹配取 `model_url`);且该 GLB 仅含 65 根骨骼动画轨道(约 100–500KB,不含 Mesh),在 Three.js / Godot 中需与 `rigging` 本体 SkinnedMesh 配合播放 |
| 3D 风格化 | `POST /v2/studio/operation/stylize` | `project_id`、`model_version`、`style`(实测 `"clay"` 黏土风可用) |
| 取消任务 | `POST /v2/studio/operation/cancel` | `operator_id`、`scene`(仅允许 `"workspace"` 或 `"assets"`)、`operation_type`(20 种枚举:`text_to_model`/`image_to_model`/`multiview_to_model`/`ai_segmentation`/`ai_completion`/`mesh_fill`/`modification`/`skeleton_adjustment`/`texture_generation`/`pre_rig_check`/`rigging`/`retarget`/`stylize`/`export`/`retexture`/`apply_texture`/`pbr`/`remesh`/`texture_upscaler`/`image_edit_to_model`) |
| 重命名项目 | `POST /v2/studio/operation/update_name` | `project_id`、`name`(成功返回 `null`) |
| 图文生 3D(已废弃) | `POST /v2/studio/operation/image-prompt-model` | ⚠️ 服务端已下线,固定返回 `code=2040 This endpoint is no longer accepting requests` |
| 智能分割 | `POST /v2/studio/operation/ai_segmentation` | ⚠️ `model_version` 用**分割模型自己的版本** `v2.0-20260430`(传项目版本会 `1001`);`segmentation_granularity:"balanced"`(界面「标准」;粗略/精细取值未确认) |
| 纹理生成 | `POST /v2/studio/operation/texture_model` | `texture_quality`、`texture_alignment`、`part_name_list`(⚠️ 已贴图模型会失败) |
| 重贴图(魔法笔刷) | `POST /v2/studio/operation/retexture_generate` / `apply_retexture` / `get_retexture` / `get_retexture_images` | ⚠️ **纯交互式**:body 需在 3D 画布上涂抹出的遮罩快照(`snapshot()` → `matrix` + 涂抹区域)+ `magicBrushPrompt:{text,weight}`,且要求模型**已贴图**、未分割、未超清。CLI 未封装 |
| 纹理放大 | `POST /v2/studio/operation/texture_upscaler` | ⚠️ 字段是 `texture_quality:"detailed"`(不是 `texture_resolution`,写错会 `1001`);+ `model_version` |
| PBR | `POST /v2/studio/operation/pbr_generate` | `project_id`、`model_version`、`part_name_list` |
| 智能 UV | 见下方三步 | 上下文驱动 |
| 部件补全 | `POST /v2/studio/operation/mesh_fill` / `ai_completion` | `part_names`(数组)、`model_version`。部件名 = 模型 GLB 的节点名(`tripo_part_<n>`),实测可用 |
| 网格编辑 | `POST /v2/studio/operation/local_edit` | `project_id`、`source_operator_id`、`bbox:[[min],[max]]`(归一化 -1..1)、`face_limit`。⚠️ 仅**智能网格(Nexus)** 且未贴图/未绑定/未分割/未 PBR 的模型可用(界面据此隐藏「编辑」页) |
### 智能 UV(三步,实测)
```
POST /v2/studio/operation/uv_edit/generate
{project_id, current_operator_id, action:"generate"} → 生成 UV 候选(新 operator)
POST /v2/studio/operation/uv_edit/apply
{project_id, current_operator_id, candidate_operator_id} → 保存/应用候选
POST /v2/studio/operation/uv_edit/context
{project_id, current_operator_id} → 查询当前处于哪一步
```
⚠️ 只 `generate` 不 `apply`,上下文会停在「待保存」,再调 `generate` 报
`2046 UV Edit action no longer matches the context`。另外要求网格为低模(约 ≤8 万三角面)。
> 说明:`ai_segmentation` / `texture_upscaler` 等对**不同模型**可能服务端失败,属模型相关行为,与请求字段无关。
### 动作预设清单(无接口,来自前端静态表)
服务端**没有**提供预设目录接口,实测:
- `POST /v2/studio/motion/list_assets`(body `{}`)→ 返回的是**用户自己的动画资产**(`{active_tasks, assets}`),不是预设目录;
- `POST /v2/studio/operation/get_user_operation_context` `{"record_type":"recent_retarget_motions"}`
→ 只返回**最近用过**的:`{preset:[...], generated:[...]}`。
完整目录在 studio 前端 chunk(`BLST4mg6.js`)的静态表里,已提取到 `tripo/data/motions.json`:
- 格式 `preset:<rig_type>:<name>`,`rig_type ∈ {biped, aquatic, quadruped, hexapod, octopod, serpentine}`
- **biped 97 个**,其余体型各 1 个(`walk`/`march`)
- 预览图:`https://tripo-public.tripo3d.ai/studio_riging_data/<rig_type>/<name>.avif`
用 `tripocli animate --list` 查看全部。
### 文字生成动作(AI 动画,实测三段式)
```
1) POST /v2/studio/motion/generate
{"segments": [{"duration_seconds": 5, "prompt": "让角色挥手打招呼"}]}
→ {task_id, status:"queued"}
(segments 是数组 → 支持多阶段动作)
2) POST /v2/studio/motion/get_task {"task_id": "..."}
→ 轮询直到 status="success",取 asset_id(即 motion_asset_id)
3) POST /v2/studio/operation/retarget_model
{"motion_asset_id": "<asset_id>", "model_version":"default",
"project_id": "...", "rig_type": "biped"} → 把动作套到模型上
```
其它已验证接口:`POST /v2/studio/motion/list_assets`(我的动作资产)、`/motion/get_asset`、
`/motion/list_active_tasks`(正在跑的任务)。
---
## 六、导出与下载
```
POST /v2/studio/operation/export
body: {project_id, operator_id, format:"fbx|gltf|obj|stl|usdz|3mf", name, model_version}
→ data.{operator_id, operation_id} # 异步,用 progress 轮询
POST /v2/studio/operation/download_with_name
body: {operator_id, file_name}
→ data.model_url # 带 Content-Disposition 的签名直链
```