tripocli v2.0.0:Tripo AI 3D 生成与加工 CLI(面向 Agent 与开发者,纯 Python 标准库、零第三方依赖)
覆盖文生 3D、图生 3D、多视图、批量生成,以及重拓扑、绑定、动画、智能分割、 纹理、PBR、智能 UV、部件补全、格式导出与下载。 代码组织:一个功能一个模块(tripo/features/),入口薄壳 tripocli.py。
This commit is contained in:
commit
977f97995a
60 files changed
+5622
No files matched your search
@@ -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"
|
||||
)
|
||||
Reference in new issue
Block a user