官方素材管理
需要读取官方素材 ID、获取下载地址或管理官方素材时使用本页。流程为:创建素材组和官方组、上传素材、按目标模型准备、读取官方详情。普通素材列表和准备状态见查询素材。
seedance-2.0-sz、seedance-2.0-sz-fast、seedance-2.0-sz-mini 和 seedance-2.5-sz 支持查询当前账号已准备素材的火山官方 ID 和 HTTPS 媒体下载地址。MoonApiX asset_id / asset_ref / group_id 仍为素材管理和生成请求的主标识。
| 操作 | 方法与路径 | model 位置 |
|---|---|---|
| 准备或续查官方素材 | POST /v1/assets/{asset_id}/upstream | JSON 正文 |
| 查询已登记的官方素材列表 | GET /v1/assets/upstream | 查询参数 |
| 查询官方素材详情及当前下载地址 | GET /v1/assets/{asset_id}/upstream | 查询参数 |
| 修改官方素材名称 | PATCH /v1/assets/{asset_id}/upstream | JSON 正文 |
| 删除官方素材 | DELETE /v1/assets/{asset_id}/upstream | 查询参数 |
| 用官方 ID 找回自己的 MoonApiX ID | POST /v1/assets/resolve | JSON 正文 |
完整调用流程
以下 Bash 示例需要 curl 和 jq,使用已设置的 MOONAPIX_API_KEY 环境变量和本地 reference.png。示例保存请求回执到权限受限目录,媒体链接可能带短期签名,避免把回执或完整链接写入共享日志。步骤中的创建、上传不要在结果未知时盲目重跑;先用已取得的 MoonApiX ID 查询。
set -euo pipefail
umask 077
: "${MOONAPIX_API_KEY:?Set MOONAPIX_API_KEY in your environment}"
BASE=https://moonapix.com
MODEL=seedance-2.0-sz
RECEIPTS=$(mktemp -d)
MODEL_BODY=$(jq -nc --arg model "$MODEL" '{model:$model}')
# 1. Create a MoonApiX group, then its official group.
curl --silent --show-error --fail-with-body "$BASE/v1/asset-groups" \
-H "Authorization: Bearer $MOONAPIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"project-a","description":"Reference materials","domain":"media"}' \
-o "$RECEIPTS/group.json"
GROUP_ID=$(jq -er '.group_id' "$RECEIPTS/group.json")
curl --silent --show-error --fail-with-body "$BASE/v1/asset-groups/$GROUP_ID/upstream" \
-H "Authorization: Bearer $MOONAPIX_API_KEY" \
-H "Content-Type: application/json" -d "$MODEL_BODY" \
-o "$RECEIPTS/official-group.json"
# 2. Create a V2 asset in this group and request a managed copy.
curl --silent --show-error --fail-with-body "$BASE/v1/assets" \
-H "Authorization: Bearer $MOONAPIX_API_KEY" \
-H "Asset-Contract: v2" \
-F "file=@./reference.png" -F "type=image" \
-F "group_id=$GROUP_ID" -F 'storage={"enabled":true}' \
-o "$RECEIPTS/upload.json"
ASSET_ID=$(jq -er '.asset_id' "$RECEIPTS/upload.json")
# 3. Prepare this same asset; HTTP 202 means it is still processing.
curl --silent --show-error --fail-with-body "$BASE/v1/assets/$ASSET_ID/prepare" \
-H "Authorization: Bearer $MOONAPIX_API_KEY" \
-H "Content-Type: application/json" -d "$MODEL_BODY" \
-o "$RECEIPTS/prepare.json"
for ATTEMPT in $(seq 1 24); do
if jq -e '.preparation.generation_ready == true' "$RECEIPTS/prepare.json" >/dev/null; then
break
fi
sleep 10
curl --silent --show-error --fail-with-body "$BASE/v1/assets/$ASSET_ID/prepare" \
-H "Authorization: Bearer $MOONAPIX_API_KEY" \
-H "Content-Type: application/json" -d "$MODEL_BODY" \
-o "$RECEIPTS/prepare.json"
done
jq -e '.preparation.generation_ready == true' "$RECEIPTS/prepare.json" >/dev/null
# 4. Read current official IDs and the download URL.
curl --silent --show-error --fail-with-body \
"$BASE/v1/assets/$ASSET_ID/upstream?model=$MODEL" \
-H "Authorization: Bearer $MOONAPIX_API_KEY" -o "$RECEIPTS/detail.json"
OFFICIAL_ASSET_ID=$(jq -er '.upstream.asset_id' "$RECEIPTS/detail.json")
CALL_GROUP_ID=$(jq -er '.upstream.group_id' "$RECEIPTS/detail.json")
OFFICIAL_OBSERVED_GROUP_ID=$(jq -er \
'.upstream.observed_group_id // .upstream.group_id' "$RECEIPTS/detail.json")
# 5. Resolve known official IDs to this account's MoonApiX IDs.
jq -n --arg model "$MODEL" --arg aid "$OFFICIAL_ASSET_ID" --arg gid "$CALL_GROUP_ID" \
'{model:$model,upstream_asset_id:$aid,upstream_group_id:$gid}' \
> "$RECEIPTS/resolve-request.json"
curl --silent --show-error --fail-with-body "$BASE/v1/assets/resolve" \
-H "Authorization: Bearer $MOONAPIX_API_KEY" -H "Content-Type: application/json" \
--data-binary "@$RECEIPTS/resolve-request.json" -o "$RECEIPTS/resolved.json"
jq -e --arg aid "$ASSET_ID" --arg gid "$GROUP_ID" \
'.asset_id == $aid and .group_id == $gid' "$RECEIPTS/resolved.json" >/dev/null准备返回 HTTP 202 时继续同一素材的 Prepare,HTTP 200 后仍检查 preparation.generation_ready。示例等待约四分钟后退出,退出不表示官方素材已删除;保留回执,再查询或继续 Prepare。不要因处理中而重新上传。POST /upstream 也可以开始或继续此准备流程,并在已取得 ID 时附带 upstream;下载地址始终从详情读取。
详情的示意字段如下,所有值均为虚构值:
{
"object": "asset",
"asset_id": "asset_example",
"asset_ref": "Asset://asset_example",
"group_id": "group_example",
"upstream": {
"asset_id": "asset-official-example",
"group_id": "group-official-example",
"url": "https://media.example.test/reference.png",
"status": "Active"
}
}| 字段 | 含义 |
|---|---|
顶层 asset_id、asset_ref、group_id | MoonApiX 标识,后续生成及管理请求继续使用这些值。 |
upstream.asset_id | 官方素材详情返回的火山原始素材 ID。 |
upstream.group_id | 当前素材已登记、可用于 ID 解析的官方组 ID。 |
upstream.observed_group_id | 可选;当详情实际返回的官方组 ID 与已登记的组 ID 不同时单独提供,不覆盖 upstream.group_id。获取本次详情观察到的组 ID 时读取此值,否则读取 upstream.group_id。 |
upstream.url | 官方素材详情提供的 HTTPS 媒体下载地址,处理中或尚未提供地址时可缺省。 |
upstream.status | 官方素材状态;不能替代同模型的 preparation.generation_ready 判断。 |
下载和刷新地址
upstream.url 可能含短期下载签名,常见有效期约 12 小时,不作为永久地址。需要下载时重新 GET 同一个素材的 /upstream?model=... 详情,使用此次返回的完整地址,保留全部查询参数;刷新地址无需重新上传或创建素材。ID 解析和列表不返回新的下载地址。
部分地址不接受 HEAD,可能返回 403,但匿名 Range GET 可返回 206、完整 GET 可返回 200。遇到 HEAD 拒绝时,用 Range: bytes=0-0 GET 核验 HTTP 状态及匹配的媒体 Content-Type;如果 GET 也失败,重新查询详情取得当前地址后再核验。媒体下载无需携带 MoonApiX API Key;不要把 API Key 发送给媒体域名。完整下载后可验证文件大小、媒体规格和 SHA-256。
下面的 Python 3 示例接续前面的详情回执,匿名验证并下载图片;不把完整 URL 放入命令参数或输出:
python3 - "$RECEIPTS" <<'PY'
import hashlib
import json
from pathlib import Path
import sys
import urllib.request
from urllib.parse import urlparse
receipts = Path(sys.argv[1])
detail = json.loads((receipts / "detail.json").read_text())
url = detail["upstream"]["url"]
assert urlparse(url).scheme == "https"
request = urllib.request.Request(url, headers={"Range": "bytes=0-0"})
with urllib.request.urlopen(request, timeout=60) as response:
assert response.status in (200, 206)
assert response.headers.get_content_type() == "image/png"
response.read(1)
digest = hashlib.sha256()
with urllib.request.urlopen(url, timeout=120) as response:
assert response.status == 200
assert response.headers.get_content_type() == "image/png"
with (receipts / "reference-downloaded.png").open("wb") as output:
while chunk := response.read(1024 * 1024):
output.write(chunk)
digest.update(chunk)
print("Downloaded image/png; SHA-256:", digest.hexdigest())
PY列表与名称更新
curl --fail-with-body "https://moonapix.com/v1/assets/upstream?model=seedance-2.0-sz&offset=0&limit=20" \
-H "Authorization: Bearer $MOONAPIX_API_KEY"
curl --fail-with-body -X PATCH https://moonapix.com/v1/assets/asset_example/upstream \
-H "Authorization: Bearer $MOONAPIX_API_KEY" -H "Content-Type: application/json" \
-d '{"model":"seedance-2.0-sz","name":"product-reference-updated"}'列表只包含当前账号在所选模型素材范围内已经登记的资源,以 offset / limit 分页,默认 0 / 20,limit 范围 1..100。列表是摘要,不提供实时下载地址。名称更新仅接受 name,最长 64 个字符且不能全为空白;不接受 description。成功后详情中的名称可能延迟数分钟更新,间隔查询确认即可。
官方 ID 解析规则
POST /v1/assets/resolve 必须传 model,upstream_asset_id 和 upstream_group_id 至少传一个,同时传入时必须属于同一 MoonApiX 组。只传组 ID 的成功结果中 asset_id 和 asset_ref 为空字符串;取得素材时才返回可供生成使用的素材标识。
只解析当前账号在同一目标模型素材范围内已登记且有效的资源。未知、已失效、其他账号或不属于该范围的 ID 返回 404;无法唯一确定资源时返回 409。此接口不导入任意官方资源。若返回过不同的 upstream.observed_group_id,解析仍使用 upstream.group_id。生成接口不能把官方 ID 直接当作 MoonApiX asset_id 或 Asset://asset_xxx 使用,先解析再提交顶层 MoonApiX 标识。
清理本次资源
以下命令接续完整示例,只删除本次创建的资源。先删除官方素材,再删除空的官方组,最后对 MoonApiX 素材和分组软删除;执行成功前保留对应回执。
curl --silent --show-error --fail-with-body -X DELETE \
"$BASE/v1/assets/$ASSET_ID/upstream?model=$MODEL" \
-H "Authorization: Bearer $MOONAPIX_API_KEY" -o "$RECEIPTS/delete-official-asset.json"
curl --silent --show-error --fail-with-body -X DELETE \
"$BASE/v1/asset-groups/$GROUP_ID/upstream?model=$MODEL" \
-H "Authorization: Bearer $MOONAPIX_API_KEY" -o "$RECEIPTS/delete-official-group.json"
curl --silent --show-error --fail-with-body -X DELETE "$BASE/v1/assets/$ASSET_ID" \
-H "Authorization: Bearer $MOONAPIX_API_KEY" -o "$RECEIPTS/delete-asset.json"
curl --silent --show-error --fail-with-body -X DELETE "$BASE/v1/asset-groups/$GROUP_ID" \
-H "Authorization: Bearer $MOONAPIX_API_KEY" -o "$RECEIPTS/delete-group.json"官方删除成功返回 HTTP 200、deleted=true。正在准备、删除中或资源共用时可能返回 409。删除结果不明时可对同一个官方子资源重试 DELETE;不要把本地软删除成功当作官方资源已删除的证明。官方资源删除后对应 ID 不再可解析;它不保证已发出的媒体链接立即失效,也不撤销已经提交的生成任务。