Files
AIGame/DGX3D_AI调用指南.md
T

44 KiB
Raw Blame History

LLM3DGraphics · 跨项目 / AI 调用指南

给其他项目、其他开发者、自动化 Agent用:如何把自然语言需求编排成对 LLM3DGraphics HTTP API 的调用,产出图片、Unity 图片素材、网格、(可选)绑骨角色与骨骼动画。

  • 服务默认:http://192.168.130.16:8008
  • OpenAPI:http://192.168.130.16:8008/docs
  • DGX 绑骨/动画规范见 DGX3D生成说明.md;本文偏「怎么编排调用」
  • 引擎可选:dgx(Spark 绑骨+动作)、hunyuan(混元官网网页)
  • 本地图像入口:http://192.168.130.16:8008/#local-images;当前仅保留 Qwen-Image-2.1-Turbo BF16,文字生成、多参考图编辑、批量草稿见 §4.4。

0. 一分钟结论

用户说法(示例) AI 应做的事
「用这张图做一个会动的狼,再给 idle / 跑」 engine=dgx:图 → 绑骨 → 多次 /animate
「官网混元出个模型就行 / 走混元网页」 engine=hunyuan:先确认微信已登录 → 出 model / model_ex(无绑骨、无 animate)
「做一个石灯道具」 优先 dgx + character_type=static;或 hunyuan 只要网格
「做一个士兵,再套走路」 engine=dgx + humanoid → Step2 Kimodo
「写段文字直接出 3D」 先通过 §4.4 本地 Turbo 生成参考图 → 再选 3D 引擎
「文字出图 / 多图生成新图 / 批量草稿」 §4.4 本地 Turbo:提交图片批次 → 轮询 → 下载 PNG / Unity ZIP
「照这个画风换成运动装男孩,再做 3D」 §4.4 上传风格参考图并写清修改要求 → 选定生成图片 → 上传 /api/jobs

硬约束(调用前必读)

  1. 先选引擎(§引擎选择):要绑骨/动作 → 只能 dgx;只要官网质量网格 → 可用 hunyuan。
  2. 无参考图时优先走 POST /api/local-images/jobs 本地 Turbo(§4.4);用户选择云端生图时走 POST /api/image/generate 转接(§4.1),勿直连上游、勿带 Key。
  3. dgx 可驱动角色 = 两步:/api/jobs → /api/jobs/{id}/animate;多动作多次 animate(注意覆盖)。
  4. hunyuan / dgx+static:禁止 /animate(会 422)。
  5. hunyuan 必须当前浏览器客户端已登录混元官网(hunyuan_logged_in);首次登录在客户端页面扫码。
  6. 3D 队列同时 queued+running ≤ 5;本地图像最多排队 4 批、每批 1–16 张。轮询间隔 ≥ 2s;单任务可能数分钟~数十分钟。
  7. Turbo 可与混元共同驻留,图像与 DGX 3D/对比/动作任务仍串行执行。图像队列结束后才能转入 DGX 3D;不要绕过本机调度器直接调用 DGXA 的 8090 worker。

1. 前置:服务与能力探测

GET /api/capabilities

关注字段(名称以实际 JSON 为准):

字段 含义
image_generate_ready 本机生图转接是否可用
hunyuan_logged_in / hunyuan_status 混元官网微信登录态
image_ready 混元网页是否已登录
dgx_ready / dgx.hy3d_ready DGX Spark 图生高模
dgx.tokenrig_ready(或 unirig_ready) 能否绑骨(static / 混元路径不需要)
dgx.unimate_ready 非人形文生动画
Mixamo 数量相关字段 人形动作库是否非空

未就绪时:不要硬调,向用户报告缺哪一段。

本地 Turbo 的能力单独探测,不用 image_generate_ready 判断:

GET /api/local-images/status

检查 connected、ready 和 models.turbo.installed;当前模型 ID 应为 Qwen/Qwen-Image-2.1-Turbo。loaded_model=turbo 表示已加载,busy=true 且 loaded_model=null 时通常正在首次加载,应先等待。co_resident、hy3d_paused、available_gb 用于观察驻留和内存状态。混元因图像模式暂时暂停时,图像队列空闲后先调用 POST /api/local-images/prepare-3d,再重新探测 DGX 能力。

1.1 Windows 跨机器部署:Hunyuan 绿灯、TokenRig/Kimodo 红灯

状态探测在 运行 LLM3D 后端的 Windows 机器与账号中执行,不在打开网页的浏览器机器执行。复制工程和 config.json 不会自动配置该账号的 SSH 别名、密钥授权、SSH Agent 和 known_hosts。

状态灯 当前探测内容
Hunyuan3D HTTP GET dgx.hy3d_url 首页,5秒内状态码小于500算通过;没有执行造型推理
TokenRig SSH 到 dgx.ssh_host,检查 SkinTokens 的入口脚本、可执行Python和两个固定权重文件;远程失败时另检查本机环境
Kimodo SSH 到同一个主机,检查 kimodo_gen、Llama文本编码器目录和LLM2Vec配置;没有执行动作推理

因此模型可以仍在 DGXA 正常安装,却因新 Windows 后端的 SSH 环境不完整而显示红灯。绿灯也不表示权重已加载到 GPU。当前每个远程探测约12秒超时,SSH错误统一折叠为 false,状态缓存20秒;多个SSH失败串行发生时,能力接口可能等待约48秒。

在部署机上,用启动 LLM3D 的同一个账号,从 LLM3DGraphics 目录运行只读自检:

.\.venv\Scripts\python.exe .\deploy\check_dgx_connection.py --output .\outputs\dgx_connection_check.json

脚本:check_dgx_connection.py。它检查账号、SSH解析配置、认证、远端各个文件及混元HTTP连接,不加载模型、不修改密钥或服务,不读取/打印私钥和API Key内容。

报告项 / 错误 排查方向
account 是否确实为运行后端的账号;管理员终端和计划任务/服务账号可能不同
resolved_ssh hostname、user、port、identityfile 是否指向该机可用的连接配置
Could not resolve hostname 当前账号未配置 DGXA 别名,或DNS无法解析
Permission denied (publickey) SSH用户、密钥文件、Agent或DGXA上的公钥授权不匹配
Connection timed out/refused 地址、端口、路由、防火墙、代理或SSH服务问题
Host key verification failed 用该账号交互登录并核对服务器指纹,完成主机身份确认
remote.checks.*.ok=false SSH已连通;按报告中的具体路径检查文件或执行权限

若采用 dgx.ssh_host=DGXA,该Windows账号的 %USERPROFILE%\.ssh\config 必须有对应连接设置;使用新机器自己的已授权密钥,例如:

Host DGXA
    HostName <DGXA实际可达地址>
    User spark
    Port 22
    IdentityFile ~/.ssh/id_ed25519

IdentityFile 以部署机实际密钥为准,DGXA需已授权对应公钥。先确认该账号执行 ssh -o BatchMode=yes DGXA "echo READY" 成功,再重启/刷新后端状态。私钥不放进工程或说明文件。部署机访问混元HTTP成功,不代表它能用SSH访问DGXA。


2. 引擎选择

POST /api/jobs 的 engine 二选一:

engine 高模从哪来 绑骨 / 动作 典型用途
dgx Spark Hunyuan3D 2.1 TokenRig + /animate(或 static 跳过) 角色可驱动、要动作、DGX 静物
hunyuan 腾讯混元3D官方网页(Playwright 自动化) 无 只要官网网格质量;不依赖 Spark

决策提示:

  • 用户明确说「混元官网 / 混元网页 / 微信混元」→ hunyuan
  • 用户要「会动 / 绑骨 / Mixamo / UniMate」→ 必须 dgx
  • 只要静物网格且 DGX 忙/未就绪 → 可降级 hunyuan
  • character_type 仅 engine=dgx 生效;混元任务里该字段会被忽略

3. 混元3D 官方网页流程(engine=hunyuan)

走 3d.hunyuan.tencent.com:服务端用 Playwright(Edge)提交图片生成;微信登录二维码显示在发起登录的客户端页面,由用户用自己的微信扫码。登录态按浏览器客户端隔离。

3.1 登录(客户端页面扫码,会话按客户端复用)

GET  /api/hunyuan/status          # logged_in?
POST /api/hunyuan/login           # 服务端启动登录;客户端页面显示二维码(约 3 分钟内)
GET  /api/hunyuan/login/qr        # 读取当前客户端的二维码图片
POST /api/hunyuan/logout          # 清除当前客户端会话

后端仍在服务机运行 Playwright,但不会要求用户去服务机窗口扫码。扫码二维码由客户端页面请求并显示。每个浏览器客户端通过独立的 HttpOnly Cookie 标识登录会话,服务端分别保存到 data/hunyuan/clients/<客户端标识>/storage_state.json。同一浏览器刷新后会复用登录态;不同设备、浏览器或无痕窗口需要分别扫码。生成任务使用提交请求的客户端登录态,退出登录只清除该客户端的会话。旧版共享文件 data/hunyuan/storage_state.json 不再使用。

Agent 侧:

  1. 读 capabilities.hunyuan_logged_in(或 /api/hunyuan/status)
  2. 若为 false:让用户在要使用的浏览器客户端打开工作台并点击「微信登录」,在该页面显示的二维码上用自己的微信扫码;轮询该客户端的 status 至 logged_in。不要让用户去服务机窗口扫码。
  3. 未登录时提交 engine=hunyuan 会 401

直接用 HTTP 客户端接入时,必须在 status、login、login/qr 和生成请求之间保留同一个服务端下发的 HttpOnly Cookie;否则请求会被识别为不同客户端。需要把二维码安全地呈现给真人扫码,单纯的无状态 curl/Agent 调用不能代替用户完成登录。

3.2 生成任务

POST /api/jobs
Content-Type: multipart/form-data

engine=hunyuan
mode=image
image=@ref.png
source_faces=50000
target_faces=5000
texture_size=1024
output_format=glb
字段 说明
mode 仅 image(混元网页引擎不接受 text)
source_faces 官网高模档:5000(5k)/ 20000(20k)/ 50000(50k)/ 500000 / 1000000;常用 50000。5k 与 20k 页面无按钮,提交时改写 faceCount
target_faces 本机低模目标;<500000 且低于高模面数时触发 Blender 烘培 → model_ex
texture_size 低模烘培贴图:512 / 1024 / 2048
output_format glb 或 fbx(fbx 时额外打 ZIP)
character_type 无效(不要指望混元出绑骨)

轮询 GET /api/jobs/{id} → status=completed。

3.3 产物(网格 only)

下载键 含义
glb / fbx 官网高模
glb_ex / fbx_ex 本机低模+烘培(若触发)
preview_url 网页预览

不要调用 /animate。若后续仍要动作:把混元网格当作参考图/资产另开 engine=dgx 流程(当前无「混元网格直接喂 TokenRig」的一键接口;需要绑骨请直接用 DGX 图生)。

3.4 耗时与依赖

  • 官网生成常见数分钟~约 20 分钟;另加本机低模烘培时间
  • 依赖:服务端 Playwright + Edge 通道、当前客户端有效的微信登录态、可选 Blender(低模/FBX)
  • 与 DGX 共用同一任务队列(≤5)

3.5 curl 示例

BASE=http://192.168.130.16:8008

# 确认登录
curl -s "$BASE/api/hunyuan/status"

# 未登录时:先在工作台当前客户端点击「微信登录」,再由真人扫描页面上的二维码。
# 纯 curl 示例需要持久化 Cookie,并自行将二维码呈现给真人;不要只靠无状态 curl 完成扫码登录。
# curl -s -X POST "$BASE/api/hunyuan/login"

curl -s -X POST "$BASE/api/jobs"   -F engine=hunyuan -F mode=image   -F source_faces=50000 -F target_faces=5000 -F texture_size=1024   -F image=@ref.png

4. 生成参考图:本地 Turbo 与云端转接

DGX 不能直接文生 3D。用户只给文字外貌时,先通过 §4.4 本地 Turbo 生成图片,再交给 §6 的 DGX 编排剧本。用户选择云端生图时使用下述 §4.1–4.3 转接接口;两条生图路径都通过 LLM3DGraphics 调度。

角色 说明
外部项目 / Agent 云端路径只调 POST /api/image/generate,不要拿上游 Key、不要直连 grsai;本地路径见 §4.4
本机服务 用 config.json → dgx.grsai(或环境变量 GRSAI_API_KEY)调上游,并把结果缓存到本机
运维配置参考 生成路径.md、HelpDoc/gpt-image_doc.md(仅服务器侧)

探测:GET /api/capabilities → image_generate_ready == true。

4.1 转接接口

POST {BASE}/api/image/generate
Content-Type: application/json

{
  "prompt": "一只棕色四足狼,全身正面三视图感,纯白背景,游戏概念设定图,无文字水印",
  "aspect_ratio": "1:1",
  "quality": "auto",
  "images": []
}
字段 必填 说明
prompt 是 外貌描述,≤4000 字
aspect_ratio 否 默认用服务端 dgx.grsai.aspect_ratio(常见 1:1)
quality 否 默认 auto
images 否 图生图参考:URL 或 data URL / base64,最多 4 张

成功响应(不含上游 URL / API Key):

{
  "id": "a1b2c3...",
  "status": "succeeded",
  "url": "/api/image/a1b2c3...",
  "content_type": "image/png",
  "bytes": 123456,
  "model": "gpt-image-2.5",
  "aspect_ratio": "1:1"
}

下载图片:

GET {BASE}/api/image/{id}

将该文件作为后续 POST /api/jobs 的 image 上传即可。

给 DGX 的构图建议(提高绑骨成功率):

  • 主体居中、轮廓清晰;尽量白底或简单底
  • 全身可见;角色类避免极端透视 / 大面积遮挡
  • 提示词写清物种、体态、材质;少杂乱场景文字

4.2 curl / Python 示例(外部只打本机)

BASE=http://192.168.130.16:8008

curl -s -X POST "$BASE/api/image/generate" \
  -H 'Content-Type: application/json' \
  -d '{
    "prompt": "石质庭院灯笼,白色背景,产品设定图",
    "aspect_ratio": "1:1"
  }'

# 记下返回的 id / url,再下载:
curl -L -o prop.png "$BASE/api/image/<id>"
import requests
from pathlib import Path

BASE = "http://192.168.130.16:8008"

def text_to_image(prompt: str, out_path: Path, aspect_ratio: str = "1:1") -> Path:
    r = requests.post(
        f"{BASE}/api/image/generate",
        json={"prompt": prompt, "aspect_ratio": aspect_ratio},
        timeout=300,
    )
    r.raise_for_status()
    data = r.json()
    if data.get("status") != "succeeded" or not data.get("url"):
        raise RuntimeError(data)
    url = data["url"]
    if url.startswith("/"):
        url = BASE + url
    img = requests.get(url, timeout=120)
    img.raise_for_status()
    out_path.write_bytes(img.content)
    return out_path

4.3 服务器侧配置(仅运维,不对外部暴露)

在本机 LLM3DGraphics/config.json(已 gitignore)中配置,例如:

"dgx": {
  "grsai": {
    "api_key": "<密钥,见生成路径.md>",
    "model": "gpt-image-2.5",
    "bases": ["https://grsai.dakka.com.cn", "https://grsaiapi.com"],
    "aspect_ratio": "1:1",
    "quality": "auto"
  }
}

也可用环境变量 GRSAI_API_KEY / GPT_IMAGE_API_KEY。外部调用方无需知道这些。

4.4 本地图像生成:Qwen-Image-2.1-Turbo BF16(当前推荐流程)

更新于 2026-10-13。当前只安装 Qwen/Qwen-Image-2.1-Turbo,原生 8 步采样、CFG=1,支持文生图、最多 10 张参考图编辑和 RGBA 输出。Qwen-Image-2512、Qwen-Image-2.1 标准版及专用缓存已移除;不要提交 model=quality 或重新安装退役模型。

网页入口:{BASE}/#local-images。图片和任务记录保存在 Windows LLM3DGraphics/data/_local_images/<批次ID>/,推理在 DGXA 的 /home/spark/llm3d-local-images/ 中运行。调用方只访问 Windows LLM3DGraphics API,本地路径不需要云端 Key。

4.4.1 页面操作与提示词方法

  1. 打开「本地图像生成」,确认 Turbo 已安装并完成首次加载。
  2. 选择素材用途,填写画面描述。纯文字生成不上传参考图;参考编辑上传实际图片文件,按输入顺序写明“图1提供造型、图2提供配色、图3提供风格”。
  3. 先用 512–1024 分辨率、4–8 张草稿选方向;固定 seed 便于迭代,每张图的 seed 自动递增。
  4. 点击“作为参考继续编辑”将选中的生成图作为新参考,提高分辨率并描述局部修改;“复用参数”可恢复原批次的提示词、参考图、用途、尺寸和种子。
  5. 需要 3D 时选择一张轮廓清晰的完整主体图,点击“送到 DGX 3D”,再按 §6 选择 character_type 并提交 3D。这个按钮负责填入图片,不会直接开始 3D 生成。
  6. 需要 2D 素材时勾选图片并导出 Unity ZIP,见 §4.4.4。

提示词按“参考图职责 → 主体 → 画风/摄影 → 姿势与构图 → 背景 → 保持项与修改项”组织。负面限制也写进主提示词,negative_prompt 留空。

需求 提示词重点与用途
换角色、保留参考画风 “保留图1的画风与构图,将角色改为……;重新绘制脸、头发、衣服和年龄特征。”明确哪些保持、哪些改变
人形 3D 参考图 “正面全身 T-pose,双臂水平伸直,头、手指、鞋完整入画,四周留白,纯白背景,无道具和遮挡。”严格正面姿势可用 sprite 并明确完整角色;concept 会追加三分之四视角要求
真人街角照片 “真实街头摄影,自然儿童/成人比例,日常便服,自然站姿,街角建筑和路面,真实肤色与布料纹理。”选择 background,避免追加白底设定图要求
透明图标/精灵 选择 sprite、transparent=true,说明独立主体、透明背景、轮廓清楚;下载后检查实际 Alpha

后端会追加所选用途的提示词,因此用途必须与目标一致。白底不是透明背景;页面显示的“含透明像素”才来自实际 Alpha 检查。街角场景照片适合作为图片素材或视觉参考;要生成独立 3D 角色时另生成简单背景、完整主体的参考图。

4.4.2 图片任务接口与参数

POST {BASE}/api/local-images/jobs
Content-Type: multipart/form-data

model=turbo
profile=sprite
prompt=保留图1的二维手绘风格,改为10岁运动装小男孩,正面全身T-pose,双手和鞋完整入画,纯白背景,无文字
width=1024
height=1504
count=4
seed=314159
transparent=false
negative_prompt=
images=@style_reference.png
字段 默认 / 范围 说明
model turbo,唯一支持值 对应 Qwen/Qwen-Image-2.1-Turbo BF16;步数和采样由 worker 固定,不传 quality、CFG 或步数
prompt 必填,1–4000 字 画面与编辑要求;限制条件也写在这里
profile 默认 concept concept:完整 3D 主体、三分之四视角、纯色背景;sprite:独立精灵/UI、居中留白;albedo:平铺 base color;background:场景背景
width / height 默认 1024;256–2048 都必须为 32 的倍数;人物竖图可用 1024×1504
count 默认 4;1–16 一个批次逐张生成;最多同时排队 4 批
seed 默认 -1;-1 或 0–4294967280 -1 随机起点;第 i 张使用起点+i,i 从 0 开始
transparent 默认 false true 追加透明 RGBA 要求,仍需检查实际 Alpha
negative_prompt 空字符串 CFG=1 不使用负面提示词;非空返回 422
images 可省略,最多 10 个同名文件字段 传 PNG/JPEG/WebP 实际文件,不传 URL/base64 字符串;每张 ≤12MB、≤1600万像素,归一化最长边1536并保留 Alpha

纯文生图省略 images 即可;无文件时也支持表单编码,不是 JSON 请求体。提交返回 202 和图片批次 id,轮询 GET /api/local-images/jobs/{id} 至 completed / failed。该 id 与之后创建的 3D job ID 不同。

结果从 images 数组取,不从 3D 的 downloads 取:每项含 index、实际 seed、has_alpha、url。PNG 路径为 /api/local-images/jobs/{id}/images/{index};参考图路径为 /api/local-images/jobs/{id}/references/{index}。failed 批次也可能已有可下载图片,应保存结果和错误记录。

4.4.3 curl 与 Python:生成、下载、转入 3D

BASE=http://192.168.130.16:8008

curl -s "$BASE/api/local-images/status"

# 多参考图编辑;纯文生图时省略两个 images 字段
curl -s -X POST "$BASE/api/local-images/jobs" \
  -F model=turbo -F profile=sprite \
  -F 'prompt=图1提供角色造型,图2提供配色。生成完整角色的正面全身T-pose,纯白背景,无文字。' \
  -F width=1024 -F height=1504 -F count=4 -F seed=314159 \
  -F transparent=false \
  -F 'images=@shape.png' -F 'images=@palette.png'

# IMG_JOB 替换为图片批次 id;轮询间隔至少2秒
curl -s "$BASE/api/local-images/jobs/$IMG_JOB"
curl -fL -o selected.png "$BASE/api/local-images/jobs/$IMG_JOB/images/0"

# 所有图像批次结束后准备DGX 3D;返回409时等待,不绕过保护
curl -s -X POST "$BASE/api/local-images/prepare-3d"
curl -s -X POST "$BASE/api/jobs" \
  -F engine=dgx -F mode=image -F character_type=humanoid \
  -F target_faces=5000 -F texture_size=1024 -F output_format=glb \
  -F 'image=@selected.png'

Windows PowerShell 使用 curl.exe 或下述 Python 示例,避免将 PowerShell 的 curl 别名当作上述 Bash 命令。

import json
import mimetypes
import time
from contextlib import ExitStack
from pathlib import Path

import requests

BASE = "http://192.168.130.16:8008"


def local_images(prompt, out_dir, references=(), *, profile="sprite",
                 width=1024, height=1504, count=4, seed=314159,
                 transparent=False, timeout=1800):
    with requests.Session() as session:
        response = session.get(f"{BASE}/api/local-images/status", timeout=20)
        response.raise_for_status()
        state = response.json()
        if not (state.get("connected") and state.get("ready")
                and state.get("models", {}).get("turbo", {}).get("installed")):
            raise RuntimeError(state)
        load_deadline = time.monotonic() + timeout
        while state.get("busy") and not state.get("loaded_model"):
            if time.monotonic() > load_deadline:
                raise TimeoutError("Turbo 尚未完成首次加载")
            time.sleep(2)
            response = session.get(f"{BASE}/api/local-images/status", timeout=20)
            response.raise_for_status()
            state = response.json()
        data = dict(model="turbo", prompt=prompt, profile=profile,
                    width=width, height=height, count=count, seed=seed,
                    transparent=str(transparent).lower(), negative_prompt="")
        with ExitStack() as stack:
            files = []
            for item in references:
                path = Path(item)
                mime = mimetypes.guess_type(path.name)[0] or "application/octet-stream"
                files.append(("images", (path.name, stack.enter_context(path.open("rb")), mime)))
            response = session.post(f"{BASE}/api/local-images/jobs",
                                    data=data, files=files or None, timeout=30)
        response.raise_for_status()
        job = response.json()
        folder = Path(out_dir) / job["id"]
        folder.mkdir(parents=True, exist_ok=True)
        record = folder / "job.json"
        deadline = time.monotonic() + timeout
        while True:
            record.write_text(json.dumps(job, ensure_ascii=False, indent=2), encoding="utf-8")
            if job["status"] in ("completed", "failed"):
                break
            if time.monotonic() > deadline:
                raise TimeoutError(f"图片任务仍在运行,记录见 {record}")
            time.sleep(2)
            response = session.get(f"{BASE}/api/local-images/jobs/{job['id']}", timeout=30)
            response.raise_for_status()
            job = response.json()
        paths = []
        for image in job["images"]:
            response = session.get(BASE + image["url"], timeout=120)
            response.raise_for_status()
            path = folder / f"image_{image['index']}_seed_{image['seed']}.png"
            path.write_bytes(response.content)
            paths.append(path)
        if job["status"] != "completed":
            raise RuntimeError(f"{job.get('error')};已保存 {len(paths)} 张图片,记录见 {record}")
        return job, paths


# 多参考编辑:references=["style.png", "colors.png"];文生图不传 references。
# image_job, paths = local_images(
#     "蓝色运动装小男孩,二维手绘,正面全身T-pose,纯白背景,无文字",
#     "generated", references=["style.png"], count=4)
# 人工或上游选定 paths 中一张,再交给 §9.2 create_rigged。
# 转入DGX前:requests.post(f"{BASE}/api/local-images/prepare-3d", timeout=360).raise_for_status()
# rig_job = create_rigged(paths[0], "humanoid")

图片下载后逐张检查主体、年龄/物种、姿势、手脚完整度、背景和伪影。批量固定种子是便于复现,不保证每张满足全部要求。需要精确 #FFFFFF 背景时另做背景清理,并保留原始输出。真人测试使用 profile=background,例如“约10岁小女孩,日常便服,自然站姿,真实街角建筑与人行道,午后自然光,真实肤色和服装纹理”。

4.4.4 Unity 导出与 3D 转接

下载选中图片和参数:GET /api/local-images/jobs/{id}/unity?selected=0,2。selected 是以逗号分隔的图片索引;省略时导出该批次全部已生成图片。

ZIP 内含 Assets/LLM3DGenerated/<批次ID>/ 下的 PNG、参考图和 manifest.json,以及 Assets/Editor/LLM3DImageImporter.cs。将 Assets 合并到 Unity 工程,保留目录结构:

用途 Unity 导入设置
sprite Sprite / Single,sRGB,Clamp,不生成 Mipmap,PPU=100,保留 Alpha
albedo Default,sRGB,Repeat,生成 Mipmap;检查平铺接缝
concept / background Default,sRGB,Clamp,不生成 Mipmap,Max Size 2048

若导入顺序导致设置尚未应用,选中生成图片后执行 Assets > LLM3D > Apply image import settings。这是 ZIP 素材包,不是 .unitypackage;生成色彩图不是完整 PBR,也不是自动切片的 Sprite Sheet。3D 贴图继续走现有 UV、烘焙和 PBR 流程。

转入 3D 必须下载 PNG 后作为 /api/jobs 的 image 文件上传;图片批次 id 不能替代 3D job id。prepare-3d 只检查/恢复资源,不创建 3D 任务;§6 的建模、绑骨和动作步骤照常执行。

4.4.5 共同驻留、内存兜底与实测耗时

当前配置为 auto_switch=true、co_resident=true。用户级服务 llm3d-qwen.service 启动时在后台预加载 Turbo;已有工作忙碌时跳过预加载。Turbo GPU 常驻约 32GiB。共同驻留不等于并行生成:混元、ComfyUI 和本机图像队列均通过预约与队列保护串行使用;图像批次结束后释放预约。

场景 当前策略
图像生成,Turbo 已加载 可用内存至少 24GiB 时保留混元;不足时释放 ComfyUI 缓存并暂停本流程拥有的混元服务
首次加载 Turbo 共享模式要求可用内存至少为 Turbo 权重大小 + 12GiB
准备 DGX 3D,混元已运行 可用内存至少 32GiB 时保留 Turbo;不足则先释放 Turbo
需要启动被暂停的混元 至少 72GiB 可用内存才同时保留 Turbo,否则先释放 Turbo
3D/动作加载期间出现内存压力 每秒检查;可用内存低于16GiB且 Turbo 空闲、无图像预约时自动释放 Turbo

调用方通过 POST /api/local-images/prepare-3d 让调度器决定,响应 images_retained=true 表示本次准备保留了 Turbo。需要手动释放时,在图像队列空闲后调用 POST /api/local-images/unload。不要停止其他用户任务、手动操作 Docker 或绕过 8090 的资源保护。

2026-10-13 的实测(不是固定 SLA):

测试 耗时口径
512×512,多参考透明图标 8步去噪约6–7秒/张,不含加载和编码/解码
1024×1504,全身角色参考图编辑 8步去噪约21秒/张
1024×1504,真人街角文生图 8步去噪约18秒;该次含换模加载总耗时约226秒
Turbo 已加载、与混元共同驻留,连续两张512×512文生图 提交至保存合计约8.2秒,无参考图
同时保留 Turbo,混元造型+贴图 128抽取分辨率、静态分支约158秒,40,000面带贴图GLB;采样最低可用内存约31.9GiB

首次加载可能需要数分钟;参考图数量、提示词长度、分辨率和场景都会改变耗时。上述3D测试没有调用 TokenRig/UniMate,不能据此保证所有动作模型或最高分辨率都能同时驻留,它们仍沿用按需加载。

详细部署、服务维护和验证说明见 本地图像生成与 Unity 素材流程;本次证据见 常驻验证说明。服务机维护脚本在 LLM3DGraphics/deploy/local_images/,运行记录为 DGXA 的 worker.log;维护需等待相关队列空闲。Turbo 使用研究/评估许可,许可链接及商业使用约束见上述模型说明。


5. 意图 → 参数映射(给 Agent 的决策表)

从用户描述里抽出:asset_kind、character_type、reference_image、motions[]。

5.1 资产类型

判断 character_type 后续
道具 / 建筑 / 静物 / 「不要骨骼」 static 只 Step1,下载 glb / glb_ex
标准双足人、士兵、NPC 人型 humanoid Step1 + Step2(Kimodo 文生)
四足、怪、非标拓扑生物 non_humanoid Step1 + Step2(UniMate 文生)

不确定时:有四肢且明显非人 → non_humanoid;明确是人 → humanoid;无生命 / 场景件 → static。

5.2 参考图从哪来

情况 做法
用户已给图 直接作 POST /api/jobs 的 image
用户只有文字外貌 §4.4 本地 Turbo → 选图 → 再选 dgx / hunyuan;选择云端时用 §4.1
用户给多张风格/造型参考 §4.4 按顺序上传 images,描述各图职责 → 选图 → 上传到 3D
只要图片、图标或场景背景 §4.4 → PNG / Unity ZIP,流程在图片阶段结束
既要外貌又要动作 §4.4 文生图 → 必须 engine=dgx → Step1 → Step2
明确要混元官网质量、不要骨骼 §4(如需)→ engine=hunyuan(§3)

5.3 动作列表

  • 用户说「idle、跑、跳」→ 拆成 motions = ["idle 待机", "四足原地跑步", "原地跳跃"](示例),每个一条 motion_prompt。
  • 人形:交给 Kimodo,写清动作(走、跑、挥手等)。
  • 非人形:写清主体与动作,可加「原地」「可循环」;中文即可(服务端会规范成英文)。

6. 标准编排剧本(主要为 engine=dgx)

剧本 A — 角色模型 + 若干动作(最常见)

输入: reference_image, character_type, motions[1..N], (可选) target_faces
输出: rigged 角色 + 每个动作对应的 animated 文件(注意覆盖问题)
flowchart LR
  A[参考图] --> B["POST /api/jobs<br/>engine=dgx"]
  B --> C{轮询 completed<br/>ready_for_motion}
  C --> D["POST .../animate<br/>motion_prompt_1"]
  D --> E[下载 animated.*]
  E --> F["animate motion_2 ..."]

Step 1

POST /api/jobs
Content-Type: multipart/form-data

engine=dgx
mode=image
character_type=non_humanoid   # 或 humanoid
output_format=glb             # Unity 需要网格 FBX 包时用 fbx
target_faces=5000             # 游戏向低模;只要高模可调极大面数跳过减面
texture_size=1024
image=@character.png

响应 202 → 记下 id。轮询:

GET /api/jobs/{id}

直到 status == "completed" 且 ready_for_motion == true。

推荐下载(角色):

用途 downloads 键 / 路径
非人形 Unity 角色 rigged_fbx(ZIP,内含 model.fbx)或 rigged_glb
人形 mixamo_glb / 对应 mixamo FBX
网页预览 preview_url

Step 2(每个动作一次)

POST /api/jobs/{id}/animate
Content-Type: multipart/form-data

motion_prompt=四足动物原地跑步,可循环

再轮询至 completed,下载:

用途 键
Unity 动画(骨架+动画,无角色网格) animated_fbx / animated_glb
带皮预览(可选) anim_preview_url

多动作注意:服务端同一 job 目录里 animated.glb / animated.fbx 会被覆盖。Agent 应:

  1. 每个动作完成后立刻下载并重命名保存(如 {job_id}_run.fbx);或
  2. 告知用户「当前接口一次只保留最新动画」,由上游自行归档。

剧本 B — 静态物体(道具)

POST /api/jobs
engine=dgx
mode=image
character_type=static
target_faces=20000
image=@prop.png

完成标志:status=completed,ready_for_motion=false,有 downloads.glb(及可选 glb_ex)。
禁止调用 /animate。

剧本 C — 「一句话」端到端(文生图 + 角色 + 动作)

伪代码(给 Agent / 编排层):

parse(user_text) -> {
  appearance_prompt,   # 外貌,给文生图
  character_type,      # static | humanoid | non_humanoid
  motions[]            # 可为空
}

image_job, image_paths = local_images(appearance_prompt, "generated")  # §4.4函数已轮询并下载
image = select_image(image_paths)  # 从保存的PNG中选一张;底层下载地址为images[].url
wait_until_all_image_batches_idle()
POST /api/local-images/prepare-3d     # 内存允许时保留Turbo,否则自动切换
# 用户选择云端时,上述生图步骤改用 §4.1 POST /api/image/generate

job = POST /api/jobs (engine=dgx, image=image, character_type=...)
wait_until(job, completed)

if character_type == static:
  return download(job, ["glb", "glb_ex"])

assert job.ready_for_motion
assets = { "rig": download(job, ["rigged_fbx", "rigged_glb"]) }

for m in motions:
  POST /api/jobs/{id}/animate (motion_prompt=m)
  wait_until(job, completed)
  assets[m] = download(job, ["animated_fbx", "animated_glb"])  # 立刻另存

return assets

剧本 D — 只要模型、稍后再加动作

  1. 只跑 Step1(engine=dgx),把 job_id 存进你们的数据库。
  2. 之后任意时刻对同一 job_id 调 /animate(任务须已 completed 且仍有绑骨文件)。

剧本 E — 混元官网只要网格

确认 hunyuan_logged_in
→(可选)§4 文生图
→ POST /api/jobs engine=hunyuan
→ 下载 glb / glb_ex
→ 禁止 animate

细节见 §3。


7. 轮询与状态机

status 含义 Agent 行为
queued / running 进行中 读 stage、progress 展示;继续轮询
completed 成功 读 downloads / ready_for_motion
failed 失败 拉 GET /api/jobs/{id}/log;部分文件可能仍可下

建议:sleep(2~5s);Step1(含 HY3D+TokenRig)常 5–20+ 分钟;UniMate 动画常 10–40+ 分钟。设超时并向上游报 stage。

本地图像批次也使用 queued/running/completed/failed,但轮询路径是 /api/local-images/jobs/{id},输出读取 images[].url。即使 failed 也保存已完成图片和 error;超时只停止调用方等待,不会取消服务端任务,不要立即重复提交。转入 DGX 前,等待所有图像批次空闲;prepare-3d 返回409时继续等待。


8. 下载键速查

相对路径:GET /api/jobs/{id}/files/{format}(或直接用响应里的 downloads.* URL)。

format 内容 典型消费者
glb 高模 预览 / 静态
glb_ex 低模+烘培 游戏 / 静态低模
rigged_glb 绑骨+蒙皮 非人形预览 / 再动画
rigged_fbx ZIP:model.fbx+贴图 Unity 角色
mixamo_glb 人形可驱动 人形再动画
animated_glb / animated_fbx 骨架+动画(精简) Unity Animator
(anim_preview_url) 蒙皮动画预览 仅预览,勿当生产动画源

Unity 非人形:角色用 rigged_fbx 内 model.fbx,动画用精简 animated.fbx,骨架路径对齐 Armature/bone_*。细节见 DGX3D生成说明.md §5。


9. 调用示例

9.1 curl(DGX,已有参考图)

BASE=http://192.168.130.16:8008

# Step 1
curl -s -X POST "$BASE/api/jobs" \
  -F engine=dgx -F mode=image \
  -F character_type=non_humanoid \
  -F target_faces=5000 -F texture_size=1024 \
  -F image=@./wolf.png

# 轮询(把 JOB 换成返回的 id)
curl -s "$BASE/api/jobs/$JOB"

# Step 2
curl -s -X POST "$BASE/api/jobs/$JOB/animate" \
  -F "motion_prompt=四足动物原地跑步,可循环"

# 下载
curl -L -o wolf_rig.zip "$BASE/api/jobs/$JOB/files/rigged_fbx"
curl -L -o wolf_run.fbx "$BASE/api/jobs/$JOB/files/animated_fbx"

9.2 Python(文生图 + DGX 最小编排)

import time, requests
from pathlib import Path

# 本地生图函数 local_images 见 §4.4.3;云端函数 text_to_image 见 §4.2。
BASE = "http://192.168.130.16:8008"

def wait_job(job_id, timeout=7200):
    t0 = time.time()
    while time.time() - t0 < timeout:
        j = requests.get(f"{BASE}/api/jobs/{job_id}").json()
        if j["status"] in ("completed", "failed"):
            return j
        time.sleep(3)
    raise TimeoutError(job_id)

def create_rigged(image_path, character_type="non_humanoid"):
    with open(image_path, "rb") as f:
        r = requests.post(
            f"{BASE}/api/jobs",
            files={"image": f},
            data={
                "engine": "dgx",
                "mode": "image",
                "character_type": character_type,
                "target_faces": "5000",
                "texture_size": "1024",
                "output_format": "glb",
            },
        )
    r.raise_for_status()
    job_id = r.json()["id"]
    job = wait_job(job_id)
    if job["status"] != "completed" or not job.get("ready_for_motion"):
        raise RuntimeError(job.get("error") or job)
    return job

def animate_and_save(job_id, motion_prompt, out_fbx):
    r = requests.post(
        f"{BASE}/api/jobs/{job_id}/animate",
        data={"motion_prompt": motion_prompt},
    )
    r.raise_for_status()
    job = wait_job(job_id)
    if job["status"] != "completed":
        raise RuntimeError(job.get("error") or job)
    url = job["downloads"]["animated_fbx"]
    if url.startswith("/"):
        url = BASE + url
    out_fbx.write_bytes(requests.get(url).content)
    return job

# 示例:文字外貌 → 图 → 角色 → 两个动作
# image_job, images = local_images("棕色四足狼,完整主体,白底设定图", "generated", profile="concept", count=4)
# 选定 images 中一张;全部图像批次空闲后:
# requests.post(f"{BASE}/api/local-images/prepare-3d", timeout=360).raise_for_status()
# job = create_rigged(images[0], "non_humanoid")
# animate_and_save(job["id"], "四足待机,轻微呼吸", Path("idle.fbx"))
# animate_and_save(job["id"], "四足动物原地跑步,可循环", Path("run.fbx"))

10. 给 AI Agent 的系统提示词片段(可复制)

可把下面段落贴进你们项目的 Agent system prompt / skill:

你通过 HTTP 调用本机 LLM3DGraphics(BASE 见调用指南顶部)生成 3D。

规则:
- 先选 engine:要绑骨/动作 → dgx;用户要混元官网网页 → hunyuan。
- 图片生成优先使用本地Turbo:GET {BASE}/api/local-images/status,确认connected/ready/models.turbo.installed。
  POST {BASE}/api/local-images/jobs,model=turbo,表单请求;多参考图用按顺序重复的images文件字段(最多10张)。
  宽高256–2048且为32倍数;count=1–16;negative_prompt留空,把限制写进prompt;不使用已退役的quality/2512模型。
  轮询图片批次至completed,读取images[].url并保存PNG;只要2D素材时可导出unity ZIP。
  按目标选择profile:3D主体concept,严格正面角色可用sprite并说明完整角色,真实街景background,平铺颜色albedo。
  无参考图时省略images;用户选择云端生图时改用POST {BASE}/api/image/generate,再GET返回url。
  所有生图请求通过本机服务;禁止直连上游、传播API Key或直接调用DGXA的8090 worker绕过调度。
- hunyuan:先确认当前客户端的 hunyuan_logged_in;否则让用户在工作台当前客户端点击「微信登录」并扫描页面二维码。直接 HTTP 接入须保留同一 HttpOnly Cookie,并把二维码呈现给真人。
  提交 engine=hunyuan, mode=image;只要 model/model_ex;禁止 /animate。
- dgx 角色:POST /api/jobs → ready_for_motion → POST .../animate;多动作多次 animate 并立刻下载。
- dgx 静物:character_type=static,禁止 animate。
- character_type 仅对 dgx 有效:人→humanoid;四足/怪→non_humanoid;静物→static。
- 先 GET /api/capabilities,缺能力则说明,不要硬调。
- 图片与DGX 3D/对比/动作串行:等待全部图片批次结束,POST /api/local-images/prepare-3d后再提交DGX。
  共同驻留由服务端决定,内存不足会释放Turbo;不要假设所有模型或所有分辨率都能一起驻留。
- 不要假设文生 3D;不要走已废弃 TopoCap/GIF 路径。
- Unity(dgx):角色 rigged_fbx,动画 animated_fbx。

详细:DGX3D_AI调用指南.md;DGX 深度规范:DGX3D生成说明.md。

11. 错误与排错(调用侧)

现象 处理
422「静态物体…不生成动作」 用错类型;静态只下网格
422「请先完成角色绑骨」 Step1 未成功或类型不对
503 UniMate / Kimodo 能力未就绪;人形要 Kimodo,其他类型要 UniMate
409 任务仍在处理 等 completed 再 animate
429 队列已满 退避重试
failed GET /api/jobs/{id}/log;规范文档 Checklist 日志顺序
503 生图转接未配置 运维在本机 config.json 配 dgx.grsai.api_key
502 生图转接失败 改写 prompt;运维查上游 / Key;外部仍勿直连 grsai
422 本地图像模型/尺寸/数量/参考图无效 仅 model=turbo;宽高为32倍数;count≤16;images≤10;negative_prompt为空
409 本地图像与 DGX 任务冲突 / 正在恢复3D 等待已有任务结束或恢复完成,再提交;勿停掉其他任务
429 本地图像队列已满 图像队列最多4批,退避后重试,不反复创建同一批次
本地图像状态未连接或模型未安装 检查 /api/local-images/status;服务机运维检查 llm3d-qwen.service 与 worker.log
本地图像批次 failed,仍有 images 保存已生成PNG与job.json;修正错误后按需要提交新批次
本地首次加载较慢 / 内存不足 查看busy/loaded_model/available_gb,等待预加载或让调度器执行内存兜底;勿自行改BF16精度
401 请先微信登录混元3D 在发起请求的客户端工作台点击「微信登录」并扫码;确认 status 与任务请求使用同一客户端 Cookie;或改用 dgx
422 混元仅支持图片 engine=hunyuan 时 mode 必须为 image
422 仅 DGX 支持动作 对 hunyuan 任务误调了 /animate

跨域:浏览器页面直连时服务有 Origin 限制;服务端 / Agent / curl 调 API 不受网页同源限制影响。


12. 与规范文档的分工

文档 读者 内容
本文 DGX3D_AI调用指南.md 其他项目、编排 AI 本地Turbo生图、多参考编辑、批量与Unity导出、引擎选择、云端转接、DGX剧本
LLM3DGraphics/docs/local-image-generation.md 图像流程实现 / 运维 Turbo部署、共同驻留、资源保护、Unity导入与实测
DGX3D生成说明.md 本仓库实现 / 深度排错 DGX 阶段、产物、UniMate、Unity、禁忌
生成路径.md 仅运维 上游模型与 Key(勿发给外部 Agent)
HelpDoc/gpt-image_doc.md 仅运维 上游画图字段细节

服务变更时:外部调用顺序以本文为准;产物与内部阶段以 DGX3D生成说明.md 为准;上游 Key 只放本机 config.json。