From 952bc1ccaae7f27bd22299815aaa6e0f48ef8c86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Wed, 23 Sep 2026 11:15:42 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A6=86=E7=9B=96=E6=96=87=E4=BB=B6=E7=BC=BA?= =?UTF-8?q?=203D=20=E6=AE=B5=E6=97=B6=E6=8C=89=E5=8F=97=E6=8E=A7=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E4=BB=B7=E8=A1=A5=E9=BD=90=EF=BC=8C=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E6=8A=8A=203D=20=E6=95=B4=E6=AE=B5=E7=AE=97=E6=88=90=E6=9C=AA?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 backfill_legacy_model3d_pricing:旧覆盖文件整段没有 3D 时补上默认 JSON 的两段并告警 - 覆盖文件继续只承担种子与兜底,避免老种子文件把 3D 生成整段关掉 - 补用例覆盖覆盖文件缺 3D 段的读取 --- .../src/editor_generation_config.rs | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/server-rs/crates/api-server/src/editor_generation_config.rs b/server-rs/crates/api-server/src/editor_generation_config.rs index 67a07fe4a..4371cb2b9 100644 --- a/server-rs/crates/api-server/src/editor_generation_config.rs +++ b/server-rs/crates/api-server/src/editor_generation_config.rs @@ -6,6 +6,7 @@ use std::{ }; use serde::{Deserialize, Serialize}; +use tracing::warn; use crate::asset_billing::current_external_generation_billing_price_mud_points; use crate::tripo3d::pricing::{ @@ -391,6 +392,7 @@ fn load_editor_generation_pricing_from_candidates( serde_json::from_str::(override_json.as_str()) .map_err(EditorGenerationPricingError::Json)?; backfill_legacy_sfx_pricing(&mut override_config, &config, source.as_ref())?; + backfill_legacy_model3d_pricing(&mut override_config, &config, source.as_ref()); override_config.validate().map_err(|error| match error { EditorGenerationPricingError::Invalid(message) => { EditorGenerationPricingError::Invalid(format!("{source}: {message}")) @@ -429,6 +431,25 @@ fn backfill_legacy_sfx_pricing( Ok(()) } +/// 旧覆盖文件可能整段没有 3D 定价(3D 是后加的段):缺失时用当前受控默认价补齐。 +/// +/// 覆盖文件只承担种子与兜底,不代表「3D 未配置」;这里补齐后,表内缺 3D 段的老行也能 +/// 按同一份默认价归一化,不会因为文件里没有这一段就把 3D 生成整段关掉。 +fn backfill_legacy_model3d_pricing( + config: &mut EditorGenerationPricingConfig, + fallback: &EditorGenerationPricingConfig, + source: &str, +) { + if config.model3d.is_some() || fallback.model3d.is_none() { + return; + } + warn!( + source, + "覆盖文件缺少 3D 定价段,已按受控默认价补齐;确认 3D 价格后再从后台保存一次" + ); + config.model3d = fallback.model3d.clone(); +} + pub(crate) fn parse_editor_generation_pricing_json( json: &str, source: &str, @@ -1136,6 +1157,36 @@ mod tests { std::fs::remove_dir_all(&temp_dir).expect("temp dir should remove"); } + #[test] + fn editor_generation_pricing_legacy_override_backfills_missing_model3d_section() { + let temp_dir = unique_temp_dir("genarrative-pricing-legacy-model3d-test"); + std::fs::create_dir_all(&temp_dir).expect("temp dir should create"); + let override_path = temp_dir.join("editor-generation-pricing.override.json"); + let mut legacy_config = default_runtime_pricing(); + legacy_config.model3d = None; + legacy_config + .models + .get_mut(EDITOR_SOUND_EFFECT_MODEL_VIDU) + .expect("legacy sound effect pricing should exist") + .price = Some(17); + std::fs::write( + &override_path, + serde_json::to_string(&legacy_config).expect("legacy config should serialize"), + ) + .expect("legacy override should write"); + + let loaded = load_editor_generation_pricing_from_paths(Some(&override_path)) + .expect("legacy override should backfill the 3D section"); + + assert_eq!( + loaded.model3d, + default_runtime_pricing().model3d, + "覆盖文件缺 3D 段时应补上受控默认价" + ); + assert_eq!(loaded.sound_effect_model_mud_points(Some("audio1.0")), 17); + std::fs::remove_dir_all(&temp_dir).expect("temp dir should remove"); + } + #[test] fn editor_generation_pricing_legacy_override_still_rejects_other_missing_models() { let temp_dir = unique_temp_dir("genarrative-pricing-legacy-required-model-test");