"""部件补全 — fill / complete parts of a segmented model. tripocli fill -p --parts all --wait tripocli fill -p --parts tripo_part_0,tripo_part_3 --wait 实测:`mesh_fill`(界面「快速封口」)与 `ai_completion`(界面「AI 补全」)都要求 `part_names`(数组)+ `model_version`;缺 `part_names` 报 `type mismatch for field "part_names"`。 部件标识 = **模型里的节点名**:未拆分模型是 `tripo_node_`, 智能分割后是每个部件一个 `tripo_part_`(实测 `tripo_part_0` 可用)。 项目详情接口不返回这些名字,`tripocli` 直接解析模型 GLB 的节点名,故 `--parts all` 即可全选。 """ from ..errors import TripoAPIError from . import _common NAME = "fill" HELP = "部件补全:补全拆分后的部件网格(快速封口 / AI 补全)" def add_arguments(parser): _common.add_op_options(parser, "补全结果保存到该路径(可选)") parser.add_argument("--parts", required=True, help="部件名(逗号分隔),或传 all 选择全部节点") parser.add_argument("--ai", action="store_true", help="使用 AI 补全(默认使用快速封口)") def resolve_parts(ctx, args): if args.parts.strip().lower() in ("all", "*"): names = ctx.client.part_names(args.project) if not names: raise TripoAPIError("无法从模型读取部件名,请用 --parts 显式指定") return names return [part.strip() for part in args.parts.split(",") if part.strip()] def run(ctx): args = ctx.args part_names = resolve_parts(ctx, args) if not part_names: raise ValueError("--parts 不能为空") endpoint = "ai_completion" if args.ai else "mesh_fill" body = {"project_id": args.project, "part_names": part_names} model_version = _common.project_version(ctx.client, args.project, args.model) if model_version: body["model_version"] = model_version data = ctx.client.get_data("POST", f"/v2/studio/operation/{endpoint}", body=body) return _common.run_operator(ctx, data, output=args.output, wait=args.wait, label="部件补全")