From 92832e56c2006b0621e265e004a536e8fb261d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Sat, 8 Aug 2026 18:06:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=81=A2=E5=A4=8D=E5=8F=AF=E9=80=89=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E7=94=9F=E6=88=90=E5=99=A8=E7=9A=84=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E7=B4=A0=E6=9D=90=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 角色图片生成在入队与同步执行预检前恢复 project 默认目录 UI 设计素材提取在入队与 worker 执行预检前恢复 project 默认目录 新增默认目录策略及四条调用路径回归测试 --- .../crates/api-server/src/editor_project.rs | 80 ++++++++++++++++++- 1 file changed, 76 insertions(+), 4 deletions(-) diff --git a/server-rs/crates/api-server/src/editor_project.rs b/server-rs/crates/api-server/src/editor_project.rs index ecdd3145f..ab2b7ef82 100644 --- a/server-rs/crates/api-server/src/editor_project.rs +++ b/server-rs/crates/api-server/src/editor_project.rs @@ -2645,7 +2645,10 @@ pub(crate) async fn enqueue_editor_image_generation_for_owner( state, caller.owner_user_id.as_str(), payload.project_id.clone(), - payload.asset_folder_id.clone(), + resolve_editor_image_generation_target_folder_id( + payload.asset_folder_id.clone(), + normalized_kind, + ), ) .await?; payload.project_id = target.project_id; @@ -2865,7 +2868,10 @@ where state, caller.owner_user_id.as_str(), payload.project_id.clone(), - payload.asset_folder_id.clone(), + resolve_editor_image_generation_target_folder_id( + payload.asset_folder_id.clone(), + normalized_kind, + ), ) .await?; payload.project_id = target.project_id; @@ -7240,7 +7246,7 @@ pub(crate) async fn enqueue_editor_ui_design_asset_extraction_for_owner( state, caller.owner_user_id.as_str(), payload.project_id.clone(), - payload.asset_folder_id.clone(), + resolve_editor_ui_design_asset_extraction_target_folder_id(payload.asset_folder_id.clone()), ) .await?; payload.project_id = target.project_id; @@ -7309,7 +7315,7 @@ pub(crate) async fn extract_editor_ui_design_assets_for_owner( state, caller.owner_user_id.as_str(), payload.project_id.clone(), - payload.asset_folder_id.clone(), + resolve_editor_ui_design_asset_extraction_target_folder_id(payload.asset_folder_id.clone()), ) .await?; payload.project_id = target.project_id; @@ -10224,6 +10230,22 @@ pub(crate) fn normalize_generated_asset_folder_id( } } +fn resolve_editor_image_generation_target_folder_id( + asset_folder_id: Option, + normalized_kind: Option<&str>, +) -> Option { + asset_folder_id.or_else(|| { + matches!(normalized_kind, Some("character")) + .then(|| EDITOR_ASSET_DEFAULT_FOLDER_ID.to_string()) + }) +} + +fn resolve_editor_ui_design_asset_extraction_target_folder_id( + asset_folder_id: Option, +) -> Option { + asset_folder_id.or_else(|| Some(EDITOR_ASSET_DEFAULT_FOLDER_ID.to_string())) +} + #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) struct EditorBillableGenerationTarget { pub(crate) project_id: Option, @@ -20037,6 +20059,56 @@ mod tests { assert_eq!(normalize_generated_asset_folder_id(None, "user-1"), None); } + #[test] + fn optional_folder_generators_restore_their_project_folder_defaults() { + assert_eq!( + resolve_editor_image_generation_target_folder_id(None, Some("character")).as_deref(), + Some(EDITOR_ASSET_DEFAULT_FOLDER_ID) + ); + assert_eq!( + resolve_editor_image_generation_target_folder_id(None, Some("scene")), + None + ); + assert_eq!( + resolve_editor_image_generation_target_folder_id( + Some("owner:asset-folder:custom".to_string()), + Some("character"), + ) + .as_deref(), + Some("owner:asset-folder:custom") + ); + assert_eq!( + resolve_editor_ui_design_asset_extraction_target_folder_id(None).as_deref(), + Some(EDITOR_ASSET_DEFAULT_FOLDER_ID) + ); + + let source = include_str!("editor_project.rs"); + for (start, end, resolver) in [ + ( + "pub(crate) async fn enqueue_editor_image_generation_for_owner", + "pub(crate) async fn validate_editor_image_generation_parameters_for_owner", + "resolve_editor_image_generation_target_folder_id(", + ), + ( + "pub(crate) async fn generate_editor_image_for_owner_with_prompt_builder", + "fn editor_image_generation_billing_asset_kind", + "resolve_editor_image_generation_target_folder_id(", + ), + ( + "pub(crate) async fn enqueue_editor_ui_design_asset_extraction_for_owner", + "pub(crate) async fn extract_editor_ui_design_assets_for_owner", + "resolve_editor_ui_design_asset_extraction_target_folder_id(", + ), + ( + "pub(crate) async fn extract_editor_ui_design_assets_for_owner", + "pub(crate) fn editor_project_payload_from_record", + "resolve_editor_ui_design_asset_extraction_target_folder_id(", + ), + ] { + assert_function_contains(source, start, end, &[resolver]); + } + } + fn assert_function_contains(source: &str, start: &str, end: &str, snippets: &[&str]) { let start_index = source .find(start)