diff --git a/.claude/skills/run-hunyuan3dweb/SKILL.md b/.claude/skills/run-hunyuan3dweb/SKILL.md new file mode 100644 index 0000000..3324182 --- /dev/null +++ b/.claude/skills/run-hunyuan3dweb/SKILL.md @@ -0,0 +1,103 @@ +--- +name: run-hunyuan3dweb +description: 运行并驱动腾讯混元 3D Python 客户端。当用户要求:跑 hunyuan3dweb、查混元 3D 配额、列作品、文生 3D / 图生 3D 生成模型、查询生成状态、下载 GLB/OBJ/USDZ 模型,或验证这个项目能否工作时使用。 +--- + +本项目是腾讯混元 3D(https://3d.hunyuan.tencent.com/)的非官方 Python 客户端:签名算法(HMAC-SHA256 + 密钥派生)、纯 HTTP API 调用、浏览器登录工具。**无需 pip install**——通过 `PYTHONPATH` 从源码直接运行。 + +唯一驱动入口:`.claude/skills/run-hunyuan3dweb/driver.sh`(下文所有路径相对仓库根 `/opt/hunyuan3dweb`)。 + +## 前置条件 + +```bash +python3 --version # ≥3.8 ✅ (本机 3.13.12) +python3 -c "import requests" # 缺则: pip install requests +``` + +浏览器功能(登录/抓包)另需 `playwright`、`cloakbrowser`、`chromium`、`xvfb-run`——本机均已装好。 + +## Setup + +无安装步骤。依赖的两个东西: + +1. **仓库路径**:driver 已内置(`PYTHONPATH` 自动指向仓库根)。 +2. **登录 cookie**:`~/.config/hunyuan3dweb/cookies.txt`(已存在,2026-08-15 登录过,当前有效)。过期后用下面"重新登录"一节处理。 + +## Run(agent 路径)——driver.sh + +```bash +.claude/skills/run-hunyuan3dweb/driver.sh verify # 三重自检(最快确认能用) +``` + +| 命令 | 作用 | +|---|---| +| `driver.sh verify` | 环境 + 离线签名 + 在线配额 三重自检 | +| `driver.sh quota` | 查配额,输出 `remainQuota/totalQuota` | +| `driver.sh list` | 作品列表(JSON,含 `totalCount`/`creations`) | +| `driver.sh status ` | 生成状态(json/轮询用 `state` 字段) | +| `driver.sh text ""` | 文生 3D 提交(**消耗配额**,出 4 个) | +| `driver.sh formats ` | 可用下载格式(glb/obj/fbx/stl/usdz/mp4/gif…) | +| `driver.sh download [--format glb] [--output PATH]` | 下载模型到当前目录 | + +其余 API(图生 3D、多视角、动画、贴图、减面)直接 import 客户端调用 +(`api_complete.py` 的 `Hunyuan3DAPIComplete`),10+ 种生成模式同签名同会话。 +本容器内已实测:`quota`/`list`/`status`/`formats`/`download`(2026-08-15,7 个作品齐全); +`text` 只验证到请求构造层(消耗配额,未实测全流程)。 + +**退出码**:`0` 成功 · `1` 环境/其他 · `2` 认证失败(需重新登录)· `3` cookie 缺失。 +收到 2/3 时按下面"重新登录"处理,不要把栈当 bug 报告。 + +典型工作流(文生 3D + 轮询): + +```bash +.claude/skills/run-hunyuan3dweb/driver.sh quota # 先看余额 +.claude/skills/run-hunyuan3dweb/driver.sh text "a ceramic teapot" # → creationsId +.claude/skills/run-hunyuan3dweb/driver.sh status # 轮询到 state=success +.claude/skills/run-hunyuan3dweb/driver.sh download --format glb +``` + +## 重新登录(认证失败时唯一出路) + +收到退出码 2(`"code":"20001"` token 无效 / `"999"` cookie 无用户)时: +**必须由人类用户在真实终端**(不是 Claude 的 `!` 前缀——stdin 非交互,`input()` 会 EOF)运行: + +```bash +PYTHONPATH=/opt/hunyuan3dweb python3 -m hunyuan3dweb.browser.login +``` + +按提示输邮箱 → 收验证码 → 输验证码,登录态自动存回 `cookies.txt`。 +登录完成后浏览器进程**自动退出,无资源残留**(2026-08-15 验证:登录后零残留进程)。 + +## Run(人类路径) + +```bash +PYTHONPATH=/opt/hunyuan3dweb python3 -m hunyuan3dweb.cli quota # 等价 CLI +PYTHONPATH=/opt/hunyuan3dweb python3 -m hunyuan3dweb.cli list +PYTHONPATH=/opt/hunyuan3dweb python3 -m hunyuan3dweb.cli text "a red apple" +``` + +## Test(离线自检) + +```bash +PYTHONPATH=/opt/hunyuan3dweb python3 -m hunyuan3dweb.sign +# 派生密钥: Hf6d6KFB3D ← 输出里有这行即签名算法正确 +``` + +--- + +## Gotchas + +- **`!` 前缀跑登录必 EOF** —— `input()` 在管道 stdin 打开即 EOF(`EOFError: EOF when reading a line`)。登录必须真实终端;agent 只能引导用户去跑。 +- **401 有两种,别混** —— `"code":"20001"`=token 过期(重登);`"code":"999"`=cookie 无用户(重登或检查 cookie 文件)。两者都证明**签名本身是对的**(服务端能分类错误)。 +- **不存在的 creationsId → HTTP 400 空 body**,不是 JSON 错误(2026-08-15 实测)。 +- **`python3 -m hunyuan3dweb.sign` 有 RuntimeWarning**(`'hunyuan3dweb.sign' found in sys.modules...`)——runpy 与 `__init__.py` 重复导入的假警报,无害,输出仍正确。 +- **文生 3D 固定出 4 个模型**(`count=4`),一次消耗 4 次配额;`generate_from_text` 的 `count` 参数会覆盖 UI 行为。 +- **`download` 输出到 CWD**——某次下载 86KB 预览图实测 2–3 秒;GLB 可能几十 MB,注意磁盘和时间。正式大规模跑之前先 `quota` 确认登录态在线。 + +## Troubleshooting + +- **`driver.sh verify` 打印 AUTH_EXPIRED / 退出码 2**:token 过期。让人在真实终端跑 `PYTHONPATH=/opt/hunyuan3dweb python3 -m hunyuan3dweb.browser.login`,成功后再 verify。 +- **`EOFError: EOF when reading a line`**(登录时):stdin 非交互。换真实终端,不要用 `!`。 +- **`requests.exceptions.HTTPError: 401` + 中文消息 'token无效'**:同上,重登。不是代码 bug,别改代码。 +- **cookie 想换账号**:`HUNYUAN3D_COOKIES=/path/to/other/cookies.txt driver.sh quota`。 +- **driver 里 python 找不到模块**:确认 `PYTHONPATH` 含仓库根(driver 会自动设置)。 \ No newline at end of file diff --git a/.claude/skills/run-hunyuan3dweb/driver.sh b/.claude/skills/run-hunyuan3dweb/driver.sh new file mode 100755 index 0000000..507b3cb --- /dev/null +++ b/.claude/skills/run-hunyuan3dweb/driver.sh @@ -0,0 +1,128 @@ +#!/usr/bin/env bash +# 腾讯混元3D Python 客户端 driver +# 从源码直接运行(PYTHONPATH 指向仓库根),无需 pip install。 +# 所有命令都是对 `python3 -m hunyuan3dweb.cli` 的薄封装,加上统一的 +# 认证/错误诊断(401 分类、退出码),方便 agent 自动化判断。 +# +# 退出码: 0=成功 1=环境/其他错误 2=认证失败(需重新登录) 3=cookie 文件缺失 +set -uo pipefail + +# 仓库根 = driver 上三级(.claude/skills/run-hunyuan3dweb/driver.sh) +UNIT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" +export PYTHONPATH="${PYTHONPATH:+$PYTHONPATH:}$UNIT_DIR" + +# cookie 可通过环境变量覆盖(多账号场景) +COOKIE_FILE="${HUNYUAN3D_COOKIES:-$HOME/.config/hunyuan3dweb/cookies.txt}" + +need_cookie() { + if [[ ! -f "$COOKIE_FILE" || ! -s "$COOKIE_FILE" ]]; then + echo "ERR3: cookie 文件缺失或为空: $COOKIE_FILE" >&2 + echo " 首次使用需人工登录: 在真实终端运行下面的命令,按提示输邮箱+验证码" >&2 + echo " PYTHONPATH=$UNIT_DIR python3 -m hunyuan3dweb.browser.login" >&2 + exit 3 + fi +} + +# 从 CLI 输出中诊断认证类错误(ec=2 表示凭证问题,不是代码问题) +diagnose() { + local out="$1" + if grep -q '"code":"20001"' <<<"$out"; then + echo "AUTH_EXPIRED: token 无效/过期 → 需人工重新登录(见下)" >&2 + echo " PYTHONPATH=$UNIT_DIR python3 -m hunyuan3dweb.browser.login" >&2 + return 2 + elif grep -q '"code":"999"' <<<"$out"; then + echo "AUTH_NO_COOKIE: 服务端说 cookie 里没有用户 → 检查 cookie 内容或重新登录" >&2 + return 2 + elif grep -qE '400 Client Error' <<<"$out"; then + echo "BAD_REQUEST: HTTP 400(常见于 creationsId 不存在/无效)" >&2 + return 1 + fi + echo "--- 原始输出尾部 ---" >&2 + tail -5 <<<"$out" >&2 + return 1 +} + +cmd_verify() { + # 1) 依赖检查 + python3 -c "import requests" 2>/dev/null \ + || { echo "ERR1: 缺少 requests,运行 pip install requests" >&2; exit 1; } + # 2) 离线签名自检(不依赖网络/登录) + python3 - <<'PY' +import os, sys +sys.path.insert(0, os.environ["PYTHONPATH"]) +from hunyuan3dweb.sign import derive_key, C, sign +k = derive_key(C) +assert k == "Hf6d6KFB3D", f"派生密钥不符: {k!r}" +s = sign({"a": 1}) +assert len(s["sign"]) == 64 and s["sign"].isalnum(), "签名格式异常" +print(f"sign OK: 密钥={k} 签名={s['sign'][:12]}...") +PY + # 3) 在线配额(认证能力检查) + cmd_quota +} + +cmd_quota() { + need_cookie + local out + out="$(python3 -m hunyuan3dweb.cli quota 2>&1)" || { diagnose "$out"; exit $?; } + echo "$out" +} + +cmd_list() { + need_cookie + local out + out="$(python3 -m hunyuan3dweb.cli list 2>&1)" || { diagnose "$out"; exit $?; } + echo "$out" +} + +cmd_status() { + need_cookie + local out + out="$(python3 -m hunyuan3dweb.cli status "$1" 2>&1)" || { diagnose "$out"; exit $?; } + echo "$out" +} + +# text 在本容器内未跑过完整成功路径(消耗配额,用户当时只授权只读验证)。 +# 其余命令均已实测:quota/list/status/formats/download(2026-08-15)。 +cmd_text() { + need_cookie + python3 -m hunyuan3dweb.cli text "$1" +} + +cmd_formats() { + need_cookie + python3 -m hunyuan3dweb.cli formats "$1" +} + +cmd_download() { + need_cookie + python3 -m hunyuan3dweb.cli download "$@" # 下载到 CWD +} + +usage() { + cat <<'USAGE' +用法: driver.sh [args] + + verify 环境+离线签名+配额 三重自检(最快确认能用) + quota 查询配额(remain/total) + list 作品列表 JSON + status 生成状态 JSON + text "" 文生 3D(提交任务,消耗配额) + formats 列出该创作的可用下载格式 + download [--format glb] [--output PATH] [--converted] + +环境: HUNYUAN3D_COOKIES=custom/path 覆盖默认 cookie 文件 +退出码: 0 成功 | 1 环境/其他 | 2 认证失败(需重登)| 3 cookie 缺失 +USAGE +} + +case "${1:-}" in + verify) shift; cmd_verify ;; + quota) shift; cmd_quota ;; + list) shift; cmd_list ;; + status) shift; cmd_status "${1:?缺少 creationsId}";; + text) shift; cmd_text "${1:?缺少 prompt}";; + formats) shift; cmd_formats "${1:?缺少 creationsId}";; + download) shift; cmd_download "$@" ;; + *) usage; exit ${1:+1};; +esac \ No newline at end of file