3D 生成请求允许缺省 textureQuality 并按 standard 计价
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
- PricingParamView::validate 不再要求 texture=true 时显式给出 textureQuality,缺省按 standard 计价 - 只有显式 detailed / extreme 才命中 hdTexture / ultraTexture 加价,缺省不改变报价 - v2.5 拒绝任何显式 texture_quality,必填规则会让 H25 + texture=true 永远不可达 - texture=false 仍禁止出现贴图档位,原有冲突校验与用例保持不变 - 同步技术方案:说明 geometryQuality / textureQuality 两个字段允许缺省的共同理由
This commit is contained in:
@@ -60,13 +60,13 @@ assetLabel? 素材名称,缺省用平台默认名
|
||||
canvasCompletion? 画布占位框回填,只在项目资源落点下生效
|
||||
```
|
||||
|
||||
`projectId` 与 `assetFolderId` 至少给一个,并且允许同时给:两个都不给直接 400;同时给时画布资源行与素材行两条都写,与图片等画布生成工具完全一致(画布链路本来就会把“当前素材夹”一起发出去,见下)。`assetLabel` 只在素材库落点下生效,缺省用本次结果标题;`canvasCompletion` 是项目资源落点的回填载荷,“没有 `projectId` 却带占位框”被拒绝。不存在“都不给就默认落素材库”的口径。
|
||||
`projectId` 与 `assetFolderId` 至少给一个,并且允许同时给:两个都不给直接 400;同时给时画布资源行与素材行两条都写;只给 `assetFolderId` 时结果只落素材库,不要求调用方先有画布工程。以上三条与图片等画布生成工具完全一致(画布链路本来就会把“当前素材夹”一起发出去,见下)。`assetLabel` 只在素材库落点下生效,缺省用本次结果标题;`canvasCompletion` 是项目资源落点的回填载荷,“没有 `projectId` 却带占位框”被拒绝。不存在“都不给就默认落素材库”的口径。
|
||||
|
||||
落点预检与其它付费编辑器生成共用同一条路径:提交时调只读 `preflight_editor_generation_target_and_return`,按认证 owner 对给出的落点逐个定点归属校验(两个都给就两个都查,不再为了一个目录 ID 读整个素材库),跨 owner / 已删除 / 不存在收敛成同一句 400。
|
||||
|
||||
**归一在预检之前完成并写回请求**:项目 ID 与素材夹 ID 都 trim,`project` / 旧 `folder-*` 走与图片画布同一个 `normalize_generated_asset_folder_id` 映射到当前 owner 的默认素材夹,素材名走同一个 `resolve_editor_generated_asset_label`(trim + 截断 + 缺省「3D 模型」)。入队的就是归一后的请求,因此预检值 = 队列载荷 = 落库值;模块侧落库原有的 `normalize_editor_generation_default_asset_folders` 继续兜底老队列载荷里的 `project`。
|
||||
|
||||
**定价相关参数在 API 层做组合校验**:`texture`、`textureQuality`、`quad`、`smartLowPoly`、`generateParts` 必须显式给出;`geometryQuality` 允许缺省,缺省按 `standard` 计价 —— provider 对 v2.5 / P1 / P2 不支持该参数,v3.x 的缺省也是 `standard`,两边同价,因此只有显式 `detailed` 才命中 `hdGeometry` 加价(写死必填只会让定价表里已有的 v2.5 / P1 / P2 永远不可达)。`texture=false` 时禁止出现 `textureQuality`,且 `pbr` 必须显式 `false`;`texture=true` 时 `textureQuality` 必填。其余会改价的参数仍必须显式给出:provider 的隐式默认值会直接改变价格,一旦依赖默认值,报价与扣费会在“调用方少传字段”时分叉。
|
||||
**定价相关参数在 API 层做组合校验**:`texture`、`quad`、`smartLowPoly`、`generateParts` 必须显式给出;`geometryQuality` 与 `textureQuality` 允许缺省,缺省按 `standard` 计价 —— provider 对 v2.5 不支持 `geometry_quality`、并拒绝任何 `texture_quality`,v3.x 的缺省档也是 `standard`,两边同价,因此只有显式 `detailed` / `extreme` 才命中 `hdGeometry` / `hdTexture` / `ultraTexture` 加价(把这两个字段写死必填只会让定价表里已有的 v2.5 / P1 / P2 永远不可达,或让 `texture=true` 的 v2.5 无论填什么都被 provider 预检拒绝)。`texture=false` 时禁止出现 `textureQuality`,且 `pbr` 必须显式 `false`。其余会改价的参数仍必须显式给出:provider 的隐式默认值会直接改变价格,一旦依赖默认值,报价与扣费会在“调用方少传字段”时分叉。
|
||||
|
||||
两个 submit 都必须携带 `Idempotency-Key`,复用现有头部校验;缺失或格式非法直接 400,不静默生成键。
|
||||
|
||||
@@ -94,7 +94,7 @@ ImageToModelResult = { modelArtifact, renderedPreview }
|
||||
|
||||
每个 artifact 只携带正式资源引用与对象元数据,不携带 provider 临时 URL。
|
||||
|
||||
**完成结果的读取**:与其它画布生成任务同形——结果落在画布 / 素材行,客户端靠读回拿到。项目资源落点的 worker 写画布 placement(预览图层),客户端在任务终态后用 `loadEditorProject` 复读项目快照,按 `layer.objectKey` 打开模型;素材库落点写素材行(画布链路两个落点都发,所以一次 3D 生成通常两条都写)。结果里的落点引用与请求落点同形:`target` 不再是被判别结构包着的分支,而是平坦的 `resourceId` / `assetId`,哪个落点写了行就带哪个 ID。前端画布链路的结果消费沿用既有画布路径(项目快照 + `applyGeneratedProjectSnapshot` 顺带刷新素材库),素材库行的 3D 缩略图按预览图渲染、不拿模型对象换签名地址。标准消费者的队列结果只回来源身份,**不透传 `result`**,因此 `/api/runtime/external-generation/jobs/{jobId}` 的 `result` 对 3D 为空——图片等其它画布生成任务也是如此。上面那份严格 tagged enum 是 worker 落库时构造的内部结果值:它只携带正式资源引用与对象元数据,不携带 provider 事实。
|
||||
**完成结果的读取**:与其它画布生成任务同形——结果落在画布 / 素材行,客户端靠读回拿到(没有 `projectId` 时只有素材行可读回,与其它画布工具在无工程时的行为一致)。项目资源落点的 worker 写画布 placement(预览图层),客户端在任务终态后用 `loadEditorProject` 复读项目快照,按 `layer.objectKey` 打开模型;素材库落点写素材行(画布链路两个落点都发,所以一次 3D 生成通常两条都写)。结果里的落点引用与请求落点同形:`target` 不再是被判别结构包着的分支,而是平坦的 `resourceId` / `assetId`,哪个落点写了行就带哪个 ID。前端画布链路的结果消费沿用既有画布路径(项目快照 + `applyGeneratedProjectSnapshot` 顺带刷新素材库),素材库行的 3D 缩略图按预览图渲染、不拿模型对象换签名地址。标准消费者的队列结果只回来源身份,**不透传 `result`**,因此 `/api/runtime/external-generation/jobs/{jobId}` 的 `result` 对 3D 为空——图片等其它画布生成任务也是如此。上面那份严格 tagged enum 是 worker 落库时构造的内部结果值:它只携带正式资源引用与对象元数据,不携带 provider 事实。
|
||||
|
||||
## 定价与扣费
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//! Tripo 生成请求的平台侧组合校验。
|
||||
//!
|
||||
//! 这里只判两类事:
|
||||
//! 1. 平台自己新增的口径——会改价的参数必须显式给出(`geometryQuality` 例外:缺省等价于
|
||||
//! provider 的 standard,不产生加价),贴图、贴图档位与 pbr 不能互相矛盾;
|
||||
//! 1. 平台自己新增的口径——会改价的参数必须显式给出(`geometryQuality` 与 `textureQuality`
|
||||
//! 例外:缺省等价于 provider 的 standard,不产生加价),贴图、贴图档位与 pbr 不能互相矛盾;
|
||||
//! 2. 模型档位与参数的能力组合——直接复用 `platform-tripo` 的请求预检,不维护第二份规则。
|
||||
//!
|
||||
//! 校验必须在扣费与任何 provider 调用之前完成;拿不到合法参数与价格就不提交、不入队。
|
||||
@@ -125,20 +125,17 @@ impl PricingParamView {
|
||||
|
||||
let texture_quality = match (texture, self.texture_quality) {
|
||||
(true, Some(quality)) => quality,
|
||||
(true, None) => {
|
||||
return Err(Model3dRequestError::invalid(
|
||||
"generation.textureQuality",
|
||||
"texture=true 时必须显式给出贴图档位",
|
||||
));
|
||||
}
|
||||
(false, Some(_)) => {
|
||||
return Err(Model3dRequestError::invalid(
|
||||
"generation.textureQuality",
|
||||
"texture=false 时不允许出现贴图档位",
|
||||
));
|
||||
}
|
||||
// 不生成贴图时贴图档位无意义,add-on 判定又被 texture 挡住,因此取标准档占位。
|
||||
(false, None) => Model3dTextureQuality::Standard,
|
||||
// 两处缺省都按 standard 计价:texture=true 时 standard 是 provider 的缺省档,
|
||||
// 也是唯一覆盖全部模型族的档位(v2.5 拒绝任何显式 texture_quality,写死必填就会
|
||||
// 让 H25 + texture=true 永远不可达);texture=false 时贴图档位本身无意义,
|
||||
// add-on 判定已被 texture 挡住。
|
||||
(_, None) => Model3dTextureQuality::Standard,
|
||||
};
|
||||
if !texture && self.pbr != Some(false) {
|
||||
return Err(Model3dRequestError::invalid(
|
||||
@@ -322,15 +319,25 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn texture_on_requires_texture_quality() {
|
||||
fn texture_on_defaults_texture_quality_to_standard() {
|
||||
let request = text_request(generation_with(json!({ "textureQuality": null })));
|
||||
let error =
|
||||
validate_text_to_model_request(&request).expect_err("texture=true 必须有贴图档位");
|
||||
assert_eq!(
|
||||
error.field().as_deref(),
|
||||
Some("generation.textureQuality"),
|
||||
"实际报错:{error}"
|
||||
let query = validate_text_to_model_request(&request)
|
||||
.unwrap_or_else(|error| panic!("texture=true 缺省贴图档位应通过校验:{error}"));
|
||||
assert!(
|
||||
!query.add_ons.contains(Model3dAddOn::HdTexture)
|
||||
&& !query.add_ons.contains(Model3dAddOn::UltraTexture),
|
||||
"缺省贴图档位按 standard 计价,不给任何贴图加价"
|
||||
);
|
||||
|
||||
// v2.5 拒绝任何显式 texture_quality:必填规则会让 H25 + texture=true 永远不可达。
|
||||
let request = text_request(generation_with(json!({
|
||||
"model": "v2.5-20250123",
|
||||
"textureQuality": null,
|
||||
"geometryQuality": null
|
||||
})));
|
||||
let query = validate_text_to_model_request(&request)
|
||||
.unwrap_or_else(|error| panic!("v2.5 缺省贴图档位应通过校验:{error}"));
|
||||
assert!(query.texture, "v2.5 缺省贴图档位仍是带贴图请求");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user