Files
Mrpzx 977f97995a tripocli v2.0.0:Tripo AI 3D 生成与加工 CLI(面向 Agent 与开发者,纯 Python 标准库、零第三方依赖)
覆盖文生 3D、图生 3D、多视图、批量生成,以及重拓扑、绑定、动画、智能分割、
纹理、PBR、智能 UV、部件补全、格式导出与下载。

代码组织:一个功能一个模块(tripo/features/),入口薄壳 tripocli.py。
2026-10-13 19:22:54 +08:00

169 lines
6.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""argparse wiring and dispatch.
``tripocli`` is a thin shell: this module builds the command tree from the
feature modules, resolves credentials (re-minting the JWT from the account's
session cookie when needed) and hands control to the selected feature.
"""
import argparse
import os
import sys
from . import __version__
from .accounts import Accounts
from .client import TripoClient
from .config import Config
from .errors import TripoAPIError, TripoTimeout, is_insufficient_credits
from .features import MODULES
from .output import Out
EPILOG = """\
常用示例:
tripocli account add --cookie "<粘贴浏览器 cookie>" # 一次性添加账号,之后免浏览器
tripocli account list # 多账号查看/切换
tripocli serve --open # 打开网页版账号管理(看积分/有效期)
tripocli update # 改完源码后更新全局 CLI
tripocli balance # 查看积分
tripocli text -p "a wooden barrel" --wait -o a.glb # 文生 3D
tripocli image -i ./photo.png --wait -o b.glb # 单图生 3D
tripocli multiview --front f.png --left l.png --right r.png --back b.png --wait -o c.glb
tripocli batch -i a.png,b.png --wait -o ./out # 批量图生 3D
tripocli remesh -p <project_id> --face-limit 8000 --wait -o low.glb
tripocli rig -p <project_id> --type biped --wait # 绑定骨骼
tripocli animate -p <project_id> --preset idle --wait -o anim.glb
tripocli segment -p <project_id> --wait # 智能分割
tripocli texture -p <project_id> --resolution 2K --wait
tripocli pbr -p <project_id> --wait # PBR 材质
tripocli upscale -p <project_id> --wait # 纹理放大
tripocli export -p <project_id> -f fbx --wait -o m.fbx
凭据:只需提供一次浏览器 cookie,CLI 会自行续期 JWT(cookie 约 30 天有效)。
也可用环境变量 TRIPO_COOKIE 提供;多账号用 --account <名字> 指定。
加 --json 可输出机器可读结果(Agent 调用推荐)。
"""
# Commands that must run without any credentials.
NO_CREDENTIAL_COMMANDS = {"account", "config", "serve", "update", "inspect", "optimize"}
class Context:
"""Everything a feature needs: client, config, accounts, output sink and args."""
def __init__(self, client, config, accounts, out, args):
self.client = client
self.config = config
self.accounts = accounts
self.out = out
self.args = args
def _add_json_flag_everywhere(parser):
"""Allow ``--json`` after the subcommand as well as before it.
``argparse`` only accepts a parent parser's options before the subcommand, but
agents habitually append ``--json`` at the end; SUPPRESS keeps the subcommand
copy from overwriting a value given on the main parser.
"""
for action in parser._actions:
if isinstance(action, argparse._SubParsersAction):
for subparser in action.choices.values():
if "--json" not in subparser._option_string_actions:
subparser.add_argument(
"--json", action="store_true", default=argparse.SUPPRESS,
help="输出结构化 JSON(Agent 调用推荐)",
)
_add_json_flag_everywhere(subparser)
def build_parser():
parser = argparse.ArgumentParser(
prog="tripocli",
description="Tripo AI 3D 生成 CLI(面向 Agent 与开发者)",
epilog=EPILOG,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument("--json", action="store_true", help="输出结构化 JSON(Agent 调用推荐)")
parser.add_argument("--account", help="使用指定账号(默认用当前账号)")
parser.add_argument(
"--no-fallback", action="store_true",
help="关闭「额度不足自动切换下一个账号」(默认开启;设 TRIPO_AUTO_FALLBACK=0 也可关闭)",
)
parser.add_argument("--token", help="临时覆盖 Bearer JWT")
parser.add_argument("--device-id", help="临时覆盖 x-tripo-device-id")
parser.add_argument("--api-base", help="临时覆盖 API 根地址")
parser.add_argument("-V", "--version", action="version", version=f"tripocli {__version__}")
subparsers = parser.add_subparsers(dest="command", metavar="<命令>")
for module in MODULES:
if hasattr(module, "register"):
module.register(subparsers)
else:
command = subparsers.add_parser(module.NAME, help=module.HELP)
module.add_arguments(command)
command.set_defaults(func=module.run)
_add_json_flag_everywhere(parser)
return parser
def main(argv=None):
parser = build_parser()
args = parser.parse_args(argv)
handler = getattr(args, "func", None)
if handler is None:
parser.print_help()
return 0
out = Out(as_json=args.json)
config = Config()
accounts = Accounts()
needs_credentials = args.command not in NO_CREDENTIAL_COMMANDS
# 默认开启账号回退;显式 --no-fallback 或 TRIPO_AUTO_FALLBACK=0 可关闭。
env_fallback = os.environ.get("TRIPO_AUTO_FALLBACK", "").strip().lower()
fallback = not args.no_fallback and env_fallback not in ("0", "false", "no")
if needs_credentials and fallback and len(accounts.names()) > 1:
order = accounts.rotation(args.account)
else:
order = [args.account]
extra_codes = config.data.get("insufficient_credit_codes") or []
last_error = None
for index, account in enumerate(order):
client = TripoClient(
token=args.token, device_id=args.device_id, api_base=args.api_base,
account=account, accounts=accounts, config=config,
)
ctx = Context(client=client, config=config, accounts=accounts, out=out, args=args)
try:
if needs_credentials:
client.ensure_credentials()
handler(ctx)
return 0
except KeyboardInterrupt:
out.error("已中断")
return 130
except (TripoAPIError, TripoTimeout, ValueError, FileNotFoundError, RuntimeError) as error:
can_retry = (
needs_credentials
and fallback
and index + 1 < len(order)
and is_insufficient_credits(error, extra_codes)
)
if can_retry:
out.notice(f"⚠️ 账号 {account or accounts.active_name()} 额度不足,切换到下一个账号重试…")
last_error = error
continue
out.error(error)
return 1
except Exception as error: # unexpected: keep stdout parseable for agents
out.error(f"运行错误: {error}")
return 1
out.error(last_error or "没有可用账号")
return 1
if __name__ == "__main__":
sys.exit(main())