diff --git a/crates/schema/public/enums/src/common/model_type.rs b/crates/schema/public/enums/src/common/model_type.rs index caeb567333..de385295be 100644 --- a/crates/schema/public/enums/src/common/model_type.rs +++ b/crates/schema/public/enums/src/common/model_type.rs @@ -40,6 +40,8 @@ pub enum ModelType { SeedEdit3, #[serde(rename = "qwen")] Qwen, + #[serde(rename = "qwen_edit_2511_angles")] + QwenEdit2511Angles, /// Gemini 2.5 Flash, AKA "Nano Banana" #[serde(rename = "gemini_25_flash")] Gemini25Flash, @@ -158,6 +160,7 @@ impl ModelType { Self::Recraft3 => "recraft_3", Self::SeedEdit3 => "seededit_3", Self::Qwen => "qwen", + Self::QwenEdit2511Angles => "qwen_edit_2511_angles", Self::Gemini25Flash => "gemini_25_flash", Self::NanoBanana => "nano_banana", Self::NanoBanana2 => "nano_banana_2", @@ -222,6 +225,7 @@ impl ModelType { "recraft_3" => Ok(Self::Recraft3), "seededit_3" => Ok(Self::SeedEdit3), "qwen" => Ok(Self::Qwen), + "qwen_edit_2511_angles" => Ok(Self::QwenEdit2511Angles), "gemini_25_flash" => Ok(Self::Gemini25Flash), "nano_banana" => Ok(Self::NanoBanana), "nano_banana_2" => Ok(Self::NanoBanana2), @@ -290,6 +294,7 @@ impl ModelType { Self::Recraft3, Self::SeedEdit3, Self::Qwen, + Self::QwenEdit2511Angles, Self::Gemini25Flash, Self::NanoBanana, Self::NanoBanana2, @@ -363,6 +368,7 @@ mod tests { assert_serialization(ModelType::Recraft3, "recraft_3"); assert_serialization(ModelType::SeedEdit3, "seededit_3"); assert_serialization(ModelType::Qwen, "qwen"); + assert_serialization(ModelType::QwenEdit2511Angles, "qwen_edit_2511_angles"); assert_serialization(ModelType::Gemini25Flash, "gemini_25_flash"); assert_serialization(ModelType::NanoBanana, "nano_banana"); assert_serialization(ModelType::NanoBanana2, "nano_banana_2"); @@ -423,6 +429,7 @@ mod tests { assert_eq!(ModelType::Recraft3.to_str(), "recraft_3"); assert_eq!(ModelType::SeedEdit3.to_str(), "seededit_3"); assert_eq!(ModelType::Qwen.to_str(), "qwen"); + assert_eq!(ModelType::QwenEdit2511Angles.to_str(), "qwen_edit_2511_angles"); assert_eq!(ModelType::Gemini25Flash.to_str(), "gemini_25_flash"); assert_eq!(ModelType::NanoBanana.to_str(), "nano_banana"); assert_eq!(ModelType::NanoBanana2.to_str(), "nano_banana_2"); @@ -485,6 +492,7 @@ mod tests { assert_eq!(ModelType::from_str("recraft_3").unwrap(), ModelType::Recraft3); assert_eq!(ModelType::from_str("seededit_3").unwrap(), ModelType::SeedEdit3); assert_eq!(ModelType::from_str("qwen").unwrap(), ModelType::Qwen); + assert_eq!(ModelType::from_str("qwen_edit_2511_angles").unwrap(), ModelType::QwenEdit2511Angles); assert_eq!(ModelType::from_str("gemini_25_flash").unwrap(), ModelType::Gemini25Flash); assert_eq!(ModelType::from_str("nano_banana").unwrap(), ModelType::NanoBanana); assert_eq!(ModelType::from_str("nano_banana_2").unwrap(), ModelType::NanoBanana2); @@ -533,7 +541,7 @@ mod tests { #[test] fn all_variants() { let mut variants = ModelType::all_variants(); - assert_eq!(variants.len(), 52); + assert_eq!(variants.len(), 53); // Image models assert_eq!(variants.pop_first(), Some(ModelType::Flux1Dev)); assert_eq!(variants.pop_first(), Some(ModelType::Flux1Schnell)); @@ -548,6 +556,7 @@ mod tests { assert_eq!(variants.pop_first(), Some(ModelType::Recraft3)); assert_eq!(variants.pop_first(), Some(ModelType::SeedEdit3)); assert_eq!(variants.pop_first(), Some(ModelType::Qwen)); + assert_eq!(variants.pop_first(), Some(ModelType::QwenEdit2511Angles)); assert_eq!(variants.pop_first(), Some(ModelType::Gemini25Flash)); assert_eq!(variants.pop_first(), Some(ModelType::NanoBanana)); assert_eq!(variants.pop_first(), Some(ModelType::NanoBanana2)); diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/generate/image/angle/qwen_edit_2511_edit_image_angle_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/image/angle/qwen_edit_2511_edit_image_angle_handler.rs index 7a703b8e2f..8df2369461 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/generate/image/angle/qwen_edit_2511_edit_image_angle_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/image/angle/qwen_edit_2511_edit_image_angle_handler.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use crate::billing::wallets::attempt_wallet_deduction::attempt_wallet_deduction_else_common_web_error; use crate::http_server::common_responses::common_web_error::CommonWebError; -use crate::http_server::endpoints::generate::common::payments_error_test::payments_error_test; +use crate::http_server::endpoint_helpers::refund_wallet_after_api_failure::refund_wallet_after_api_failure; use crate::http_server::validations::validate_idempotency_token_format::validate_idempotency_token_format; use crate::state::server_state::ServerState; use crate::util::lookup::lookup_image_urls_as_optional_list::lookup_image_urls_as_optional_list; @@ -131,19 +131,21 @@ pub async fn qwen_edit_2511_edit_image_angle_handler( info!("Charging wallet: {}", cost); - attempt_wallet_deduction_else_common_web_error( + let wallet_deduction = attempt_wallet_deduction_else_common_web_error( user_token, Some(apriori_job_token.as_str()), cost, &mut mysql_connection, ).await?; - let fal_result = enqueue_qwen_edit_2511_edit_image_angle_webhook(args) - .await - .map_err(|err| { - warn!("Error calling enqueue_qwen_edit_2511_edit_image_angle_webhook: {:?}", err); - CommonWebError::ServerError - })?; + let fal_result = match enqueue_qwen_edit_2511_edit_image_angle_webhook(args).await { + Ok(result) => result, + Err(err) => { + warn!("Error calling enqueue_qwen_edit_2511_edit_image_angle_webhook: {:?}", err); + refund_wallet_after_api_failure(&wallet_deduction.ledger_entry_token, &mut mysql_connection).await?; + return Err(CommonWebError::ServerError); + } + }; let external_job_id = fal_result.request_id .ok_or_else(|| { @@ -167,7 +169,7 @@ pub async fn qwen_edit_2511_edit_image_angle_handler( maybe_apriori_prompt_token: None, prompt_type: PromptType::ArtcraftApp, maybe_creator_user_token: Some(&user_token), - maybe_model_type: Some(ModelType::Qwen), + maybe_model_type: Some(ModelType::QwenEdit2511Angles), maybe_generation_provider: Some(GenerationProvider::Artcraft), maybe_positive_prompt: request.additional_prompt.as_deref(), maybe_negative_prompt: None,