mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 01:18:34 +00:00
nano banana via router
This commit is contained in:
1 parent
5740125a05
commit
3ead4cfcb2
8 files changed
+296
No files matched your search
+34
@@ -0,0 +1,34 @@
|
||||
use crate::generate::generate_image::image_generation_cost_estimate::ImageGenerationCostEstimate;
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_nano_banana::{
|
||||
FalNbNumImages, PlanFalNanoBanana,
|
||||
};
|
||||
|
||||
pub(crate) fn estimate_image_cost_fal_nano_banana(
|
||||
plan: &PlanFalNanoBanana<'_>,
|
||||
) -> ImageGenerationCostEstimate {
|
||||
// Pricing: $0.039/image (no resolution multiplier — Gemini 25 Flash has no resolution option).
|
||||
// Rounded to 4 cents per image.
|
||||
//
|
||||
// Fal docs:
|
||||
// Your request will cost $0.039 per image. For $1.00, you can run this model 25 times.
|
||||
//
|
||||
let cost_per_image: u64 = 4;
|
||||
|
||||
let num_images: u64 = match plan.num_images {
|
||||
FalNbNumImages::One => 1,
|
||||
FalNbNumImages::Two => 2,
|
||||
FalNbNumImages::Three => 3,
|
||||
FalNbNumImages::Four => 4,
|
||||
};
|
||||
|
||||
let cost_in_usd_cents = cost_per_image * num_images;
|
||||
|
||||
ImageGenerationCostEstimate {
|
||||
cost_in_credits: Some(cost_in_usd_cents),
|
||||
cost_in_usd_cents: Some(cost_in_usd_cents),
|
||||
is_free: false,
|
||||
is_unlimited: false,
|
||||
is_rate_limited: false,
|
||||
has_watermark: false,
|
||||
}
|
||||
}
|
||||
+1
@@ -1,2 +1,3 @@
|
||||
pub(crate) mod estimate_image_cost_fal_nano_banana;
|
||||
pub(crate) mod estimate_image_cost_fal_nano_banana_2;
|
||||
pub(crate) mod estimate_image_cost_fal_nano_banana_pro;
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
use crate::generate::generate_image::generate_image_response::{
|
||||
FalImageResponsePayload, GenerateImageResponse,
|
||||
};
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_nano_banana::{
|
||||
FalNbNumImages, PlanFalNanoBanana,
|
||||
};
|
||||
use fal_client::requests::webhook::image::edit::enqueue_gemini_25_flash_edit_webhook::{
|
||||
enqueue_gemini_25_flash_edit_webhook, Gemini25FlashEditArgs,
|
||||
Gemini25FlashEditNumImages,
|
||||
};
|
||||
use fal_client::requests::webhook::image::text::enqueue_gemini_25_flash_text_to_image_webhook::{
|
||||
enqueue_gemini_25_flash_text_to_image_webhook, Gemini25FlashTextToImageArgs,
|
||||
Gemini25FlashTextToImageNumImages,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_nano_banana(
|
||||
plan: &PlanFalNanoBanana<'_>,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateImageResponse, ArtcraftRouterError> {
|
||||
let webhook_response = if plan.image_urls.is_empty() {
|
||||
// Text-to-image mode
|
||||
let args = Gemini25FlashTextToImageArgs {
|
||||
prompt: plan.prompt.unwrap_or(""),
|
||||
num_images: to_t2i_num_images(plan.num_images),
|
||||
aspect_ratio: plan.t2i_aspect_ratio,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_gemini_25_flash_text_to_image_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
} else {
|
||||
// Image-edit mode
|
||||
let args = Gemini25FlashEditArgs {
|
||||
prompt: plan.prompt.unwrap_or(""),
|
||||
image_urls: plan.image_urls.clone(),
|
||||
num_images: to_edit_num_images(plan.num_images),
|
||||
aspect_ratio: plan.edit_aspect_ratio,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_gemini_25_flash_edit_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?
|
||||
};
|
||||
|
||||
Ok(GenerateImageResponse::Fal(FalImageResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
}))
|
||||
}
|
||||
|
||||
fn to_t2i_num_images(n: FalNbNumImages) -> Gemini25FlashTextToImageNumImages {
|
||||
match n {
|
||||
FalNbNumImages::One => Gemini25FlashTextToImageNumImages::One,
|
||||
FalNbNumImages::Two => Gemini25FlashTextToImageNumImages::Two,
|
||||
FalNbNumImages::Three => Gemini25FlashTextToImageNumImages::Three,
|
||||
FalNbNumImages::Four => Gemini25FlashTextToImageNumImages::Four,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_edit_num_images(n: FalNbNumImages) -> Gemini25FlashEditNumImages {
|
||||
match n {
|
||||
FalNbNumImages::One => Gemini25FlashEditNumImages::One,
|
||||
FalNbNumImages::Two => Gemini25FlashEditNumImages::Two,
|
||||
FalNbNumImages::Three => Gemini25FlashEditNumImages::Three,
|
||||
FalNbNumImages::Four => Gemini25FlashEditNumImages::Four,
|
||||
}
|
||||
}
|
||||
+1
@@ -1,2 +1,3 @@
|
||||
pub mod generate_image_fal_nano_banana;
|
||||
pub mod generate_image_fal_nano_banana_2;
|
||||
pub mod generate_image_fal_nano_banana_pro;
|
||||
+2
@@ -21,6 +21,7 @@ use crate::generate::generate_image::plan::artcraft::plan_generate_image_artcraf
|
||||
use crate::generate::generate_image::plan::artcraft::plan_generate_image_artcraft_seedream_4::plan_generate_image_artcraft_seedream_4;
|
||||
use crate::generate::generate_image::plan::artcraft::plan_generate_image_artcraft_seedream_4p5::plan_generate_image_artcraft_seedream_4p5;
|
||||
use crate::generate::generate_image::plan::artcraft::plan_generate_image_artcraft_seedream_5_lite::plan_generate_image_artcraft_seedream_5_lite;
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_nano_banana::plan_generate_image_fal_nano_banana;
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_nano_banana_2::plan_generate_image_fal_nano_banana_2;
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_nano_banana_pro::plan_generate_image_fal_nano_banana_pro;
|
||||
|
||||
@@ -101,6 +102,7 @@ impl<'a> GenerateImageRequest<'a> {
|
||||
|
||||
fn build_fal(&self) -> Result<ImageGenerationPlan<'_>, ArtcraftRouterError> {
|
||||
match self.model {
|
||||
CommonImageModel::NanoBanana => plan_generate_image_fal_nano_banana(self),
|
||||
CommonImageModel::NanoBanana2 => plan_generate_image_fal_nano_banana_2(self),
|
||||
CommonImageModel::NanoBananaPro => plan_generate_image_fal_nano_banana_pro(self),
|
||||
_ => {
|
||||
|
||||
+11
@@ -13,6 +13,7 @@ use crate::generate::generate_image::cost::artcraft::estimate_image_cost_artcraf
|
||||
use crate::generate::generate_image::cost::artcraft::estimate_image_cost_artcraft_seedream_5_lite::estimate_image_cost_artcraft_seedream_5_lite;
|
||||
use crate::generate::generate_image::cost::artcraft::estimate_image_cost_artcraft_qwen_edit_2511_angles::estimate_image_cost_artcraft_qwen_edit_2511_angles;
|
||||
use crate::generate::generate_image::cost::artcraft::estimate_image_cost_artcraft_flux_2_lora_angles::estimate_image_cost_artcraft_flux_2_lora_angles;
|
||||
use crate::generate::generate_image::cost::fal::estimate_image_cost_fal_nano_banana::estimate_image_cost_fal_nano_banana;
|
||||
use crate::generate::generate_image::cost::fal::estimate_image_cost_fal_nano_banana_2::estimate_image_cost_fal_nano_banana_2;
|
||||
use crate::generate::generate_image::cost::fal::estimate_image_cost_fal_nano_banana_pro::estimate_image_cost_fal_nano_banana_pro;
|
||||
use crate::generate::generate_image::execute::artcraft::generate_image_artcraft_flux_1_dev::execute_artcraft_flux_1_dev;
|
||||
@@ -28,6 +29,7 @@ use crate::generate::generate_image::execute::artcraft::generate_image_artcraft_
|
||||
use crate::generate::generate_image::execute::artcraft::generate_image_artcraft_seedream_5_lite::execute_artcraft_seedream_5_lite;
|
||||
use crate::generate::generate_image::execute::artcraft::generate_image_artcraft_qwen_edit_2511_angles::execute_artcraft_qwen_edit_2511_angles;
|
||||
use crate::generate::generate_image::execute::artcraft::generate_image_artcraft_flux_2_lora_angles::execute_artcraft_flux_2_lora_angles;
|
||||
use crate::generate::generate_image::execute::fal::generate_image_fal_nano_banana::execute_fal_nano_banana;
|
||||
use crate::generate::generate_image::execute::fal::generate_image_fal_nano_banana_2::execute_fal_nano_banana_2;
|
||||
use crate::generate::generate_image::execute::fal::generate_image_fal_nano_banana_pro::execute_fal_nano_banana_pro;
|
||||
use crate::generate::generate_image::generate_image_response::GenerateImageResponse;
|
||||
@@ -45,6 +47,7 @@ use crate::generate::generate_image::plan::artcraft::plan_generate_image_artcraf
|
||||
use crate::generate::generate_image::plan::artcraft::plan_generate_image_artcraft_seedream_5_lite::PlanArtcraftSeedream5Lite;
|
||||
use crate::generate::generate_image::plan::artcraft::plan_generate_image_artcraft_qwen_edit_2511_angles::PlanArtcraftQwenEdit2511Angles;
|
||||
use crate::generate::generate_image::plan::artcraft::plan_generate_image_artcraft_flux_2_lora_angles::PlanArtcraftFlux2LoraAngles;
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_nano_banana::PlanFalNanoBanana;
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_nano_banana_2::PlanFalNanaBanana2;
|
||||
use crate::generate::generate_image::plan::fal::plan_generate_image_fal_nano_banana_pro::PlanFalNanaBananaPro;
|
||||
|
||||
@@ -63,6 +66,7 @@ pub enum ImageGenerationPlan<'a> {
|
||||
ArtcraftSeedream5Lite(PlanArtcraftSeedream5Lite<'a>),
|
||||
ArtcraftQwenEdit2511Angles(PlanArtcraftQwenEdit2511Angles<'a>),
|
||||
ArtcraftFlux2LoraAngles(PlanArtcraftFlux2LoraAngles<'a>),
|
||||
FalNanoBanana(PlanFalNanoBanana<'a>),
|
||||
FalNanaBanana2(PlanFalNanaBanana2<'a>),
|
||||
FalNanaBananaPro(PlanFalNanaBananaPro<'a>),
|
||||
}
|
||||
@@ -125,6 +129,10 @@ impl<'a> ImageGenerationPlan<'a> {
|
||||
let artcraft_client = client.get_artcraft_client_ref()?;
|
||||
execute_artcraft_flux_2_lora_angles(plan, artcraft_client).await
|
||||
}
|
||||
ImageGenerationPlan::FalNanoBanana(plan) => {
|
||||
let fal_client = client.get_fal_client_ref()?;
|
||||
execute_fal_nano_banana(plan, fal_client).await
|
||||
}
|
||||
ImageGenerationPlan::FalNanaBanana2(plan) => {
|
||||
let fal_client = client.get_fal_client_ref()?;
|
||||
execute_fal_nano_banana_2(plan, fal_client).await
|
||||
@@ -177,6 +185,9 @@ impl<'a> ImageGenerationPlan<'a> {
|
||||
ImageGenerationPlan::ArtcraftFlux2LoraAngles(plan) => {
|
||||
estimate_image_cost_artcraft_flux_2_lora_angles(plan)
|
||||
}
|
||||
ImageGenerationPlan::FalNanoBanana(plan) => {
|
||||
estimate_image_cost_fal_nano_banana(plan)
|
||||
}
|
||||
ImageGenerationPlan::FalNanaBanana2(plan) => {
|
||||
estimate_image_cost_fal_nano_banana_2(plan)
|
||||
}
|
||||
|
||||
+1
@@ -1,2 +1,3 @@
|
||||
pub mod plan_generate_image_fal_nano_banana;
|
||||
pub mod plan_generate_image_fal_nano_banana_2;
|
||||
pub mod plan_generate_image_fal_nano_banana_pro;
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan;
|
||||
use fal_client::requests::webhook::image::edit::enqueue_gemini_25_flash_edit_webhook::Gemini25FlashEditAspectRatio;
|
||||
use fal_client::requests::webhook::image::text::enqueue_gemini_25_flash_text_to_image_webhook::Gemini25FlashTextToImageAspectRatio;
|
||||
|
||||
/// Intermediate num-images type shared between t2i and edit enums.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum FalNbNumImages {
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PlanFalNanoBanana<'a> {
|
||||
pub prompt: Option<&'a str>,
|
||||
/// Image URLs for editing. Empty vec = text-to-image mode.
|
||||
pub image_urls: Vec<String>,
|
||||
/// Pre-resolved aspect ratio for text-to-image mode.
|
||||
pub t2i_aspect_ratio: Option<Gemini25FlashTextToImageAspectRatio>,
|
||||
/// Pre-resolved aspect ratio for image-edit mode.
|
||||
pub edit_aspect_ratio: Option<Gemini25FlashEditAspectRatio>,
|
||||
/// Pre-resolved number of images (1–4, shared for both modes).
|
||||
pub num_images: FalNbNumImages,
|
||||
}
|
||||
|
||||
pub fn plan_generate_image_fal_nano_banana<'a>(
|
||||
request: &'a GenerateImageRequest<'a>,
|
||||
) -> Result<ImageGenerationPlan<'a>, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
let is_edit_mode = request.image_inputs.is_some();
|
||||
let image_urls = resolve_image_list_ref(request.image_inputs)?;
|
||||
let t2i_aspect_ratio = plan_t2i_aspect_ratio(request.aspect_ratio, strategy)?;
|
||||
let edit_aspect_ratio = plan_edit_aspect_ratio(request.aspect_ratio, is_edit_mode, strategy)?;
|
||||
let num_images = plan_num_images(request.image_batch_count, strategy)?;
|
||||
|
||||
Ok(ImageGenerationPlan::FalNanoBanana(PlanFalNanoBanana {
|
||||
prompt: request.prompt,
|
||||
image_urls,
|
||||
t2i_aspect_ratio,
|
||||
edit_aspect_ratio,
|
||||
num_images,
|
||||
}))
|
||||
}
|
||||
|
||||
fn resolve_image_list_ref(
|
||||
image_list_ref: Option<ImageListRef<'_>>,
|
||||
) -> Result<Vec<String>, ArtcraftRouterError> {
|
||||
match image_list_ref {
|
||||
None => Ok(vec![]),
|
||||
Some(ImageListRef::Urls(urls)) => Ok(urls.clone()),
|
||||
Some(ImageListRef::MediaFileTokens(_)) => {
|
||||
Err(ArtcraftRouterError::Client(ClientError::FalOnlySupportsUrls))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Gemini 25 Flash text-to-image supported aspect ratios:
|
||||
// 1:1, 5:4, 4:3, 3:2, 16:9, 21:9, 4:5, 3:4, 2:3, 9:16
|
||||
// (no Auto for text-to-image)
|
||||
fn plan_t2i_aspect_ratio(
|
||||
aspect_ratio: Option<CommonAspectRatio>,
|
||||
strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<Option<Gemini25FlashTextToImageAspectRatio>, ArtcraftRouterError> {
|
||||
use Gemini25FlashTextToImageAspectRatio as T2iAr;
|
||||
match aspect_ratio {
|
||||
None => Ok(None),
|
||||
|
||||
// Auto not valid for text-to-image; fall back to square
|
||||
Some(CommonAspectRatio::Auto)
|
||||
| Some(CommonAspectRatio::Auto2k)
|
||||
| Some(CommonAspectRatio::Auto4k) => Ok(Some(T2iAr::OneByOne)),
|
||||
|
||||
Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(T2iAr::OneByOne)),
|
||||
Some(CommonAspectRatio::WideFiveByFour) => Ok(Some(T2iAr::FiveByFour)),
|
||||
Some(CommonAspectRatio::WideFourByThree) => Ok(Some(T2iAr::FourByThree)),
|
||||
Some(CommonAspectRatio::WideThreeByTwo) => Ok(Some(T2iAr::ThreeByTwo)),
|
||||
Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(T2iAr::SixteenByNine)),
|
||||
Some(CommonAspectRatio::WideTwentyOneByNine) => Ok(Some(T2iAr::TwentyOneByNine)),
|
||||
Some(CommonAspectRatio::TallFourByFive) => Ok(Some(T2iAr::FourByFive)),
|
||||
Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(T2iAr::ThreeByFour)),
|
||||
Some(CommonAspectRatio::TallTwoByThree) => Ok(Some(T2iAr::TwoByThree)),
|
||||
Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(T2iAr::NineBySixteen)),
|
||||
|
||||
Some(unsupported) => match strategy {
|
||||
RequestMismatchMitigationStrategy::ErrorOut => {
|
||||
Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
|
||||
field: "aspect_ratio",
|
||||
value: format!("{:?}", unsupported),
|
||||
}))
|
||||
}
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade
|
||||
| RequestMismatchMitigationStrategy::PayLessDowngrade => {
|
||||
Ok(Some(T2iAr::NineBySixteen))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Gemini 25 Flash image-edit supported aspect ratios: same as t2i plus Auto
|
||||
fn plan_edit_aspect_ratio(
|
||||
aspect_ratio: Option<CommonAspectRatio>,
|
||||
is_edit_mode: bool,
|
||||
strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<Option<Gemini25FlashEditAspectRatio>, ArtcraftRouterError> {
|
||||
use Gemini25FlashEditAspectRatio as EditAr;
|
||||
match aspect_ratio {
|
||||
None => Ok(None),
|
||||
|
||||
Some(CommonAspectRatio::Auto)
|
||||
| Some(CommonAspectRatio::Auto2k)
|
||||
| Some(CommonAspectRatio::Auto4k) => {
|
||||
if is_edit_mode {
|
||||
Ok(Some(EditAr::Auto))
|
||||
} else {
|
||||
Ok(Some(EditAr::OneByOne))
|
||||
}
|
||||
}
|
||||
|
||||
Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(EditAr::OneByOne)),
|
||||
Some(CommonAspectRatio::WideFiveByFour) => Ok(Some(EditAr::FiveByFour)),
|
||||
Some(CommonAspectRatio::WideFourByThree) => Ok(Some(EditAr::FourByThree)),
|
||||
Some(CommonAspectRatio::WideThreeByTwo) => Ok(Some(EditAr::ThreeByTwo)),
|
||||
Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(EditAr::SixteenByNine)),
|
||||
Some(CommonAspectRatio::WideTwentyOneByNine) => Ok(Some(EditAr::TwentyOneByNine)),
|
||||
Some(CommonAspectRatio::TallFourByFive) => Ok(Some(EditAr::FourByFive)),
|
||||
Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(EditAr::ThreeByFour)),
|
||||
Some(CommonAspectRatio::TallTwoByThree) => Ok(Some(EditAr::TwoByThree)),
|
||||
Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(EditAr::NineBySixteen)),
|
||||
|
||||
Some(unsupported) => match strategy {
|
||||
RequestMismatchMitigationStrategy::ErrorOut => {
|
||||
Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
|
||||
field: "aspect_ratio",
|
||||
value: format!("{:?}", unsupported),
|
||||
}))
|
||||
}
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade
|
||||
| RequestMismatchMitigationStrategy::PayLessDowngrade => {
|
||||
Ok(Some(EditAr::NineBySixteen))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn plan_num_images(
|
||||
image_batch_count: Option<u16>,
|
||||
strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<FalNbNumImages, ArtcraftRouterError> {
|
||||
let count = image_batch_count.unwrap_or(1);
|
||||
match count {
|
||||
0 => Err(ArtcraftRouterError::Client(ClientError::UserRequestedZeroGenerations)),
|
||||
1 => Ok(FalNbNumImages::One),
|
||||
2 => Ok(FalNbNumImages::Two),
|
||||
3 => Ok(FalNbNumImages::Three),
|
||||
4 => Ok(FalNbNumImages::Four),
|
||||
_ => match strategy {
|
||||
RequestMismatchMitigationStrategy::ErrorOut => {
|
||||
Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
|
||||
field: "image_batch_count",
|
||||
value: format!("{}", count),
|
||||
}))
|
||||
}
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade
|
||||
| RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(FalNbNumImages::Four),
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user