3D 落点与结果引用对齐其它生成工具的文档同步
- 技术方案:落点改为「至少一个、两个可同给」,补上归一在预检之前完成并写回请求(预检值 = 队列载荷 = 落库值);完成结果读取补上双落点与平坦引用的说明。 - 技术方案素材库一节改为「素材库行已接 model3d 分支(预览图渲染 + 拖入画布)」,后台 renderer / 精选 read model / 公开 grant 仍未接。 - 里程碑与实施计划(API 契约、前端入口、结果前端预览)同步新口径:两个落点同给合法、前端同时发 projectId + assetFolderId + assetLabel、素材库行已进入。 - 共享记忆 decision-log 追加本次决策(原因、代价、影响面、验证方式),并在旧的「二选一」条目上标注 2026-09-23 追加修正。 - 验证:node scripts/check-doc-index.mjs(221 份 Markdown 通过)、npm run check:encoding、git diff --check 通过。
This commit is contained in:
@@ -10,10 +10,10 @@ Milestone Spec: `docs/project-memory/plans/【里程碑】Tripo生成API契约
|
||||
1. **API 契约**
|
||||
- `shared-contracts::model3d` 分两层:provider 生成参数(`Model3dTextToModelParams` / `Model3dImageToModelParams`)与 API 层请求(`Model3dTextToModelRequest` / `Model3dImageToModelRequest` = `generation` + 平台字段)。
|
||||
- 两层都保持 `deny_unknown_fields`,不使用 `flatten`:serde 的 `deny_unknown_fields` 与 `flatten` 不兼容,展开会让顶层未知字段静默通过。
|
||||
- `common/` 新增平台字段类型:`Model3dGenerationSource`(resource / asset 二选一)、结果落点引用(`Model3dGenerationTargetRef`,projectResource / assetLibrary 二选一)与产物元数据类型;请求侧落点与其它生成接口同形,用平坦的可选 `projectId` / `assetFolderId` / `assetLabel` / `canvasCompletion`,不引入 tagged enum。
|
||||
- `common/` 新增平台字段类型:`Model3dGenerationSource`(resource / asset 二选一)、结果落点引用(`Model3dGenerationTargetRef`,平坦可选的 `resourceId` / `assetId`,与请求落点同形)与产物元数据类型;请求侧落点与其它生成接口同形,用平坦的可选 `projectId` / `assetFolderId` / `assetLabel` / `canvasCompletion`,不引入 tagged enum。
|
||||
- 图片输入不属于 provider 参数:客户端只能给 `source`,`input` 由服务端解析后注入 provider 调用,避免绕过归属校验传任意 URL。
|
||||
- 新增按端点的严格结果 payload 类型(模型 artifact + 预览 artifact),二者都只携带正式资源引用与对象元数据。
|
||||
- 交付:类型定义、serde 组合测试(`projectId` 与 `assetFolderId` 都不给或都给拒绝、`canvasCompletion` 与 `assetFolderId` 同现拒绝、`source` 两个 ID 同现拒绝)。
|
||||
- 交付:类型定义、serde 组合测试(`projectId` 与 `assetFolderId` 都不给拒绝、两个都给合法、`canvasCompletion` 与“没有 `projectId`”同现拒绝、`source` 两个 ID 同现拒绝)。
|
||||
- 验收:`cargo test --locked -p shared-contracts --manifest-path server-rs/Cargo.toml` 通过。
|
||||
|
||||
2. **ts-rs 目录绑定**
|
||||
|
||||
@@ -16,7 +16,7 @@ Parent Spec: `docs/technical/【技术方案】Tripo 3D生成API集成-2026-09-2
|
||||
2. 入口形态照 `music` / `spec`:工具栏一项入口 → 浮动子选项 → 各自一个提交面板。子项文案沿用后端 `phaseLabel`:「文生 3D 模型」「图生 3D 模型」。
|
||||
3. 价格**只**来自 `GET /api/editor/generation-pricing` 的 `model3d` 段(前端已有 `loadEditorGenerationPricing` 与运行时缓存)。段缺失即两个子面板都不可提交且不发请求;前端不写任何 3D 兜底数值,也不把缺价当 0。
|
||||
4. 参数永远全量非空提交:`model`、`texture`、`pbr`、`geometryQuality`、`quad`、`smartLowPoly`、`generateParts` 一律显式给出,不依赖后端默认值(provider 隐式默认会改变价格)。唯一例外是 `textureQuality`:后端 `api-server::tripo3d::validation` 显式拒绝 `texture=false` 时出现贴图档位,因此纯几何档位必须**不带**该字段,而不是给 `null`。
|
||||
5. 落点固定为项目资源(发 `projectId` + `canvasCompletion: { dialogId, title, placeholder }`,不发 `assetFolderId`),照现有生成工具的做法(发送门禁为 `projectId && canvasCompletionPlaceholder`)。
|
||||
5. 落点照现有画布生成工具的做法:**同时**发 `projectId`(发送门禁为 `projectId`)与当前素材夹 `assetFolderId` + `assetLabel`,画布占位框 `canvasCompletion: { dialogId, title, placeholder }` 在 `projectId && canvasCompletionPlaceholder` 时带上;结果因此同时落画布与素材库。
|
||||
6. 图生输入照现有参考图来源菜单:从画布中选择 / 上传图片 / 从项目素材中选择,最终收敛成契约允许的 `{ kind: "resource", resourceId }` 或 `{ kind: "asset", assetId }`;只允许一张,不接 multiview。
|
||||
7. `Idempotency-Key` 由前端铸造并绑定当次请求,用户主动重试铸造新键、不复用旧键。落地形态是「尝试代次 + 请求内容指纹」(`Model3dGenerationSubmission.resolveModel3dRequestKey`):同一份内容重复提交(双击)仍命中同一个 operation,内容一变(含换参考图、换上传图、换素材库图片)自动换键;重试换代次即换键。之所以把内容指纹并进键里,是因为会改内容的入口散落在 `ImageCanvasGenerationDialogModel` / `ImageCanvasUploadModel` 的通用函数中,靠「每处都记得重铸键」迟早漏一处。
|
||||
8. 失败与退款沿用既有链路:文案由后端归一为「3D 模型生成失败,请稍后重试。」,侧栏与面板展示失败原因与已退还泥点。
|
||||
@@ -60,7 +60,7 @@ Parent Spec: `docs/technical/【技术方案】Tripo 3D生成API集成-2026-09-2
|
||||
- 验收:同一组合在用例中给出与后端 `model3d_add_ons` 相同的 add-on 集合。
|
||||
3. **请求与幂等身份**
|
||||
- 两个客户端函数分别打 `/api/assets/tripo/text-to-model` 与 `/api/assets/tripo/image-to-model`,带 Bearer、`Content-Type: application/json`、`Idempotency-Key`,请求体类型直接消费 `packages/shared/src/contracts/model3d/*`。
|
||||
- 落点固定为项目资源:只发 `projectId`,并携带 `canvasCompletion`;图生把选中图片收敛成 `resource` / `asset` 引用。
|
||||
- 落点与其它画布生成工具同形:同时发 `projectId` 与 `assetFolderId` / `assetLabel`,并携带 `canvasCompletion`;图生把选中图片收敛成 `resource` / `asset` 引用。
|
||||
- 验收:请求体全量非空;同一次提交重放同键;重试换新键。
|
||||
4. **入口与子选项**
|
||||
- 工具栏入口 + 浮动子选项菜单 + 对话框两个 mode,形态与 `music` / `spec` 一致。
|
||||
|
||||
@@ -14,7 +14,7 @@ Tripo 生成的 3D 资源在图片画布里作为 `model3d` 类别落地:卡
|
||||
4. 类型角标新增「3D模型」,与其它类别互为独立媒体族;覆盖资格只在 `model3d` 与空类别之间成立,图片族不能覆盖成 3D。
|
||||
5. 后端 `imageSrc` / `thumbnailSrc` 都是预览图、`objectKey` 是模型本体;投影由 `project_editor_client_media_src` 统一决定,预览缺失才回落到历史口径。
|
||||
6. 下载 3D 资源导出模型本体:MIME 优先、对象键扩展名兜底、最后回落 `glb`。
|
||||
7. 本期只做画布工具条入口,素材库行、后台 renderer、精选 read model、公开 grant 与 External v1 不进入。
|
||||
7. 素材库行已接 `model3d` 分支(缩略图按预览图渲染、拖入画布走既有素材链路);后台 renderer、精选 read model、公开 grant 与 External v1 不进入。
|
||||
8. 画布编辑器不承诺移动端,查看器模态固定 `lg` 尺寸、高度 `min(58vh, 30rem)`,不自动旋转,页脚「重置视角」仅在查看器状态为 `ready` 时可用。
|
||||
9. 后端写入 `content_type` 前按字节魔数识别 3D 产物;查看器单模型上限 64 MiB;客户端不抄格式清单,格式判定在 `packages/model3d-viewer` 内按「声明 `Content-Type` → 字节魔数 → 地址扩展名」进行,判不出来即 `unsupported-format`。
|
||||
10. 「哪些宿主能开 3D 预览」通过工具条的 `preview-model3d` capability 位表达,AGC 项目画布本期不进入该能力集合。
|
||||
@@ -39,5 +39,5 @@ Tripo 生成的 3D 资源在图片画布里作为 `model3d` 类别落地:卡
|
||||
|
||||
- glTF 的多文件兄弟资源(`.bin`、贴图)暂不解析,只支持自包含模型;provider 若返回多文件 glTF,查看器会加载失败并提示。
|
||||
- 一张模型只显示一张预览图;多视角、动画播放、材质切换与模型信息(面数、体积)都不在本次范围。
|
||||
- 素材库行、后台列表、精选卡片与公开 grant 未接 3D renderer,只保证字段正确、不承诺展示。
|
||||
- 后台列表、精选卡片与公开 grant 未接 3D renderer,只保证字段正确、不承诺展示;素材库行只做预览图渲染,行内不开 3D 查看器。
|
||||
- AGC 项目画布自带两份格式判断(`isResourceModelFbx` 的 `octet-stream` 当 FBX、资源卡预览的扩展名正则)本期不动,后续统一收敛到 `packages/model3d-viewer`。
|
||||
|
||||
@@ -29,7 +29,7 @@ Implementation Plan: `docs/project-memory/plans/【实施计划】Tripo生成API
|
||||
## 验收标准
|
||||
|
||||
1. API 请求与结果契约可编译,并通过 ts-rs 生成到 `packages/shared/src/contracts/model3d/` 的对应目录;生成产物经 prettier 后提交。
|
||||
2. 请求落点用平坦可选字段:`projectId` 与 `assetFolderId` 都不给或都给都失败;`canvasCompletion` 与 `assetFolderId` 同现失败。
|
||||
2. 请求落点用平坦可选字段:`projectId` 与 `assetFolderId` 至少给一个,两个都给合法(与其它画布生成工具一致);`canvasCompletion` 与“没有 `projectId`”同现失败。
|
||||
3. `source` 同时给出两个 ID、或使用裸字符串时被拒绝。
|
||||
4. `external_generation_job` 新字段追加在结构体末尾且带显式默认值;`migration.rs`、表目录与生成绑定同步,`npm run check:spacetime-schema` 通过。
|
||||
5. checkpoint procedure 只在租约有效且 lease token 匹配时写入;过期或错误 token 被拒。
|
||||
|
||||
@@ -24,7 +24,7 @@ Related: `docs/adr/【ADR】0004-3D生成入口价格与幂等身份-2026-09-21.
|
||||
|
||||
- 不新建独立生成页、结果页、runtime、作品架、广场、作品统计;3D 是资产型产出,不进玩法闭环。
|
||||
- 不接 multiview-to-model、Splat、rig、animation、texture、convert。
|
||||
- 不做素材库落点入口(前端只发 `projectId`,不发 `assetFolderId`)、后台 renderer、精选 read model、公开 grant、External v1。
|
||||
- 不做后台 renderer、精选 read model、公开 grant、External v1。(素材库落点与素材库行消费端已接:提交与其它画布生成工具同形,同时发 `projectId` + `assetFolderId` + `assetLabel`。)
|
||||
- 不接画布 Agent 对话调度。
|
||||
- 不改后端、不改 schema、不新增公开 API。
|
||||
- 不在前端内置任何 3D 价格兜底数值;不承诺移动端画布(跟随现状)。
|
||||
|
||||
@@ -9393,6 +9393,7 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
- 影响面:`server-rs/crates/shared-contracts/src/model3d/{text_to_model/request.rs,image_to_model/request.rs,common/mod.rs}`(删除 `common/generation_target.rs`)、`server-rs/crates/api-server/src/tripo3d/{job.rs,validation.rs,target.rs,routes.rs,worker.rs}`、`server-rs/crates/api-server/src/editor_project.rs`(删除 Standard 的 `result` 透传)、`packages/shared/src/contracts/model3d/`(删除 `common/Model3dGenerationTarget.ts` 与 barrel 导出)、`src/components/image-editor/model3d-generation/{Model3dGenerationSubmission.ts,useModel3dGenerationTask.test.tsx}`、`src/services/image-editor/editorProjectClient.ts`、技术方案 / 里程碑 / 实施计划与共享记忆。
|
||||
- 验证方式:`cargo test -p shared-contracts`、`cargo test -p api-server`(1193 passed)、`cargo test -p api-server tripo3d::`(55 passed,含 `target_requires_exactly_one_flat_locator`、`flat_locator_maps_to_point_lookup_without_rewriting_ids` 与 `flat_target_is_normalized_before_enqueue`)、`npx vitest run src/components/image-editor/model3d-generation src/components/image-editor/model3d-preview`(63 passed)、`npm run typecheck`、`npm run contracts:model3d:generate`、`npm run check:encoding`、`npm run check:rustfmt`、`git diff --check`。
|
||||
- 关联文档:[技术方案 Tripo 3D生成API集成](../../technical/【技术方案】Tripo 3D生成API集成-2026-09-21.md)、[实施计划 Tripo生成API契约与数据模型](../plans/【实施计划】Tripo生成API契约与数据模型-2026-09-21.md)。
|
||||
- 2026-09-23 追加修正:本条里的「恰好一个落点」「二选一不变」已被同日后续决策推翻——服务端改为「至少一个落点、两个可同给」,结果引用也一并改平坦;见下文「3D 落点对齐其它生成工具」。
|
||||
|
||||
## 2026-09-23 图生 3D 的图片输入失败语义:只收敛「引用不可用」,缺对象键改判 502
|
||||
|
||||
@@ -9413,3 +9414,13 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
- 影响面:`server-rs/crates/api-server/src/tripo3d/storage.rs`(新增 `sniff_preview_content_type`、`resolve_artifact_content_type` 改为按槽位判定、定向用例重写为「字节优先 / 未知回落」两组)、[技术方案 Tripo 3D生成API集成](../../technical/【技术方案】Tripo 3D生成API集成-2026-09-21.md)。
|
||||
- 验证方式:`cargo test --locked -p api-server tripo3d::`(56 passed,含 `preview_content_type_follows_bytes_over_declaration` 与 `preview_content_type_keeps_declaration_when_bytes_are_unknown`)、`rustfmt --check`、`npm run check:encoding`、`node scripts/check-doc-index.mjs`。
|
||||
- 关联文档:[技术方案 Tripo 3D生成API集成](../../technical/【技术方案】Tripo 3D生成API集成-2026-09-21.md)、[实施计划 Tripo生成API契约与数据模型](../plans/【实施计划】Tripo生成API契约与数据模型-2026-09-21.md)。
|
||||
|
||||
## 2026-09-23 3D 落点对齐其它生成工具:双落点同给、结果引用改平坦、素材库行接 3D 消费
|
||||
|
||||
- 背景:G5 复核(对照图片 / 图标 / 音效 / 角色动作等所有画布生成工具的前后端)发现 3D 仍有三处自成一派:① 服务端要求「`projectId` 与 `assetFolderId` 恰好一个」,而其它工具两个都能给,且前端画布链路**始终**同时发 `projectId` + `assetFolderId`(当前素材夹) + `assetLabel`,落库时项目资源行与素材行两条都写;② 3D 前端提交只发 `projectId`,于是 3D 结果永远不进素材库,同一张画布上的其它生成工具却都会进;③ 结果里的落点引用还是 tagged enum(`{ kind: "projectResource" | "assetLibrary" }`),与请求侧的平坦落点形状不一致;素材库行也没有 `model3d` 分支,一旦真落了素材行,缩略图会拿 `objectKey`(模型 `.glb`)去换签名地址。
|
||||
- 决策:① 服务端校验放宽为「至少一个落点」:两个都不给 400 点名 `projectId`,`canvasCompletion` 与「没有 `projectId`」同现 400 点名 `canvasCompletion`,两个都给合法;预检对给出的每个落点逐个定点查,出错时字段名只在「只给一个」时点名该字段,两个都给无法归因就回落到 `target`。② `Model3dGenerationTargetRef` 从 tagged enum 改成与请求落点同形的平坦可选字段 `resourceId?` / `assetId?`:哪个落点写了行就带哪个 ID,两个都写就都带。③ 前端 `buildModel3dSubmissionPlan` 接收当前素材夹与素材名,与其它工具一样同时发 `projectId` + `assetFolderId` + `assetLabel`(缺省名回落本次结果标题),`useModel3dGenerationTask` 从画布生成链路拿到 `assetFolderId`;结果消费沿用既有画布路径(`applyGeneratedProjectSnapshot` 顺带刷新素材库),不再需要 3D 专用刷新。④ 素材库行加 `model3d` 分支:缩略图按预览图(`asset.src`)渲染,`objectKey`(模型本体)不参与图片签名,与画布 3D 卡片的 `objectKey={null}` 口径一致。
|
||||
- 原因:**同一件事在各工具间必须同形**——落点是「结果放哪儿」的同一语义,3D 没有理由单独要求二选一;其它工具「画布 + 素材库同时落」既是现状也是用户预期(同一画布上的产出应当都能在素材库里找到)。结果引用跟着请求形状走,消费方不需要为同一个概念准备两套类型。素材库行的隐患属于「不接就永远发现不了」的类型:后端投影已经把 `imageSrc` 指向预览、`objectKey` 指向模型本体(`project_editor_client_media_src`),前端再拿 `objectKey` 签名就会去加载 `.glb`。
|
||||
- 代价与取舍:3D 现在会像其它画布工具一样,每次都往素材库写一条素材行(落点是当前素材夹,默认 `project` → owner 默认素材夹),素材库体积与写入量随 3D 使用增加,这是与其它工具一致的既有代价。素材库行只做预览图渲染与拖入画布,行内不开 3D 查看器,要看模型仍需拖到画布后点「3D 预览」。3D **仍要求 `projectId`**(画布链路必须已保存工程,否则提示「请先保存当前画布工程」),这一点与「`projectId` 可空、只落素材库」的其它工具仍有差异,属于有意保留:3D 入口只在有画布的编辑器里,没有画布就没有 3D 查看入口。本分支未合并,无外部调用方,结果引用形状变化不需要兼容层。
|
||||
- 影响面:`server-rs/crates/shared-contracts/src/model3d/common/generation_target_ref.rs`(tagged enum → 平坦结构,`packages/shared/src/contracts/model3d/common/Model3dGenerationTargetRef.ts` 随之变宽)、`server-rs/crates/api-server/src/tripo3d/{validation.rs,target.rs,job.rs,worker.rs}`、`server-rs/crates/shared-contracts/tests/model3d_api_request_contract.rs`、`src/components/image-editor/model3d-generation/{Model3dGenerationSubmission.ts,useModel3dGenerationTask.ts}`、`src/components/image-editor/useImageCanvasGenerationSubmissionWorkflow.ts`、`src/components/image-editor/ImageCanvasAssetRowView.tsx`、技术方案 / 里程碑 / 实施计划三份 3D 文档与共享记忆。
|
||||
- 验证方式:`cargo test -p api-server tripo3d::`(56 passed,含 `target_accepts_both_locators_but_requires_at_least_one`、`flat_locator_maps_to_point_lookup_without_rewriting_ids`、`unavailable_field_names_the_given_locators`、`completed_result_is_strict_per_endpoint_and_free_of_provider_facts`)、`cargo test -p shared-contracts`、`npm run contracts:model3d:generate`、`npx vitest run src/components/image-editor/model3d-generation src/components/image-editor/ImageCanvasAssetRowView.test.tsx`(67 passed)、`npm run typecheck`、`npm run check:encoding`、`npm run check:rustfmt`、`node scripts/check-doc-index.mjs`、`git diff --check`。
|
||||
- 关联文档:[技术方案 Tripo 3D生成API集成](../../technical/【技术方案】Tripo 3D生成API集成-2026-09-21.md)、[里程碑 Tripo生成API契约与数据模型](../plans/【里程碑】Tripo生成API契约与数据模型-2026-09-21.md)、[实施计划 Tripo生成前端入口](../plans/【实施计划】Tripo生成前端入口-2026-09-21.md)、[实施计划 Tripo生成结果前端预览接入](../plans/【实施计划】Tripo生成结果前端预览接入-2026-09-21.md)。
|
||||
|
||||
Reference in New Issue
Block a user