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

+81
View File
@@ -0,0 +1,81 @@
"""智能 UV — unfold UVs for a low-poly model.
tripocli uv -p <project_id> --wait
实测流程(在页面上真操作抓到的请求):
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 不 apply,
上下文会停在「待保存」,再调 generate 就会报 `2046 UV Edit action no longer matches the context`。
另外服务端要求网格是低模(约 ≤8 万三角面),否则需要先 `tripocli remesh`。
"""
from . import _common
NAME = "uv"
HELP = "智能 UV:为低模展开 UV(需 ≤8 万三角面)"
def add_arguments(parser):
_common.add_op_options(parser, "应用 UV 后的模型保存到该路径(可选)")
parser.add_argument("--action", default="generate", help="UV 操作动作(默认 generate)")
parser.add_argument("--generate-only", action="store_true", help="只生成候选,不自动保存应用")
def run(ctx):
args = ctx.args
client = ctx.client
operator = client.project_operator(args.project)
current_operator_id = operator.get("operator_id")
if not current_operator_id:
raise ValueError(f"无法读取项目 {args.project} 的 operator_id")
generate_body = {
"project_id": args.project,
"current_operator_id": current_operator_id,
"action": args.action,
}
model_version = _common.project_version(client, args.project, args.model)
if model_version:
generate_body["model_version"] = model_version
ctx.out.line(f"🚀 生成 UV 候选 (current_operator_id={current_operator_id})...")
generated = client.get_data("POST", "/v2/studio/operation/uv_edit/generate", body=generate_body) or {}
candidate_id = generated.get("candidate_operator_id") or generated.get("operator_id")
if not candidate_id:
raise RuntimeError(f"generate 未返回候选 operator: {generated}")
if args.wait and candidate_id:
# The generate step produces a candidate; wait for it, but never hang on it —
# if it does not report a terminal state we still go on to apply.
try:
_common.wait_and_report(ctx, candidate_id, timeout=180)
except Exception as error:
ctx.out.line(f"(候选未在 180s 内就绪,继续尝试保存: {error})")
if args.generate_only:
ctx.out.data(
{"generate": generated, "candidate_operator_id": candidate_id},
human=lambda: ctx.out.line(f"✅ 已生成候选(未保存): {candidate_id}"),
)
return {"generate": generated, "candidate_operator_id": candidate_id}
apply_body = {
"project_id": args.project,
"current_operator_id": current_operator_id,
"candidate_operator_id": candidate_id,
}
ctx.out.line("💾 应用(保存)UV 候选...")
applied = client.get_data("POST", "/v2/studio/operation/uv_edit/apply", body=apply_body) or {}
return _common.run_operator(
ctx, applied, output=args.output, wait=args.wait, label="智能 UV"
)