From b342f1eecbaa96cf8591b9e698009b7a7d82258d Mon Sep 17 00:00:00 2001 From: Linghong Date: Thu, 9 Jul 2026 13:53:12 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=97=AE=E9=A2=98:=E9=98=BF?= =?UTF-8?q?=E9=87=8C=E4=BA=91=E6=9C=AA=E9=85=8D=E7=BD=AE/=E7=A6=81?= =?UTF-8?q?=E7=94=A8=E4=BC=9A=E8=A2=AB=E8=AE=B0=E5=BD=95=E6=88=90=E5=8F=AF?= =?UTF-8?q?=E9=87=8D=E8=AF=95=E7=9A=84=E5=A4=96=E9=83=A8=20503=20=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crates/api-server/src/aliyun_matting.rs | 24 ++++++++++---- .../src/character_animation_assets.rs | 32 ++++++++++--------- .../crates/api-server/src/editor_project.rs | 30 +++++++++-------- .../api-server/src/external_api_audit.rs | 24 ++++++++++++++ 4 files changed, 75 insertions(+), 35 deletions(-) diff --git a/server-rs/crates/api-server/src/aliyun_matting.rs b/server-rs/crates/api-server/src/aliyun_matting.rs index 2bccca389..cf2e9a4e0 100644 --- a/server-rs/crates/api-server/src/aliyun_matting.rs +++ b/server-rs/crates/api-server/src/aliyun_matting.rs @@ -17,12 +17,9 @@ pub(crate) async fn segment_image_with_aliyun_matting( image: &DownloadedOpenAiImage, log_label: &str, ) -> Result { - let matting_client = state.matting_client().ok_or_else(|| { - AppError::from_status(StatusCode::SERVICE_UNAVAILABLE).with_details(json!({ - "provider": "aliyun-matting", - "message": "阿里云抠图客户端未配置或未启用。", - })) - })?; + let matting_client = state + .matting_client() + .ok_or_else(aliyun_matting_unconfigured_error)?; let file_name = format!("{log_label}.png"); let started_at = std::time::Instant::now(); @@ -81,6 +78,14 @@ fn aliyun_matting_error_is_transport(message: &str) -> bool { aliyun_matting_error_http_status(message).is_none() } +fn aliyun_matting_unconfigured_error() -> AppError { + AppError::from_status(StatusCode::SERVICE_UNAVAILABLE).with_details(json!({ + "provider": "aliyun-matting", + "message": "阿里云抠图客户端未配置或未启用。", + "externalCallAttempted": false, + })) +} + #[cfg(test)] mod tests { use super::*; @@ -122,4 +127,11 @@ mod tests { "通用抠图接口返回失败(HTTP 429,Code=Throttled):QPS exceeded" )); } + + #[test] + fn aliyun_matting_unconfigured_error_marks_no_external_call_attempt() { + let error = aliyun_matting_unconfigured_error(); + + assert!(!crate::external_api_audit::matting_failure_external_call_attempted(&error)); + } } diff --git a/server-rs/crates/api-server/src/character_animation_assets.rs b/server-rs/crates/api-server/src/character_animation_assets.rs index 03e83157c..deb266331 100644 --- a/server-rs/crates/api-server/src/character_animation_assets.rs +++ b/server-rs/crates/api-server/src/character_animation_assets.rs @@ -2238,21 +2238,23 @@ async fn remove_editor_character_animation_frame_backgrounds( error_details = ?error.details(), "editor_animation_frame_aliyun_matting_fallback_to_local" ); - crate::external_api_audit::record_matting_external_api_failure( - state, - audit, - "aliyun-matting", - state.config.aliyun_matting_endpoint.clone(), - "editor-character-animation-frame-matting", - "aliyun_segment", - crate::external_api_audit::matting_failure_audit_status_code(&error), - crate::external_api_audit::matting_failure_audit_timeout(&error), - crate::external_api_audit::matting_failure_audit_latency_ms(&error), - error.message().to_string(), - crate::external_api_audit::matting_failure_audit_raw_excerpt(&error) - .or_else(|| Some(format!("frame_index={frame_index}"))), - ) - .await; + if crate::external_api_audit::matting_failure_external_call_attempted(&error) { + crate::external_api_audit::record_matting_external_api_failure( + state, + audit, + "aliyun-matting", + state.config.aliyun_matting_endpoint.clone(), + "editor-character-animation-frame-matting", + "aliyun_segment", + crate::external_api_audit::matting_failure_audit_status_code(&error), + crate::external_api_audit::matting_failure_audit_timeout(&error), + crate::external_api_audit::matting_failure_audit_latency_ms(&error), + error.message().to_string(), + crate::external_api_audit::matting_failure_audit_raw_excerpt(&error) + .or_else(|| Some(format!("frame_index={frame_index}"))), + ) + .await; + } remove_editor_generated_green_screen_background(&image, screen_color)? } }; diff --git a/server-rs/crates/api-server/src/editor_project.rs b/server-rs/crates/api-server/src/editor_project.rs index c4576087b..ab683f709 100644 --- a/server-rs/crates/api-server/src/editor_project.rs +++ b/server-rs/crates/api-server/src/editor_project.rs @@ -2304,20 +2304,22 @@ async fn fallback_editor_screen_background_removal( error_details = ?error.details(), "editor_aliyun_matting_fallback_to_local_screen_background_removal" ); - crate::external_api_audit::record_matting_external_api_failure( - state, - audit, - "aliyun-matting", - state.config.aliyun_matting_endpoint.clone(), - "editor-screen-background-removal", - "aliyun_segment", - crate::external_api_audit::matting_failure_audit_status_code(&error), - crate::external_api_audit::matting_failure_audit_timeout(&error), - crate::external_api_audit::matting_failure_audit_latency_ms(&error), - error.message().to_string(), - crate::external_api_audit::matting_failure_audit_raw_excerpt(&error), - ) - .await; + if crate::external_api_audit::matting_failure_external_call_attempted(&error) { + crate::external_api_audit::record_matting_external_api_failure( + state, + audit, + "aliyun-matting", + state.config.aliyun_matting_endpoint.clone(), + "editor-screen-background-removal", + "aliyun_segment", + crate::external_api_audit::matting_failure_audit_status_code(&error), + crate::external_api_audit::matting_failure_audit_timeout(&error), + crate::external_api_audit::matting_failure_audit_latency_ms(&error), + error.message().to_string(), + crate::external_api_audit::matting_failure_audit_raw_excerpt(&error), + ) + .await; + } remove_editor_generated_green_screen_background(image, screen_color) } } diff --git a/server-rs/crates/api-server/src/external_api_audit.rs b/server-rs/crates/api-server/src/external_api_audit.rs index 9f9417e49..e62d3a0fb 100644 --- a/server-rs/crates/api-server/src/external_api_audit.rs +++ b/server-rs/crates/api-server/src/external_api_audit.rs @@ -248,6 +248,14 @@ pub(crate) fn matting_failure_audit_latency_ms(error: &AppError) -> Option .and_then(Value::as_u64) } +pub(crate) fn matting_failure_external_call_attempted(error: &AppError) -> bool { + error + .details() + .and_then(|details| details.get("externalCallAttempted")) + .and_then(Value::as_bool) + .unwrap_or(true) +} + pub(crate) fn matting_failure_audit_raw_excerpt(error: &AppError) -> Option { error .details() @@ -741,4 +749,20 @@ mod tests { assert_eq!(tracking.metadata["retryable"], false); assert_eq!(tracking.metadata["latencyMs"], 67); } + + #[test] + fn matting_failure_external_call_attempted_defaults_to_true() { + let attempted = AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({ + "provider": "aliyun-matting", + "message": "真实上游失败", + })); + let skipped = AppError::from_status(StatusCode::SERVICE_UNAVAILABLE).with_details(json!({ + "provider": "aliyun-matting", + "message": "阿里云抠图客户端未配置或未启用。", + "externalCallAttempted": false, + })); + + assert!(matting_failure_external_call_attempted(&attempted)); + assert!(!matting_failure_external_call_attempted(&skipped)); + } }