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,132 @@
|
||||
"""Multi-account credential store.
|
||||
|
||||
A user hands the CLI a session cookie once (paste it, or pass ``TRIPO_COOKIE``);
|
||||
from then on the CLI mints short-lived JWTs on demand over plain HTTP — no
|
||||
browser, no repeated login.
|
||||
|
||||
~/.tripo/accounts.json
|
||||
{
|
||||
"active": "main",
|
||||
"accounts": {
|
||||
"main": {"cookie": "...", "token": "...", "session_expires_at": "...",
|
||||
"user_id": "...", "email": "...", "added_at": 1791800000}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
import json
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
DEFAULT_ACCOUNTS_PATH = Path.home() / ".tripo" / "accounts.json"
|
||||
|
||||
|
||||
class Accounts:
|
||||
def __init__(self, path=None):
|
||||
self.path = Path(path) if path else DEFAULT_ACCOUNTS_PATH
|
||||
self.data = {"active": None, "accounts": {}}
|
||||
self.load()
|
||||
|
||||
# --- persistence ---
|
||||
|
||||
def load(self):
|
||||
if self.path.exists():
|
||||
try:
|
||||
loaded = json.loads(self.path.read_text(encoding="utf-8"))
|
||||
self.data = {
|
||||
"active": loaded.get("active"),
|
||||
"accounts": loaded.get("accounts", {}),
|
||||
}
|
||||
except Exception:
|
||||
self.data = {"active": None, "accounts": {}}
|
||||
|
||||
def save(self):
|
||||
self.path.parent.mkdir(parents=True, exist_ok=True)
|
||||
self.path.write_text(json.dumps(self.data, indent=2, ensure_ascii=False), encoding="utf-8")
|
||||
try:
|
||||
self.path.chmod(0o600) # holds a session cookie: keep it private
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# --- queries ---
|
||||
|
||||
def names(self):
|
||||
return sorted(self.data["accounts"])
|
||||
|
||||
def rotation(self, start=None):
|
||||
"""Account names starting at ``start`` (default: active), wrapping around.
|
||||
|
||||
Used by the optional auto-fallback so a command can try the next account
|
||||
when the current one is out of credits.
|
||||
"""
|
||||
names = self.names()
|
||||
if not names:
|
||||
return []
|
||||
start = start or self.data.get("active")
|
||||
if start not in names:
|
||||
return names
|
||||
index = names.index(start)
|
||||
return names[index:] + names[:index]
|
||||
|
||||
def exists(self, name):
|
||||
return name in self.data["accounts"]
|
||||
|
||||
def active_name(self):
|
||||
return self.data.get("active")
|
||||
|
||||
def get(self, name=None):
|
||||
"""Return ``(name, record)`` for ``name`` or the active account."""
|
||||
name = name or self.data.get("active")
|
||||
if not name or name not in self.data["accounts"]:
|
||||
return None, None
|
||||
return name, self.data["accounts"][name]
|
||||
|
||||
# --- mutations ---
|
||||
|
||||
def add(self, name, cookie, token=None, session_expires_at=None, user_id=None, email=None):
|
||||
record = self.data["accounts"].get(name, {})
|
||||
record.update({
|
||||
"cookie": cookie,
|
||||
"token": token,
|
||||
"session_expires_at": session_expires_at,
|
||||
"user_id": user_id,
|
||||
"email": email,
|
||||
"added_at": record.get("added_at") or int(time.time()),
|
||||
"updated_at": int(time.time()),
|
||||
})
|
||||
self.data["accounts"][name] = record
|
||||
if not self.data.get("active"):
|
||||
self.data["active"] = name
|
||||
self.save()
|
||||
return name
|
||||
|
||||
def use(self, name):
|
||||
if name not in self.data["accounts"]:
|
||||
raise KeyError(name)
|
||||
self.data["active"] = name
|
||||
self.save()
|
||||
|
||||
def remove(self, name):
|
||||
if name not in self.data["accounts"]:
|
||||
raise KeyError(name)
|
||||
del self.data["accounts"][name]
|
||||
if self.data.get("active") == name:
|
||||
self.data["active"] = self.names()[0] if self.data["accounts"] else None
|
||||
self.save()
|
||||
|
||||
def update_token(self, name, token, session_expires_at=None):
|
||||
record = self.data["accounts"].get(name)
|
||||
if record is None:
|
||||
return
|
||||
record["token"] = token
|
||||
record["updated_at"] = int(time.time())
|
||||
if session_expires_at:
|
||||
record["session_expires_at"] = session_expires_at
|
||||
self.save()
|
||||
|
||||
def update_cookie(self, name, cookie):
|
||||
record = self.data["accounts"].get(name)
|
||||
if record is None:
|
||||
return
|
||||
record["cookie"] = cookie
|
||||
self.save()
|
||||
Reference in new issue
Block a user