建模 SDK

用世界模型把一段文字、一张照片、一张 360° 全景、同一空间的几张照片或一段视频,变成可以走进去的 3D 世界(高斯溅射 + 碰撞网格 + 全景),再把世界里的位置绑到公司的业务对象上——设备、工位、传感器——这是数字孪生的地基。上游是 World Labs 的 Marble 世界模型(World API);所有调用都经过 AIDC:额度、并发、复用、留痕、账单都在平台这一侧,浏览器里拿不到上游密钥。

import { modeling } from "/developer/sdk/v1/aidc.js";
做什么 SDK CLI
看价钱(不联网) modeling.estimate(model, input) aidc modeling estimate
生成一个世界 modeling.generate(spec) → modeling.wait(id) aidc modeling generate
看 / 找世界 modeling.get(id) · modeling.list() aidc modeling get · list
在网页里走进去 modeling.viewer(el, world) —
绑业务对象(孪生) modeling.setAnchors(id, anchors) aidc modeling anchors
导出 / 下载到本机 modeling.exportAsset(id, …) aidc modeling export · download
额度 modeling.budget() aidc modeling budget

公开展示:世界模型 · 空间建模(只读展示,不接受生成请求)。

1. 先看价钱

World Labs 按 credits 计费,1,250 credits = 1 美元。一次生成 = 全景生成(按输入类型;给现成全景则免)+ 世界生成(按模型):

模型 文字 单张图片 360° 全景 多张图片 / 视频 适合
marble-1.0-draft(缺省) 230($0.18) 230($0.18) 150($0.12) 250($0.20) 试提示词、看构图
marble-1.1 1,580($1.26) 1,580($1.26) 1,500($1.20) 1,600($1.28) 正式质量,价格固定
marble-1.1-plus 1,580–3,080 1,580–3,080 1,500–3,000 1,600–3,100(≤ $2.48) 最大的世界,按规模加收

另外:HQ 网格导出每个世界 3,500 credits($2.80,同一世界只收一次);PLY 高斯溅射导出、上传输入、查询进度都不收钱。

modeling.estimate("marble-1.1", "video");
// { maxCredits: 1600, maxUsd: 1.28, lines: [{ name: "全景生成(视频)", credits: 100 }, { name: "世界生成", credits: 1500 }] }
aidc modeling estimate -m marble-1.1-plus --input multi-image    # 本机算,不用登录

2. 费用控制:闸在平台这一侧

World Labs 不按单次成本拦截请求——余额不够照样执行、月底按超额补扣,自动充值也不设上限。所以 AIDC 在调上游之前就把钱的事判完,按这个顺序:

  1. 估价:按最坏情况(Plus 的浮动部分按上限)算这一次最多花多少。
  2. 策略:模型是否开放、是否超过单次上限;调用方可以再给一个更严的 maxCredits。
  3. 复用:同一公司里同样的请求(模型 + 输入 + seed)已有结果 → 直接返回那个世界,不花钱(regenerate: true 才重新生成)。
  4. 幂等:必须带 Idempotency-Key(SDK / CLI 自动生成);网络重试用同一个 Key,拿到的是同一个世界。
  5. dry-run 到此为止:返回估价、额度、将发给上游的载荷,不调上游、不落库。
  6. 每小时次数(每公司)→ 同时在跑的上限(全平台、每公司)→ 月度额度(全平台总闸 + 公司额度 + 应用每日额度):在同一把事务锁里判完并按最坏情况预留,并发请求不会一起挤过去。
  7. 调上游:明确失败 → 释放预留;结果不明(超时 / 断网,上游可能已受理)→ 预留不释放,按已花费计。
  8. 结账:完成时按上游结算的 cost.total_credits 结账(拿不到就按预留,宁多不少),同时在用量台账记一行(与模型通道同一本账,按公司计费)。

缺省策略(平台 env AIDC_MODELING_POLICY 可以部分覆盖;写坏了就停止一切花费):

项 缺省
开放的模型 marble-1.0-draft、marble-1.1(Plus 浮动计价,缺省不开)
单次上限 1,600 credits(挡住 Plus 与 HQ 网格导出)
全平台每月 6,250 credits($5)
公司每月 AIDC 6,250;其他公司 0 = 只能看,要开通找 AIDC 平台
HQ 网格导出 关闭
同时在跑 全平台 3 个、每公司 2 个;每公司每小时 10 次

应用里生成要在清单写每日额度 limits.worldCreditsPerDay(不写 = 0 = 只看);只读访客(分享链接 / viewer)不能生成。官方公开应用(namespace public)永远不能生成、上传、导出或改锚点——公开展示只看不花钱,这条写死在平台里,不靠清单。

const plan = await modeling.generate({ input: { kind: "text", text: "一个整洁的汽车零部件装配工位" } }, { dryRun: true });
plan.plan.estimate.maxCredits;   // 230
plan.plan.decision;              // { ok: true } 或 { ok: false, message: "…本月的世界模型额度不够…" }
await modeling.budget();         // { month, company: { cap, settled, reserved, remaining } }

3. 生成一个世界

const { world, reused } = await modeling.generate({
  input: { kind: "text", text: "一个整洁的汽车零部件装配工位:右侧白色六轴机械臂,前方红色检测台,黄色安全围栏" },
  model: "marble-1.0-draft",       // 先试稿;满意了再 marble-1.1
  displayName: "装配工位(试稿)",
  maxCredits: 300,                  // 这一次的硬上限
});
const done = await modeling.wait(world.id, { onProgress: (w) => console.log(w.progress?.description) });   // 约 5 分钟
aidc modeling generate --text "一个整洁的装配工位…" --dry-run            # 先看估价与额度
aidc modeling generate --text "一个整洁的装配工位…" -m marble-1.1        # 等到完成,打印资产与坐标系
aidc modeling generate --image cell.jpg --text "保留机械臂与检测台的位置"   # 本地文件自动直传 World Labs
aidc modeling generate --image a.jpg --image b.jpg --image c.jpg --reconstruct   # 同一空间多图重建
aidc modeling generate --video walk.mp4 --no-wait                       # 立即返回,稍后 aidc modeling wait <id>
输入 input.kind 写法 建议(World Labs 官方与 AIDC 09-14 实测)
text { kind: "text", text } ≤ 2,000 字,描述一个地点而不是一个物件
image { kind: "image", image: { mediaId } | { url }, text? } 长边 ≥ 1024、≤ 20 MB;要有地面 / 墙面 / 纵深;人物、特写、强反光效果差
pano { kind: "pano", image, text? } 2:1 等距柱状 360° 全景(约 2560 宽);空间布局最准,不收全景生成费
multi-image { kind: "multi-image", images: [{ mediaId | url, azimuth? }], reconstruct } reconstruct: true:2–8 张同一空间、同一宽高比、相邻有重叠的照片;不开时最多 4 张按方位角拼
video { kind: "video", video, text? } ≤ 30 秒 / 100 MB(mp4 / mov / webm);稳、慢、一镜到底,覆盖 180°–360°;锁焦距与曝光;画面里别有人走动

text 是可选的文字引导(图片类输入不给就由上游自动描述);recaption: false 让上游原样使用你的文字。seed 固定随机性。

生成的是「看起来合理」的空间,不是测绘。 照片没拍到的背面、遮挡处由模型补全;侧向移动时细杆、线缆、近处物件会拉伸或模糊;标牌文字不可信。AIDC 09-14 的四组实测(文字、单张照片、视频、四图重建)结论一致:适合工位导览、空间入口、培训与方案沟通;不能用于尺寸验收、碰撞安全、机器人离线编程——那需要标定、实测尺寸或 CAD。

4. 世界里有什么

world.assets.splats["500k"];   // 高斯溅射 SPZ:100k / 150k / 500k / full_res(约 1.4 / 2.5 / 8 / 30 MB)
world.assets.collider;          // 碰撞网格 GLB(低模,用于走动、拾取、物理)
world.assets.pano;              // 生成用的全景图
world.assets.thumbnail;         // 缩略图
world.caption;                  // 上游对世界的描述
world.frame;                    // AIDC 空间坐标系(下一节)
world.cost;                     // { estimatedCredits, settledCredits, usd, lines }

资产放在 World Labs 的 CDN(cdn.marble.worldlabs.ai)上,地址本身就是访问凭证(不可猜的长路径)——只交给有权看这个世界的人。平台只存地址、坐标系与锚点,不存文件。

5. AIDC 空间坐标系

Marble 的原始坐标是 OpenCV 约定(Y 向下、任意单位)。平台按每个世界的尺度信息换成统一的空间坐标系:米、Y 向上、地面 y = 0;生成视点在 (0, groundPlaneOffset, 0),初始视线朝 -Z。锚点、测距、以后接进来的设备位姿都在这个坐标系里。

const frame = modeling.frameOf(world);          // { metricScaleFactor, groundPlaneOffset, metric }
modeling.toMetric([0.2, 0.6, 1.1], frame);      // 原始坐标(SPZ / 碰撞网格顶点)→ 米
modeling.fromMetric([1.2, 0.8, -3.4], frame);   // 米 → 原始坐标
modeling.distance(a, b);                        // 米

换算:米 = [s·x, g − s·y, −s·z](s = metricScaleFactor,g = groundPlaneOffset)。碰撞网格与 SPZ 同一套原始坐标,用同一个换算。frame.metric = false 的老世界没有尺度信息(按 1 / 0 处理);即使有,生成的尺度也是估计值,没有标定过。

6. 在网页里走进去:查看器

查看器用 World Labs 维护的高斯溅射渲染器 Spark(2.2.0)+ three.js(0.180.0),钉死版本、从 jsDelivr 加载。页面先放 import map(在任何 module 脚本之前),清单 sdk 登记 modeling、cdn 登记 cdn.jsdelivr.net——平台据此给应用的 CSP 放行 World Labs 资产与 WebAssembly 编译:

<script type="importmap">
  { "imports": {
      "three": "https://cdn.jsdelivr.net/npm/three@0.180.0/build/three.module.js",
      "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.180.0/examples/jsm/",
      "@sparkjsdev/spark": "https://cdn.jsdelivr.net/npm/@sparkjsdev/spark@2.2.0/dist/spark.module.js" } }
</script>
<div id="stage" style="height: 70vh"></div>
<script type="module">
  import { modeling } from "/developer/sdk/v1/aidc.js";
  const [world] = await modeling.list({ status: "succeeded" });
  const view = await modeling.viewer(document.querySelector("#stage"), world, {
    quality: "500k",                     // 手机上用 "100k"
    collider: true,                      // 加载碰撞网格,支持 pick()
    onAnchor: (anchor) => console.log(anchor.object),
  });
  view.view("top");                      // home / side / back / top
  stage.addEventListener("dblclick", async (e) => console.log(await view.pick(e.clientX, e.clientY)));   // → [x, y, z](米)
</script>

modeling.importMap() 返回同一份 import map。左键拖动旋转、滚轮缩放、右键平移;focus(anchor) 飞到锚点;setQuality() 换精度;snapshot() 截图;dispose() 释放 WebGL 资源。需要 WebGL2。

7. 锚点:数字孪生的地基

世界只是空间;锚点把空间里的位置绑到业务对象上。每个锚点:位置(米)、名称、类型(equipment / sensor / zone / camera / note)、静态属性(型号、编号…),以及可选的语义层对象(object: { type, pk },类型必须在本公司语义层里)。

await modeling.setAnchors(world.id, [
  { id: "robot-1", label: "焊接机械臂 R-01", kind: "equipment", position: [1.2, 0.8, -3.4],
    object: { type: "production.equipment", pk: "R-01" }, meta: { 型号: "ER20" }, verified: true },
  { id: "fence-a", label: "安全围栏 A 区", kind: "zone", position: [0, 0, -2] },
], { ifRev: world.anchorsRev });

整组替换(幂等),ifRev 做乐观并发(别人改过就 409)。verified 标明位置与身份是否经人工核验——生成的世界有模型补全,未核验的锚点在查看器里是空心点,只能当示意。

把锚点接到实时数据,就是一个最小的数字孪生:

import { modeling, data } from "/developer/sdk/v1/aidc.js";
const view = await modeling.viewer(stage, world, {
  onAnchor: async (anchor) => {
    if (!anchor.object) return;
    const { object } = await data.table(anchor.object.type).get(anchor.object.pk);   // 语义层里的设备:状态、报警、工单…
    panel.textContent = `${anchor.label}:${object.props.status}`;
  },
});
data.watch({ types: ["production.equipment"] }, { onChange: () => refreshPanels() });   // 数据一变就更新

8. 导出与下载

aidc modeling export <id> --ply --resolution full_res   # 高斯溅射 PLY(免费、立即完成)
aidc modeling export <id> --mesh --dry-run              # HQ 网格 GLB:3,500 credits,缺省策略关闭
aidc modeling download <id> --out ./cell-01             # SPZ + 碰撞网格 + 缩略图 + world.json(坐标系与锚点)

下载下来的 SPZ / PLY 可以进 Unity、Unreal、Blender、Houdini(各引擎的高斯溅射插件),按 world.json 里的坐标系摆正。

9. 输入媒体与数据边界

const { mediaId } = await modeling.upload(file);   // 先向平台换签名地址,字节直传 World Labs,不经过 AIDC
await modeling.generate({ input: { kind: "image", image: { mediaId }, text: "保留设备位置" } });

10. 清单与 API

{
  "sdk": ["modeling", "ui"],
  "cdn": ["cdn.jsdelivr.net"],
  "limits": { "dailyTokens": 1000000, "requestsPerMinute": 30, "realtimeSessionsPerDay": 0, "worldCreditsPerDay": 1600 }
}
方法 路径 做什么
GET /api/v1/developer/modeling 目录:模型、价目、策略、上游是否已配置(公开)
GET /api/v1/developer/modeling/{ns}/budget 本月额度
GET / POST /api/v1/developer/modeling/{ns}/worlds 列表 / 生成(Idempotency-Key 必填,支持 dry-run)
GET / DELETE /api/v1/developer/modeling/{ns}/worlds/{id} 详情(进行中会同步进度)/ 删除(?purge=1)
PUT /api/v1/developer/modeling/{ns}/worlds/{id}/anchors 锚点(整组替换,ifRev)
POST /api/v1/developer/modeling/{ns}/worlds/{id}/exports 导出 PLY / HQ 网格
POST /api/v1/developer/modeling/{ns}/media 上传输入:换签名地址
POST /api/v1/developer/modeling/{ns}/imports 登记已有的 Marble 世界(AIDC 平台账号)

{ns} = public 或 cell-…。public 的世界谁都能读(只列已完成的、不带发起人)。错误码:quota_exhausted(额度 / 单次上限,details.scope 说明是哪一层)、rate_limited、idempotency_key_required、idempotency_conflict、media_not_found、world_not_found、modeling_unconfigured(平台还没配置上游)、model_upstream_failed。

11. 接下来:从空间到孪生

世界(空间底座)+ 锚点(空间 ↔ 对象)+ 语义层(对象的状态)+ 数据流(实时)+ 工作流(联动)= 数字孪生。建模 SDK 先把前两块做成稳定的契约:统一的空间坐标系、按公司隔离的世界与锚点、可控的成本。下一步:同一工位的环拍采集规范与实测尺寸标定、设备位姿接入、世界版本对比、World Labs 新模型(Atlas 的多视图重建与相机控制)开放后接入。

本页由 developer/docs/modeling.md 生成 · Markdown 原文 · llms.txt