From b0bb71a79e920e8938c2ecb55302a932a696f473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Tue, 22 Sep 2026 14:03:19 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=A9=20resolve=5Fimage=5Fprovider=20?= =?UTF-8?q?=E7=9A=84=E6=8B=92=E7=BB=9D=E5=8E=9F=E5=9B=A0=E5=B8=A6=E4=B8=8A?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - resolve_image_provider 错误类型从 &'static str 改为 String,未知模型返回「不支持的图片模型:{model}」 - ensure_provider_matches_model 去掉重复拼接的模型名,避免错误信息出现两遍输入 - openai_image_generation 缺少参考图的本地校验改用显式 match,不再用 unwrap_or 静默假定 Tiantoken - 补充断言:业务模型名与 unknown-model 的拒绝原因里必须包含被拒绝的模型值 --- .../api-server/src/openai_image_generation.rs | 7 ++++++- .../src/image_provider/protocol/request.rs | 4 ++-- .../src/image_provider/runtime/executor.rs | 3 ++- .../crates/platform-image/tests/image_provider.rs | 14 ++++++++++++-- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/server-rs/crates/api-server/src/openai_image_generation.rs b/server-rs/crates/api-server/src/openai_image_generation.rs index 03adbc863..f3aa2d797 100644 --- a/server-rs/crates/api-server/src/openai_image_generation.rs +++ b/server-rs/crates/api-server/src/openai_image_generation.rs @@ -243,7 +243,12 @@ pub(crate) async fn create_openai_image_edit_with_references_and_model( // 中文注释:先做本地参考图校验,避免 provider 客户端缺失时在校验前 panic。 // provider 归属与下方非空参考图路径保持一致,按模型解析而不是固定 Tiantoken。 if reference_images.is_empty() { - let provider = resolve_image_provider(model).unwrap_or(ImageProvider::Tiantoken); + let provider = match resolve_image_provider(model) { + Ok(provider) => provider, + // 这里只为一个本地校验错误选归属标签;未知模型无法归属 provider 时 + // 显式回落到 Tiantoken,不再用 unwrap_or 静默吞掉解析失败。 + Err(_) => ImageProvider::Tiantoken, + }; return map_platform_image_result( settings, Err(missing_reference_images_error(provider, failure_context)), diff --git a/server-rs/crates/platform-image/src/image_provider/protocol/request.rs b/server-rs/crates/platform-image/src/image_provider/protocol/request.rs index 23470a04e..f46fe299e 100644 --- a/server-rs/crates/platform-image/src/image_provider/protocol/request.rs +++ b/server-rs/crates/platform-image/src/image_provider/protocol/request.rs @@ -120,13 +120,13 @@ pub(crate) fn normalize_nanobanana_model(model: &str) -> &str { /// nanobanana 走 VectorEngine。业务模型名 `gpt-image-2.5` /// (`GPT_IMAGE_2_5_BUSINESS_NAME`) 必须在任务边界解析成具体 key;已删除的 /// `gpt-image-2-c` 命中即拒绝。`gpt-image-2` 仍按历史可读值接受。 -pub fn resolve_image_provider(model: &str) -> Result { +pub fn resolve_image_provider(model: &str) -> Result { match normalize_image_model(model) { GPT_IMAGE_2_MODEL | GPT_IMAGE_2_5_GENERATION_MODEL | GPT_IMAGE_2_5_EDIT_MODEL => { Ok(ImageProvider::Tiantoken) } NANOBANANA_2_MODEL => Ok(ImageProvider::VectorEngine), - _ => Err("不支持的图片模型"), + _ => Err(format!("不支持的图片模型:{model}")), } } diff --git a/server-rs/crates/platform-image/src/image_provider/runtime/executor.rs b/server-rs/crates/platform-image/src/image_provider/runtime/executor.rs index 0f25bcd58..c907099f3 100644 --- a/server-rs/crates/platform-image/src/image_provider/runtime/executor.rs +++ b/server-rs/crates/platform-image/src/image_provider/runtime/executor.rs @@ -709,10 +709,11 @@ pub(crate) fn ensure_provider_matches_model( model: &str, failure_context: &str, ) -> Result<(), PlatformImageError> { + // `resolve_image_provider` 的错误信息已经带上被拒绝的模型名,这里不再重复拼接。 let resolved = resolve_image_provider(model).map_err(|message| PlatformImageError::InvalidRequest { provider: settings.provider.as_str(), - message: format!("{failure_context}:{message}:{model}"), + message: format!("{failure_context}:{message}"), })?; if resolved != settings.provider { return Err(PlatformImageError::InvalidRequest { diff --git a/server-rs/crates/platform-image/tests/image_provider.rs b/server-rs/crates/platform-image/tests/image_provider.rs index c1ca9439d..8c0f50fa1 100644 --- a/server-rs/crates/platform-image/tests/image_provider.rs +++ b/server-rs/crates/platform-image/tests/image_provider.rs @@ -220,7 +220,12 @@ fn nanobanana_generate_content_url_blank_model_falls_back_to_nanobanana_model() #[test] fn resolve_image_provider_rejects_business_model_and_accepts_concrete_models() { // 中文注释:业务模型名不是 provider model,必须在 api-server 任务边界先解析成具体 model。 - assert!(resolve_image_provider(GPT_IMAGE_2_5_BUSINESS_NAME).is_err()); + let business_model_error = + resolve_image_provider(GPT_IMAGE_2_5_BUSINESS_NAME).expect_err("业务模型名必须被拒绝"); + assert!( + business_model_error.contains(GPT_IMAGE_2_5_BUSINESS_NAME), + "拒绝原因必须带上被拒绝的模型名,实际为:{business_model_error}" + ); // 中文注释:已删除的 gpt-image-2-c 不再被任何层接受。 assert!(resolve_image_provider("gpt-image-2-c").is_err()); @@ -242,7 +247,12 @@ fn resolve_image_provider_rejects_business_model_and_accepts_concrete_models() { resolve_image_provider("gemini-3.1-flash-image-preview"), Ok(ImageProvider::VectorEngine) ); - assert!(resolve_image_provider("unknown-model").is_err()); + let unknown_model_error = + resolve_image_provider("unknown-model").expect_err("未知模型必须被拒绝"); + assert!( + unknown_model_error.contains("unknown-model"), + "拒绝原因必须带上被拒绝的模型名,实际为:{unknown_model_error}" + ); } #[tokio::test]