3DCellForge 后端原理解读:Node.js 多提供商 3D 生成任务队列与本地缓存设计
【免费下载链接】3DCellForgeAI-powered interactive 3D model generation, inspection, and presentation studio.项目地址: https://gitcode.com/gh_mirrors/3d/3DCellForge
3DCellForge 是一个 AI 驱动的交互式 3D 模型生成与演示工作台。它的 Node.js 后端用一套「多提供商 3D 生成任务队列 + 本地 GLB 缓存」设计,把 Hyper3D Rodin、Tripo、Fal.ai、Hunyuan3D 等多家图生 3D 服务统一成同一个异步任务接口,再用本地缓存目录避免临时链接失效与重复下载。本文不带大量代码,用通俗方式带你完整看懂这套后端设计。
一、整体架构:前端只问一个后端,后端统一对接多家 3D 服务
3DCellForge 的前端是 React + Three.js 工作台,它不直接调用任何 3D 厂商的 API,而是全部请求本地 Node.js 后端(默认http://127.0.0.1:8787)。整个后端只有一个入口文件 server.mjs,用原生node:http搭建,暴露的接口非常克制:
| 接口 | 作用 |
|---|---|
POST /api/3d/generate | 创建 3D 生成任务,立刻返回taskId |
GET /api/3d/status/:taskId | 轮询任务状态、进度与模型地址 |
GET /api/3d/model?url=... | 代理下载远端模型(仅允许 HTTPS/本机地址) |
POST /api/3d/local-model | 导入本地.glb/.gltf文件 |
GET /api/3d/local-model/:id | 读取本地缓存的模型文件 |
GET /api/3d/health | 查看各提供商是否已配置 |
GET /api/3d/logs | 本地诊断日志(仅限本机访问) |
这种「创建任务 + 轮询状态」的异步任务队列模式,是所有长耗时 AI 生成的通用解法:生成一个 3D 模型动辄几十秒到几分钟,后端不可能同步等待,所以先给你一个taskId小票,你再拿着小票来查进度。
二、多提供商适配层:4 个文件,4 条生成通道 🔌
后端把每种生成服务封装成独立的 Provider 文件,统一放在 server/providers/ 目录下,每个文件对外只暴露三个函数:健康检查、创建任务、查询任务。
| 提供商 | 源码 | 调用链路 |
|---|---|---|
| Hyper3D Rodin(默认) | rodin.mjs | multipart 提交/rodin任务 → 轮询/status→ 通过/download取回 GLB |
| Tripo | tripo.mjs | 先申请 STS 临时凭证上传对象存储 → 创建image_to_model任务 → 轮询任务 |
| Fal.ai | fal.mjs | 用官方 client 的 storage 上传 + queue 队列提交,可在设置里切换 5 种模型 |
| Hunyuan3D(本地) | hunyuan.mjs | 对接本地 Hunyuan3D API:POST /send→GET /status/:uid,支持直接返回 base64 GLB |
几个值得新手学习的设计点:
- 统一调度:入口 createGenerationTask 只按
provider名字做一层简单分发,路由层完全不知道具体厂商的细节; - 统一任务形状:无论哪家厂商,返回都是
{ provider, taskId, status, progress, modelUrl }结构,各 Provider 内部负责把厂商五花八门的状态词(done、succeeded、in_progress…)归一化成queued / running / success / failed四态; - 自动降级链:前端 getProviderPlan 里,
auto模式会按rodin → tripo → fal → hunyuan → 浏览器端 JS Depth依次降级,保证没有配置任何云端 Key 时依然有兜底方案。
三、生成任务队列:提交 → 轮询 → 完成 🔁
一次生成的完整生命周期是这样的:
- 提交:前端把参考图转成 data URL,随文件名、提示词一起发给
POST /api/3d/generate(modelApi.js)。后端解析图片、组装厂商参数(例如 Tripo 的 STS 上传流程),拿到任务 ID 后立即响应; - 轮询:前端 waitFor3dModel 按固定间隔循环调用
GET /api/3d/status/:taskId,把progress百分比实时渲染到左侧的「生成队列」面板(GenerationTaskCenter.jsx),直到成功、失败或超时; - 完成:成功时返回
modelUrl,前端把模型拉进中央 3D 舞台,并写入 IndexedDB,刷新页面后仍可从模型库恢复。
一个巧妙细节:Rodin / Fal 这类需要多段信息的任务,会把taskUuid、requestId等元数据用 base64url 编码进taskId本身(如rodin-xxxx,见 encodeRodinTaskId),后端因此可以保持无状态——不需要在内存里保存任务表,重启也不丢任务。
四、本地缓存设计:.generated-models目录的四道防线 🧊
厂商返回的模型链接通常是临时签名 URL,几小时后就会过期。3DCellForge 的解法是:每次轮询到「成功」,后端立刻把 GLB 下载到本地.generated-models/目录(目录名在 config.mjs 配置),并从此只给你本地地址。
核心实现 cacheRemoteModelAs 有四个防御动作:
- 缓存优先:每次查状态先问一句 hasLocalModel——本地已有就直接返回
success,连厂商 API 都不调用(见 getRodinTask)。这意味着重启后端、重开页面,已完成的任务秒级复用; - 临时文件落盘:先写入
xxx.tmp临时文件,确认无误后才rename成正式文件,避免半成品被当作有效模型; - 魔数校验:validateModelBuffer 会检查 GLB 文件头是否为
glTF魔数、GLTF 是否为合法 JSON,垃圾数据进不了缓存; - 本地服务:serveLocalModel 以正确的
model/gltf-binary类型和Cache-Control: private, max-age=3600响应,浏览器还会再缓存一小时。
本地导入的模型(importLocalModel)和生成模型共用同一套缓存目录,所以「自己拖进来的 GLB」和「AI 生成的 GLB」在工作台里享受完全一致的加载路径。
五、安全与可观测性:新手容易忽略的细节 🔐
- 密钥只留在服务端:所有 API Key 放在
.env.local,由 loadLocalEnv 在启动时加载,前端构建产物里一个字符都看不到; - 日志自动脱敏:logger.mjs 定义了敏感字段名单(API Key、
imageDataUrl、modelBase64等),写入.logs/的 JSON 日志前统一打码,诊断接口/api/3d/logs也只允许本机访问; - 请求可追踪:每个请求生成短
requestId并写入X-Request-Id响应头,出问题时能对上日志; - 体积护栏:图片请求体上限 28MB、模型上传上限 180MB(config.mjs),超大文件在入口就被拦下;
- 代理友好:所有出站请求支持
HTTPS_PROXY代理(config.mjs),内网环境也能调通云端 3D 服务。
六、小结:这套后端设计好在哪里 ✅
- 一份接口,多家服务:路由层只认「任务」抽象,新增提供商只需加一个 Provider 文件 + 两行分发;
- 异步任务队列:创建即返回 + 轮询查状态,天然适合长耗时的图生 3D 流程;
- 本地缓存兜底:临时链接过期不怕,模型永远在
.generated-models/里,刷新、重启、离线演示都可用; - 无状态设计:任务元数据编码进
taskId,后端不需要任务数据库,轻量到只依赖node:http+ undici。
想亲手体验?克隆仓库后执行下面两步,就能打开左侧任务队列,把一张参考图变成可交互的 3D 模型:
npm run dev:api # 启动 3D 生成后端(8787 端口) npm run dev # 启动前端工作台更多配置说明(各提供商 Key、Auto 降级链、Hunyuan 本地模式)可查阅 README.zh-CN.md。
【免费下载链接】3DCellForgeAI-powered interactive 3D model generation, inspection, and presentation studio.项目地址: https://gitcode.com/gh_mirrors/3d/3DCellForge
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考