3D 生成定价迁移先落文档:两段并列结构、SpacetimeDB 权威与后台编辑

- 主规范把 3D 定价改成按端点两段并列结构,事实源改为 SpacetimeDB,补契约归一化、后台保存语义与验收项
- 新增 ADR 0005,记录权威事实源迁移、公开读模型不变的取舍与四条被否决做法
- 新增里程碑规范与实施计划,列出范围、验收标准、文件切分、验证命令与两个回滚点
- 同步 Tripo 技术方案的定价段形状、后端架构表目录的两列说明、CONTEXT.md 术语与决策记录
This commit is contained in:
2026-09-23 10:53:28 +08:00
parent caafb8baa3
commit 1327cd53b7
9 changed files with 202 additions and 26 deletions
@@ -92,22 +92,22 @@ ImageToModelResult = { modelArtifact, renderedPreview }
## 定价与扣费
定价是**真实扣费**,不是计量占位。Tripo 的计费形态是“底价 + 可叠加 add-on”,现有图片/视频那套“模型 → 档位 → 单价”查表表达不了,因此在同一份定价配置中新增 `model3d` 段,全部以泥点计价:
定价是**真实扣费**,不是计量占位。Tripo 的计费形态是“底价 + 可叠加加价项”,现有图片/视频那套“模型 → 档位 → 单价”查表表达不了,因此在同一份定价配置中另立 `model3d` 段,按端点拆成两段并列设置,全部以泥点计价:
```json
"model3d": {
"basePrices": {
"text-to-model": { "<modelVersion>": { "noTexture": 泥点, "texture": 泥点 } },
"image-to-model": { "<modelVersion>": { "noTexture": 泥点, "texture": 泥点 } }
"textToModelPricing": {
"versionPrices": { "<modelVersion>": { "noTexture": 泥点, "texture": 泥点 } },
"addOnPrices": { "hdTexture": 泥点, "ultraTexture": 泥点, "hdGeometry": 泥点, "quadMesh": 泥点, "smartLowPoly": 泥点, "generateParts": 泥点 }
},
"addOnPrices": {
"hdTexture": 泥点, "ultraTexture": 泥点, "hdGeometry": 泥点,
"quadMesh": 泥点, "smartLowPoly": 泥点, "generateParts": 泥点
"imageToModelPricing": {
"versionPrices": { "<modelVersion>": { "noTexture": 泥点, "texture": 泥点 } },
"addOnPrices": { "hdTexture": 泥点, "ultraTexture": 泥点, "hdGeometry": 泥点, "quadMesh": 泥点, "smartLowPoly": 泥点, "generateParts": 泥点 }
}
}
```
模型版本键使用 `Model3dModelVersion` 的枚举值,不另造字符串。add-on 由请求参数判定,判定规则固定为:
模型版本键使用 `Model3dModelVersion` 的枚举值,不另造字符串。两段各自持有自己的加价项价目(当前数值相同),因此同一加价项在不同端点可以不同价。加价项由请求参数判定,判定规则固定为:
```text
hdTexture ← texture=true && textureQuality=detailed
@@ -122,19 +122,21 @@ textureQuality=fast | standard → 不给任何贴图加价
最终价格:
```text
price = basePrices[endpoint][modelVersion][texture ? "texture" : "noTexture"]
+ Σ addOnPrices[命中的 add-on]
price = <端点段>.versionPrices[modelVersion][texture ? "texture" : "noTexture"]
+ Σ <端点段>.addOnPrices[命中的加价项]
```
两条硬约束:
1. **加载即校验**:`model3d` 段一旦存在,两个 endpoint × 每个受支持模型版本 × 两种贴图态与全部 add-on 键必须同时存在,缺一即配置非法、服务拒绝启动;段内不再写 `unit`,3D 生成恒为按次计价。
1. **加载即校验**:两段各自强校验——每段的每个受支持模型版本 × 两种贴图态与全部六个加价项键必须同时存在,缺一即该段非法、服务拒绝加载;段内不再写 `unit`,3D 生成恒为按次计价。
2. **提交即拒绝**:价格计算发生在调用 provider 之前;拿不到价格就不提交、不扣费、不入队。
泥点数值已确认并写入受控默认配置 `server-rs/crates/api-server/config/editor-generation-pricing.default.json`。换算口径固定为 **泥点 = `ceil(0.8 × Tripo 官方 credit)`**,credit 取自 Tripo 官方价目表的 H 系列与 P 系列:文生 3D 的 H 系列 `10 / 20`、P1 `30 / 40`、P2 `100 / 110`,图生 3D 的 H 系列 `20 / 30`、P1 `40 / 50`、P2 `100 / 110`(依次为无贴图 / 标准贴图),六个 add-on 为 `HD Texture 10`、`8K Ultra Texture 20`、`HD Geometry 20`、`Quad Mesh 5`、`Smart Low-poly 10`、`Generate Parts 20`。`editor_generation_config` 的定向用例按这张 credit 表反算默认泥点价,改价必须先改 credit 表,避免默认值脱离换算口径。
`model3d` 段缺失仍是合法形态:缺失即 3D 定价未配置,提交被拒绝(fail closed),既不扣费也不调用 provider;段存在时走上面的强校验路径。
2026-09-23 起这两段的事实源是 SpacetimeDB `editor_generation_pricing_config` 的两段强类型列,后台「模型定价」页面直接编辑,保存与 `models` 段在同一事务内生效,改价不再需要改文件或重启进程。读取方向按契约归一化:表内缺键用默认 JSON / 覆盖文件同段值补齐,契约之外的遗留键剔除并告警;写入方向要求两段完整合法。公开读模型 `GET /api/editor/generation-pricing` 的 3D 段形状保持不变,画布 3D 入口的价格真相与前端零兜底口径不变。详见 [ADR 0005](../adr/【ADR】0005-3D生成定价迁入SpacetimeDB与后台编辑-2026-09-23.md) 与 [编辑器模型定价配置管理方案](../【编辑器】模型定价配置管理方案-2026-06-22.md)。
扣费依据固定为**提交时定价**:用户在提交前就能得到确定价格,失败退款是单次冲正,不需要按实际消耗退差额。provider 返回的实际消耗只写日志用于成本对账,不进入契约、不进 API 响应、不进资源行。
价格随 job 写入 `price_mud_points`,扣费与冲正沿用现有资产操作账务(attempt 级 consume / refund ledger);素材侧继续用 `generation_cost_mud_points` 记录单次成本。同一 `Idempotency-Key` 命中已有 job 时直接返回原 operation,不新建、不重复扣费。
@@ -199,6 +201,6 @@ width/height = 预览图像素尺寸
## 未决问题
- add-on 价格目前是跨模型统一一份;若 Tripo 后续对某个模型版本差异化加价,再补“按模型版本覆盖”一层,现在不预留。
- 加价项已按端点各持一份价目(当前数值相同);若 Tripo 后续对某个模型版本差异化加价,再补“按模型版本覆盖”一层,现在不预留。
- 3D 模型的多文件 glTF 兄弟资源(`.bin`、贴图)、多视角与模型信息展示仍未安排;画布侧接入见 [`【实施计划】Tripo生成结果前端预览接入-2026-09-21.md`](../project-memory/plans/【实施计划】Tripo生成结果前端预览接入-2026-09-21.md)。
- AGC 项目画布自带两份格式判断(`resourceModelScene.ts` 的 `isResourceModelFbx` 把 `octet-stream` 当 FBX、`resourceCardPreviewModel.ts` 的资源卡预览按扩展名正则选解析器),本期不动,后续统一收敛到 `packages/model3d-viewer`;素材库行、后台 renderer、精选 read model 与公开 grant 的 3D 展示同样未进入。