diff --git a/Cargo.lock b/Cargo.lock index 861295d67e..0df590fc40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -805,7 +805,6 @@ dependencies = [ "gmicloud_client", "grok_api_client", "log", - "muapi_client", "reqwest 0.12.23", "seedance2pro_client", "serde", diff --git a/crates/api_clients/artcraft/artcraft_router/Cargo.toml b/crates/api_clients/artcraft/artcraft_router/Cargo.toml index 30bb172d7c..5ed89ecdb3 100644 --- a/crates/api_clients/artcraft/artcraft_router/Cargo.toml +++ b/crates/api_clients/artcraft/artcraft_router/Cargo.toml @@ -22,7 +22,6 @@ artcraft_client.workspace = true fal_client.workspace = true gmicloud_client.workspace = true grok_api_client.workspace = true -muapi_client.workspace = true seedance2pro_client.workspace = true tokens.workspace = true url_utils.workspace = true diff --git a/crates/api_clients/artcraft/artcraft_router/src/api/provider.rs b/crates/api_clients/artcraft/artcraft_router/src/api/provider.rs index cbfb9b3d99..15bdb0cc16 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/api/provider.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/api/provider.rs @@ -8,6 +8,5 @@ pub enum Provider { Fal, GmiCloud, GrokApi, - Muapi, Seedance2Pro, } diff --git a/crates/api_clients/artcraft/artcraft_router/src/client/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/client/mod.rs index 40e86010c0..06377b546f 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/client/mod.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/client/mod.rs @@ -8,5 +8,4 @@ pub mod router_fal_client; pub mod router_fal_webhook_optional_client; pub mod router_gmicloud_client; pub mod router_grok_api_client; -pub mod router_muapi_client; pub mod router_seedance2pro_client; diff --git a/crates/api_clients/artcraft/artcraft_router/src/client/multi_router_client.rs b/crates/api_clients/artcraft/artcraft_router/src/client/multi_router_client.rs index f2070dfbbe..cfe6883997 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/client/multi_router_client.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/client/multi_router_client.rs @@ -3,7 +3,6 @@ use crate::client::router_fal_client::RouterFalClient; use crate::client::router_fal_webhook_optional_client::RouterFalWebhookOptionalClient; use crate::client::router_gmicloud_client::RouterGmiCloudClient; use crate::client::router_grok_api_client::RouterGrokApiClient; -use crate::client::router_muapi_client::RouterMuapiClient; use crate::client::router_seedance2pro_client::RouterSeedance2ProClient; use crate::errors::client_error::{ClientError, ClientType}; @@ -13,7 +12,6 @@ pub struct MultiRouterClient { pub(crate) fal_webhook_optional_client: Option, pub(crate) gmicloud_client: Option, pub(crate) grok_api_client: Option, - pub(crate) muapi_client: Option, pub(crate) seedance2pro_client: Option, } @@ -43,11 +41,6 @@ impl MultiRouterClient { .ok_or(ClientError::ClientNotConfigured(ClientType::GrokApi)) } - pub fn get_muapi_client_ref(&self) -> Result<&RouterMuapiClient, ClientError> { - self.muapi_client.as_ref() - .ok_or(ClientError::ClientNotConfigured(ClientType::Muapi)) - } - pub fn get_seedance2pro_client_ref(&self) -> Result<&RouterSeedance2ProClient, ClientError> { self.seedance2pro_client.as_ref() .ok_or(ClientError::ClientNotConfigured(ClientType::Seedance2Pro)) diff --git a/crates/api_clients/artcraft/artcraft_router/src/client/multi_router_client_builder.rs b/crates/api_clients/artcraft/artcraft_router/src/client/multi_router_client_builder.rs index 3c11d43af7..87ed88fa2e 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/client/multi_router_client_builder.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/client/multi_router_client_builder.rs @@ -4,7 +4,6 @@ use crate::client::router_fal_client::RouterFalClient; use crate::client::router_fal_webhook_optional_client::RouterFalWebhookOptionalClient; use crate::client::router_gmicloud_client::RouterGmiCloudClient; use crate::client::router_grok_api_client::RouterGrokApiClient; -use crate::client::router_muapi_client::RouterMuapiClient; use crate::client::router_seedance2pro_client::RouterSeedance2ProClient; pub struct MultiRouterClientBuilder { @@ -13,7 +12,6 @@ pub struct MultiRouterClientBuilder { fal_webhook_optional_client: Option, gmicloud_client: Option, grok_api_client: Option, - muapi_client: Option, seedance2pro_client: Option, } @@ -25,7 +23,6 @@ impl MultiRouterClientBuilder { fal_webhook_optional_client: None, gmicloud_client: None, grok_api_client: None, - muapi_client: None, seedance2pro_client: None, } } @@ -55,11 +52,6 @@ impl MultiRouterClientBuilder { self } - pub fn set_muapi_client(mut self, client: RouterMuapiClient) -> Self { - self.muapi_client = Some(client); - self - } - pub fn set_seedance2pro_client(mut self, client: RouterSeedance2ProClient) -> Self { self.seedance2pro_client = Some(client); self @@ -72,7 +64,6 @@ impl MultiRouterClientBuilder { fal_webhook_optional_client: self.fal_webhook_optional_client, gmicloud_client: self.gmicloud_client, grok_api_client: self.grok_api_client, - muapi_client: self.muapi_client, seedance2pro_client: self.seedance2pro_client, } } diff --git a/crates/api_clients/artcraft/artcraft_router/src/client/router_client.rs b/crates/api_clients/artcraft/artcraft_router/src/client/router_client.rs index 36987a38fa..6234ee6e86 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/client/router_client.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/client/router_client.rs @@ -4,7 +4,6 @@ use crate::client::router_fal_client::RouterFalClient; use crate::client::router_fal_webhook_optional_client::RouterFalWebhookOptionalClient; use crate::client::router_gmicloud_client::RouterGmiCloudClient; use crate::client::router_grok_api_client::RouterGrokApiClient; -use crate::client::router_muapi_client::RouterMuapiClient; use crate::client::router_seedance2pro_client::RouterSeedance2ProClient; use crate::errors::client_error::{ClientError, ClientType}; @@ -15,7 +14,6 @@ pub enum RouterClient { FalWebhookOptional(RouterFalWebhookOptionalClient), GmiCloud(RouterGmiCloudClient), GrokApi(RouterGrokApiClient), - Muapi(RouterMuapiClient), Seedance2Pro(RouterSeedance2ProClient), } @@ -60,14 +58,6 @@ impl RouterClient { } } - pub fn get_muapi_client_ref(&self) -> Result<&RouterMuapiClient, ClientError> { - match self { - RouterClient::Muapi(client) => Ok(client), - RouterClient::Multi(multi) => multi.get_muapi_client_ref(), - _ => Err(ClientError::ClientNotConfigured(ClientType::Muapi)), - } - } - pub fn get_seedance2pro_client_ref(&self) -> Result<&RouterSeedance2ProClient, ClientError> { match self { RouterClient::Seedance2Pro(client) => Ok(client), diff --git a/crates/api_clients/artcraft/artcraft_router/src/client/router_muapi_client.rs b/crates/api_clients/artcraft/artcraft_router/src/client/router_muapi_client.rs deleted file mode 100644 index 3c8a690122..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/client/router_muapi_client.rs +++ /dev/null @@ -1,11 +0,0 @@ -use muapi_client::creds::muapi_session::MuapiSession; - -pub struct RouterMuapiClient { - pub(crate) session: MuapiSession, -} - -impl RouterMuapiClient { - pub fn new(session: MuapiSession) -> Self { - RouterMuapiClient { session } - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/errors/client_error.rs b/crates/api_clients/artcraft/artcraft_router/src/errors/client_error.rs index 0f74c7421f..64b63afe9b 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/errors/client_error.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/errors/client_error.rs @@ -10,7 +10,6 @@ pub enum ClientType { FalWebhookOptional, GmiCloud, GrokApi, - Muapi, Seedance2Pro, } @@ -22,7 +21,6 @@ impl Display for ClientType { Self::FalWebhookOptional => write!(f, "FalWebhookOptional"), Self::GmiCloud => write!(f, "GmiCloud"), Self::GrokApi => write!(f, "GrokApi"), - Self::Muapi => write!(f, "Muapi"), Self::Seedance2Pro => write!(f, "Seedance2Pro"), } } @@ -49,9 +47,6 @@ pub enum ClientError { /// Fal only accepts image URLs for image inputs, not media tokens. FalOnlySupportsUrls, - /// Muapi only accepts URLs for image inputs, not media tokens. - MuapiOnlySupportsUrls, - /// Seedance2Pro only accepts URLs for media inputs, not media tokens. Seedance2ProOnlySupportsUrls, @@ -91,9 +86,6 @@ impl Display for ClientError { Self::FalOnlySupportsUrls => { write!(f, "Fal only supports image URLs for image inputs, not media tokens") } - Self::MuapiOnlySupportsUrls => { - write!(f, "Muapi only supports URLs for image inputs; resolve media tokens to URLs before calling this provider") - } Self::Seedance2ProOnlySupportsUrls => { write!(f, "Seedance2Pro only supports URLs for media inputs; resolve media tokens to URLs before calling this provider") } diff --git a/crates/api_clients/artcraft/artcraft_router/src/errors/provider_error.rs b/crates/api_clients/artcraft/artcraft_router/src/errors/provider_error.rs index 155f0db787..40ba0e3035 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/errors/provider_error.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/errors/provider_error.rs @@ -4,7 +4,6 @@ use artcraft_client::error::storyteller_error::StorytellerError; use fal_client::error::fal_error_plus::FalErrorPlus; use gmicloud_client::error::gmicloud_error::GmiCloudError; use grok_api_client::error::grok_error::GrokError; -use muapi_client::error::muapi_error::MuapiError; use seedance2pro_client::error::seedance2pro_error::Seedance2ProError; #[derive(Debug)] @@ -13,7 +12,6 @@ pub enum ProviderError { Fal(FalErrorPlus), GmiCloud(GmiCloudError), Grok(GrokError), - Muapi(MuapiError), Seedance2Pro(Seedance2ProError), } @@ -26,7 +24,6 @@ impl Display for ProviderError { Self::Fal(e) => write!(f, "Fal provider error: {}", e), Self::GmiCloud(e) => write!(f, "GmiCloud provider error: {}", e), Self::Grok(e) => write!(f, "Grok provider error: {}", e), - Self::Muapi(e) => write!(f, "Muapi provider error: {}", e), Self::Seedance2Pro(e) => write!(f, "Seedance2Pro provider error: {}", e), } } @@ -56,12 +53,6 @@ impl From for ProviderError { } } -impl From for ProviderError { - fn from(error: MuapiError) -> Self { - Self::Muapi(error) - } -} - impl From for ProviderError { fn from(error: Seedance2ProError) -> Self { Self::Seedance2Pro(error) diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling3p0_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling3p0_pro.rs deleted file mode 100644 index 656f10762f..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling3p0_pro.rs +++ /dev/null @@ -1,99 +0,0 @@ -use artcraft_api_defs::generate::video::multi_function::kling_3p0_pro_multi_function_video_gen::Kling3p0ProMultiFunctionVideoGenDuration; -use fal_client::requests::traits::fal_request_cost_calculator_trait::FalRequestCostCalculator; -use fal_client::requests::webhook::video::text::enqueue_kling_3p0_pro_text_to_video_webhook::{ - EnqueueKling3p0ProTextToVideoRequest, - EnqueueKling3p0ProTextToVideoDuration, -}; - -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling3p0_pro::PlanArtcraftKling3p0Pro; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_artcraft_kling3p0_pro( - plan: &PlanArtcraftKling3p0Pro, -) -> VideoGenerationCostEstimate { - let duration = plan.duration - .map(|d| match d { - Kling3p0ProMultiFunctionVideoGenDuration::ThreeSeconds => EnqueueKling3p0ProTextToVideoDuration::ThreeSeconds, - Kling3p0ProMultiFunctionVideoGenDuration::FourSeconds => EnqueueKling3p0ProTextToVideoDuration::FourSeconds, - Kling3p0ProMultiFunctionVideoGenDuration::FiveSeconds => EnqueueKling3p0ProTextToVideoDuration::FiveSeconds, - Kling3p0ProMultiFunctionVideoGenDuration::SixSeconds => EnqueueKling3p0ProTextToVideoDuration::SixSeconds, - Kling3p0ProMultiFunctionVideoGenDuration::SevenSeconds => EnqueueKling3p0ProTextToVideoDuration::SevenSeconds, - Kling3p0ProMultiFunctionVideoGenDuration::EightSeconds => EnqueueKling3p0ProTextToVideoDuration::EightSeconds, - Kling3p0ProMultiFunctionVideoGenDuration::NineSeconds => EnqueueKling3p0ProTextToVideoDuration::NineSeconds, - Kling3p0ProMultiFunctionVideoGenDuration::TenSeconds => EnqueueKling3p0ProTextToVideoDuration::TenSeconds, - Kling3p0ProMultiFunctionVideoGenDuration::ElevenSeconds => EnqueueKling3p0ProTextToVideoDuration::ElevenSeconds, - Kling3p0ProMultiFunctionVideoGenDuration::TwelveSeconds => EnqueueKling3p0ProTextToVideoDuration::TwelveSeconds, - Kling3p0ProMultiFunctionVideoGenDuration::ThirteenSeconds => EnqueueKling3p0ProTextToVideoDuration::ThirteenSeconds, - Kling3p0ProMultiFunctionVideoGenDuration::FourteenSeconds => EnqueueKling3p0ProTextToVideoDuration::FourteenSeconds, - Kling3p0ProMultiFunctionVideoGenDuration::FifteenSeconds => EnqueueKling3p0ProTextToVideoDuration::FifteenSeconds, - }); - - // Use text-to-video cost calculator (same pricing for both modes) - let req = EnqueueKling3p0ProTextToVideoRequest { - prompt: String::new(), - generate_audio: plan.generate_audio, - negative_prompt: None, - duration, - aspect_ratio: None, - shot_type: None, - }; - - let cost_in_usd_cents = req.calculate_cost_in_cents(); - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} - -#[cfg(test)] -mod tests { - use crate::api::common_video_model::CommonVideoModel; - use crate::api::provider::Provider; - use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy; - use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; - - fn estimate_usd_cents(duration_seconds: u16) -> u64 { - let request = GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling3p0Pro, - provider: Provider::Artcraft, - prompt: None, - negative_prompt: None, - start_frame: None, - end_frame: None, - reference_images: None, - reference_videos: None, - reference_audio: None, - reference_character_tokens: None, - resolution: None, - aspect_ratio: None, - duration_seconds: Some(duration_seconds), - video_batch_count: None, - generate_audio: None, - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut, - idempotency_token: None, - }; - request.build() - .expect("build should succeed") - .estimate_costs() - .cost_in_usd_cents - .expect("cost_in_usd_cents should be present") - } - - #[test] - fn test_estimate_cost_usd_cents() { - // Kling 3.0 Pro: $0.336/sec (audio on, the default when None) - // Formula: (336 * duration_secs + 9) / 10 → ceiling division - // 5s: (336 * 5 + 9) / 10 = 1689 / 10 = 168 - assert_eq!(estimate_usd_cents(5), 168); - // 10s: (336 * 10 + 9) / 10 = 3369 / 10 = 336 - assert_eq!(estimate_usd_cents(10), 336); - // 15s: (336 * 15 + 9) / 10 = 5049 / 10 = 504 - assert_eq!(estimate_usd_cents(15), 504); - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling3p0_standard.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling3p0_standard.rs deleted file mode 100644 index 953dbe847b..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling3p0_standard.rs +++ /dev/null @@ -1,99 +0,0 @@ -use artcraft_api_defs::generate::video::multi_function::kling_3p0_standard_multi_function_video_gen::Kling3p0StandardMultiFunctionVideoGenDuration; -use fal_client::requests::traits::fal_request_cost_calculator_trait::FalRequestCostCalculator; -use fal_client::requests::webhook::video::text::enqueue_kling_3p0_standard_text_to_video_webhook::{ - EnqueueKling3p0StandardTextToVideoRequest, - EnqueueKling3p0StandardTextToVideoDuration, -}; - -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling3p0_standard::PlanArtcraftKling3p0Standard; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_artcraft_kling3p0_standard( - plan: &PlanArtcraftKling3p0Standard, -) -> VideoGenerationCostEstimate { - let duration = plan.duration - .map(|d| match d { - Kling3p0StandardMultiFunctionVideoGenDuration::ThreeSeconds => EnqueueKling3p0StandardTextToVideoDuration::ThreeSeconds, - Kling3p0StandardMultiFunctionVideoGenDuration::FourSeconds => EnqueueKling3p0StandardTextToVideoDuration::FourSeconds, - Kling3p0StandardMultiFunctionVideoGenDuration::FiveSeconds => EnqueueKling3p0StandardTextToVideoDuration::FiveSeconds, - Kling3p0StandardMultiFunctionVideoGenDuration::SixSeconds => EnqueueKling3p0StandardTextToVideoDuration::SixSeconds, - Kling3p0StandardMultiFunctionVideoGenDuration::SevenSeconds => EnqueueKling3p0StandardTextToVideoDuration::SevenSeconds, - Kling3p0StandardMultiFunctionVideoGenDuration::EightSeconds => EnqueueKling3p0StandardTextToVideoDuration::EightSeconds, - Kling3p0StandardMultiFunctionVideoGenDuration::NineSeconds => EnqueueKling3p0StandardTextToVideoDuration::NineSeconds, - Kling3p0StandardMultiFunctionVideoGenDuration::TenSeconds => EnqueueKling3p0StandardTextToVideoDuration::TenSeconds, - Kling3p0StandardMultiFunctionVideoGenDuration::ElevenSeconds => EnqueueKling3p0StandardTextToVideoDuration::ElevenSeconds, - Kling3p0StandardMultiFunctionVideoGenDuration::TwelveSeconds => EnqueueKling3p0StandardTextToVideoDuration::TwelveSeconds, - Kling3p0StandardMultiFunctionVideoGenDuration::ThirteenSeconds => EnqueueKling3p0StandardTextToVideoDuration::ThirteenSeconds, - Kling3p0StandardMultiFunctionVideoGenDuration::FourteenSeconds => EnqueueKling3p0StandardTextToVideoDuration::FourteenSeconds, - Kling3p0StandardMultiFunctionVideoGenDuration::FifteenSeconds => EnqueueKling3p0StandardTextToVideoDuration::FifteenSeconds, - }); - - // Use text-to-video cost calculator (same pricing for both modes) - let req = EnqueueKling3p0StandardTextToVideoRequest { - prompt: String::new(), - generate_audio: plan.generate_audio, - negative_prompt: None, - duration, - aspect_ratio: None, - shot_type: None, - }; - - let cost_in_usd_cents = req.calculate_cost_in_cents(); - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} - -#[cfg(test)] -mod tests { - use crate::api::common_video_model::CommonVideoModel; - use crate::api::provider::Provider; - use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy; - use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; - - fn estimate_usd_cents(duration_seconds: u16) -> u64 { - let request = GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling3p0Standard, - provider: Provider::Artcraft, - prompt: None, - negative_prompt: None, - start_frame: None, - end_frame: None, - reference_images: None, - reference_videos: None, - reference_audio: None, - reference_character_tokens: None, - resolution: None, - aspect_ratio: None, - duration_seconds: Some(duration_seconds), - video_batch_count: None, - generate_audio: None, - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut, - idempotency_token: None, - }; - request.build() - .expect("build should succeed") - .estimate_costs() - .cost_in_usd_cents - .expect("cost_in_usd_cents should be present") - } - - #[test] - fn test_estimate_cost_usd_cents() { - // Kling 3.0 Standard: $0.252/sec (audio on, the default when None) - // Formula: (252 * duration_secs + 9) / 10 → ceiling division - // 5s: (252 * 5 + 9) / 10 = 1269 / 10 = 126 - assert_eq!(estimate_usd_cents(5), 126); - // 10s: (252 * 10 + 9) / 10 = 2529 / 10 = 252 - assert_eq!(estimate_usd_cents(10), 252); - // 15s: (252 * 15 + 9) / 10 = 3789 / 10 = 378 - assert_eq!(estimate_usd_cents(15), 378); - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling_1_6_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling_1_6_pro.rs deleted file mode 100644 index eb1cb750e3..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling_1_6_pro.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_1_6_pro::PlanArtcraftKling16Pro; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_artcraft_kling_1_6_pro( - plan: &PlanArtcraftKling16Pro, -) -> VideoGenerationCostEstimate { - // Mirrors fal_client kling_v1p6_pro: 5s = $0.475 (rounded up to 48¢), 10s = $0.95 (95¢). - let cost_in_usd_cents: u64 = if plan.is_ten_seconds() { 95 } else { 48 }; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling_2_1_master.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling_2_1_master.rs deleted file mode 100644 index fb14bcbcae..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling_2_1_master.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_1_master::PlanArtcraftKling21Master; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_artcraft_kling_2_1_master( - plan: &PlanArtcraftKling21Master, -) -> VideoGenerationCostEstimate { - // Mirrors fal_client kling_v2p1_master: 5s = $1.40, 10s = $2.80. - let cost_in_usd_cents: u64 = if plan.is_ten_seconds() { 280 } else { 140 }; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling_2_1_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling_2_1_pro.rs deleted file mode 100644 index 5c7afa0d7a..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling_2_1_pro.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_1_pro::PlanArtcraftKling21Pro; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_artcraft_kling_2_1_pro( - plan: &PlanArtcraftKling21Pro, -) -> VideoGenerationCostEstimate { - // Mirrors fal_client kling_v2p1_pro: 5s = $0.45, 10s = $0.90. - let cost_in_usd_cents: u64 = if plan.is_ten_seconds() { 90 } else { 45 }; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling_2_5_turbo_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling_2_5_turbo_pro.rs deleted file mode 100644 index 5335911fe7..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling_2_5_turbo_pro.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_5_turbo_pro::PlanArtcraftKling2p5TurboPro; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_artcraft_kling_2_5_turbo_pro( - plan: &PlanArtcraftKling2p5TurboPro, -) -> VideoGenerationCostEstimate { - // Mirrors fal_client kling_v2p5_turbo_pro: 5s = $0.35, 10s = $0.70. - let cost_in_usd_cents: u64 = if plan.is_ten_seconds() { 70 } else { 35 }; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling_2_6_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling_2_6_pro.rs deleted file mode 100644 index 20562855fd..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_kling_2_6_pro.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_6_pro::PlanArtcraftKling2p6Pro; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_artcraft_kling_2_6_pro( - plan: &PlanArtcraftKling2p6Pro, -) -> VideoGenerationCostEstimate { - // Mirrors fal_client kling_v2p6_pro: - // audio off: $0.07/sec → 5s=35¢, 10s=70¢ - // audio on: $0.14/sec → 5s=70¢, 10s=140¢ - // Default duration is 5s; default generate_audio is true. - let cost_in_usd_cents: u64 = match (plan.generate_audio_for_cost(), plan.is_ten_seconds()) { - (false, false) => 35, - (false, true) => 70, - (true, false) => 70, - (true, true) => 140, - }; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_seedance1p5_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_seedance1p5_pro.rs deleted file mode 100644 index f2ad2157a0..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_seedance1p5_pro.rs +++ /dev/null @@ -1,102 +0,0 @@ -use artcraft_api_defs::generate::video::multi_function::seedance_1p5_pro_multi_function_video_gen::Seedance1p5ProMultiFunctionVideoGenDuration; -use fal_client::requests::traits::fal_request_cost_calculator_trait::FalRequestCostCalculator; -use fal_client::requests::webhook::video::text::enqueue_seedance_1p5_pro_text_to_video_webhook::{ - EnqueueSeedance1p5ProTextToVideoRequest, - EnqueueSeedance1p5ProTextToVideoDuration, - EnqueueSeedance1p5ProTextToVideoResolution, -}; - -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance1p5_pro::PlanArtcraftSeedance1p5Pro; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_artcraft_seedance1p5_pro( - plan: &PlanArtcraftSeedance1p5Pro, -) -> VideoGenerationCostEstimate { - let duration = plan.duration - .map(|d| match d { - Seedance1p5ProMultiFunctionVideoGenDuration::FourSeconds => EnqueueSeedance1p5ProTextToVideoDuration::FourSeconds, - Seedance1p5ProMultiFunctionVideoGenDuration::FiveSeconds => EnqueueSeedance1p5ProTextToVideoDuration::FiveSeconds, - Seedance1p5ProMultiFunctionVideoGenDuration::SixSeconds => EnqueueSeedance1p5ProTextToVideoDuration::SixSeconds, - Seedance1p5ProMultiFunctionVideoGenDuration::SevenSeconds => EnqueueSeedance1p5ProTextToVideoDuration::SevenSeconds, - Seedance1p5ProMultiFunctionVideoGenDuration::EightSeconds => EnqueueSeedance1p5ProTextToVideoDuration::EightSeconds, - Seedance1p5ProMultiFunctionVideoGenDuration::NineSeconds => EnqueueSeedance1p5ProTextToVideoDuration::NineSeconds, - Seedance1p5ProMultiFunctionVideoGenDuration::TenSeconds => EnqueueSeedance1p5ProTextToVideoDuration::TenSeconds, - Seedance1p5ProMultiFunctionVideoGenDuration::ElevenSeconds => EnqueueSeedance1p5ProTextToVideoDuration::ElevenSeconds, - Seedance1p5ProMultiFunctionVideoGenDuration::TwelveSeconds => EnqueueSeedance1p5ProTextToVideoDuration::TwelveSeconds, - }); - - let resolution = plan.resolution - .map(|r| match r { - artcraft_api_defs::generate::video::multi_function::seedance_1p5_pro_multi_function_video_gen::Seedance1p5ProMultiFunctionVideoGenResolution::FourEightyP => EnqueueSeedance1p5ProTextToVideoResolution::FourEightyP, - artcraft_api_defs::generate::video::multi_function::seedance_1p5_pro_multi_function_video_gen::Seedance1p5ProMultiFunctionVideoGenResolution::SevenTwentyP => EnqueueSeedance1p5ProTextToVideoResolution::SevenTwentyP, - artcraft_api_defs::generate::video::multi_function::seedance_1p5_pro_multi_function_video_gen::Seedance1p5ProMultiFunctionVideoGenResolution::TenEightyP => EnqueueSeedance1p5ProTextToVideoResolution::TenEightyP, - }); - - // Use text-to-video cost calculator (same pricing for both modes) - let req = EnqueueSeedance1p5ProTextToVideoRequest { - prompt: String::new(), - duration, - resolution, - aspect_ratio: None, - generate_audio: plan.generate_audio, - }; - - let cost_in_usd_cents = req.calculate_cost_in_cents(); - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} - -#[cfg(test)] -mod tests { - use crate::api::common_video_model::CommonVideoModel; - use crate::api::provider::Provider; - use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy; - use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; - - fn estimate_usd_cents(duration_seconds: u16) -> u64 { - let request = GenerateVideoRequestBuilder { - model: CommonVideoModel::Seedance1p5Pro, - provider: Provider::Artcraft, - prompt: None, - negative_prompt: None, - start_frame: None, - end_frame: None, - reference_images: None, - reference_videos: None, - reference_audio: None, - reference_character_tokens: None, - resolution: None, - aspect_ratio: None, - duration_seconds: Some(duration_seconds), - video_batch_count: None, - generate_audio: None, - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut, - idempotency_token: None, - }; - request.build() - .expect("build should succeed") - .estimate_costs() - .cost_in_usd_cents - .expect("cost_in_usd_cents should be present") - } - - #[test] - fn test_estimate_cost_usd_cents() { - // Default resolution is 720p (when None) - // 720p 5s = 26 cents (constant from Fal) - assert_eq!(estimate_usd_cents(5), 26); - - // Other durations use token-based calculation - assert_eq!(estimate_usd_cents(4), 26); - assert_eq!(estimate_usd_cents(10), 65); - assert_eq!(estimate_usd_cents(12), 78); - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_seedance2p0.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_seedance2p0.rs deleted file mode 100644 index 71ea84aa3b..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_seedance2p0.rs +++ /dev/null @@ -1,204 +0,0 @@ -use artcraft_api_defs::generate::video::multi_function::seedance_2p0_multi_function_video_gen::Seedance2p0BatchCount; -use seedance2pro_client::requests::generate_video::generate_video::{KinoviAspectRatio, KinoviBatchCount, KinoviGenerateVideoRequest, KinoviModelType, KinoviOutputResolution}; - -use crate::api::common_resolution::CommonResolution; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance2p0::PlanArtcraftSeedance2p0; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub (crate) fn estimate_video_cost_artcraft_seedance2p0( - plan: &PlanArtcraftSeedance2p0, -) -> VideoGenerationCostEstimate { - let duration_seconds = plan.duration_seconds.unwrap_or(5).clamp(4, 15); - - let batch_count = match plan.batch_count { - Seedance2p0BatchCount::One => KinoviBatchCount::One, - Seedance2p0BatchCount::Two => KinoviBatchCount::Two, - Seedance2p0BatchCount::Four => KinoviBatchCount::Four, - }; - - let output_resolution = plan.resolution.map(map_common_resolution_to_kinovi); - - let request = KinoviGenerateVideoRequest { - model_type: KinoviModelType::Seedance2Pro, - prompt: String::new(), - aspect_ratio: KinoviAspectRatio::Square1x1, - duration_seconds, - batch_count, - output_resolution, - - // TODO: This is a cost factor - reference_video_urls: None, - - // NB: These do not contribute to costs in the Seedance2 integration - start_frame_url: None, - end_frame_url: None, - reference_image_urls: None, - reference_audio_urls: None, - character_ids: None, - use_face_blur_hack: None, - }; - - let cost_in_usd_cents = request.estimate_cost_in_usd_cents(); - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} - -fn map_common_resolution_to_kinovi(resolution: CommonResolution) -> KinoviOutputResolution { - match resolution { - CommonResolution::FourEightyP => KinoviOutputResolution::FourEightyP, - CommonResolution::SevenTwentyP => KinoviOutputResolution::SevenTwentyP, - CommonResolution::TenEightyP => KinoviOutputResolution::TenEightyP, - // For resolutions that don't map directly, default to 720p - _ => KinoviOutputResolution::SevenTwentyP, - } -} - -#[cfg(test)] -mod tests { - use crate::api::common_resolution::CommonResolution; - use crate::api::common_video_model::CommonVideoModel; - use crate::api::provider::Provider; - use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy; - use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; - - fn estimate_usd_cents( - duration_seconds: u16, - video_batch_count: u16, - resolution: Option, - ) -> u64 { - let request = GenerateVideoRequestBuilder { - model: CommonVideoModel::Seedance2p0, - provider: Provider::Artcraft, - prompt: None, - negative_prompt: None, - start_frame: None, - end_frame: None, - reference_images: None, - reference_videos: None, - reference_audio: None, - reference_character_tokens: None, - resolution, - aspect_ratio: None, - duration_seconds: Some(duration_seconds), - video_batch_count: Some(video_batch_count), - generate_audio: None, - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut, - idempotency_token: None, - }; - request.build() - .expect("build should succeed") - .estimate_costs() - .cost_in_usd_cents - .expect("cost_in_usd_cents should be present") - } - - // -- 720p (default / legacy pricing: 250 credits/$1) -- - - #[test] - fn pro_720p_batch_1() { - assert_eq!(estimate_usd_cents(4, 1, Some(CommonResolution::SevenTwentyP)), 64); - assert_eq!(estimate_usd_cents(5, 1, Some(CommonResolution::SevenTwentyP)), 80); - assert_eq!(estimate_usd_cents(6, 1, Some(CommonResolution::SevenTwentyP)), 96); - assert_eq!(estimate_usd_cents(7, 1, Some(CommonResolution::SevenTwentyP)), 112); - assert_eq!(estimate_usd_cents(15, 1, Some(CommonResolution::SevenTwentyP)), 240); - } - - #[test] - fn pro_720p_batch_2() { - assert_eq!(estimate_usd_cents(4, 2, Some(CommonResolution::SevenTwentyP)), 128); - assert_eq!(estimate_usd_cents(5, 2, Some(CommonResolution::SevenTwentyP)), 160); - assert_eq!(estimate_usd_cents(15, 2, Some(CommonResolution::SevenTwentyP)), 480); - } - - #[test] - fn pro_720p_batch_4() { - assert_eq!(estimate_usd_cents(4, 4, Some(CommonResolution::SevenTwentyP)), 256); - assert_eq!(estimate_usd_cents(5, 4, Some(CommonResolution::SevenTwentyP)), 320); - assert_eq!(estimate_usd_cents(15, 4, Some(CommonResolution::SevenTwentyP)), 960); - } - - #[test] - fn pro_none_resolution_same_as_720p() { - assert_eq!( - estimate_usd_cents(5, 1, None), - estimate_usd_cents(5, 1, Some(CommonResolution::SevenTwentyP)), - ); - } - - // -- 480p (new pricing: 193 credits/$1) -- - - #[test] - fn pro_480p_batch_1() { - assert_eq!(estimate_usd_cents(4, 1, Some(CommonResolution::FourEightyP)), 31); - assert_eq!(estimate_usd_cents(5, 1, Some(CommonResolution::FourEightyP)), 39); - assert_eq!(estimate_usd_cents(10, 1, Some(CommonResolution::FourEightyP)), 78); - assert_eq!(estimate_usd_cents(15, 1, Some(CommonResolution::FourEightyP)), 117); - } - - #[test] - fn pro_480p_batch_2() { - assert_eq!(estimate_usd_cents(5, 2, Some(CommonResolution::FourEightyP)), 78); - } - - #[test] - fn pro_480p_batch_4() { - assert_eq!(estimate_usd_cents(5, 4, Some(CommonResolution::FourEightyP)), 155); - } - - // -- 1080p (new pricing: 193 credits/$1) -- - - #[test] - fn pro_1080p_batch_1() { - assert_eq!(estimate_usd_cents(4, 1, Some(CommonResolution::TenEightyP)), 187); - assert_eq!(estimate_usd_cents(5, 1, Some(CommonResolution::TenEightyP)), 233); - assert_eq!(estimate_usd_cents(10, 1, Some(CommonResolution::TenEightyP)), 466); - assert_eq!(estimate_usd_cents(15, 1, Some(CommonResolution::TenEightyP)), 699); - } - - #[test] - fn pro_1080p_batch_2() { - assert_eq!(estimate_usd_cents(5, 2, Some(CommonResolution::TenEightyP)), 466); - } - - #[test] - fn pro_1080p_batch_4() { - assert_eq!(estimate_usd_cents(5, 4, Some(CommonResolution::TenEightyP)), 933); - } - - // -- Relative pricing -- - - #[test] - fn pro_480p_cheaper_than_720p_cheaper_than_1080p() { - let c480 = estimate_usd_cents(5, 1, Some(CommonResolution::FourEightyP)); - let c720 = estimate_usd_cents(5, 1, Some(CommonResolution::SevenTwentyP)); - let c1080 = estimate_usd_cents(5, 1, Some(CommonResolution::TenEightyP)); - assert!(c480 < c720, "480p ({}) should be cheaper than 720p ({})", c480, c720); - assert!(c720 < c1080, "720p ({}) should be cheaper than 1080p ({})", c720, c1080); - } - - #[test] - fn cost_scales_with_duration() { - let c4 = estimate_usd_cents(4, 1, Some(CommonResolution::SevenTwentyP)); - let c10 = estimate_usd_cents(10, 1, Some(CommonResolution::SevenTwentyP)); - let c15 = estimate_usd_cents(15, 1, Some(CommonResolution::SevenTwentyP)); - assert!(c4 < c10); - assert!(c10 < c15); - } - - #[test] - fn cost_scales_with_batch() { - let b1 = estimate_usd_cents(5, 1, Some(CommonResolution::TenEightyP)); - let b2 = estimate_usd_cents(5, 2, Some(CommonResolution::TenEightyP)); - let b4 = estimate_usd_cents(5, 4, Some(CommonResolution::TenEightyP)); - assert!(b1 < b2); - assert!(b2 < b4); - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_seedance2p0_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_seedance2p0_fast.rs deleted file mode 100644 index fafada1154..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_seedance2p0_fast.rs +++ /dev/null @@ -1,295 +0,0 @@ -use artcraft_api_defs::generate::video::multi_function::seedance_2p0_multi_function_video_gen::Seedance2p0BatchCount; -use seedance2pro_client::requests::generate_video::generate_video::{KinoviGenerateVideoRequest, KinoviBatchCount, KinoviModelType, KinoviOutputResolution, KinoviAspectRatio}; - -use crate::api::common_resolution::CommonResolution; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance2p0::PlanArtcraftSeedance2p0; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_artcraft_seedance2p0_fast( - plan: &PlanArtcraftSeedance2p0, -) -> VideoGenerationCostEstimate { - let duration_seconds = plan.duration_seconds.unwrap_or(5).clamp(4, 15); - - let batch_count = match plan.batch_count { - Seedance2p0BatchCount::One => KinoviBatchCount::One, - Seedance2p0BatchCount::Two => KinoviBatchCount::Two, - Seedance2p0BatchCount::Four => KinoviBatchCount::Four, - }; - - let output_resolution = plan.resolution.map(map_common_resolution_to_kinovi); - - let request = KinoviGenerateVideoRequest { - model_type: KinoviModelType::Seedance2Fast, - prompt: String::new(), - aspect_ratio: KinoviAspectRatio::Square1x1, - duration_seconds, - batch_count, - output_resolution, - - // TODO: This is a cost factor - reference_video_urls: None, - - // NB: These do not contribute to costs in the Seedance2 integration - start_frame_url: None, - end_frame_url: None, - reference_image_urls: None, - reference_audio_urls: None, - character_ids: None, - use_face_blur_hack: None, - }; - - let cost_in_usd_cents = request.estimate_cost_in_usd_cents(); - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} - -fn map_common_resolution_to_kinovi(resolution: CommonResolution) -> KinoviOutputResolution { - match resolution { - CommonResolution::FourEightyP => KinoviOutputResolution::FourEightyP, - CommonResolution::SevenTwentyP => KinoviOutputResolution::SevenTwentyP, - CommonResolution::TenEightyP => KinoviOutputResolution::TenEightyP, - // For resolutions that don't map directly, default to 720p - _ => KinoviOutputResolution::SevenTwentyP, - } -} - -#[cfg(test)] -mod tests { - use crate::api::common_resolution::CommonResolution; - use crate::api::common_video_model::CommonVideoModel; - use crate::api::provider::Provider; - use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy; - use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; - - fn estimate_usd_cents( - duration_seconds: u16, - video_batch_count: u16, - resolution: Option, - ) -> u64 { - let request = GenerateVideoRequestBuilder { - model: CommonVideoModel::Seedance2p0Fast, - provider: Provider::Artcraft, - prompt: None, - negative_prompt: None, - start_frame: None, - end_frame: None, - reference_images: None, - reference_videos: None, - reference_audio: None, - reference_character_tokens: None, - resolution, - aspect_ratio: None, - duration_seconds: Some(duration_seconds), - video_batch_count: Some(video_batch_count), - generate_audio: None, - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut, - idempotency_token: None, - }; - request.build() - .expect("build should succeed") - .estimate_costs() - .cost_in_usd_cents - .expect("cost_in_usd_cents should be present") - } - - fn estimate_usd_cents_downgrade( - duration_seconds: u16, - video_batch_count: u16, - resolution: Option, - ) -> u64 { - let request = GenerateVideoRequestBuilder { - model: CommonVideoModel::Seedance2p0Fast, - provider: Provider::Artcraft, - prompt: None, - negative_prompt: None, - start_frame: None, - end_frame: None, - reference_images: None, - reference_videos: None, - reference_audio: None, - reference_character_tokens: None, - resolution, - aspect_ratio: None, - duration_seconds: Some(duration_seconds), - video_batch_count: Some(video_batch_count), - generate_audio: None, - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayLessDowngrade, - idempotency_token: None, - }; - request.build() - .expect("build should succeed") - .estimate_costs() - .cost_in_usd_cents - .expect("cost_in_usd_cents should be present") - } - - fn estimate_pro_usd_cents( - duration_seconds: u16, - video_batch_count: u16, - resolution: Option, - ) -> u64 { - let request = GenerateVideoRequestBuilder { - model: CommonVideoModel::Seedance2p0, - provider: Provider::Artcraft, - prompt: None, - negative_prompt: None, - start_frame: None, - end_frame: None, - reference_images: None, - reference_videos: None, - reference_audio: None, - reference_character_tokens: None, - resolution, - aspect_ratio: None, - duration_seconds: Some(duration_seconds), - video_batch_count: Some(video_batch_count), - generate_audio: None, - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut, - idempotency_token: None, - }; - request.build() - .expect("build should succeed") - .estimate_costs() - .cost_in_usd_cents - .expect("cost_in_usd_cents should be present") - } - - // -- 720p (default / legacy pricing: 220 credits/$1) -- - - #[test] - fn fast_720p_batch_1() { - assert_eq!(estimate_usd_cents(4, 1, Some(CommonResolution::SevenTwentyP)), 51); - assert_eq!(estimate_usd_cents(5, 1, Some(CommonResolution::SevenTwentyP)), 64); - assert_eq!(estimate_usd_cents(10, 1, Some(CommonResolution::SevenTwentyP)), 127); - assert_eq!(estimate_usd_cents(15, 1, Some(CommonResolution::SevenTwentyP)), 191); - } - - #[test] - fn fast_720p_batch_2() { - assert_eq!(estimate_usd_cents(5, 2, Some(CommonResolution::SevenTwentyP)), 127); - } - - #[test] - fn fast_720p_batch_4() { - assert_eq!(estimate_usd_cents(5, 4, Some(CommonResolution::SevenTwentyP)), 255); - } - - #[test] - fn fast_none_resolution_same_as_720p() { - assert_eq!( - estimate_usd_cents(5, 1, None), - estimate_usd_cents(5, 1, Some(CommonResolution::SevenTwentyP)), - ); - } - - // -- 480p (new pricing: 193 credits/$1) -- - - #[test] - fn fast_480p_batch_1() { - assert_eq!(estimate_usd_cents(4, 1, Some(CommonResolution::FourEightyP)), 21); - assert_eq!(estimate_usd_cents(5, 1, Some(CommonResolution::FourEightyP)), 26); - assert_eq!(estimate_usd_cents(10, 1, Some(CommonResolution::FourEightyP)), 52); - assert_eq!(estimate_usd_cents(15, 1, Some(CommonResolution::FourEightyP)), 78); - } - - #[test] - fn fast_480p_batch_2() { - assert_eq!(estimate_usd_cents(5, 2, Some(CommonResolution::FourEightyP)), 52); - } - - #[test] - fn fast_480p_batch_4() { - assert_eq!(estimate_usd_cents(5, 4, Some(CommonResolution::FourEightyP)), 104); - } - - // -- 1080p is not supported by Fast; ErrorOut rejects it -- - - #[test] - fn fast_1080p_error_out_rejects() { - let request = GenerateVideoRequestBuilder { - model: CommonVideoModel::Seedance2p0Fast, - provider: Provider::Artcraft, - prompt: None, - negative_prompt: None, - start_frame: None, - end_frame: None, - reference_images: None, - reference_videos: None, - reference_audio: None, - reference_character_tokens: None, - resolution: Some(CommonResolution::TenEightyP), - aspect_ratio: None, - duration_seconds: Some(5), - video_batch_count: Some(1), - generate_audio: None, - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut, - idempotency_token: None, - }; - assert!(request.build().is_err()); - } - - // -- 1080p rounds down to 720p with PayLessDowngrade -- - - #[test] - fn fast_1080p_downgraded_same_as_720p() { - for duration in [4, 5, 10, 15] { - assert_eq!( - estimate_usd_cents_downgrade(duration, 1, Some(CommonResolution::TenEightyP)), - estimate_usd_cents(duration, 1, Some(CommonResolution::SevenTwentyP)), - ); - } - } - - // -- Relative pricing -- - - #[test] - fn fast_480p_cheaper_than_720p() { - let c480 = estimate_usd_cents(5, 1, Some(CommonResolution::FourEightyP)); - let c720 = estimate_usd_cents(5, 1, Some(CommonResolution::SevenTwentyP)); - assert!(c480 < c720, "480p ({}) should be cheaper than 720p ({})", c480, c720); - } - - #[test] - fn fast_is_cheaper_than_pro() { - for res in [ - Some(CommonResolution::FourEightyP), - Some(CommonResolution::SevenTwentyP), - ] { - for duration in [4, 5, 10, 15] { - let fast = estimate_usd_cents(duration, 1, res); - let pro = estimate_pro_usd_cents(duration, 1, res); - assert!( - fast < pro, - "Fast ({}) should be cheaper than Pro ({}) at {}s {:?}", - fast, pro, duration, res, - ); - } - } - } - - #[test] - fn cost_scales_with_duration() { - let c4 = estimate_usd_cents(4, 1, Some(CommonResolution::SevenTwentyP)); - let c10 = estimate_usd_cents(10, 1, Some(CommonResolution::SevenTwentyP)); - let c15 = estimate_usd_cents(15, 1, Some(CommonResolution::SevenTwentyP)); - assert!(c4 < c10); - assert!(c10 < c15); - } - - #[test] - fn cost_scales_with_batch() { - let b1 = estimate_usd_cents(5, 1, Some(CommonResolution::SevenTwentyP)); - let b2 = estimate_usd_cents(5, 2, Some(CommonResolution::SevenTwentyP)); - let b4 = estimate_usd_cents(5, 4, Some(CommonResolution::SevenTwentyP)); - assert!(b1 < b2); - assert!(b2 < b4); - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_seedance_1_0_lite.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_seedance_1_0_lite.rs deleted file mode 100644 index 1dd5f7a2d4..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_seedance_1_0_lite.rs +++ /dev/null @@ -1,47 +0,0 @@ -use artcraft_api_defs::generate::video::generate_seedance_1_0_lite_image_to_video::GenerateSeedance10LiteResolution; -use fal_client::requests::traits::fal_request_cost_calculator_trait::FalRequestCostCalculator; -use fal_client::requests::webhook::video::image::enqueue_seedance_1_lite_image_to_video_webhook::{ - Seedance1LiteDuration, Seedance1LiteRequest, Seedance1LiteResolution, -}; - -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance_1_0_lite::PlanArtcraftSeedance10Lite; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_artcraft_seedance_1_0_lite( - plan: &PlanArtcraftSeedance10Lite, -) -> VideoGenerationCostEstimate { - // Legacy handler defaults: 5 seconds, 720p. Delegate to the Fal client's - // cost calculator to guarantee parity with what we actually charge. - let duration = if plan.duration_seconds_for_cost() == 10 { - Seedance1LiteDuration::TenSeconds - } else { - Seedance1LiteDuration::FiveSeconds - }; - let resolution = match plan.resolution_for_cost() { - GenerateSeedance10LiteResolution::FourEightyP => Seedance1LiteResolution::FourEightyP, - GenerateSeedance10LiteResolution::SevenTwentyP => Seedance1LiteResolution::SevenTwentyP, - }; - - let req = Seedance1LiteRequest { - image_url: String::new(), - end_frame_image_url: None, - prompt: String::new(), - duration, - resolution, - aspect_ratio: None, - camera_fixed: false, - seed: None, - }; - - let cost_in_usd_cents = req.calculate_cost_in_cents(); - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_sora_2.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_sora_2.rs deleted file mode 100644 index 34f1623480..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_sora_2.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_sora_2::PlanArtcraftSora2; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_artcraft_sora_2( - plan: &PlanArtcraftSora2, -) -> VideoGenerationCostEstimate { - // Sora 2: $0.10/second. Default duration (Fal client): 4 seconds. - let cost_in_usd_cents = plan.duration_seconds_for_cost() * 10; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_sora_2_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_sora_2_pro.rs deleted file mode 100644 index 5aac892b6e..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_sora_2_pro.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_sora_2_pro::PlanArtcraftSora2Pro; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_artcraft_sora_2_pro( - plan: &PlanArtcraftSora2Pro, -) -> VideoGenerationCostEstimate { - // Sora 2 Pro: $0.30/second @ 720p, $0.50/second @ 1080p. - // Default duration 4s. Default resolution: 1080p for text-to-video, 720p (Auto) for image-to-video. - let seconds = plan.duration_seconds_for_cost(); - let per_second_cents: u64 = if plan.is_ten_eighty_p_for_cost() { 50 } else { 30 }; - let cost_in_usd_cents = per_second_cents * seconds; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_veo_2.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_veo_2.rs deleted file mode 100644 index 68e56811a5..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_veo_2.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_2::PlanArtcraftVeo2; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_artcraft_veo_2( - plan: &PlanArtcraftVeo2, -) -> VideoGenerationCostEstimate { - // Mirrors fal_client veo_2 cost calculator: 5s = $2.50, +$0.50/s above 5s. - let seconds = plan.duration_seconds_for_cost(); - let extra = seconds.saturating_sub(5); - let cost_in_usd_cents = 250 + extra * 50; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_veo_3.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_veo_3.rs deleted file mode 100644 index 25349259e5..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_veo_3.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_3::PlanArtcraftVeo3; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_artcraft_veo_3( - plan: &PlanArtcraftVeo3, -) -> VideoGenerationCostEstimate { - // Mirrors fal_client veo_3 cost calculator (720p/1080p): - // $0.20/sec audio off, $0.40/sec audio on. Default 8s, audio off (legacy handler). - let seconds = plan.duration_seconds_for_cost(); - let per_second_cents: u64 = if plan.generate_audio_for_cost() { 40 } else { 20 }; - let cost_in_usd_cents = per_second_cents * seconds; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_veo_3_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_veo_3_fast.rs deleted file mode 100644 index a391bb6155..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_veo_3_fast.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_3_fast::PlanArtcraftVeo3Fast; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_artcraft_veo_3_fast( - plan: &PlanArtcraftVeo3Fast, -) -> VideoGenerationCostEstimate { - // Mirrors fal_client veo_3_fast cost calculator (720p/1080p): - // $0.10/sec audio off, $0.15/sec audio on. Default 8s, audio off (legacy handler). - let seconds = plan.duration_seconds_for_cost(); - let per_second_cents: u64 = if plan.generate_audio_for_cost() { 15 } else { 10 }; - let cost_in_usd_cents = per_second_cents * seconds; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_veo_3p1.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_veo_3p1.rs deleted file mode 100644 index bebb1127e0..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_veo_3p1.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_3p1::PlanArtcraftVeo3p1; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_artcraft_veo_3p1( - plan: &PlanArtcraftVeo3p1, -) -> VideoGenerationCostEstimate { - // Mirrors fal_client veo_3p1 cost calculator (720p/1080p): - // $0.20/sec audio off, $0.40/sec audio on. Default 6s, audio on (legacy handler). - let seconds = plan.duration_seconds_for_cost(); - let per_second_cents: u64 = if plan.generate_audio_for_cost() { 40 } else { 20 }; - let cost_in_usd_cents = per_second_cents * seconds; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_veo_3p1_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_veo_3p1_fast.rs deleted file mode 100644 index 716974302f..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/estimate_video_cost_artcraft_veo_3p1_fast.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_3p1_fast::PlanArtcraftVeo3p1Fast; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_artcraft_veo_3p1_fast( - plan: &PlanArtcraftVeo3p1Fast, -) -> VideoGenerationCostEstimate { - // Mirrors fal_client veo_3p1_fast cost calculator (720p/1080p): - // $0.10/sec audio off, $0.15/sec audio on. Default 6s, audio on (legacy handler). - let seconds = plan.duration_seconds_for_cost(); - let per_second_cents: u64 = if plan.generate_audio_for_cost() { 15 } else { 10 }; - let cost_in_usd_cents = per_second_cents * seconds; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/mod.rs deleted file mode 100644 index 87559bbc34..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/artcraft/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -pub mod estimate_video_cost_artcraft_kling_1_6_pro; -pub mod estimate_video_cost_artcraft_kling_2_1_master; -pub mod estimate_video_cost_artcraft_kling_2_1_pro; -pub mod estimate_video_cost_artcraft_kling_2_5_turbo_pro; -pub mod estimate_video_cost_artcraft_kling_2_6_pro; -pub mod estimate_video_cost_artcraft_kling3p0_pro; -pub mod estimate_video_cost_artcraft_kling3p0_standard; -pub mod estimate_video_cost_artcraft_seedance_1_0_lite; -pub mod estimate_video_cost_artcraft_seedance1p5_pro; -pub mod estimate_video_cost_artcraft_seedance2p0; -pub mod estimate_video_cost_artcraft_seedance2p0_fast; -pub mod estimate_video_cost_artcraft_sora_2; -pub mod estimate_video_cost_artcraft_sora_2_pro; -pub mod estimate_video_cost_artcraft_veo_2; -pub mod estimate_video_cost_artcraft_veo_3; -pub mod estimate_video_cost_artcraft_veo_3_fast; -pub mod estimate_video_cost_artcraft_veo_3p1; -pub mod estimate_video_cost_artcraft_veo_3p1_fast; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_1_6_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_1_6_pro.rs deleted file mode 100644 index e079571409..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_1_6_pro.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_1_6_pro::PlanFalKling16Pro; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_fal_kling_1_6_pro( - plan: &PlanFalKling16Pro, -) -> VideoGenerationCostEstimate { - // Mirrors fal_client kling_v1p6_pro: 5s = 48¢, 10s = 95¢ (Default → 5s). - let cost_in_usd_cents: u64 = if plan.is_ten_seconds() { 95 } else { 48 }; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_2_1_master.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_2_1_master.rs deleted file mode 100644 index 13a6ef987d..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_2_1_master.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_2_1_master::PlanFalKling21Master; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_fal_kling_2_1_master( - plan: &PlanFalKling21Master, -) -> VideoGenerationCostEstimate { - // Mirrors fal_client kling_v2p1_master: 5s = $1.40, 10s = $2.80. - let cost_in_usd_cents: u64 = if plan.is_ten_seconds() { 280 } else { 140 }; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_2_1_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_2_1_pro.rs deleted file mode 100644 index c39af04359..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_2_1_pro.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_2_1_pro::PlanFalKling21Pro; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_fal_kling_2_1_pro( - plan: &PlanFalKling21Pro, -) -> VideoGenerationCostEstimate { - // Mirrors fal_client kling_v2p1_pro: 5s = 45¢, 10s = 90¢. - let cost_in_usd_cents: u64 = if plan.is_ten_seconds() { 90 } else { 45 }; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_2_5_turbo_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_2_5_turbo_pro.rs deleted file mode 100644 index 9af48c154e..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_2_5_turbo_pro.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_2_5_turbo_pro::PlanFalKling2p5TurboPro; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_fal_kling_2_5_turbo_pro( - plan: &PlanFalKling2p5TurboPro, -) -> VideoGenerationCostEstimate { - // Mirrors fal_client kling_v2p5_turbo_pro: 5s = 35¢, 10s = 70¢. None → 5s. - let cost_in_usd_cents: u64 = if plan.is_ten_seconds() { 70 } else { 35 }; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_2_6_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_2_6_pro.rs deleted file mode 100644 index 9ffd7e2874..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_2_6_pro.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_2_6_pro::PlanFalKling2p6Pro; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_fal_kling_2_6_pro( - plan: &PlanFalKling2p6Pro, -) -> VideoGenerationCostEstimate { - // Mirrors fal_client kling_v2p6_pro: - // audio off: $0.07/sec → 5s=35¢, 10s=70¢ - // audio on: $0.14/sec → 5s=70¢, 10s=140¢ - // Default duration is 5s; default generate_audio is true. - let cost_in_usd_cents: u64 = match (plan.generate_audio_for_cost(), plan.is_ten_seconds()) { - (false, false) => 35, - (false, true) => 70, - (true, false) => 70, - (true, true) => 140, - }; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_3p0_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_3p0_pro.rs deleted file mode 100644 index 11a5ba837f..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_3p0_pro.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_3p0_pro::PlanFalKling3p0Pro; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_fal_kling_3p0_pro( - plan: &PlanFalKling3p0Pro, -) -> VideoGenerationCostEstimate { - // Mirrors fal_client kling_3p0_pro: - // audio off: $0.224/sec (rate=224 in tenths-of-cents) - // audio on: $0.336/sec (rate=336) - // ceiling-divided to whole cents. - let seconds = plan.duration_seconds_for_cost(); - let rate: u64 = if plan.generate_audio_for_cost() { 336 } else { 224 }; - let cost_in_usd_cents = (rate * seconds + 9) / 10; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_3p0_standard.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_3p0_standard.rs deleted file mode 100644 index ba5dd4daee..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_kling_3p0_standard.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_3p0_standard::PlanFalKling3p0Standard; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_fal_kling_3p0_standard( - plan: &PlanFalKling3p0Standard, -) -> VideoGenerationCostEstimate { - // Mirrors fal_client kling_3p0_standard: - // audio off: $0.168/sec (rate=168) - // audio on: $0.252/sec (rate=252) - let seconds = plan.duration_seconds_for_cost(); - let rate: u64 = if plan.generate_audio_for_cost() { 252 } else { 168 }; - let cost_in_usd_cents = (rate * seconds + 9) / 10; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_seedance_1_0_lite.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_seedance_1_0_lite.rs deleted file mode 100644 index 5704b9a18c..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_seedance_1_0_lite.rs +++ /dev/null @@ -1,33 +0,0 @@ -use fal_client::requests::traits::fal_request_cost_calculator_trait::FalRequestCostCalculator; -use fal_client::requests::webhook::video::image::enqueue_seedance_1_lite_image_to_video_webhook::Seedance1LiteRequest; - -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_seedance_1_0_lite::PlanFalSeedance10Lite; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_fal_seedance_1_0_lite( - plan: &PlanFalSeedance10Lite, -) -> VideoGenerationCostEstimate { - // Delegate to the Fal client's cost calculator to guarantee parity with billing. - let req = Seedance1LiteRequest { - image_url: plan.image_url.clone(), - end_frame_image_url: plan.end_image_url.clone(), - prompt: plan.prompt.clone(), - duration: plan.duration, - resolution: plan.resolution, - aspect_ratio: plan.aspect_ratio, - camera_fixed: false, - seed: None, - }; - - let cost_in_usd_cents = req.calculate_cost_in_cents(); - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_seedance_1p5_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_seedance_1p5_pro.rs deleted file mode 100644 index 34bbd7c5d5..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_seedance_1p5_pro.rs +++ /dev/null @@ -1,59 +0,0 @@ -use fal_client::requests::traits::fal_request_cost_calculator_trait::FalRequestCostCalculator; -use fal_client::requests::webhook::video::text::enqueue_seedance_1p5_pro_text_to_video_webhook::{ - EnqueueSeedance1p5ProTextToVideoRequest, EnqueueSeedance1p5ProTextToVideoDuration, - EnqueueSeedance1p5ProTextToVideoResolution, -}; - -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_seedance_1p5_pro::{ - FalSeedance1p5ProDuration, FalSeedance1p5ProResolution, PlanFalSeedance1p5Pro, -}; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_fal_seedance_1p5_pro( - plan: &PlanFalSeedance1p5Pro, -) -> VideoGenerationCostEstimate { - // Seedance 1.5 Pro t2v and i2v have identical pricing; delegate to the t2v - // calculator to guarantee parity with billing. - let req = EnqueueSeedance1p5ProTextToVideoRequest { - prompt: String::new(), - resolution: plan.resolution.map(to_t2v_resolution), - duration: plan.duration.map(to_t2v_duration), - aspect_ratio: None, - generate_audio: plan.generate_audio, - }; - - let cost_in_usd_cents = req.calculate_cost_in_cents(); - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} - -fn to_t2v_resolution(r: FalSeedance1p5ProResolution) -> EnqueueSeedance1p5ProTextToVideoResolution { - match r { - FalSeedance1p5ProResolution::FourEightyP => EnqueueSeedance1p5ProTextToVideoResolution::FourEightyP, - FalSeedance1p5ProResolution::SevenTwentyP => EnqueueSeedance1p5ProTextToVideoResolution::SevenTwentyP, - FalSeedance1p5ProResolution::TenEightyP => EnqueueSeedance1p5ProTextToVideoResolution::TenEightyP, - } -} - -fn to_t2v_duration(d: FalSeedance1p5ProDuration) -> EnqueueSeedance1p5ProTextToVideoDuration { - use EnqueueSeedance1p5ProTextToVideoDuration as T; - match d { - FalSeedance1p5ProDuration::Four => T::FourSeconds, - FalSeedance1p5ProDuration::Five => T::FiveSeconds, - FalSeedance1p5ProDuration::Six => T::SixSeconds, - FalSeedance1p5ProDuration::Seven => T::SevenSeconds, - FalSeedance1p5ProDuration::Eight => T::EightSeconds, - FalSeedance1p5ProDuration::Nine => T::NineSeconds, - FalSeedance1p5ProDuration::Ten => T::TenSeconds, - FalSeedance1p5ProDuration::Eleven => T::ElevenSeconds, - FalSeedance1p5ProDuration::Twelve => T::TwelveSeconds, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_sora_2.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_sora_2.rs deleted file mode 100644 index 8fcdd71e16..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_sora_2.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_sora_2::PlanFalSora2; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_fal_sora_2( - plan: &PlanFalSora2, -) -> VideoGenerationCostEstimate { - // Sora 2: $0.10/second. Default duration (Fal client): 4s. - let cost_in_usd_cents = plan.duration_seconds_for_cost() * 10; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_sora_2_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_sora_2_pro.rs deleted file mode 100644 index 571f0f1fcc..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_sora_2_pro.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_sora_2_pro::PlanFalSora2Pro; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_fal_sora_2_pro( - plan: &PlanFalSora2Pro, -) -> VideoGenerationCostEstimate { - // Sora 2 Pro: $0.30/second @ 720p, $0.50/second @ 1080p. - let seconds = plan.duration_seconds_for_cost(); - let per_second_cents: u64 = if plan.is_ten_eighty_p_for_cost() { 50 } else { 30 }; - let cost_in_usd_cents = per_second_cents * seconds; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_veo_2.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_veo_2.rs deleted file mode 100644 index 7fb13ee260..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_veo_2.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_2::PlanFalVeo2; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_fal_veo_2( - plan: &PlanFalVeo2, -) -> VideoGenerationCostEstimate { - // 5s = $2.50, +$0.50 per additional second. - let seconds = plan.duration_seconds_for_cost(); - let extra = seconds.saturating_sub(5); - let cost_in_usd_cents = 250 + extra * 50; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_veo_3.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_veo_3.rs deleted file mode 100644 index 6c3dbdd031..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_veo_3.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3::PlanFalVeo3; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_fal_veo_3( - plan: &PlanFalVeo3, -) -> VideoGenerationCostEstimate { - // $0.20/sec audio off, $0.40/sec audio on (720p/1080p). - let seconds = plan.duration_seconds_for_cost(); - let per_second_cents: u64 = if plan.generate_audio { 40 } else { 20 }; - let cost_in_usd_cents = per_second_cents * seconds; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_veo_3_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_veo_3_fast.rs deleted file mode 100644 index a54674bd83..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_veo_3_fast.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3_fast::PlanFalVeo3Fast; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_fal_veo_3_fast( - plan: &PlanFalVeo3Fast, -) -> VideoGenerationCostEstimate { - // $0.10/sec audio off, $0.15/sec audio on (720p/1080p). - let seconds = plan.duration_seconds_for_cost(); - let per_second_cents: u64 = if plan.generate_audio { 15 } else { 10 }; - let cost_in_usd_cents = per_second_cents * seconds; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_veo_3p1.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_veo_3p1.rs deleted file mode 100644 index e7595d88ed..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_veo_3p1.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1::PlanFalVeo3p1; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_fal_veo_3p1( - plan: &PlanFalVeo3p1, -) -> VideoGenerationCostEstimate { - // $0.20/sec audio off, $0.40/sec audio on (720p/1080p). - let seconds = plan.duration_seconds_for_cost(); - let per_second_cents: u64 = if plan.generate_audio_for_cost() { 40 } else { 20 }; - let cost_in_usd_cents = per_second_cents * seconds; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_veo_3p1_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_veo_3p1_fast.rs deleted file mode 100644 index 3f2f6f7a03..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/estimate_video_cost_fal_veo_3p1_fast.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1_fast::PlanFalVeo3p1Fast; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_fal_veo_3p1_fast( - plan: &PlanFalVeo3p1Fast, -) -> VideoGenerationCostEstimate { - // $0.10/sec audio off, $0.15/sec audio on (720p/1080p). - let seconds = plan.inner.duration_seconds_for_cost(); - let per_second_cents: u64 = if plan.inner.generate_audio_for_cost() { 15 } else { 10 }; - let cost_in_usd_cents = per_second_cents * seconds; - - VideoGenerationCostEstimate { - 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, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/mod.rs deleted file mode 100644 index c737bbea2f..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/fal/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -pub(crate) mod estimate_video_cost_fal_kling_1_6_pro; -pub(crate) mod estimate_video_cost_fal_kling_2_1_master; -pub(crate) mod estimate_video_cost_fal_kling_2_1_pro; -pub(crate) mod estimate_video_cost_fal_kling_2_5_turbo_pro; -pub(crate) mod estimate_video_cost_fal_kling_2_6_pro; -pub(crate) mod estimate_video_cost_fal_kling_3p0_pro; -pub(crate) mod estimate_video_cost_fal_kling_3p0_standard; -pub(crate) mod estimate_video_cost_fal_seedance_1_0_lite; -pub(crate) mod estimate_video_cost_fal_seedance_1p5_pro; -pub(crate) mod estimate_video_cost_fal_sora_2; -pub(crate) mod estimate_video_cost_fal_sora_2_pro; -pub(crate) mod estimate_video_cost_fal_veo_2; -pub(crate) mod estimate_video_cost_fal_veo_3; -pub(crate) mod estimate_video_cost_fal_veo_3_fast; -pub(crate) mod estimate_video_cost_fal_veo_3p1; -pub(crate) mod estimate_video_cost_fal_veo_3p1_fast; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/mod.rs deleted file mode 100644 index 950a44c484..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub (crate) mod artcraft; -pub (crate) mod fal; -pub (crate) mod muapi; -pub (crate) mod seedance2pro; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/muapi/estimate_video_cost_muapi_seedance2p0.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/muapi/estimate_video_cost_muapi_seedance2p0.rs deleted file mode 100644 index bb75a1d097..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/muapi/estimate_video_cost_muapi_seedance2p0.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::generate::generate_video::plan::muapi::plan_generate_video_muapi_seedance2p0::{ - MuapiSeedance2p0Mode, PlanMuapiSeedance2p0, -}; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; -use muapi_client::creds::muapi_api_key::MuapiApiKey; -use muapi_client::creds::muapi_session::MuapiSession; -use muapi_client::requests::seedance_2p0_image_to_video::seedance_2p0_image_to_video::Seedance2p0ImageToVideoArgs; -use muapi_client::requests::seedance_2p0_text_to_video::seedance_2p0_text_to_video::Seedance2p0TextToVideoArgs; - -pub(crate) fn estimate_video_cost_muapi_seedance2p0( - plan: &PlanMuapiSeedance2p0, -) -> VideoGenerationCostEstimate { - // A dummy session is sufficient — cost estimation does not make any network calls. - let dummy_session = MuapiSession::new(MuapiApiKey::new(String::new())); - - let cost_in_usd_cents; - let cost_in_credits; - - match &plan.mode { - MuapiSeedance2p0Mode::TextToVideo { aspect_ratio, duration, quality } => { - let args = Seedance2p0TextToVideoArgs { - session: &dummy_session, - prompt: String::new(), - aspect_ratio: *aspect_ratio, - duration: *duration, - quality: *quality, - }; - - cost_in_usd_cents = args.estimate_cost_in_usd_cents(); - - // NB: This is off by a factor of 100 because they use a fractional system. - cost_in_credits = (args.estimate_credits() * 100.0f64).round() as u64; - } - MuapiSeedance2p0Mode::ImageToVideo { aspect_ratio, duration, quality, .. } => { - let args = Seedance2p0ImageToVideoArgs { - session: &dummy_session, - prompt: String::new(), - image_urls: vec![], - aspect_ratio: *aspect_ratio, - duration: *duration, - quality: *quality, - }; - - cost_in_usd_cents = args.estimate_cost_in_usd_cents(); - - // NB: This is off by a factor of 100 because they use a fractional system. - cost_in_credits = (args.estimate_credits() * 100.0f64).round() as u64; - } - } - - VideoGenerationCostEstimate { - cost_in_credits: Some(cost_in_credits), - cost_in_usd_cents: Some(cost_in_usd_cents), - is_free: false, - is_unlimited: false, - is_rate_limited: false, - has_watermark: false, - failures_are_refunded: None, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/muapi/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/muapi/mod.rs deleted file mode 100644 index 83d61f0c0a..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/muapi/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod estimate_video_cost_muapi_seedance2p0; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/seedance2pro/estimate_video_cost_seedance2pro_seedance2p0.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/seedance2pro/estimate_video_cost_seedance2pro_seedance2p0.rs deleted file mode 100644 index f88c740327..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/seedance2pro/estimate_video_cost_seedance2pro_seedance2p0.rs +++ /dev/null @@ -1,162 +0,0 @@ -use crate::generate::generate_video::plan::seedance2pro::plan_generate_video_seedance2pro_seedance2p0::PlanSeedance2proSeedance2p0; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_seedance2pro_seedance2p0( - plan: &PlanSeedance2proSeedance2p0, -) -> VideoGenerationCostEstimate { - let cost_in_credits = plan.request.estimate_credits(); - let cost_in_usd_cents = plan.request.estimate_cost_in_usd_cents(); - - VideoGenerationCostEstimate { - cost_in_credits: Some(cost_in_credits as u64), - cost_in_usd_cents: Some(cost_in_usd_cents), - is_free: false, - is_unlimited: false, - is_rate_limited: false, - has_watermark: false, - failures_are_refunded: None, - } -} - -#[cfg(test)] -mod tests { - use crate::api::common_resolution::CommonResolution; - use crate::api::common_video_model::CommonVideoModel; - use crate::api::provider::Provider; - use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy; - use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; - - fn estimate_usd_cents( - duration_seconds: u16, - video_batch_count: u16, - resolution: Option, - ) -> u64 { - let request = GenerateVideoRequestBuilder { - model: CommonVideoModel::Seedance2p0, - provider: Provider::Seedance2Pro, - prompt: None, - negative_prompt: None, - start_frame: None, - end_frame: None, - reference_images: None, - reference_videos: None, - reference_audio: None, - reference_character_tokens: None, - resolution, - aspect_ratio: None, - duration_seconds: Some(duration_seconds), - video_batch_count: Some(video_batch_count), - generate_audio: None, - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade, - idempotency_token: None, - }; - request.build() - .expect("build should succeed") - .estimate_costs() - .cost_in_usd_cents - .expect("cost_in_usd_cents should be present") - } - - // -- 720p (default / legacy pricing: 250 credits/$1) -- - - #[test] - fn pro_720p_batch_1() { - assert_eq!(estimate_usd_cents(4, 1, Some(CommonResolution::SevenTwentyP)), 64); - assert_eq!(estimate_usd_cents(5, 1, Some(CommonResolution::SevenTwentyP)), 80); - assert_eq!(estimate_usd_cents(6, 1, Some(CommonResolution::SevenTwentyP)), 96); - assert_eq!(estimate_usd_cents(7, 1, Some(CommonResolution::SevenTwentyP)), 112); - assert_eq!(estimate_usd_cents(10, 1, Some(CommonResolution::SevenTwentyP)), 160); - assert_eq!(estimate_usd_cents(15, 1, Some(CommonResolution::SevenTwentyP)), 240); - } - - #[test] - fn pro_720p_batch_2() { - assert_eq!(estimate_usd_cents(4, 2, Some(CommonResolution::SevenTwentyP)), 128); - assert_eq!(estimate_usd_cents(5, 2, Some(CommonResolution::SevenTwentyP)), 160); - assert_eq!(estimate_usd_cents(15, 2, Some(CommonResolution::SevenTwentyP)), 480); - } - - #[test] - fn pro_720p_batch_4() { - assert_eq!(estimate_usd_cents(4, 4, Some(CommonResolution::SevenTwentyP)), 256); - assert_eq!(estimate_usd_cents(5, 4, Some(CommonResolution::SevenTwentyP)), 320); - assert_eq!(estimate_usd_cents(15, 4, Some(CommonResolution::SevenTwentyP)), 960); - } - - #[test] - fn pro_none_resolution_same_as_720p() { - assert_eq!( - estimate_usd_cents(5, 1, None), - estimate_usd_cents(5, 1, Some(CommonResolution::SevenTwentyP)), - ); - } - - // -- 480p (new pricing: 193 credits/$1) -- - - #[test] - fn pro_480p_batch_1() { - assert_eq!(estimate_usd_cents(4, 1, Some(CommonResolution::FourEightyP)), 31); - assert_eq!(estimate_usd_cents(5, 1, Some(CommonResolution::FourEightyP)), 39); - assert_eq!(estimate_usd_cents(10, 1, Some(CommonResolution::FourEightyP)), 78); - assert_eq!(estimate_usd_cents(15, 1, Some(CommonResolution::FourEightyP)), 117); - } - - #[test] - fn pro_480p_batch_2() { - assert_eq!(estimate_usd_cents(5, 2, Some(CommonResolution::FourEightyP)), 78); - } - - #[test] - fn pro_480p_batch_4() { - assert_eq!(estimate_usd_cents(5, 4, Some(CommonResolution::FourEightyP)), 155); - } - - // -- 1080p (new pricing: 193 credits/$1) -- - - #[test] - fn pro_1080p_batch_1() { - assert_eq!(estimate_usd_cents(4, 1, Some(CommonResolution::TenEightyP)), 187); - assert_eq!(estimate_usd_cents(5, 1, Some(CommonResolution::TenEightyP)), 233); - assert_eq!(estimate_usd_cents(10, 1, Some(CommonResolution::TenEightyP)), 466); - assert_eq!(estimate_usd_cents(15, 1, Some(CommonResolution::TenEightyP)), 699); - } - - #[test] - fn pro_1080p_batch_2() { - assert_eq!(estimate_usd_cents(5, 2, Some(CommonResolution::TenEightyP)), 466); - } - - #[test] - fn pro_1080p_batch_4() { - assert_eq!(estimate_usd_cents(5, 4, Some(CommonResolution::TenEightyP)), 933); - } - - // -- Relative pricing -- - - #[test] - fn pro_480p_cheaper_than_720p_cheaper_than_1080p() { - let c480 = estimate_usd_cents(5, 1, Some(CommonResolution::FourEightyP)); - let c720 = estimate_usd_cents(5, 1, Some(CommonResolution::SevenTwentyP)); - let c1080 = estimate_usd_cents(5, 1, Some(CommonResolution::TenEightyP)); - assert!(c480 < c720, "480p ({}) should be cheaper than 720p ({})", c480, c720); - assert!(c720 < c1080, "720p ({}) should be cheaper than 1080p ({})", c720, c1080); - } - - #[test] - fn cost_scales_with_duration() { - let c4 = estimate_usd_cents(4, 1, Some(CommonResolution::SevenTwentyP)); - let c10 = estimate_usd_cents(10, 1, Some(CommonResolution::SevenTwentyP)); - let c15 = estimate_usd_cents(15, 1, Some(CommonResolution::SevenTwentyP)); - assert!(c4 < c10); - assert!(c10 < c15); - } - - #[test] - fn cost_scales_with_batch() { - let b1 = estimate_usd_cents(5, 1, Some(CommonResolution::TenEightyP)); - let b2 = estimate_usd_cents(5, 2, Some(CommonResolution::TenEightyP)); - let b4 = estimate_usd_cents(5, 4, Some(CommonResolution::TenEightyP)); - assert!(b1 < b2); - assert!(b2 < b4); - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/seedance2pro/estimate_video_cost_seedance2pro_seedance2p0_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/seedance2pro/estimate_video_cost_seedance2pro_seedance2p0_fast.rs deleted file mode 100644 index a20d598498..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/seedance2pro/estimate_video_cost_seedance2pro_seedance2p0_fast.rs +++ /dev/null @@ -1,212 +0,0 @@ -use crate::generate::generate_video::plan::seedance2pro::plan_generate_video_seedance2pro_seedance2p0_fast::PlanSeedance2proSeedance2p0Fast; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -pub(crate) fn estimate_video_cost_seedance2pro_seedance2p0_fast( - plan: &PlanSeedance2proSeedance2p0Fast, -) -> VideoGenerationCostEstimate { - let cost_in_credits = plan.request.estimate_credits(); - let cost_in_usd_cents = plan.request.estimate_cost_in_usd_cents(); - - VideoGenerationCostEstimate { - cost_in_credits: Some(cost_in_credits as u64), - cost_in_usd_cents: Some(cost_in_usd_cents), - is_free: false, - is_unlimited: false, - is_rate_limited: false, - has_watermark: false, - failures_are_refunded: None, - } -} - -#[cfg(test)] -mod tests { - use crate::api::common_resolution::CommonResolution; - use crate::api::common_video_model::CommonVideoModel; - use crate::api::provider::Provider; - use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy; - use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; - - fn estimate_usd_cents( - duration_seconds: u16, - video_batch_count: u16, - resolution: Option, - ) -> u64 { - let request = GenerateVideoRequestBuilder { - model: CommonVideoModel::Seedance2p0Fast, - provider: Provider::Seedance2Pro, - prompt: None, - negative_prompt: None, - start_frame: None, - end_frame: None, - reference_images: None, - reference_videos: None, - reference_audio: None, - reference_character_tokens: None, - resolution, - aspect_ratio: None, - duration_seconds: Some(duration_seconds), - video_batch_count: Some(video_batch_count), - generate_audio: None, - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade, - idempotency_token: None, - }; - request.build() - .expect("build should succeed") - .estimate_costs() - .cost_in_usd_cents - .expect("cost_in_usd_cents should be present") - } - - fn estimate_pro_usd_cents( - duration_seconds: u16, - video_batch_count: u16, - resolution: Option, - ) -> u64 { - let request = GenerateVideoRequestBuilder { - model: CommonVideoModel::Seedance2p0, - provider: Provider::Seedance2Pro, - prompt: None, - negative_prompt: None, - start_frame: None, - end_frame: None, - reference_images: None, - reference_videos: None, - reference_audio: None, - reference_character_tokens: None, - resolution, - aspect_ratio: None, - duration_seconds: Some(duration_seconds), - video_batch_count: Some(video_batch_count), - generate_audio: None, - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade, - idempotency_token: None, - }; - request.build() - .expect("build should succeed") - .estimate_costs() - .cost_in_usd_cents - .expect("cost_in_usd_cents should be present") - } - - // -- 720p (default / legacy pricing: 220 credits/$1) -- - - #[test] - fn fast_720p_batch_1() { - assert_eq!(estimate_usd_cents(4, 1, Some(CommonResolution::SevenTwentyP)), 51); - assert_eq!(estimate_usd_cents(5, 1, Some(CommonResolution::SevenTwentyP)), 64); - assert_eq!(estimate_usd_cents(10, 1, Some(CommonResolution::SevenTwentyP)), 127); - assert_eq!(estimate_usd_cents(15, 1, Some(CommonResolution::SevenTwentyP)), 191); - } - - #[test] - fn fast_720p_batch_2() { - assert_eq!(estimate_usd_cents(5, 2, Some(CommonResolution::SevenTwentyP)), 127); - } - - #[test] - fn fast_720p_batch_4() { - assert_eq!(estimate_usd_cents(5, 4, Some(CommonResolution::SevenTwentyP)), 255); - } - - #[test] - fn fast_none_resolution_same_as_720p() { - assert_eq!( - estimate_usd_cents(5, 1, None), - estimate_usd_cents(5, 1, Some(CommonResolution::SevenTwentyP)), - ); - } - - // -- 480p (new pricing: 193 credits/$1) -- - - #[test] - fn fast_480p_batch_1() { - assert_eq!(estimate_usd_cents(4, 1, Some(CommonResolution::FourEightyP)), 21); - assert_eq!(estimate_usd_cents(5, 1, Some(CommonResolution::FourEightyP)), 26); - assert_eq!(estimate_usd_cents(10, 1, Some(CommonResolution::FourEightyP)), 52); - assert_eq!(estimate_usd_cents(15, 1, Some(CommonResolution::FourEightyP)), 78); - } - - #[test] - fn fast_480p_batch_2() { - assert_eq!(estimate_usd_cents(5, 2, Some(CommonResolution::FourEightyP)), 52); - } - - #[test] - fn fast_480p_batch_4() { - assert_eq!(estimate_usd_cents(5, 4, Some(CommonResolution::FourEightyP)), 104); - } - - // -- 1080p maps to 720p for Fast (Kinovi doesn't support 1080p fast) -- - - #[test] - fn fast_1080p_same_as_720p() { - for duration in [4, 5, 10, 15] { - assert_eq!( - estimate_usd_cents(duration, 1, Some(CommonResolution::TenEightyP)), - estimate_usd_cents(duration, 1, Some(CommonResolution::SevenTwentyP)), - ); - } - } - - #[test] - fn fast_1080p_batch_2() { - assert_eq!( - estimate_usd_cents(5, 2, Some(CommonResolution::TenEightyP)), - estimate_usd_cents(5, 2, Some(CommonResolution::SevenTwentyP)), - ); - } - - #[test] - fn fast_1080p_batch_4() { - assert_eq!( - estimate_usd_cents(5, 4, Some(CommonResolution::TenEightyP)), - estimate_usd_cents(5, 4, Some(CommonResolution::SevenTwentyP)), - ); - } - - // -- Relative pricing -- - - #[test] - fn fast_480p_cheaper_than_720p() { - let c480 = estimate_usd_cents(5, 1, Some(CommonResolution::FourEightyP)); - let c720 = estimate_usd_cents(5, 1, Some(CommonResolution::SevenTwentyP)); - assert!(c480 < c720, "480p ({}) should be cheaper than 720p ({})", c480, c720); - } - - #[test] - fn fast_is_cheaper_than_pro() { - for res in [ - Some(CommonResolution::FourEightyP), - Some(CommonResolution::SevenTwentyP), - Some(CommonResolution::TenEightyP), - ] { - for duration in [4, 5, 10, 15] { - let fast = estimate_usd_cents(duration, 1, res); - let pro = estimate_pro_usd_cents(duration, 1, res); - assert!( - fast < pro, - "Fast ({}) should be cheaper than Pro ({}) at {}s {:?}", - fast, pro, duration, res, - ); - } - } - } - - #[test] - fn cost_scales_with_duration() { - let c4 = estimate_usd_cents(4, 1, Some(CommonResolution::SevenTwentyP)); - let c10 = estimate_usd_cents(10, 1, Some(CommonResolution::SevenTwentyP)); - let c15 = estimate_usd_cents(15, 1, Some(CommonResolution::SevenTwentyP)); - assert!(c4 < c10); - assert!(c10 < c15); - } - - #[test] - fn cost_scales_with_batch() { - let b1 = estimate_usd_cents(5, 1, Some(CommonResolution::TenEightyP)); - let b2 = estimate_usd_cents(5, 2, Some(CommonResolution::TenEightyP)); - let b4 = estimate_usd_cents(5, 4, Some(CommonResolution::TenEightyP)); - assert!(b1 < b2); - assert!(b2 < b4); - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/seedance2pro/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/seedance2pro/mod.rs deleted file mode 100644 index 7bdb334f14..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/cost/seedance2pro/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod estimate_video_cost_seedance2pro_seedance2p0; -pub mod estimate_video_cost_seedance2pro_seedance2p0_fast; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling3p0_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling3p0_pro.rs deleted file mode 100644 index 66e3fe3a32..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling3p0_pro.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling3p0_pro::PlanArtcraftKling3p0Pro; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use artcraft_api_defs::generate::video::multi_function::kling_3p0_pro_multi_function_video_gen::Kling3p0ProMultiFunctionVideoGenRequest; -use artcraft_client::endpoints::generate::video::multi_function::kling_3p0_pro_multi_function_video_gen::kling_3p0_pro_multi_function_video_gen; - -pub async fn execute_artcraft_kling3p0_pro( - plan: &PlanArtcraftKling3p0Pro, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let request = Kling3p0ProMultiFunctionVideoGenRequest { - uuid_idempotency_token: plan.idempotency_token.clone(), - prompt: plan.prompt.clone(), - negative_prompt: plan.negative_prompt.clone(), - image_media_token: plan.start_frame.clone(), - end_image_media_token: plan.end_frame.clone(), - duration: plan.duration, - generate_audio: plan.generate_audio, - aspect_ratio: plan.aspect_ratio, - }; - - let response = kling_3p0_pro_multi_function_video_gen( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - let all_tokens = vec![response.inference_job_token.clone()]; - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token, - all_inference_job_tokens: all_tokens, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling3p0_standard.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling3p0_standard.rs deleted file mode 100644 index 28124ce782..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling3p0_standard.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling3p0_standard::PlanArtcraftKling3p0Standard; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use artcraft_api_defs::generate::video::multi_function::kling_3p0_standard_multi_function_video_gen::Kling3p0StandardMultiFunctionVideoGenRequest; -use artcraft_client::endpoints::generate::video::multi_function::kling_3p0_standard_multi_function_video_gen::kling_3p0_standard_multi_function_video_gen; - -pub async fn execute_artcraft_kling3p0_standard( - plan: &PlanArtcraftKling3p0Standard, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let request = Kling3p0StandardMultiFunctionVideoGenRequest { - uuid_idempotency_token: plan.idempotency_token.clone(), - prompt: plan.prompt.clone(), - negative_prompt: plan.negative_prompt.clone(), - image_media_token: plan.start_frame.clone(), - end_image_media_token: plan.end_frame.clone(), - duration: plan.duration, - generate_audio: plan.generate_audio, - aspect_ratio: plan.aspect_ratio, - }; - - let response = kling_3p0_standard_multi_function_video_gen( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - let all_tokens = vec![response.inference_job_token.clone()]; - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token, - all_inference_job_tokens: all_tokens, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling_1_6_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling_1_6_pro.rs deleted file mode 100644 index d0cf126250..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling_1_6_pro.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_1_6_pro::PlanArtcraftKling16Pro; -use artcraft_api_defs::generate::video::generate_kling_1_6_pro_image_to_video::GenerateKling16ProImageToVideoRequest; -use artcraft_client::endpoints::generate::video::generate_kling_16_pro_image_to_video::generate_kling_16_pro_image_to_video; - -pub async fn execute_artcraft_kling_1_6_pro( - plan: &PlanArtcraftKling16Pro, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let request = GenerateKling16ProImageToVideoRequest { - uuid_idempotency_token: plan.idempotency_token.clone(), - media_file_token: Some(plan.start_frame.clone()), - end_frame_image_media_token: plan.end_frame.clone(), - prompt: plan.prompt.clone(), - aspect_ratio: plan.aspect_ratio, - duration: plan.duration, - }; - - let response = generate_kling_16_pro_image_to_video( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - let all_tokens = vec![response.inference_job_token.clone()]; - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token, - all_inference_job_tokens: all_tokens, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling_2_1_master.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling_2_1_master.rs deleted file mode 100644 index fe055f012c..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling_2_1_master.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_1_master::PlanArtcraftKling21Master; -use artcraft_api_defs::generate::video::generate_kling_2_1_master_image_to_video::GenerateKling21MasterImageToVideoRequest; -use artcraft_client::endpoints::generate::video::generate_kling_21_master_image_to_video::generate_kling_21_master_image_to_video; - -pub async fn execute_artcraft_kling_2_1_master( - plan: &PlanArtcraftKling21Master, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let request = GenerateKling21MasterImageToVideoRequest { - uuid_idempotency_token: plan.idempotency_token.clone(), - media_file_token: Some(plan.start_frame.clone()), - prompt: plan.prompt.clone(), - aspect_ratio: plan.aspect_ratio, - duration: plan.duration, - }; - - let response = generate_kling_21_master_image_to_video( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - let all_tokens = vec![response.inference_job_token.clone()]; - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token, - all_inference_job_tokens: all_tokens, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling_2_1_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling_2_1_pro.rs deleted file mode 100644 index 9a5086b15a..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling_2_1_pro.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_1_pro::PlanArtcraftKling21Pro; -use artcraft_api_defs::generate::video::generate_kling_2_1_pro_image_to_video::GenerateKling21ProImageToVideoRequest; -use artcraft_client::endpoints::generate::video::generate_kling_21_pro_image_to_video::generate_kling_21_pro_image_to_video; - -pub async fn execute_artcraft_kling_2_1_pro( - plan: &PlanArtcraftKling21Pro, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let request = GenerateKling21ProImageToVideoRequest { - uuid_idempotency_token: plan.idempotency_token.clone(), - media_file_token: Some(plan.start_frame.clone()), - end_frame_image_media_token: plan.end_frame.clone(), - prompt: plan.prompt.clone(), - aspect_ratio: plan.aspect_ratio, - duration: plan.duration, - }; - - let response = generate_kling_21_pro_image_to_video( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - let all_tokens = vec![response.inference_job_token.clone()]; - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token, - all_inference_job_tokens: all_tokens, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling_2_5_turbo_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling_2_5_turbo_pro.rs deleted file mode 100644 index 72ce9319fa..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling_2_5_turbo_pro.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_5_turbo_pro::PlanArtcraftKling2p5TurboPro; -use artcraft_api_defs::generate::video::multi_function::kling_2_5_turbo_multi_function_video_gen::Kling2p5TurboProMultiFunctionVideoGenRequest; -use artcraft_client::endpoints::generate::video::multi_function::kling_2p5_turbo_pro_multi_function_video_gen::kling_2p5_turbo_pro_multi_function_video_gen; - -pub async fn execute_artcraft_kling_2_5_turbo_pro( - plan: &PlanArtcraftKling2p5TurboPro, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let request = Kling2p5TurboProMultiFunctionVideoGenRequest { - uuid_idempotency_token: plan.idempotency_token.clone(), - prompt: plan.prompt.clone(), - negative_prompt: plan.negative_prompt.clone(), - start_frame_image_media_token: plan.start_frame.clone(), - end_frame_image_media_token: plan.end_frame.clone(), - duration: plan.duration, - aspect_ratio: plan.aspect_ratio, - }; - - let response = kling_2p5_turbo_pro_multi_function_video_gen( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - let all_tokens = vec![response.inference_job_token.clone()]; - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token, - all_inference_job_tokens: all_tokens, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling_2_6_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling_2_6_pro.rs deleted file mode 100644 index af8174270f..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_kling_2_6_pro.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_6_pro::PlanArtcraftKling2p6Pro; -use artcraft_api_defs::generate::video::multi_function::kling_2_6_multi_function_video_gen::Kling2p6ProMultiFunctionVideoGenRequest; -use artcraft_client::endpoints::generate::video::multi_function::kling_2p6_pro_multi_function_video_gen::kling_2p6_pro_multi_function_video_gen; - -pub async fn execute_artcraft_kling_2_6_pro( - plan: &PlanArtcraftKling2p6Pro, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let request = Kling2p6ProMultiFunctionVideoGenRequest { - uuid_idempotency_token: plan.idempotency_token.clone(), - prompt: plan.prompt.clone(), - negative_prompt: plan.negative_prompt.clone(), - start_frame_image_media_token: plan.start_frame.clone(), - duration: plan.duration, - generate_audio: plan.generate_audio, - aspect_ratio: plan.aspect_ratio, - }; - - let response = kling_2p6_pro_multi_function_video_gen( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - let all_tokens = vec![response.inference_job_token.clone()]; - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token, - all_inference_job_tokens: all_tokens, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_seedance1p5_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_seedance1p5_pro.rs deleted file mode 100644 index a166bdf135..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_seedance1p5_pro.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance1p5_pro::PlanArtcraftSeedance1p5Pro; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use artcraft_api_defs::generate::video::multi_function::seedance_1p5_pro_multi_function_video_gen::Seedance1p5ProMultiFunctionVideoGenRequest; -use artcraft_client::endpoints::generate::video::multi_function::seedance_1p5_pro_multi_function_video_gen::seedance_1p5_pro_multi_function_video_gen; - -pub async fn execute_artcraft_seedance1p5_pro( - plan: &PlanArtcraftSeedance1p5Pro, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let request = Seedance1p5ProMultiFunctionVideoGenRequest { - uuid_idempotency_token: plan.idempotency_token.clone(), - prompt: plan.prompt.clone(), - start_frame_image_media_token: plan.start_frame.clone(), - end_frame_image_media_token: plan.end_frame.clone(), - aspect_ratio: plan.aspect_ratio, - duration: plan.duration, - resolution: plan.resolution, - generate_audio: plan.generate_audio, - }; - - let response = seedance_1p5_pro_multi_function_video_gen( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - let all_tokens = vec![response.inference_job_token.clone()]; - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token, - all_inference_job_tokens: all_tokens, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_seedance2p0.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_seedance2p0.rs deleted file mode 100644 index 87b95e45dd..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_seedance2p0.rs +++ /dev/null @@ -1,107 +0,0 @@ -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance2p0::PlanArtcraftSeedance2p0; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use crate::api::common_resolution::CommonResolution as CommonResolutionRouter; -use artcraft_api_defs::generate::video::multi_function::seedance_2p0_multi_function_video_gen::{ - Seedance2p0MultiFunctionVideoGenRequest, Seedance2p0OutputResolution, -}; -use artcraft_client::endpoints::generate::video::multi_function::seedance_2p0_multi_function_video_gen::seedance_2p0_multi_function_video_gen; - -pub async fn execute_artcraft_seedance2p0( - plan: &PlanArtcraftSeedance2p0, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let output_resolution = plan.resolution.map(|r| match r { - CommonResolutionRouter::FourEightyP => Seedance2p0OutputResolution::FourEightyP, - CommonResolutionRouter::SevenTwentyP => Seedance2p0OutputResolution::SevenTwentyP, - CommonResolutionRouter::TenEightyP => Seedance2p0OutputResolution::TenEightyP, - _ => Seedance2p0OutputResolution::SevenTwentyP, - }); - - let request = Seedance2p0MultiFunctionVideoGenRequest { - uuid_idempotency_token: plan.idempotency_token.clone(), - prompt: plan.prompt.clone(), - start_frame_media_token: plan.start_frame.clone(), - end_frame_media_token: plan.end_frame.clone(), - reference_image_media_tokens: plan.reference_images.clone(), - reference_video_media_tokens: plan.reference_videos.clone(), - reference_audio_media_tokens: plan.reference_audio.clone(), - reference_character_tokens: plan.reference_characters.clone(), - aspect_ratio: plan.aspect_ratio, - output_resolution, - duration_seconds: plan.duration_seconds, - batch_count: Some(plan.batch_count), - }; - - let response = seedance_2p0_multi_function_video_gen( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token, - all_inference_job_tokens: response.all_inference_job_tokens, - })) -} - -#[cfg(test)] -mod tests { - use crate::api::common_aspect_ratio::CommonAspectRatio; - use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; - use crate::test_helpers::{base_video_request, get_artcraft_client}; - - #[tokio::test] - #[ignore] // manually run — fires a real API request and incurs cost - async fn test_text_to_video_seedance_2p0() { - let client = get_artcraft_client(); - let request = crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine), - video_batch_count: Some(1), - prompt: Some("a cat walking through a cyberpunk city at night".to_string()), - ..base_video_request() - }; - - let plan = request.build().unwrap(); - let result = plan.generate_video(&client).await; - - println!("Result: {:?}", result); - let response = result.expect("generate_video request failed"); - let payload = response.get_artcraft_payload().expect("expected Artcraft payload"); - println!("Job token: {:?}", payload.inference_job_token); - println!("All job tokens: {:?}", payload.all_inference_job_tokens); - - assert_eq!(1, 2); // NB: Intentional failure to inspect the response above. - } - - #[tokio::test] - #[ignore] // manually run — fires a real API request and incurs cost - async fn test_text_to_video_seedance_2p0_batch_two() { - let client = get_artcraft_client(); - let request = crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::Square), - video_batch_count: Some(2), - prompt: Some("a dog surfing a wave, cinematic".to_string()), - ..base_video_request() - }; - - let plan = request.build().unwrap(); - let result = plan.generate_video(&client).await; - - println!("Result: {:?}", result); - let response = result.expect("generate_video request failed"); - let payload = response.get_artcraft_payload().expect("expected Artcraft payload"); - println!("Job tokens ({} total):", payload.all_inference_job_tokens.len()); - for token in &payload.all_inference_job_tokens { - println!(" {:?}", token); - } - - assert_eq!(1, 2); // NB: Intentional failure to inspect the response above. - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_seedance2p0_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_seedance2p0_fast.rs deleted file mode 100644 index 812e63c562..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_seedance2p0_fast.rs +++ /dev/null @@ -1,236 +0,0 @@ -use crate::api::common_resolution::CommonResolution as CommonResolutionRouter; -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance2p0::PlanArtcraftSeedance2p0; -use artcraft_api_defs::generate::video::multi_function::seedance_2p0_multi_function_video_gen::{Seedance2p0AspectRatio, Seedance2p0BatchCount}; -use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; -use artcraft_client::endpoints::omni_gen::generate::video::omni_gen_video::omni_gen_video_generate; -use enums::common::generation::common_aspect_ratio::CommonAspectRatio; -use enums::common::generation::common_resolution::CommonResolution; -use enums::common::generation::common_video_model::CommonVideoModel; - -/// Execute Seedance 2.0 Fast via the Artcraft omni-gen video endpoint. -/// -/// Unlike Seedance 2.0 Pro (which uses the legacy dedicated endpoint), -/// Seedance 2.0 Fast routes through the omni-gen unified video endpoint. -pub async fn execute_artcraft_seedance2p0_fast( - plan: &PlanArtcraftSeedance2p0, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let aspect_ratio = plan.aspect_ratio.map(|ar| match ar { - Seedance2p0AspectRatio::Landscape16x9 => CommonAspectRatio::WideSixteenByNine, - Seedance2p0AspectRatio::Portrait9x16 => CommonAspectRatio::TallNineBySixteen, - Seedance2p0AspectRatio::Square1x1 => CommonAspectRatio::Square, - Seedance2p0AspectRatio::Standard4x3 => CommonAspectRatio::WideFourByThree, - Seedance2p0AspectRatio::Portrait3x4 => CommonAspectRatio::TallThreeByFour, - }); - - let resolution = plan.resolution.map(|r| match r { - CommonResolutionRouter::FourEightyP => CommonResolution::FourEightyP, - CommonResolutionRouter::SevenTwentyP => CommonResolution::SevenTwentyP, - CommonResolutionRouter::TenEightyP => CommonResolution::TenEightyP, - CommonResolutionRouter::HalfK => CommonResolution::HalfK, - CommonResolutionRouter::OneK => CommonResolution::OneK, - CommonResolutionRouter::TwoK => CommonResolution::TwoK, - CommonResolutionRouter::ThreeK => CommonResolution::ThreeK, - CommonResolutionRouter::FourK => CommonResolution::FourK, - }); - - let request = OmniGenVideoCostAndGenerateRequest { - idempotency_token: Some(plan.idempotency_token.clone()), - model: Some(CommonVideoModel::Seedance2p0Fast), - prompt: plan.prompt.clone(), - start_frame_image_media_token: plan.start_frame.clone(), - end_frame_image_media_token: plan.end_frame.clone(), - reference_image_media_tokens: plan.reference_images.clone(), - reference_video_media_tokens: plan.reference_videos.clone(), - reference_audio_media_tokens: plan.reference_audio.clone(), - reference_character_tokens: plan.reference_characters.clone(), - resolution, - aspect_ratio, - duration_seconds: plan.duration_seconds.map(|d| d as u16), - video_batch_count: Some(match plan.batch_count { - Seedance2p0BatchCount::One => 1, - Seedance2p0BatchCount::Two => 2, - Seedance2p0BatchCount::Four => 4, - }), - quality: None, - generate_audio: None, - negative_prompt: None, - }; - - let response = omni_gen_video_generate( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - let all_tokens = vec![response.inference_job_token.clone()]; - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token, - all_inference_job_tokens: all_tokens, - })) -} - -#[cfg(test)] -mod tests { - use crate::api::common_aspect_ratio::CommonAspectRatio; - use crate::api::common_resolution::CommonResolution; - use crate::api::common_video_model::CommonVideoModel; - use crate::api::image_ref::ImageRef; - use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; - use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; - use crate::test_helpers::{base_video_request, get_artcraft_client}; - use tokens::tokens::media_files::MediaFileToken; - - fn fast_request() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Seedance2p0Fast, - prompt: Some("a corgi walking through a cyberpunk city at night".to_string()), - ..base_video_request() - } - } - - #[tokio::test] - #[ignore] // manually run — fires a real API request and incurs cost - async fn test_text_to_video_fast_720p_wide() { - let client = get_artcraft_client(); - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine), - resolution: Some(CommonResolution::SevenTwentyP), - video_batch_count: Some(1), - ..fast_request() - }; - - let plan = request.build().unwrap(); - let result = plan.generate_video(&client).await; - println!("Result: {:?}", result); - let response = result.expect("generate_video request failed"); - let payload = response.get_artcraft_payload().expect("expected Artcraft payload"); - println!("Job token: {:?}", payload.inference_job_token); - assert_eq!(1, 2); // NB: Intentional failure to inspect the response above. - } - - #[tokio::test] - #[ignore] // manually run — fires a real API request and incurs cost - async fn test_text_to_video_fast_480p_square() { - let client = get_artcraft_client(); - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::Square), - resolution: Some(CommonResolution::FourEightyP), - video_batch_count: Some(1), - ..fast_request() - }; - - let plan = request.build().unwrap(); - let result = plan.generate_video(&client).await; - println!("Result: {:?}", result); - let response = result.expect("generate_video request failed"); - let payload = response.get_artcraft_payload().expect("expected Artcraft payload"); - println!("Job token: {:?}", payload.inference_job_token); - assert_eq!(1, 2); - } - - #[tokio::test] - #[ignore] // manually run — fires a real API request and incurs cost - async fn test_image_to_video_fast_with_start_keyframe() { - let client = get_artcraft_client(); - let request = GenerateVideoRequestBuilder { - start_frame: Some(ImageRef::MediaFileToken( - MediaFileToken::new("mf_test_keyframe_placeholder".to_string()), - )), - aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine), - resolution: Some(CommonResolution::SevenTwentyP), - video_batch_count: Some(1), - ..fast_request() - }; - - let plan = request.build().unwrap(); - let result = plan.generate_video(&client).await; - println!("Result: {:?}", result); - let response = result.expect("generate_video request failed"); - let payload = response.get_artcraft_payload().expect("expected Artcraft payload"); - println!("Job token: {:?}", payload.inference_job_token); - assert_eq!(1, 2); - } - - #[tokio::test] - #[ignore] // manually run — fires a real API request and incurs cost - async fn test_text_to_video_fast_batch_2() { - let client = get_artcraft_client(); - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::TallNineBySixteen), - resolution: Some(CommonResolution::SevenTwentyP), - video_batch_count: Some(2), - ..fast_request() - }; - - let plan = request.build().unwrap(); - let result = plan.generate_video(&client).await; - println!("Result: {:?}", result); - let response = result.expect("generate_video request failed"); - let payload = response.get_artcraft_payload().expect("expected Artcraft payload"); - println!("Job tokens ({} total):", payload.all_inference_job_tokens.len()); - for token in &payload.all_inference_job_tokens { - println!(" {:?}", token); - } - assert_eq!(1, 2); - } - - #[tokio::test] - #[ignore] // manually run — fires a real API request and incurs cost - async fn test_text_to_video_fast_with_reference_images() { - let client = get_artcraft_client(); - let request = GenerateVideoRequestBuilder { - reference_images: Some(crate::api::image_list_ref::ImageListRef::MediaFileTokens(vec![ - MediaFileToken::new("mf_test_ref_image_placeholder".to_string()), - ])), - aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine), - resolution: Some(CommonResolution::SevenTwentyP), - video_batch_count: Some(1), - ..fast_request() - }; - - let plan = request.build().unwrap(); - let result = plan.generate_video(&client).await; - println!("Result: {:?}", result); - let response = result.expect("generate_video request failed"); - let payload = response.get_artcraft_payload().expect("expected Artcraft payload"); - println!("Job token: {:?}", payload.inference_job_token); - assert_eq!(1, 2); - } - - #[test] - fn plan_includes_resolution() { - let request = GenerateVideoRequestBuilder { - resolution: Some(CommonResolution::FourEightyP), - ..fast_request() - }; - let plan = request.build().unwrap(); - let VideoGenerationPlan::ArtcraftSeedance2p0Fast(p) = plan else { panic!("wrong variant") }; - assert!(matches!(p.resolution, Some(CommonResolution::FourEightyP))); - } - - #[test] - fn plan_includes_characters() { - use crate::api::character_list_ref::CharacterListRef; - use tokens::tokens::characters::CharacterToken; - - let request = GenerateVideoRequestBuilder { - reference_character_tokens: Some(CharacterListRef::CharacterTokens(vec![ - CharacterToken::new("char_test123".to_string()), - ])), - ..fast_request() - }; - let plan = request.build().unwrap(); - let VideoGenerationPlan::ArtcraftSeedance2p0Fast(p) = plan else { panic!("wrong variant") }; - assert!(p.reference_characters.is_some()); - assert_eq!(p.reference_characters.unwrap().len(), 1); - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_seedance_1_0_lite.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_seedance_1_0_lite.rs deleted file mode 100644 index dcebb65b4c..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_seedance_1_0_lite.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance_1_0_lite::PlanArtcraftSeedance10Lite; -use artcraft_api_defs::generate::video::generate_seedance_1_0_lite_image_to_video::GenerateSeedance10LiteImageToVideoRequest; -use artcraft_client::endpoints::generate::video::generate_seedance_1_0_lite_image_to_video::generate_seedance_1_0_lite_image_to_video; - -pub async fn execute_artcraft_seedance_1_0_lite( - plan: &PlanArtcraftSeedance10Lite, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let request = GenerateSeedance10LiteImageToVideoRequest { - uuid_idempotency_token: plan.idempotency_token.clone(), - media_file_token: Some(plan.start_frame.clone()), - end_frame_image_media_token: plan.end_frame.clone(), - prompt: plan.prompt.clone(), - resolution: plan.resolution, - duration: plan.duration, - aspect_ratio: plan.aspect_ratio, - }; - - let response = generate_seedance_1_0_lite_image_to_video( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - let all_tokens = vec![response.inference_job_token.clone()]; - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token, - all_inference_job_tokens: all_tokens, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_sora_2.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_sora_2.rs deleted file mode 100644 index 4eba65fb5d..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_sora_2.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_sora_2::PlanArtcraftSora2; -use artcraft_api_defs::generate::video::multi_function::sora_2_multi_function_video_gen::Sora2MultiFunctionVideoGenRequest; -use artcraft_client::endpoints::generate::video::multi_function::sora_2_multi_function_video_gen::sora_2_multi_function_video_gen; - -pub async fn execute_artcraft_sora_2( - plan: &PlanArtcraftSora2, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let request = Sora2MultiFunctionVideoGenRequest { - uuid_idempotency_token: plan.idempotency_token.clone(), - prompt: plan.prompt.clone(), - image_media_token: plan.start_frame.clone(), - resolution: plan.resolution, - duration: plan.duration, - aspect_ratio: plan.aspect_ratio, - }; - - let response = sora_2_multi_function_video_gen( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - let all_tokens = vec![response.inference_job_token.clone()]; - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token, - all_inference_job_tokens: all_tokens, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_sora_2_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_sora_2_pro.rs deleted file mode 100644 index 573fc92c92..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_sora_2_pro.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_sora_2_pro::PlanArtcraftSora2Pro; -use artcraft_api_defs::generate::video::multi_function::sora_2_pro_multi_function_video_gen::Sora2ProMultiFunctionVideoGenRequest; -use artcraft_client::endpoints::generate::video::multi_function::sora_2_pro_multi_function_video_gen::sora_2_pro_multi_function_video_gen; - -pub async fn execute_artcraft_sora_2_pro( - plan: &PlanArtcraftSora2Pro, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let request = Sora2ProMultiFunctionVideoGenRequest { - uuid_idempotency_token: plan.idempotency_token.clone(), - prompt: plan.prompt.clone(), - image_media_token: plan.start_frame.clone(), - resolution: plan.resolution, - duration: plan.duration, - aspect_ratio: plan.aspect_ratio, - }; - - let response = sora_2_pro_multi_function_video_gen( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - let all_tokens = vec![response.inference_job_token.clone()]; - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token, - all_inference_job_tokens: all_tokens, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_veo_2.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_veo_2.rs deleted file mode 100644 index 0ff5627e6c..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_veo_2.rs +++ /dev/null @@ -1,77 +0,0 @@ -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_2::PlanArtcraftVeo2; -use artcraft_api_defs::generate::video::generate_veo_2_image_to_video::GenerateVeo2ImageToVideoRequest; -use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; -use artcraft_client::endpoints::generate::video::generate_veo_2_image_to_video::generate_veo_2_image_to_video; -use artcraft_client::endpoints::omni_gen::generate::video::omni_gen_video::omni_gen_video_generate; -use enums::common::generation::common_video_model::CommonVideoModel; - -pub async fn execute_artcraft_veo_2( - plan: &PlanArtcraftVeo2, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let inference_job_token = match plan.start_frame.clone() { - Some(media_file_token) => { - // Image-to-video: use the legacy dedicated endpoint. - let request = GenerateVeo2ImageToVideoRequest { - uuid_idempotency_token: plan.idempotency_token.clone(), - media_file_token: Some(media_file_token.to_owned()), - prompt: plan.prompt.clone(), - aspect_ratio: plan.aspect_ratio.clone(), - duration: plan.duration.clone(), - }; - - let response = generate_veo_2_image_to_video( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - response.inference_job_token - } - None => { - // Text-to-video: use the omni-gen unified endpoint. - let request = OmniGenVideoCostAndGenerateRequest { - idempotency_token: Some(plan.idempotency_token.clone()), - model: Some(CommonVideoModel::Veo2), - prompt: plan.prompt.clone(), - negative_prompt: None, - start_frame_image_media_token: None, - end_frame_image_media_token: None, - reference_image_media_tokens: None, - reference_video_media_tokens: None, - reference_audio_media_tokens: None, - reference_character_tokens: None, - resolution: None, - aspect_ratio: None, - quality: None, - duration_seconds: None, - video_batch_count: None, - generate_audio: None, - }; - - let response = omni_gen_video_generate( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - response.inference_job_token - } - }; - - let all_tokens = vec![inference_job_token.clone()]; - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token, - all_inference_job_tokens: all_tokens, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_veo_3.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_veo_3.rs deleted file mode 100644 index bd98cf47a9..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_veo_3.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_3::PlanArtcraftVeo3; -use artcraft_api_defs::generate::video::generate_veo_3_image_to_video::GenerateVeo3ImageToVideoRequest; -use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; -use artcraft_client::endpoints::generate::video::generate_veo_3_image_to_video::generate_veo_3_image_to_video; -use artcraft_client::endpoints::omni_gen::generate::video::omni_gen_video::omni_gen_video_generate; -use enums::common::generation::common_video_model::CommonVideoModel; - -pub async fn execute_artcraft_veo_3( - plan: &PlanArtcraftVeo3, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let inference_job_token = match plan.start_frame.clone() { - Some(media_file_token) => { - // Image-to-video: use the legacy dedicated endpoint. - let request = GenerateVeo3ImageToVideoRequest { - uuid_idempotency_token: plan.idempotency_token.clone(), - media_file_token: Some(media_file_token.to_owned()), - prompt: plan.prompt.clone(), - aspect_ratio: plan.aspect_ratio, - resolution: plan.resolution, - duration: plan.duration, - generate_audio: plan.generate_audio, - }; - - let response = generate_veo_3_image_to_video( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - response.inference_job_token - } - None => { - // Text-to-video: use the omni-gen unified endpoint. - let request = OmniGenVideoCostAndGenerateRequest { - idempotency_token: Some(plan.idempotency_token.clone()), - model: Some(CommonVideoModel::Veo3), - prompt: plan.prompt.clone(), - negative_prompt: None, - start_frame_image_media_token: None, - end_frame_image_media_token: None, - reference_image_media_tokens: None, - reference_video_media_tokens: None, - reference_audio_media_tokens: None, - reference_character_tokens: None, - resolution: None, - aspect_ratio: None, - quality: None, - duration_seconds: None, - video_batch_count: None, - generate_audio: plan.generate_audio, - }; - - let response = omni_gen_video_generate( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - response.inference_job_token - } - }; - - let all_tokens = vec![inference_job_token.clone()]; - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token, - all_inference_job_tokens: all_tokens, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_veo_3_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_veo_3_fast.rs deleted file mode 100644 index 72a9c01a39..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_veo_3_fast.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_3_fast::PlanArtcraftVeo3Fast; -use artcraft_api_defs::generate::video::generate_veo_3_fast_image_to_video::GenerateVeo3FastImageToVideoRequest; -use artcraft_client::endpoints::generate::video::generate_veo_3_fast_image_to_video::generate_veo_3_fast_image_to_video; - -pub async fn execute_artcraft_veo_3_fast( - plan: &PlanArtcraftVeo3Fast, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let request = GenerateVeo3FastImageToVideoRequest { - uuid_idempotency_token: plan.idempotency_token.clone(), - media_file_token: plan.start_frame.clone(), - prompt: plan.prompt.clone(), - aspect_ratio: plan.aspect_ratio, - resolution: plan.resolution, - duration: plan.duration, - generate_audio: plan.generate_audio, - }; - - let response = generate_veo_3_fast_image_to_video( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - let all_tokens = vec![response.inference_job_token.clone()]; - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token, - all_inference_job_tokens: all_tokens, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_veo_3p1.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_veo_3p1.rs deleted file mode 100644 index 6e96a4f495..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_veo_3p1.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_3p1::PlanArtcraftVeo3p1; -use artcraft_api_defs::generate::video::multi_function::veo_3p1_multi_function_video_gen::Veo3p1MultiFunctionVideoGenRequest; -use artcraft_client::endpoints::generate::video::multi_function::veo_3p1_multi_function_video_gen::veo_3p1_multi_function_video_gen; - -pub async fn execute_artcraft_veo_3p1( - plan: &PlanArtcraftVeo3p1, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let request = Veo3p1MultiFunctionVideoGenRequest { - uuid_idempotency_token: plan.idempotency_token.clone(), - prompt: plan.prompt.clone(), - negative_prompt: plan.negative_prompt.clone(), - start_frame_image_media_token: plan.start_frame.clone(), - end_frame_image_media_token: plan.end_frame.clone(), - duration: plan.duration, - aspect_ratio: plan.aspect_ratio, - resolution: plan.resolution, - generate_audio: plan.generate_audio, - enhance_prompt: None, - seed: None, - auto_fix: None, - }; - - let response = veo_3p1_multi_function_video_gen( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - let all_tokens = vec![response.inference_job_token.clone()]; - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token, - all_inference_job_tokens: all_tokens, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_veo_3p1_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_veo_3p1_fast.rs deleted file mode 100644 index c8916d6d49..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/generate_video_artcraft_veo_3p1_fast.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::client::router_artcraft_client::RouterArtcraftClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - ArtcraftVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_3p1_fast::PlanArtcraftVeo3p1Fast; -use artcraft_api_defs::generate::video::multi_function::veo_3p1_fast_multi_function_video_gen::Veo3p1FastMultiFunctionVideoGenRequest; -use artcraft_client::endpoints::generate::video::multi_function::veo_3p1_fast_multi_function_video_gen::veo_3p1_fast_multi_function_video_gen; - -pub async fn execute_artcraft_veo_3p1_fast( - plan: &PlanArtcraftVeo3p1Fast, - artcraft_client: &RouterArtcraftClient, -) -> Result { - let request = Veo3p1FastMultiFunctionVideoGenRequest { - uuid_idempotency_token: plan.idempotency_token.clone(), - prompt: plan.prompt.clone(), - negative_prompt: plan.negative_prompt.clone(), - start_frame_image_media_token: plan.start_frame.clone(), - end_frame_image_media_token: plan.end_frame.clone(), - duration: plan.duration, - aspect_ratio: plan.aspect_ratio, - resolution: plan.resolution, - generate_audio: plan.generate_audio, - enhance_prompt: None, - seed: None, - auto_fix: None, - }; - - let response = veo_3p1_fast_multi_function_video_gen( - &artcraft_client.api_host, - Some(&artcraft_client.credentials), - request, - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - let all_tokens = vec![response.inference_job_token.clone()]; - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token, - all_inference_job_tokens: all_tokens, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/mod.rs deleted file mode 100644 index 07d2df536c..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/artcraft/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -pub mod generate_video_artcraft_kling_1_6_pro; -pub mod generate_video_artcraft_kling_2_1_master; -pub mod generate_video_artcraft_kling_2_1_pro; -pub mod generate_video_artcraft_kling_2_5_turbo_pro; -pub mod generate_video_artcraft_kling_2_6_pro; -pub mod generate_video_artcraft_kling3p0_pro; -pub mod generate_video_artcraft_kling3p0_standard; -pub mod generate_video_artcraft_seedance_1_0_lite; -pub mod generate_video_artcraft_seedance1p5_pro; -pub mod generate_video_artcraft_seedance2p0; -pub mod generate_video_artcraft_seedance2p0_fast; -pub mod generate_video_artcraft_sora_2; -pub mod generate_video_artcraft_sora_2_pro; -pub mod generate_video_artcraft_veo_2; -pub mod generate_video_artcraft_veo_3; -pub mod generate_video_artcraft_veo_3_fast; -pub mod generate_video_artcraft_veo_3p1; -pub mod generate_video_artcraft_veo_3p1_fast; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_1_6_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_1_6_pro.rs deleted file mode 100644 index d8baeddcb2..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_1_6_pro.rs +++ /dev/null @@ -1,44 +0,0 @@ -use std::fmt::Debug; -use std::sync::Arc; - -use crate::client::router_fal_client::RouterFalClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - FalVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_1_6_pro::PlanFalKling16Pro; -use fal_client::requests::webhook::video::image::enqueue_kling_v1p6_pro_image_to_video_webhook::{ - enqueue_kling_v1p6_pro_image_to_video_webhook, Kling1p6ProArgs, Kling1p6ProRequest, -}; - -pub async fn execute_fal_kling_1_6_pro( - plan: &PlanFalKling16Pro, - fal_client: &RouterFalClient, -) -> Result { - let request = Kling1p6ProRequest { - image_url: plan.image_url.clone(), - end_frame_image_url: plan.end_image_url.clone(), - prompt: plan.prompt.clone(), - duration: plan.duration, - aspect_ratio: plan.aspect_ratio, - }; - - let outbound_request: Arc = Arc::new(request.clone()); - - let args = Kling1p6ProArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - - let webhook_response = enqueue_kling_v1p6_pro_image_to_video_webhook(args) - .await - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - - Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload { - request_id: webhook_response.request_id, - gateway_request_id: webhook_response.gateway_request_id, - maybe_outbound_request: Some(outbound_request), - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_2_1_master.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_2_1_master.rs deleted file mode 100644 index 471bc77d6d..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_2_1_master.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::fmt::Debug; -use std::sync::Arc; - -use crate::client::router_fal_client::RouterFalClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - FalVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_2_1_master::PlanFalKling21Master; -use fal_client::requests::webhook::video::image::enqueue_kling_v2p1_master_image_to_video_webhook::{ - enqueue_kling_v2p1_master_image_to_video_webhook, Kling2p1MasterArgs, Kling2p1MasterRequest, -}; - -pub async fn execute_fal_kling_2_1_master( - plan: &PlanFalKling21Master, - fal_client: &RouterFalClient, -) -> Result { - let request = Kling2p1MasterRequest { - image_url: plan.image_url.clone(), - prompt: plan.prompt.clone(), - duration: plan.duration, - aspect_ratio: plan.aspect_ratio, - }; - - let outbound_request: Arc = Arc::new(request.clone()); - - let args = Kling2p1MasterArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - - let webhook_response = enqueue_kling_v2p1_master_image_to_video_webhook(args) - .await - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - - Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload { - request_id: webhook_response.request_id, - gateway_request_id: webhook_response.gateway_request_id, - maybe_outbound_request: Some(outbound_request), - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_2_1_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_2_1_pro.rs deleted file mode 100644 index 42a54d470b..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_2_1_pro.rs +++ /dev/null @@ -1,44 +0,0 @@ -use std::fmt::Debug; -use std::sync::Arc; - -use crate::client::router_fal_client::RouterFalClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - FalVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_2_1_pro::PlanFalKling21Pro; -use fal_client::requests::webhook::video::image::enqueue_kling_v2p1_pro_image_to_video_webhook::{ - enqueue_kling_v2p1_pro_image_to_video_webhook, Kling2p1ProArgs, Kling2p1ProRequest, -}; - -pub async fn execute_fal_kling_2_1_pro( - plan: &PlanFalKling21Pro, - fal_client: &RouterFalClient, -) -> Result { - let request = Kling2p1ProRequest { - image_url: plan.image_url.clone(), - end_frame_image_url: plan.end_image_url.clone(), - prompt: plan.prompt.clone(), - duration: plan.duration, - aspect_ratio: plan.aspect_ratio, - }; - - let outbound_request: Arc = Arc::new(request.clone()); - - let args = Kling2p1ProArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - - let webhook_response = enqueue_kling_v2p1_pro_image_to_video_webhook(args) - .await - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - - Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload { - request_id: webhook_response.request_id, - gateway_request_id: webhook_response.gateway_request_id, - maybe_outbound_request: Some(outbound_request), - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_2_5_turbo_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_2_5_turbo_pro.rs deleted file mode 100644 index 2eb0033c21..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_2_5_turbo_pro.rs +++ /dev/null @@ -1,92 +0,0 @@ -use std::fmt::Debug; -use std::sync::Arc; - -use crate::client::router_fal_client::RouterFalClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - FalVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_2_5_turbo_pro::{ - FalKling2p5TurboProAspectRatio, FalKling2p5TurboProDuration, FalKling2p5TurboProMode, - PlanFalKling2p5TurboPro, -}; -use fal_client::requests::webhook::video::image::enqueue_kling_v2p5_turbo_pro_image_to_video_webhook::{ - enqueue_kling_v2p5_turbo_pro_image_to_video_webhook, EnqueueKlingV2p5TurboProImageToVideoArgs, - EnqueueKlingV2p5TurboProImageToVideoRequest, EnqueueKlingV2p5TurboProImageToVideoDurationSeconds, -}; -use fal_client::requests::webhook::video::text::enqueue_kling_v2p5_turbo_pro_text_to_video_webhook::{ - enqueue_kling_v2p5_turbo_pro_text_to_video_webhook, EnqueueKlingV2p5TurboProTextToVideoArgs, - EnqueueKlingV2p5TurboProTextToVideoRequest, EnqueueKlingV2p5TurboProTextToVideoAspectRatio, - EnqueueKlingV2p5TurboProTextToVideoDurationSeconds, -}; - -pub async fn execute_fal_kling_2_5_turbo_pro( - plan: &PlanFalKling2p5TurboPro, - fal_client: &RouterFalClient, -) -> Result { - let (webhook_response, outbound_request) = match &plan.mode { - FalKling2p5TurboProMode::TextToVideo => { - let request = EnqueueKlingV2p5TurboProTextToVideoRequest { - prompt: plan.prompt.clone(), - negative_prompt: plan.negative_prompt.clone(), - duration: plan.duration.map(to_t2v_duration), - aspect_ratio: plan.aspect_ratio.map(to_t2v_aspect_ratio), - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueKlingV2p5TurboProTextToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_kling_v2p5_turbo_pro_text_to_video_webhook(args).await, outbound) - } - FalKling2p5TurboProMode::ImageToVideo { image_url, end_image_url } => { - let request = EnqueueKlingV2p5TurboProImageToVideoRequest { - prompt: plan.prompt.clone(), - image_url: image_url.clone(), - tail_image_url: end_image_url.clone(), - negative_prompt: plan.negative_prompt.clone(), - duration: plan.duration.map(to_i2v_duration), - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueKlingV2p5TurboProImageToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_kling_v2p5_turbo_pro_image_to_video_webhook(args).await, outbound) - } - }; - - let webhook_response = webhook_response - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - - Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload { - request_id: webhook_response.request_id, - gateway_request_id: webhook_response.gateway_request_id, - maybe_outbound_request: Some(outbound_request), - })) -} - -fn to_t2v_duration(d: FalKling2p5TurboProDuration) -> EnqueueKlingV2p5TurboProTextToVideoDurationSeconds { - match d { - FalKling2p5TurboProDuration::Five => EnqueueKlingV2p5TurboProTextToVideoDurationSeconds::Five, - FalKling2p5TurboProDuration::Ten => EnqueueKlingV2p5TurboProTextToVideoDurationSeconds::Ten, - } -} - -fn to_t2v_aspect_ratio(a: FalKling2p5TurboProAspectRatio) -> EnqueueKlingV2p5TurboProTextToVideoAspectRatio { - match a { - FalKling2p5TurboProAspectRatio::Square => EnqueueKlingV2p5TurboProTextToVideoAspectRatio::Square, - FalKling2p5TurboProAspectRatio::SixteenByNine => EnqueueKlingV2p5TurboProTextToVideoAspectRatio::SixteenByNine, - FalKling2p5TurboProAspectRatio::NineBySixteen => EnqueueKlingV2p5TurboProTextToVideoAspectRatio::NineBySixteen, - } -} - -fn to_i2v_duration(d: FalKling2p5TurboProDuration) -> EnqueueKlingV2p5TurboProImageToVideoDurationSeconds { - match d { - FalKling2p5TurboProDuration::Five => EnqueueKlingV2p5TurboProImageToVideoDurationSeconds::Five, - FalKling2p5TurboProDuration::Ten => EnqueueKlingV2p5TurboProImageToVideoDurationSeconds::Ten, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_2_6_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_2_6_pro.rs deleted file mode 100644 index 46046ed76c..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_2_6_pro.rs +++ /dev/null @@ -1,92 +0,0 @@ -use std::fmt::Debug; -use std::sync::Arc; - -use crate::client::router_fal_client::RouterFalClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - FalVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_2_6_pro::{ - FalKling2p6ProAspectRatio, FalKling2p6ProDuration, FalKling2p6ProMode, PlanFalKling2p6Pro, -}; -use fal_client::requests::webhook::video::image::enqueue_kling_v2p6_pro_image_to_video_webhook::{ - enqueue_kling_v2p6_pro_image_to_video_webhook, EnqueueKlingV2p6ProImageToVideoArgs, - EnqueueKlingV2p6ProImageToVideoRequest, EnqueueKlingV2p6ProImageToVideoDurationSeconds, -}; -use fal_client::requests::webhook::video::text::enqueue_kling_v2p6_pro_text_to_video_webhook::{ - enqueue_kling_v2p6_pro_text_to_video_webhook, EnqueueKlingV2p6ProTextToVideoArgs, - EnqueueKlingV2p6ProTextToVideoRequest, EnqueueKlingV2p6ProTextToVideoAspectRatio, - EnqueueKlingV2p6ProTextToVideoDurationSeconds, -}; - -pub async fn execute_fal_kling_2_6_pro( - plan: &PlanFalKling2p6Pro, - fal_client: &RouterFalClient, -) -> Result { - let (webhook_response, outbound_request) = match &plan.mode { - FalKling2p6ProMode::TextToVideo => { - let request = EnqueueKlingV2p6ProTextToVideoRequest { - prompt: plan.prompt.clone(), - generate_audio: plan.generate_audio, - negative_prompt: plan.negative_prompt.clone(), - duration: plan.duration.map(to_t2v_duration), - aspect_ratio: plan.aspect_ratio.map(to_t2v_aspect_ratio), - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueKlingV2p6ProTextToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_kling_v2p6_pro_text_to_video_webhook(args).await, outbound) - } - FalKling2p6ProMode::ImageToVideo { image_url } => { - let request = EnqueueKlingV2p6ProImageToVideoRequest { - prompt: plan.prompt.clone(), - image_url: image_url.clone(), - generate_audio: plan.generate_audio, - negative_prompt: plan.negative_prompt.clone(), - duration: plan.duration.map(to_i2v_duration), - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueKlingV2p6ProImageToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_kling_v2p6_pro_image_to_video_webhook(args).await, outbound) - } - }; - - let webhook_response = webhook_response - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - - Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload { - request_id: webhook_response.request_id, - gateway_request_id: webhook_response.gateway_request_id, - maybe_outbound_request: Some(outbound_request), - })) -} - -fn to_t2v_duration(d: FalKling2p6ProDuration) -> EnqueueKlingV2p6ProTextToVideoDurationSeconds { - match d { - FalKling2p6ProDuration::Five => EnqueueKlingV2p6ProTextToVideoDurationSeconds::Five, - FalKling2p6ProDuration::Ten => EnqueueKlingV2p6ProTextToVideoDurationSeconds::Ten, - } -} - -fn to_t2v_aspect_ratio(a: FalKling2p6ProAspectRatio) -> EnqueueKlingV2p6ProTextToVideoAspectRatio { - match a { - FalKling2p6ProAspectRatio::Square => EnqueueKlingV2p6ProTextToVideoAspectRatio::Square, - FalKling2p6ProAspectRatio::SixteenByNine => EnqueueKlingV2p6ProTextToVideoAspectRatio::SixteenByNine, - FalKling2p6ProAspectRatio::NineBySixteen => EnqueueKlingV2p6ProTextToVideoAspectRatio::NineBySixteen, - } -} - -fn to_i2v_duration(d: FalKling2p6ProDuration) -> EnqueueKlingV2p6ProImageToVideoDurationSeconds { - match d { - FalKling2p6ProDuration::Five => EnqueueKlingV2p6ProImageToVideoDurationSeconds::Five, - FalKling2p6ProDuration::Ten => EnqueueKlingV2p6ProImageToVideoDurationSeconds::Ten, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_3p0_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_3p0_pro.rs deleted file mode 100644 index 56c417c9ff..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_3p0_pro.rs +++ /dev/null @@ -1,129 +0,0 @@ -use std::fmt::Debug; -use std::sync::Arc; - -use crate::client::router_fal_client::RouterFalClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - FalVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_3p0_pro::{ - FalKling3p0AspectRatio, FalKling3p0Duration, FalKling3p0Mode, PlanFalKling3p0Pro, -}; -use fal_client::requests::webhook::video::image::enqueue_kling_3p0_pro_image_to_video_webhook::{ - enqueue_kling_3p0_pro_image_to_video_webhook, EnqueueKling3p0ProImageToVideoArgs, - EnqueueKling3p0ProImageToVideoRequest, EnqueueKling3p0ProImageToVideoAspectRatio, - EnqueueKling3p0ProImageToVideoDuration, -}; -use fal_client::requests::webhook::video::text::enqueue_kling_3p0_pro_text_to_video_webhook::{ - enqueue_kling_3p0_pro_text_to_video_webhook, EnqueueKling3p0ProTextToVideoArgs, - EnqueueKling3p0ProTextToVideoRequest, EnqueueKling3p0ProTextToVideoAspectRatio, - EnqueueKling3p0ProTextToVideoDuration, -}; - -pub async fn execute_fal_kling_3p0_pro( - plan: &PlanFalKling3p0Pro, - fal_client: &RouterFalClient, -) -> Result { - let (webhook_response, outbound_request) = match &plan.mode { - FalKling3p0Mode::TextToVideo => { - let request = EnqueueKling3p0ProTextToVideoRequest { - prompt: plan.prompt.clone(), - generate_audio: plan.generate_audio, - negative_prompt: plan.negative_prompt.clone(), - duration: plan.duration.map(to_t2v_duration), - aspect_ratio: plan.aspect_ratio.map(to_t2v_aspect_ratio), - shot_type: None, - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueKling3p0ProTextToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_kling_3p0_pro_text_to_video_webhook(args).await, outbound) - } - FalKling3p0Mode::ImageToVideo { image_url, end_image_url } => { - let request = EnqueueKling3p0ProImageToVideoRequest { - prompt: plan.prompt.clone(), - image_url: image_url.clone(), - end_image_url: end_image_url.clone(), - generate_audio: plan.generate_audio, - negative_prompt: plan.negative_prompt.clone(), - duration: plan.duration.map(to_i2v_duration), - aspect_ratio: plan.aspect_ratio.map(to_i2v_aspect_ratio), - shot_type: None, - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueKling3p0ProImageToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_kling_3p0_pro_image_to_video_webhook(args).await, outbound) - } - }; - - let webhook_response = webhook_response - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - - Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload { - request_id: webhook_response.request_id, - gateway_request_id: webhook_response.gateway_request_id, - maybe_outbound_request: Some(outbound_request), - })) -} - -fn to_t2v_duration(d: FalKling3p0Duration) -> EnqueueKling3p0ProTextToVideoDuration { - use EnqueueKling3p0ProTextToVideoDuration as D; - match d.0 { - 3 => D::ThreeSeconds, - 4 => D::FourSeconds, - 5 => D::FiveSeconds, - 6 => D::SixSeconds, - 7 => D::SevenSeconds, - 8 => D::EightSeconds, - 9 => D::NineSeconds, - 10 => D::TenSeconds, - 11 => D::ElevenSeconds, - 12 => D::TwelveSeconds, - 13 => D::ThirteenSeconds, - 14 => D::FourteenSeconds, - _ => D::FifteenSeconds, - } -} - -fn to_i2v_duration(d: FalKling3p0Duration) -> EnqueueKling3p0ProImageToVideoDuration { - use EnqueueKling3p0ProImageToVideoDuration as D; - match d.0 { - 3 => D::ThreeSeconds, - 4 => D::FourSeconds, - 5 => D::FiveSeconds, - 6 => D::SixSeconds, - 7 => D::SevenSeconds, - 8 => D::EightSeconds, - 9 => D::NineSeconds, - 10 => D::TenSeconds, - 11 => D::ElevenSeconds, - 12 => D::TwelveSeconds, - 13 => D::ThirteenSeconds, - 14 => D::FourteenSeconds, - _ => D::FifteenSeconds, - } -} - -fn to_t2v_aspect_ratio(a: FalKling3p0AspectRatio) -> EnqueueKling3p0ProTextToVideoAspectRatio { - match a { - FalKling3p0AspectRatio::Square => EnqueueKling3p0ProTextToVideoAspectRatio::Square, - FalKling3p0AspectRatio::SixteenByNine => EnqueueKling3p0ProTextToVideoAspectRatio::SixteenByNine, - FalKling3p0AspectRatio::NineBySixteen => EnqueueKling3p0ProTextToVideoAspectRatio::NineBySixteen, - } -} - -fn to_i2v_aspect_ratio(a: FalKling3p0AspectRatio) -> EnqueueKling3p0ProImageToVideoAspectRatio { - match a { - FalKling3p0AspectRatio::Square => EnqueueKling3p0ProImageToVideoAspectRatio::Square, - FalKling3p0AspectRatio::SixteenByNine => EnqueueKling3p0ProImageToVideoAspectRatio::SixteenByNine, - FalKling3p0AspectRatio::NineBySixteen => EnqueueKling3p0ProImageToVideoAspectRatio::NineBySixteen, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_3p0_standard.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_3p0_standard.rs deleted file mode 100644 index 14c47a0cec..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_kling_3p0_standard.rs +++ /dev/null @@ -1,130 +0,0 @@ -use std::fmt::Debug; -use std::sync::Arc; - -use crate::client::router_fal_client::RouterFalClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - FalVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_3p0_pro::{ - FalKling3p0AspectRatio, FalKling3p0Duration, FalKling3p0Mode, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_3p0_standard::PlanFalKling3p0Standard; -use fal_client::requests::webhook::video::image::enqueue_kling_3p0_standard_image_to_video_webhook::{ - enqueue_kling_3p0_standard_image_to_video_webhook, EnqueueKling3p0StandardImageToVideoArgs, - EnqueueKling3p0StandardImageToVideoRequest, EnqueueKling3p0StandardImageToVideoAspectRatio, - EnqueueKling3p0StandardImageToVideoDuration, -}; -use fal_client::requests::webhook::video::text::enqueue_kling_3p0_standard_text_to_video_webhook::{ - enqueue_kling_3p0_standard_text_to_video_webhook, EnqueueKling3p0StandardTextToVideoArgs, - EnqueueKling3p0StandardTextToVideoRequest, EnqueueKling3p0StandardTextToVideoAspectRatio, - EnqueueKling3p0StandardTextToVideoDuration, -}; - -pub async fn execute_fal_kling_3p0_standard( - plan: &PlanFalKling3p0Standard, - fal_client: &RouterFalClient, -) -> Result { - let (webhook_response, outbound_request) = match &plan.mode { - FalKling3p0Mode::TextToVideo => { - let request = EnqueueKling3p0StandardTextToVideoRequest { - prompt: plan.prompt.clone(), - generate_audio: plan.generate_audio, - negative_prompt: plan.negative_prompt.clone(), - duration: plan.duration.map(to_t2v_duration), - aspect_ratio: plan.aspect_ratio.map(to_t2v_aspect_ratio), - shot_type: None, - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueKling3p0StandardTextToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_kling_3p0_standard_text_to_video_webhook(args).await, outbound) - } - FalKling3p0Mode::ImageToVideo { image_url, end_image_url } => { - let request = EnqueueKling3p0StandardImageToVideoRequest { - prompt: plan.prompt.clone(), - image_url: image_url.clone(), - end_image_url: end_image_url.clone(), - generate_audio: plan.generate_audio, - negative_prompt: plan.negative_prompt.clone(), - duration: plan.duration.map(to_i2v_duration), - aspect_ratio: plan.aspect_ratio.map(to_i2v_aspect_ratio), - shot_type: None, - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueKling3p0StandardImageToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_kling_3p0_standard_image_to_video_webhook(args).await, outbound) - } - }; - - let webhook_response = webhook_response - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - - Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload { - request_id: webhook_response.request_id, - gateway_request_id: webhook_response.gateway_request_id, - maybe_outbound_request: Some(outbound_request), - })) -} - -fn to_t2v_duration(d: FalKling3p0Duration) -> EnqueueKling3p0StandardTextToVideoDuration { - use EnqueueKling3p0StandardTextToVideoDuration as D; - match d.0 { - 3 => D::ThreeSeconds, - 4 => D::FourSeconds, - 5 => D::FiveSeconds, - 6 => D::SixSeconds, - 7 => D::SevenSeconds, - 8 => D::EightSeconds, - 9 => D::NineSeconds, - 10 => D::TenSeconds, - 11 => D::ElevenSeconds, - 12 => D::TwelveSeconds, - 13 => D::ThirteenSeconds, - 14 => D::FourteenSeconds, - _ => D::FifteenSeconds, - } -} - -fn to_i2v_duration(d: FalKling3p0Duration) -> EnqueueKling3p0StandardImageToVideoDuration { - use EnqueueKling3p0StandardImageToVideoDuration as D; - match d.0 { - 3 => D::ThreeSeconds, - 4 => D::FourSeconds, - 5 => D::FiveSeconds, - 6 => D::SixSeconds, - 7 => D::SevenSeconds, - 8 => D::EightSeconds, - 9 => D::NineSeconds, - 10 => D::TenSeconds, - 11 => D::ElevenSeconds, - 12 => D::TwelveSeconds, - 13 => D::ThirteenSeconds, - 14 => D::FourteenSeconds, - _ => D::FifteenSeconds, - } -} - -fn to_t2v_aspect_ratio(a: FalKling3p0AspectRatio) -> EnqueueKling3p0StandardTextToVideoAspectRatio { - match a { - FalKling3p0AspectRatio::Square => EnqueueKling3p0StandardTextToVideoAspectRatio::Square, - FalKling3p0AspectRatio::SixteenByNine => EnqueueKling3p0StandardTextToVideoAspectRatio::SixteenByNine, - FalKling3p0AspectRatio::NineBySixteen => EnqueueKling3p0StandardTextToVideoAspectRatio::NineBySixteen, - } -} - -fn to_i2v_aspect_ratio(a: FalKling3p0AspectRatio) -> EnqueueKling3p0StandardImageToVideoAspectRatio { - match a { - FalKling3p0AspectRatio::Square => EnqueueKling3p0StandardImageToVideoAspectRatio::Square, - FalKling3p0AspectRatio::SixteenByNine => EnqueueKling3p0StandardImageToVideoAspectRatio::SixteenByNine, - FalKling3p0AspectRatio::NineBySixteen => EnqueueKling3p0StandardImageToVideoAspectRatio::NineBySixteen, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_seedance_1_0_lite.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_seedance_1_0_lite.rs deleted file mode 100644 index c8c9c5119b..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_seedance_1_0_lite.rs +++ /dev/null @@ -1,47 +0,0 @@ -use std::fmt::Debug; -use std::sync::Arc; - -use crate::client::router_fal_client::RouterFalClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - FalVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_seedance_1_0_lite::PlanFalSeedance10Lite; -use fal_client::requests::webhook::video::image::enqueue_seedance_1_lite_image_to_video_webhook::{ - enqueue_seedance_1_lite_image_to_video_webhook, Seedance1LiteArgs, Seedance1LiteRequest, -}; - -pub async fn execute_fal_seedance_1_0_lite( - plan: &PlanFalSeedance10Lite, - fal_client: &RouterFalClient, -) -> Result { - let request = Seedance1LiteRequest { - image_url: plan.image_url.clone(), - end_frame_image_url: plan.end_image_url.clone(), - prompt: plan.prompt.clone(), - duration: plan.duration, - resolution: plan.resolution, - aspect_ratio: plan.aspect_ratio, - camera_fixed: false, - seed: None, - }; - - let outbound_request: Arc = Arc::new(request.clone()); - - let args = Seedance1LiteArgs { - request, - api_key: &fal_client.api_key, - webhook_url: fal_client.webhook_url.as_str(), - }; - - let webhook_response = enqueue_seedance_1_lite_image_to_video_webhook(args) - .await - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - - Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload { - request_id: webhook_response.request_id, - gateway_request_id: webhook_response.gateway_request_id, - maybe_outbound_request: Some(outbound_request), - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_seedance_1p5_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_seedance_1p5_pro.rs deleted file mode 100644 index 4031db8be9..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_seedance_1p5_pro.rs +++ /dev/null @@ -1,146 +0,0 @@ -use std::fmt::Debug; -use std::sync::Arc; - -use crate::client::router_fal_client::RouterFalClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - FalVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_seedance_1p5_pro::{ - FalSeedance1p5ProAspectRatio, FalSeedance1p5ProDuration, FalSeedance1p5ProMode, - FalSeedance1p5ProResolution, PlanFalSeedance1p5Pro, -}; -use fal_client::requests::webhook::video::image::enqueue_seedance_1p5_pro_image_to_video_webhook::{ - enqueue_seedance_1p5_pro_image_to_video_webhook, EnqueueSeedance1p5ProImageToVideoArgs, - EnqueueSeedance1p5ProImageToVideoAspectRatio, EnqueueSeedance1p5ProImageToVideoDuration, - EnqueueSeedance1p5ProImageToVideoRequest, EnqueueSeedance1p5ProImageToVideoResolution, -}; -use fal_client::requests::webhook::video::text::enqueue_seedance_1p5_pro_text_to_video_webhook::{ - enqueue_seedance_1p5_pro_text_to_video_webhook, EnqueueSeedance1p5ProTextToVideoArgs, - EnqueueSeedance1p5ProTextToVideoRequest, EnqueueSeedance1p5ProTextToVideoAspectRatio, - EnqueueSeedance1p5ProTextToVideoDuration, EnqueueSeedance1p5ProTextToVideoResolution, -}; - -pub async fn execute_fal_seedance_1p5_pro( - plan: &PlanFalSeedance1p5Pro, - fal_client: &RouterFalClient, -) -> Result { - let (webhook_response, outbound_request) = match &plan.mode { - FalSeedance1p5ProMode::TextToVideo => { - let request = EnqueueSeedance1p5ProTextToVideoRequest { - prompt: plan.prompt.clone(), - resolution: plan.resolution.map(to_t2v_resolution), - duration: plan.duration.map(to_t2v_duration), - aspect_ratio: plan.aspect_ratio.map(to_t2v_aspect_ratio), - generate_audio: plan.generate_audio, - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueSeedance1p5ProTextToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_seedance_1p5_pro_text_to_video_webhook(args).await, outbound) - } - FalSeedance1p5ProMode::ImageToVideo { image_url, end_image_url } => { - let request = EnqueueSeedance1p5ProImageToVideoRequest { - prompt: plan.prompt.clone(), - image_url: image_url.clone(), - end_image_url: end_image_url.clone(), - resolution: plan.resolution.map(to_i2v_resolution), - duration: plan.duration.map(to_i2v_duration), - aspect_ratio: plan.aspect_ratio.map(to_i2v_aspect_ratio), - generate_audio: plan.generate_audio, - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueSeedance1p5ProImageToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_seedance_1p5_pro_image_to_video_webhook(args).await, outbound) - } - }; - - let webhook_response = webhook_response - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - - Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload { - request_id: webhook_response.request_id, - gateway_request_id: webhook_response.gateway_request_id, - maybe_outbound_request: Some(outbound_request), - })) -} - -fn to_t2v_resolution(r: FalSeedance1p5ProResolution) -> EnqueueSeedance1p5ProTextToVideoResolution { - match r { - FalSeedance1p5ProResolution::FourEightyP => EnqueueSeedance1p5ProTextToVideoResolution::FourEightyP, - FalSeedance1p5ProResolution::SevenTwentyP => EnqueueSeedance1p5ProTextToVideoResolution::SevenTwentyP, - FalSeedance1p5ProResolution::TenEightyP => EnqueueSeedance1p5ProTextToVideoResolution::TenEightyP, - } -} - -fn to_t2v_duration(d: FalSeedance1p5ProDuration) -> EnqueueSeedance1p5ProTextToVideoDuration { - use EnqueueSeedance1p5ProTextToVideoDuration as T; - match d { - FalSeedance1p5ProDuration::Four => T::FourSeconds, - FalSeedance1p5ProDuration::Five => T::FiveSeconds, - FalSeedance1p5ProDuration::Six => T::SixSeconds, - FalSeedance1p5ProDuration::Seven => T::SevenSeconds, - FalSeedance1p5ProDuration::Eight => T::EightSeconds, - FalSeedance1p5ProDuration::Nine => T::NineSeconds, - FalSeedance1p5ProDuration::Ten => T::TenSeconds, - FalSeedance1p5ProDuration::Eleven => T::ElevenSeconds, - FalSeedance1p5ProDuration::Twelve => T::TwelveSeconds, - } -} - -fn to_t2v_aspect_ratio(a: FalSeedance1p5ProAspectRatio) -> EnqueueSeedance1p5ProTextToVideoAspectRatio { - use EnqueueSeedance1p5ProTextToVideoAspectRatio as T; - match a { - FalSeedance1p5ProAspectRatio::Auto => T::Auto, - FalSeedance1p5ProAspectRatio::TwentyOneByNine => T::TwentyOneByNine, - FalSeedance1p5ProAspectRatio::SixteenByNine => T::SixteenByNine, - FalSeedance1p5ProAspectRatio::FourByThree => T::FourByThree, - FalSeedance1p5ProAspectRatio::Square => T::Square, - FalSeedance1p5ProAspectRatio::ThreeByFour => T::ThreeByFour, - FalSeedance1p5ProAspectRatio::NineBySixteen => T::NineBySixteen, - } -} - -fn to_i2v_resolution(r: FalSeedance1p5ProResolution) -> EnqueueSeedance1p5ProImageToVideoResolution { - match r { - FalSeedance1p5ProResolution::FourEightyP => EnqueueSeedance1p5ProImageToVideoResolution::FourEightyP, - FalSeedance1p5ProResolution::SevenTwentyP => EnqueueSeedance1p5ProImageToVideoResolution::SevenTwentyP, - FalSeedance1p5ProResolution::TenEightyP => EnqueueSeedance1p5ProImageToVideoResolution::TenEightyP, - } -} - -fn to_i2v_duration(d: FalSeedance1p5ProDuration) -> EnqueueSeedance1p5ProImageToVideoDuration { - use EnqueueSeedance1p5ProImageToVideoDuration as T; - match d { - FalSeedance1p5ProDuration::Four => T::FourSeconds, - FalSeedance1p5ProDuration::Five => T::FiveSeconds, - FalSeedance1p5ProDuration::Six => T::SixSeconds, - FalSeedance1p5ProDuration::Seven => T::SevenSeconds, - FalSeedance1p5ProDuration::Eight => T::EightSeconds, - FalSeedance1p5ProDuration::Nine => T::NineSeconds, - FalSeedance1p5ProDuration::Ten => T::TenSeconds, - FalSeedance1p5ProDuration::Eleven => T::ElevenSeconds, - FalSeedance1p5ProDuration::Twelve => T::TwelveSeconds, - } -} - -fn to_i2v_aspect_ratio(a: FalSeedance1p5ProAspectRatio) -> EnqueueSeedance1p5ProImageToVideoAspectRatio { - use EnqueueSeedance1p5ProImageToVideoAspectRatio as T; - match a { - FalSeedance1p5ProAspectRatio::Auto => T::Auto, - FalSeedance1p5ProAspectRatio::TwentyOneByNine => T::TwentyOneByNine, - FalSeedance1p5ProAspectRatio::SixteenByNine => T::SixteenByNine, - FalSeedance1p5ProAspectRatio::FourByThree => T::FourByThree, - FalSeedance1p5ProAspectRatio::Square => T::Square, - FalSeedance1p5ProAspectRatio::ThreeByFour => T::ThreeByFour, - FalSeedance1p5ProAspectRatio::NineBySixteen => T::NineBySixteen, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_sora_2.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_sora_2.rs deleted file mode 100644 index 68b93a372c..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_sora_2.rs +++ /dev/null @@ -1,117 +0,0 @@ -use std::fmt::Debug; -use std::sync::Arc; - -use crate::client::router_fal_client::RouterFalClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - FalVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_sora_2::{ - FalSora2AspectRatio, FalSora2Duration, FalSora2Mode, FalSora2Resolution, PlanFalSora2, -}; -use fal_client::requests::webhook::video::image::enqueue_sora_2_image_to_video_webhook::{ - enqueue_sora_2_image_to_video_webhook, EnqueueSora2ImageToVideoArgs, - EnqueueSora2ImageToVideoAspectRatio, EnqueueSora2ImageToVideoDurationSeconds, - EnqueueSora2ImageToVideoRequest, EnqueueSora2ImageToVideoResolution, -}; -use fal_client::requests::webhook::video::text::enqueue_sora_2_text_to_video_webhook::{ - enqueue_sora_2_text_to_video_webhook, EnqueueSora2TextToVideoArgs, - EnqueueSora2TextToVideoRequest, EnqueueSora2TextToVideoAspectRatio, - EnqueueSora2TextToVideoDurationSeconds, EnqueueSora2TextToVideoResolution, -}; - -pub async fn execute_fal_sora_2( - plan: &PlanFalSora2, - fal_client: &RouterFalClient, -) -> Result { - let (webhook_response, outbound_request) = match &plan.mode { - FalSora2Mode::TextToVideo => { - // Text-to-video does not support Auto aspect ratio or Auto resolution. - let request = EnqueueSora2TextToVideoRequest { - prompt: plan.prompt.clone(), - resolution: plan.resolution.and_then(to_t2v_resolution), - duration: plan.duration.map(to_t2v_duration), - aspect_ratio: plan.aspect_ratio.and_then(to_t2v_aspect_ratio), - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueSora2TextToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_sora_2_text_to_video_webhook(args).await, outbound) - } - FalSora2Mode::ImageToVideo { image_url } => { - let request = EnqueueSora2ImageToVideoRequest { - prompt: plan.prompt.clone(), - image_url: image_url.clone(), - duration: plan.duration.map(to_i2v_duration), - resolution: plan.resolution.map(to_i2v_resolution), - aspect_ratio: plan.aspect_ratio.map(to_i2v_aspect_ratio), - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueSora2ImageToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_sora_2_image_to_video_webhook(args).await, outbound) - } - }; - - let webhook_response = webhook_response - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - - Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload { - request_id: webhook_response.request_id, - gateway_request_id: webhook_response.gateway_request_id, - maybe_outbound_request: Some(outbound_request), - })) -} - -fn to_t2v_duration(d: FalSora2Duration) -> EnqueueSora2TextToVideoDurationSeconds { - match d { - FalSora2Duration::Four => EnqueueSora2TextToVideoDurationSeconds::Four, - FalSora2Duration::Eight => EnqueueSora2TextToVideoDurationSeconds::Eight, - FalSora2Duration::Twelve => EnqueueSora2TextToVideoDurationSeconds::Twelve, - } -} - -fn to_t2v_resolution(r: FalSora2Resolution) -> Option { - match r { - FalSora2Resolution::SevenTwentyP => Some(EnqueueSora2TextToVideoResolution::SevenTwentyP), - FalSora2Resolution::Auto => None, - } -} - -fn to_t2v_aspect_ratio(a: FalSora2AspectRatio) -> Option { - match a { - FalSora2AspectRatio::SixteenByNine => Some(EnqueueSora2TextToVideoAspectRatio::SixteenByNine), - FalSora2AspectRatio::NineBySixteen => Some(EnqueueSora2TextToVideoAspectRatio::NineBySixteen), - FalSora2AspectRatio::Auto => None, - } -} - -fn to_i2v_duration(d: FalSora2Duration) -> EnqueueSora2ImageToVideoDurationSeconds { - match d { - FalSora2Duration::Four => EnqueueSora2ImageToVideoDurationSeconds::Four, - FalSora2Duration::Eight => EnqueueSora2ImageToVideoDurationSeconds::Eight, - FalSora2Duration::Twelve => EnqueueSora2ImageToVideoDurationSeconds::Twelve, - } -} - -fn to_i2v_resolution(r: FalSora2Resolution) -> EnqueueSora2ImageToVideoResolution { - match r { - FalSora2Resolution::SevenTwentyP => EnqueueSora2ImageToVideoResolution::SevenTwentyP, - FalSora2Resolution::Auto => EnqueueSora2ImageToVideoResolution::Auto, - } -} - -fn to_i2v_aspect_ratio(a: FalSora2AspectRatio) -> EnqueueSora2ImageToVideoAspectRatio { - match a { - FalSora2AspectRatio::SixteenByNine => EnqueueSora2ImageToVideoAspectRatio::SixteenByNine, - FalSora2AspectRatio::NineBySixteen => EnqueueSora2ImageToVideoAspectRatio::NineBySixteen, - FalSora2AspectRatio::Auto => EnqueueSora2ImageToVideoAspectRatio::Auto, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_sora_2_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_sora_2_pro.rs deleted file mode 100644 index 5818cbe626..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_sora_2_pro.rs +++ /dev/null @@ -1,120 +0,0 @@ -use std::fmt::Debug; -use std::sync::Arc; - -use crate::client::router_fal_client::RouterFalClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - FalVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_sora_2_pro::{ - FalSora2ProAspectRatio, FalSora2ProDuration, FalSora2ProMode, FalSora2ProResolution, - PlanFalSora2Pro, -}; -use fal_client::requests::webhook::video::image::enqueue_sora_2_pro_image_to_video_webhook::{ - enqueue_sora_2_pro_image_to_video_webhook, EnqueueSora2ProImageToVideoArgs, - EnqueueSora2ProImageToVideoAspectRatio, EnqueueSora2ProImageToVideoDurationSeconds, - EnqueueSora2ProImageToVideoRequest, EnqueueSora2ProImageToVideoResolution, -}; -use fal_client::requests::webhook::video::text::enqueue_sora_2_pro_text_to_video_webhook::{ - enqueue_sora_2_pro_text_to_video_webhook, EnqueueSora2ProTextToVideoArgs, - EnqueueSora2ProTextToVideoRequest, EnqueueSora2ProTextToVideoAspectRatio, - EnqueueSora2ProTextToVideoDurationSeconds, EnqueueSora2ProTextToVideoResolution, -}; - -pub async fn execute_fal_sora_2_pro( - plan: &PlanFalSora2Pro, - fal_client: &RouterFalClient, -) -> Result { - let (webhook_response, outbound_request) = match &plan.mode { - FalSora2ProMode::TextToVideo => { - // Text-to-video does not support Auto aspect ratio or Auto resolution. - let request = EnqueueSora2ProTextToVideoRequest { - prompt: plan.prompt.clone(), - resolution: plan.resolution.and_then(to_t2v_resolution), - duration: plan.duration.map(to_t2v_duration), - aspect_ratio: plan.aspect_ratio.and_then(to_t2v_aspect_ratio), - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueSora2ProTextToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_sora_2_pro_text_to_video_webhook(args).await, outbound) - } - FalSora2ProMode::ImageToVideo { image_url } => { - let request = EnqueueSora2ProImageToVideoRequest { - prompt: plan.prompt.clone(), - image_url: image_url.clone(), - duration: plan.duration.map(to_i2v_duration), - resolution: plan.resolution.map(to_i2v_resolution), - aspect_ratio: plan.aspect_ratio.map(to_i2v_aspect_ratio), - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueSora2ProImageToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_sora_2_pro_image_to_video_webhook(args).await, outbound) - } - }; - - let webhook_response = webhook_response - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - - Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload { - request_id: webhook_response.request_id, - gateway_request_id: webhook_response.gateway_request_id, - maybe_outbound_request: Some(outbound_request), - })) -} - -fn to_t2v_duration(d: FalSora2ProDuration) -> EnqueueSora2ProTextToVideoDurationSeconds { - match d { - FalSora2ProDuration::Four => EnqueueSora2ProTextToVideoDurationSeconds::Four, - FalSora2ProDuration::Eight => EnqueueSora2ProTextToVideoDurationSeconds::Eight, - FalSora2ProDuration::Twelve => EnqueueSora2ProTextToVideoDurationSeconds::Twelve, - } -} - -fn to_t2v_resolution(r: FalSora2ProResolution) -> Option { - match r { - FalSora2ProResolution::SevenTwentyP => Some(EnqueueSora2ProTextToVideoResolution::SevenTwentyP), - FalSora2ProResolution::TenEightyP => Some(EnqueueSora2ProTextToVideoResolution::TenEightyP), - FalSora2ProResolution::Auto => None, - } -} - -fn to_t2v_aspect_ratio(a: FalSora2ProAspectRatio) -> Option { - match a { - FalSora2ProAspectRatio::SixteenByNine => Some(EnqueueSora2ProTextToVideoAspectRatio::SixteenByNine), - FalSora2ProAspectRatio::NineBySixteen => Some(EnqueueSora2ProTextToVideoAspectRatio::NineBySixteen), - FalSora2ProAspectRatio::Auto => None, - } -} - -fn to_i2v_duration(d: FalSora2ProDuration) -> EnqueueSora2ProImageToVideoDurationSeconds { - match d { - FalSora2ProDuration::Four => EnqueueSora2ProImageToVideoDurationSeconds::Four, - FalSora2ProDuration::Eight => EnqueueSora2ProImageToVideoDurationSeconds::Eight, - FalSora2ProDuration::Twelve => EnqueueSora2ProImageToVideoDurationSeconds::Twelve, - } -} - -fn to_i2v_resolution(r: FalSora2ProResolution) -> EnqueueSora2ProImageToVideoResolution { - match r { - FalSora2ProResolution::Auto => EnqueueSora2ProImageToVideoResolution::Auto, - FalSora2ProResolution::SevenTwentyP => EnqueueSora2ProImageToVideoResolution::SevenTwentyP, - FalSora2ProResolution::TenEightyP => EnqueueSora2ProImageToVideoResolution::TenEightyP, - } -} - -fn to_i2v_aspect_ratio(a: FalSora2ProAspectRatio) -> EnqueueSora2ProImageToVideoAspectRatio { - match a { - FalSora2ProAspectRatio::Auto => EnqueueSora2ProImageToVideoAspectRatio::Auto, - FalSora2ProAspectRatio::SixteenByNine => EnqueueSora2ProImageToVideoAspectRatio::SixteenByNine, - FalSora2ProAspectRatio::NineBySixteen => EnqueueSora2ProImageToVideoAspectRatio::NineBySixteen, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_veo_2.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_veo_2.rs deleted file mode 100644 index 20e4983ffc..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_veo_2.rs +++ /dev/null @@ -1,69 +0,0 @@ -use std::fmt::Debug; -use std::sync::Arc; - -use crate::client::router_fal_client::RouterFalClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - FalVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_2::{ - FalVeo2Mode, PlanFalVeo2, -}; -use fal_client::requests::webhook::video::image::enqueue_veo_2_image_to_video_webhook::{ - enqueue_veo_2_image_to_video_webhook, Veo2Args, Veo2AspectRatio, Veo2Request, -}; -use fal_client::requests::webhook::video::text::enqueue_veo_2_text_to_video_webhook::{ - enqueue_veo_2_text_to_video_webhook, Veo2TextToVideoArgs, Veo2TextToVideoRequest, -}; - -pub async fn execute_fal_veo_2( - plan: &PlanFalVeo2, - fal_client: &RouterFalClient, -) -> Result { - let (webhook_response, outbound_request) = match &plan.mode { - FalVeo2Mode::TextToVideo => { - let request = Veo2TextToVideoRequest { - prompt: plan.prompt.clone(), - negative_prompt: plan.negative_prompt.clone(), - duration: plan.duration, - aspect_ratio: plan.aspect_ratio.unwrap_or(Veo2AspectRatio::Auto), - }; - let outbound: Arc = Arc::new(request.clone()); - let args = Veo2TextToVideoArgs { - request, - api_key: &fal_client.api_key, - webhook_url: fal_client.webhook_url.as_str(), - }; - let resp = enqueue_veo_2_text_to_video_webhook(args) - .await - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - (resp, outbound) - } - FalVeo2Mode::ImageToVideo { image_url } => { - // Image-to-video does not support aspect_ratio — the output - // inherits the source image's aspect ratio. - let request = Veo2Request { - image_url: image_url.to_string(), - prompt: plan.prompt.clone(), - duration: plan.duration, - }; - let outbound: Arc = Arc::new(request.clone()); - let args = Veo2Args { - request, - api_key: &fal_client.api_key, - webhook_url: fal_client.webhook_url.as_str(), - }; - let resp = enqueue_veo_2_image_to_video_webhook(args) - .await - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - (resp, outbound) - } - }; - - Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload { - request_id: webhook_response.request_id, - gateway_request_id: webhook_response.gateway_request_id, - maybe_outbound_request: Some(outbound_request), - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_veo_3.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_veo_3.rs deleted file mode 100644 index 73043f2a14..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_veo_3.rs +++ /dev/null @@ -1,125 +0,0 @@ -use std::fmt::Debug; -use std::sync::Arc; - -use crate::client::router_fal_client::RouterFalClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - FalVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3::{ - FalVeo3Duration, FalVeo3I2vAspectRatio, FalVeo3Mode, FalVeo3Resolution, - FalVeo3T2vAspectRatio, PlanFalVeo3, -}; -use fal_client::requests::webhook::video::image::enqueue_veo_3_image_to_video_webhook::{ - enqueue_veo_3_image_to_video_webhook, Veo3Args, Veo3I2vAspectRatio, Veo3I2vDuration, - Veo3I2vResolution, Veo3Request, -}; -use fal_client::requests::webhook::video::text::enqueue_veo_3_text_to_video_webhook::{ - enqueue_veo_3_text_to_video_webhook, Veo3T2vAspectRatio, Veo3T2vDuration, Veo3T2vResolution, - Veo3TextToVideoArgs, Veo3TextToVideoRequest, -}; - -pub async fn execute_fal_veo_3( - plan: &PlanFalVeo3, - fal_client: &RouterFalClient, -) -> Result { - let (webhook_response, outbound_request) = match &plan.mode { - FalVeo3Mode::TextToVideo => { - let request = Veo3TextToVideoRequest { - prompt: plan.prompt.clone(), - negative_prompt: plan.negative_prompt.clone(), - duration: to_t2v_duration(plan.duration), - aspect_ratio: plan.t2v_aspect_ratio.map(to_t2v_aspect_ratio).unwrap_or(Veo3T2vAspectRatio::Default), - resolution: to_t2v_resolution(plan.resolution), - generate_audio: plan.generate_audio, - }; - let outbound: Arc = Arc::new(request.clone()); - let args = Veo3TextToVideoArgs { - request, - api_key: &fal_client.api_key, - webhook_url: fal_client.webhook_url.as_str(), - }; - let resp = enqueue_veo_3_text_to_video_webhook(args) - .await - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - (resp, outbound) - } - FalVeo3Mode::ImageToVideo { image_url } => { - let request = Veo3Request { - image_url: image_url.to_string(), - prompt: plan.prompt.clone(), - duration: to_i2v_duration(plan.duration), - aspect_ratio: plan.i2v_aspect_ratio.map(to_i2v_aspect_ratio).unwrap_or(Veo3I2vAspectRatio::Auto), - resolution: to_i2v_resolution(plan.resolution), - generate_audio: plan.generate_audio, - }; - let outbound: Arc = Arc::new(request.clone()); - let args = Veo3Args { - request, - api_key: &fal_client.api_key, - webhook_url: fal_client.webhook_url.as_str(), - }; - let resp = enqueue_veo_3_image_to_video_webhook(args) - .await - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - (resp, outbound) - } - }; - - Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload { - request_id: webhook_response.request_id, - gateway_request_id: webhook_response.gateway_request_id, - maybe_outbound_request: Some(outbound_request), - })) -} - -fn to_i2v_duration(d: FalVeo3Duration) -> Veo3I2vDuration { - match d { - FalVeo3Duration::Default => Veo3I2vDuration::Default, - FalVeo3Duration::FourSeconds => Veo3I2vDuration::FourSeconds, - FalVeo3Duration::SixSeconds => Veo3I2vDuration::SixSeconds, - FalVeo3Duration::EightSeconds => Veo3I2vDuration::EightSeconds, - } -} - -fn to_t2v_duration(d: FalVeo3Duration) -> Veo3T2vDuration { - match d { - FalVeo3Duration::Default => Veo3T2vDuration::Default, - FalVeo3Duration::FourSeconds => Veo3T2vDuration::FourSeconds, - FalVeo3Duration::SixSeconds => Veo3T2vDuration::SixSeconds, - FalVeo3Duration::EightSeconds => Veo3T2vDuration::EightSeconds, - } -} - -fn to_i2v_resolution(r: FalVeo3Resolution) -> Veo3I2vResolution { - match r { - FalVeo3Resolution::Default => Veo3I2vResolution::Default, - FalVeo3Resolution::SevenTwentyP => Veo3I2vResolution::SevenTwentyP, - FalVeo3Resolution::TenEightyP => Veo3I2vResolution::TenEightyP, - } -} - -fn to_t2v_resolution(r: FalVeo3Resolution) -> Veo3T2vResolution { - match r { - FalVeo3Resolution::Default => Veo3T2vResolution::Default, - FalVeo3Resolution::SevenTwentyP => Veo3T2vResolution::SevenTwentyP, - FalVeo3Resolution::TenEightyP => Veo3T2vResolution::TenEightyP, - } -} - -fn to_t2v_aspect_ratio(ar: FalVeo3T2vAspectRatio) -> Veo3T2vAspectRatio { - match ar { - FalVeo3T2vAspectRatio::Default => Veo3T2vAspectRatio::Default, - FalVeo3T2vAspectRatio::WideSixteenNine => Veo3T2vAspectRatio::WideSixteenNine, - FalVeo3T2vAspectRatio::TallNineSixteen => Veo3T2vAspectRatio::TallNineSixteen, - } -} - -fn to_i2v_aspect_ratio(ar: FalVeo3I2vAspectRatio) -> Veo3I2vAspectRatio { - match ar { - FalVeo3I2vAspectRatio::Auto => Veo3I2vAspectRatio::Auto, - FalVeo3I2vAspectRatio::WideSixteenNine => Veo3I2vAspectRatio::WideSixteenNine, - FalVeo3I2vAspectRatio::TallNineSixteen => Veo3I2vAspectRatio::TallNineSixteen, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_veo_3_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_veo_3_fast.rs deleted file mode 100644 index 35b6b65ffd..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_veo_3_fast.rs +++ /dev/null @@ -1,45 +0,0 @@ -use std::fmt::Debug; -use std::sync::Arc; - -use crate::client::router_fal_client::RouterFalClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - FalVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3_fast::PlanFalVeo3Fast; -use fal_client::requests::webhook::video::image::enqueue_veo_3_fast_image_to_video_webhook::{ - enqueue_veo_3_fast_image_to_video_webhook, Veo3FastArgs, Veo3FastRequest, -}; - -pub async fn execute_fal_veo_3_fast( - plan: &PlanFalVeo3Fast, - fal_client: &RouterFalClient, -) -> Result { - let request = Veo3FastRequest { - prompt: plan.prompt.clone(), - image_url: plan.start_frame_url.clone(), - aspect_ratio: plan.aspect_ratio, - duration: plan.duration, - resolution: plan.resolution, - generate_audio: plan.generate_audio, - }; - - let outbound_request: Arc = Arc::new(request.clone()); - - let args = Veo3FastArgs { - request, - api_key: &fal_client.api_key, - webhook_url: fal_client.webhook_url.as_str(), - }; - - let webhook_response = enqueue_veo_3_fast_image_to_video_webhook(args) - .await - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - - Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload { - request_id: webhook_response.request_id, - gateway_request_id: webhook_response.gateway_request_id, - maybe_outbound_request: Some(outbound_request), - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_veo_3p1.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_veo_3p1.rs deleted file mode 100644 index 00f1cfb6ff..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_veo_3p1.rs +++ /dev/null @@ -1,171 +0,0 @@ -use std::fmt::Debug; -use std::sync::Arc; - -use crate::client::router_fal_client::RouterFalClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - FalVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1::{ - FalVeo3p1AspectRatio, FalVeo3p1Duration, FalVeo3p1Mode, FalVeo3p1Resolution, PlanFalVeo3p1, -}; -use fal_client::requests::webhook::video::image::enqueue_veo_3p1_first_last_frame_image_to_video_webhook::{ - enqueue_veo_3p1_first_last_frame_image_to_video_webhook, - EnqueueVeo3p1FirstLastFrameImageToVideoArgs, - EnqueueVeo3p1FirstLastFrameImageToVideoAspectRatio, - EnqueueVeo3p1FirstLastFrameImageToVideoDurationSeconds, - EnqueueVeo3p1FirstLastFrameImageToVideoRequest, - EnqueueVeo3p1FirstLastFrameImageToVideoResolution, -}; -use fal_client::requests::webhook::video::image::enqueue_veo_3p1_image_to_video_webhook::{ - enqueue_veo_3p1_image_to_video_webhook, EnqueueVeo3p1ImageToVideoArgs, - EnqueueVeo3p1ImageToVideoAspectRatio, EnqueueVeo3p1ImageToVideoDurationSeconds, - EnqueueVeo3p1ImageToVideoRequest, EnqueueVeo3p1ImageToVideoResolution, -}; -use fal_client::requests::webhook::video::text::enqueue_veo_3p1_text_to_video_webhook::{ - enqueue_veo_3p1_text_to_video_webhook, EnqueueVeo3p1TextToVideoArgs, - EnqueueVeo3p1TextToVideoRequest, EnqueueVeo3p1TextToVideoAspectRatio, - EnqueueVeo3p1TextToVideoDurationSeconds, EnqueueVeo3p1TextToVideoResolution, -}; - -pub async fn execute_fal_veo_3p1( - plan: &PlanFalVeo3p1, - fal_client: &RouterFalClient, -) -> Result { - let (webhook_response, outbound_request) = match &plan.mode { - FalVeo3p1Mode::TextToVideo => { - let request = EnqueueVeo3p1TextToVideoRequest { - prompt: plan.prompt.clone(), - duration: plan.duration.map(to_t2v_duration), - aspect_ratio: plan.aspect_ratio.map(to_t2v_aspect_ratio), - resolution: plan.resolution.map(to_t2v_resolution), - generate_audio: plan.generate_audio, - enhance_prompt: None, - negative_prompt: plan.negative_prompt.clone(), - seed: None, - auto_fix: None, - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueVeo3p1TextToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_veo_3p1_text_to_video_webhook(args).await, outbound) - } - FalVeo3p1Mode::ImageToVideo { start_frame_url } => { - let request = EnqueueVeo3p1ImageToVideoRequest { - prompt: plan.prompt.clone(), - image_url: start_frame_url.clone(), - duration: plan.duration.map(to_i2v_duration), - aspect_ratio: plan.aspect_ratio.map(to_i2v_aspect_ratio), - resolution: plan.resolution.map(to_i2v_resolution), - generate_audio: plan.generate_audio, - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueVeo3p1ImageToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_veo_3p1_image_to_video_webhook(args).await, outbound) - } - FalVeo3p1Mode::FirstLastFrame { first_frame_url, last_frame_url } => { - let request = EnqueueVeo3p1FirstLastFrameImageToVideoRequest { - prompt: plan.prompt.clone(), - first_frame_url: first_frame_url.clone(), - last_frame_url: last_frame_url.clone(), - duration: plan.duration.map(to_flf_duration), - aspect_ratio: plan.aspect_ratio.map(to_flf_aspect_ratio), - resolution: plan.resolution.map(to_flf_resolution), - generate_audio: plan.generate_audio, - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueVeo3p1FirstLastFrameImageToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_veo_3p1_first_last_frame_image_to_video_webhook(args).await, outbound) - } - }; - - let webhook_response = webhook_response - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - - Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload { - request_id: webhook_response.request_id, - gateway_request_id: webhook_response.gateway_request_id, - maybe_outbound_request: Some(outbound_request), - })) -} - -fn to_t2v_duration(d: FalVeo3p1Duration) -> EnqueueVeo3p1TextToVideoDurationSeconds { - match d { - FalVeo3p1Duration::Four => EnqueueVeo3p1TextToVideoDurationSeconds::Four, - FalVeo3p1Duration::Six => EnqueueVeo3p1TextToVideoDurationSeconds::Six, - FalVeo3p1Duration::Eight => EnqueueVeo3p1TextToVideoDurationSeconds::Eight, - } -} - -fn to_t2v_aspect_ratio(a: FalVeo3p1AspectRatio) -> EnqueueVeo3p1TextToVideoAspectRatio { - match a { - FalVeo3p1AspectRatio::Auto => EnqueueVeo3p1TextToVideoAspectRatio::Auto, - FalVeo3p1AspectRatio::SixteenByNine => EnqueueVeo3p1TextToVideoAspectRatio::SixteenByNine, - FalVeo3p1AspectRatio::NineBySixteen => EnqueueVeo3p1TextToVideoAspectRatio::NineBySixteen, - } -} - -fn to_t2v_resolution(r: FalVeo3p1Resolution) -> EnqueueVeo3p1TextToVideoResolution { - match r { - FalVeo3p1Resolution::SevenTwentyP => EnqueueVeo3p1TextToVideoResolution::SevenTwentyP, - FalVeo3p1Resolution::TenEightyP => EnqueueVeo3p1TextToVideoResolution::TenEightyP, - } -} - -fn to_i2v_duration(d: FalVeo3p1Duration) -> EnqueueVeo3p1ImageToVideoDurationSeconds { - match d { - FalVeo3p1Duration::Four => EnqueueVeo3p1ImageToVideoDurationSeconds::Four, - FalVeo3p1Duration::Six => EnqueueVeo3p1ImageToVideoDurationSeconds::Six, - FalVeo3p1Duration::Eight => EnqueueVeo3p1ImageToVideoDurationSeconds::Eight, - } -} - -fn to_i2v_aspect_ratio(a: FalVeo3p1AspectRatio) -> EnqueueVeo3p1ImageToVideoAspectRatio { - match a { - FalVeo3p1AspectRatio::Auto => EnqueueVeo3p1ImageToVideoAspectRatio::Auto, - FalVeo3p1AspectRatio::SixteenByNine => EnqueueVeo3p1ImageToVideoAspectRatio::SixteenByNine, - FalVeo3p1AspectRatio::NineBySixteen => EnqueueVeo3p1ImageToVideoAspectRatio::NineBySixteen, - } -} - -fn to_i2v_resolution(r: FalVeo3p1Resolution) -> EnqueueVeo3p1ImageToVideoResolution { - match r { - FalVeo3p1Resolution::SevenTwentyP => EnqueueVeo3p1ImageToVideoResolution::SevenTwentyP, - FalVeo3p1Resolution::TenEightyP => EnqueueVeo3p1ImageToVideoResolution::TenEightyP, - } -} - -fn to_flf_duration(d: FalVeo3p1Duration) -> EnqueueVeo3p1FirstLastFrameImageToVideoDurationSeconds { - match d { - FalVeo3p1Duration::Four => EnqueueVeo3p1FirstLastFrameImageToVideoDurationSeconds::Four, - FalVeo3p1Duration::Six => EnqueueVeo3p1FirstLastFrameImageToVideoDurationSeconds::Six, - FalVeo3p1Duration::Eight => EnqueueVeo3p1FirstLastFrameImageToVideoDurationSeconds::Eight, - } -} - -fn to_flf_aspect_ratio(a: FalVeo3p1AspectRatio) -> EnqueueVeo3p1FirstLastFrameImageToVideoAspectRatio { - match a { - FalVeo3p1AspectRatio::Auto => EnqueueVeo3p1FirstLastFrameImageToVideoAspectRatio::Auto, - FalVeo3p1AspectRatio::SixteenByNine => EnqueueVeo3p1FirstLastFrameImageToVideoAspectRatio::SixteenByNine, - FalVeo3p1AspectRatio::NineBySixteen => EnqueueVeo3p1FirstLastFrameImageToVideoAspectRatio::NineBySixteen, - } -} - -fn to_flf_resolution(r: FalVeo3p1Resolution) -> EnqueueVeo3p1FirstLastFrameImageToVideoResolution { - match r { - FalVeo3p1Resolution::SevenTwentyP => EnqueueVeo3p1FirstLastFrameImageToVideoResolution::SevenTwentyP, - FalVeo3p1Resolution::TenEightyP => EnqueueVeo3p1FirstLastFrameImageToVideoResolution::TenEightyP, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_veo_3p1_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_veo_3p1_fast.rs deleted file mode 100644 index 0a0ee21520..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/generate_video_fal_veo_3p1_fast.rs +++ /dev/null @@ -1,174 +0,0 @@ -use std::fmt::Debug; -use std::sync::Arc; - -use crate::client::router_fal_client::RouterFalClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - FalVideoResponsePayload, GenerateVideoResponse, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1::{ - FalVeo3p1AspectRatio, FalVeo3p1Duration, FalVeo3p1Mode, FalVeo3p1Resolution, -}; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1_fast::PlanFalVeo3p1Fast; -use fal_client::requests::webhook::video::image::enqueue_veo_3p1_fast_first_last_frame_image_to_video_webhook::{ - enqueue_veo_3p1_fast_first_last_frame_image_to_video_webhook, - EnqueueVeo3p1FastFirstLastFrameImageToVideoArgs, - EnqueueVeo3p1FastFirstLastFrameImageToVideoAspectRatio, - EnqueueVeo3p1FastFirstLastFrameImageToVideoDurationSeconds, - EnqueueVeo3p1FastFirstLastFrameImageToVideoRequest, - EnqueueVeo3p1FastFirstLastFrameImageToVideoResolution, -}; -use fal_client::requests::webhook::video::image::enqueue_veo_3p1_fast_image_to_video_webhook::{ - enqueue_veo_3p1_fast_image_to_video_webhook, EnqueueVeo3p1FastImageToVideoArgs, - EnqueueVeo3p1FastImageToVideoAspectRatio, EnqueueVeo3p1FastImageToVideoDurationSeconds, - EnqueueVeo3p1FastImageToVideoRequest, EnqueueVeo3p1FastImageToVideoResolution, -}; -use fal_client::requests::webhook::video::text::enqueue_veo_3p1_fast_text_to_video_webhook::{ - enqueue_veo_3p1_fast_text_to_video_webhook, EnqueueVeo3p1FastTextToVideoArgs, - EnqueueVeo3p1FastTextToVideoRequest, EnqueueVeo3p1FastTextToVideoAspectRatio, - EnqueueVeo3p1FastTextToVideoDurationSeconds, EnqueueVeo3p1FastTextToVideoResolution, -}; - -pub async fn execute_fal_veo_3p1_fast( - plan: &PlanFalVeo3p1Fast, - fal_client: &RouterFalClient, -) -> Result { - let inner = &plan.inner; - - let (webhook_response, outbound_request) = match &inner.mode { - FalVeo3p1Mode::TextToVideo => { - let request = EnqueueVeo3p1FastTextToVideoRequest { - prompt: inner.prompt.clone(), - duration: inner.duration.map(to_t2v_duration), - aspect_ratio: inner.aspect_ratio.map(to_t2v_aspect_ratio), - resolution: inner.resolution.map(to_t2v_resolution), - generate_audio: inner.generate_audio, - enhance_prompt: None, - negative_prompt: inner.negative_prompt.clone(), - seed: None, - auto_fix: None, - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueVeo3p1FastTextToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_veo_3p1_fast_text_to_video_webhook(args).await, outbound) - } - FalVeo3p1Mode::ImageToVideo { start_frame_url } => { - let request = EnqueueVeo3p1FastImageToVideoRequest { - prompt: inner.prompt.clone(), - image_url: start_frame_url.clone(), - duration: inner.duration.map(to_i2v_duration), - aspect_ratio: inner.aspect_ratio.map(to_i2v_aspect_ratio), - resolution: inner.resolution.map(to_i2v_resolution), - generate_audio: inner.generate_audio, - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueVeo3p1FastImageToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_veo_3p1_fast_image_to_video_webhook(args).await, outbound) - } - FalVeo3p1Mode::FirstLastFrame { first_frame_url, last_frame_url } => { - let request = EnqueueVeo3p1FastFirstLastFrameImageToVideoRequest { - prompt: inner.prompt.clone(), - first_frame_url: first_frame_url.clone(), - last_frame_url: last_frame_url.clone(), - duration: inner.duration.map(to_flf_duration), - aspect_ratio: inner.aspect_ratio.map(to_flf_aspect_ratio), - resolution: inner.resolution.map(to_flf_resolution), - generate_audio: inner.generate_audio, - }; - let outbound: Arc = Arc::new(request.clone()); - let args = EnqueueVeo3p1FastFirstLastFrameImageToVideoArgs { - request, - webhook_url: fal_client.webhook_url.as_str(), - api_key: &fal_client.api_key, - }; - (enqueue_veo_3p1_fast_first_last_frame_image_to_video_webhook(args).await, outbound) - } - }; - - let webhook_response = webhook_response - .map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?; - - Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload { - request_id: webhook_response.request_id, - gateway_request_id: webhook_response.gateway_request_id, - maybe_outbound_request: Some(outbound_request), - })) -} - -fn to_t2v_duration(d: FalVeo3p1Duration) -> EnqueueVeo3p1FastTextToVideoDurationSeconds { - match d { - FalVeo3p1Duration::Four => EnqueueVeo3p1FastTextToVideoDurationSeconds::Four, - FalVeo3p1Duration::Six => EnqueueVeo3p1FastTextToVideoDurationSeconds::Six, - FalVeo3p1Duration::Eight => EnqueueVeo3p1FastTextToVideoDurationSeconds::Eight, - } -} - -fn to_t2v_aspect_ratio(a: FalVeo3p1AspectRatio) -> EnqueueVeo3p1FastTextToVideoAspectRatio { - match a { - FalVeo3p1AspectRatio::Auto => EnqueueVeo3p1FastTextToVideoAspectRatio::Auto, - FalVeo3p1AspectRatio::SixteenByNine => EnqueueVeo3p1FastTextToVideoAspectRatio::SixteenByNine, - FalVeo3p1AspectRatio::NineBySixteen => EnqueueVeo3p1FastTextToVideoAspectRatio::NineBySixteen, - } -} - -fn to_t2v_resolution(r: FalVeo3p1Resolution) -> EnqueueVeo3p1FastTextToVideoResolution { - match r { - FalVeo3p1Resolution::SevenTwentyP => EnqueueVeo3p1FastTextToVideoResolution::SevenTwentyP, - FalVeo3p1Resolution::TenEightyP => EnqueueVeo3p1FastTextToVideoResolution::TenEightyP, - } -} - -fn to_i2v_duration(d: FalVeo3p1Duration) -> EnqueueVeo3p1FastImageToVideoDurationSeconds { - match d { - FalVeo3p1Duration::Four => EnqueueVeo3p1FastImageToVideoDurationSeconds::Four, - FalVeo3p1Duration::Six => EnqueueVeo3p1FastImageToVideoDurationSeconds::Six, - FalVeo3p1Duration::Eight => EnqueueVeo3p1FastImageToVideoDurationSeconds::Eight, - } -} - -fn to_i2v_aspect_ratio(a: FalVeo3p1AspectRatio) -> EnqueueVeo3p1FastImageToVideoAspectRatio { - match a { - FalVeo3p1AspectRatio::Auto => EnqueueVeo3p1FastImageToVideoAspectRatio::Auto, - FalVeo3p1AspectRatio::SixteenByNine => EnqueueVeo3p1FastImageToVideoAspectRatio::SixteenByNine, - FalVeo3p1AspectRatio::NineBySixteen => EnqueueVeo3p1FastImageToVideoAspectRatio::NineBySixteen, - } -} - -fn to_i2v_resolution(r: FalVeo3p1Resolution) -> EnqueueVeo3p1FastImageToVideoResolution { - match r { - FalVeo3p1Resolution::SevenTwentyP => EnqueueVeo3p1FastImageToVideoResolution::SevenTwentyP, - FalVeo3p1Resolution::TenEightyP => EnqueueVeo3p1FastImageToVideoResolution::TenEightyP, - } -} - -fn to_flf_duration(d: FalVeo3p1Duration) -> EnqueueVeo3p1FastFirstLastFrameImageToVideoDurationSeconds { - match d { - FalVeo3p1Duration::Four => EnqueueVeo3p1FastFirstLastFrameImageToVideoDurationSeconds::Four, - FalVeo3p1Duration::Six => EnqueueVeo3p1FastFirstLastFrameImageToVideoDurationSeconds::Six, - FalVeo3p1Duration::Eight => EnqueueVeo3p1FastFirstLastFrameImageToVideoDurationSeconds::Eight, - } -} - -fn to_flf_aspect_ratio(a: FalVeo3p1AspectRatio) -> EnqueueVeo3p1FastFirstLastFrameImageToVideoAspectRatio { - match a { - FalVeo3p1AspectRatio::Auto => EnqueueVeo3p1FastFirstLastFrameImageToVideoAspectRatio::Auto, - FalVeo3p1AspectRatio::SixteenByNine => EnqueueVeo3p1FastFirstLastFrameImageToVideoAspectRatio::SixteenByNine, - FalVeo3p1AspectRatio::NineBySixteen => EnqueueVeo3p1FastFirstLastFrameImageToVideoAspectRatio::NineBySixteen, - } -} - -fn to_flf_resolution(r: FalVeo3p1Resolution) -> EnqueueVeo3p1FastFirstLastFrameImageToVideoResolution { - match r { - FalVeo3p1Resolution::SevenTwentyP => EnqueueVeo3p1FastFirstLastFrameImageToVideoResolution::SevenTwentyP, - FalVeo3p1Resolution::TenEightyP => EnqueueVeo3p1FastFirstLastFrameImageToVideoResolution::TenEightyP, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/mod.rs deleted file mode 100644 index 84f18ee9a5..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/fal/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -pub mod generate_video_fal_kling_1_6_pro; -pub mod generate_video_fal_kling_2_1_master; -pub mod generate_video_fal_kling_2_1_pro; -pub mod generate_video_fal_kling_2_5_turbo_pro; -pub mod generate_video_fal_kling_2_6_pro; -pub mod generate_video_fal_kling_3p0_pro; -pub mod generate_video_fal_kling_3p0_standard; -pub mod generate_video_fal_seedance_1_0_lite; -pub mod generate_video_fal_seedance_1p5_pro; -pub mod generate_video_fal_sora_2; -pub mod generate_video_fal_sora_2_pro; -pub mod generate_video_fal_veo_2; -pub mod generate_video_fal_veo_3; -pub mod generate_video_fal_veo_3_fast; -pub mod generate_video_fal_veo_3p1; -pub mod generate_video_fal_veo_3p1_fast; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/mod.rs deleted file mode 100644 index da07b9e7b8..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod artcraft; -pub mod fal; -pub mod muapi; -pub mod seedance2pro; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/muapi/execute_muapi_seedance2p0.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/muapi/execute_muapi_seedance2p0.rs deleted file mode 100644 index 7577eefc15..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/muapi/execute_muapi_seedance2p0.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::client::router_muapi_client::RouterMuapiClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - GenerateVideoResponse, MuapiVideoResponsePayload, -}; -use crate::generate::generate_video::plan::muapi::plan_generate_video_muapi_seedance2p0::{ - MuapiSeedance2p0Mode, PlanMuapiSeedance2p0, -}; -use muapi_client::requests::seedance_2p0_image_to_video::seedance_2p0_image_to_video::{ - Seedance2p0ImageToVideoArgs, seedance_2p0_image_to_video, -}; -use muapi_client::requests::seedance_2p0_text_to_video::seedance_2p0_text_to_video::{ - Seedance2p0TextToVideoArgs, seedance_2p0_text_to_video, -}; - -pub async fn execute_muapi_seedance2p0( - plan: &PlanMuapiSeedance2p0, - muapi_client: &RouterMuapiClient, -) -> Result { - let session = &muapi_client.session; - - let request_id = match &plan.mode { - MuapiSeedance2p0Mode::TextToVideo { aspect_ratio, duration, quality } => { - let args = Seedance2p0TextToVideoArgs { - session, - prompt: plan.prompt.clone(), - aspect_ratio: *aspect_ratio, - duration: *duration, - quality: *quality, - }; - let response = seedance_2p0_text_to_video(args) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Muapi(err)))?; - response.request_id - } - MuapiSeedance2p0Mode::ImageToVideo { image_urls, aspect_ratio, duration, quality } => { - let args = Seedance2p0ImageToVideoArgs { - session, - prompt: plan.prompt.clone(), - image_urls: image_urls.clone(), - aspect_ratio: *aspect_ratio, - duration: *duration, - quality: *quality, - }; - let response = seedance_2p0_image_to_video(args) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Muapi(err)))?; - response.request_id - } - }; - - Ok(GenerateVideoResponse::Muapi(MuapiVideoResponsePayload { - request_id, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/muapi/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/muapi/mod.rs deleted file mode 100644 index b5eb8ea609..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/muapi/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod execute_muapi_seedance2p0; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/seedance2pro/execute_seedance2pro_seedance2p0.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/seedance2pro/execute_seedance2pro_seedance2p0.rs deleted file mode 100644 index d0b1d47d94..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/seedance2pro/execute_seedance2pro_seedance2p0.rs +++ /dev/null @@ -1,115 +0,0 @@ -use crate::client::router_seedance2pro_client::RouterSeedance2ProClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::generate_video_response::{ - GenerateVideoResponse, Seedance2proVideoResponsePayload, -}; -use crate::generate::generate_video::plan::seedance2pro::plan_generate_video_seedance2pro_seedance2p0::PlanSeedance2proSeedance2p0; -use crate::utils::download_file::download_file; -use seedance2pro_client::requests::generate_video::generate_video::{ - generate_video, GenerateVideoArgs, -}; -use seedance2pro_client::requests::prepare_file_upload::prepare_file_upload::{ - prepare_file_upload, PrepareFileUploadArgs, -}; -use seedance2pro_client::requests::upload_file::upload_file::{ - upload_file, UploadFileArgs, -}; -use url_utils::extension::extract_extension_from_url::{ - extract_extension_from_url_str, ExtractExtensions, -}; - -pub async fn execute_seedance2pro_seedance2p0( - plan: &PlanSeedance2proSeedance2p0, - seedance2pro_client: &RouterSeedance2ProClient, -) -> Result { - let session = &seedance2pro_client.session; - - // Upload media files to seedance2pro CDN - let start_frame_url = upload_optional_url(session, plan.request.start_frame_url.as_deref()).await?; - let end_frame_url = upload_optional_url(session, plan.request.end_frame_url.as_deref()).await?; - let reference_image_urls = upload_optional_url_list(session, plan.request.reference_image_urls.as_deref()).await?; - let reference_video_urls = upload_optional_url_list(session, plan.request.reference_video_urls.as_deref()).await?; - let reference_audio_urls = upload_optional_url_list(session, plan.request.reference_audio_urls.as_deref()).await?; - - let mut request = plan.request.clone(); - request.start_frame_url = start_frame_url; - request.end_frame_url = end_frame_url; - request.reference_image_urls = reference_image_urls; - request.reference_video_urls = reference_video_urls; - request.reference_audio_urls = reference_audio_urls; - - let args = GenerateVideoArgs { - session, - host_override: None, - request, - }; - - let response = generate_video(args) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Seedance2Pro(err)))?; - - Ok(GenerateVideoResponse::Seedance2Pro(Seedance2proVideoResponsePayload { - order_id: response.order_id, - task_id: response.task_id, - maybe_order_ids: response.order_ids, - maybe_task_ids: response.task_ids, - })) -} - -/// Downloads a file from a source URL and re-uploads it to seedance2pro CDN. -pub(crate) async fn upload_to_seedance2pro( - session: &seedance2pro_client::creds::seedance2pro_session::Seedance2ProSession, - source_url: &str, -) -> Result { - let extension = extract_extension_from_url_str(source_url, &ExtractExtensions::All) - .map(|ext| ext.without_period().to_string()) - .unwrap_or_else(|| "jpg".to_string()); - - let file_bytes = download_file(source_url).await?; - - let prepare_response = prepare_file_upload(PrepareFileUploadArgs { - session, - extension, - host_override: None, - }) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Seedance2Pro(err)))?; - - let upload_response = upload_file(UploadFileArgs { - upload_url: prepare_response.upload_url, - file_bytes, - host_override: None, - }) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Seedance2Pro(err)))?; - - Ok(upload_response.public_url) -} - -pub(crate) async fn upload_optional_url( - session: &seedance2pro_client::creds::seedance2pro_session::Seedance2ProSession, - url: Option<&str>, -) -> Result, ArtcraftRouterError> { - match url { - None => Ok(None), - Some(u) => Ok(Some(upload_to_seedance2pro(session, u).await?)), - } -} - -pub(crate) async fn upload_optional_url_list( - session: &seedance2pro_client::creds::seedance2pro_session::Seedance2ProSession, - urls: Option<&[String]>, -) -> Result>, ArtcraftRouterError> { - match urls { - None => Ok(None), - Some(url_list) if url_list.is_empty() => Ok(None), - Some(url_list) => { - let mut uploaded = Vec::with_capacity(url_list.len()); - for url in url_list { - uploaded.push(upload_to_seedance2pro(session, url).await?); - } - Ok(Some(uploaded)) - } - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/seedance2pro/execute_seedance2pro_seedance2p0_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/seedance2pro/execute_seedance2pro_seedance2p0_fast.rs deleted file mode 100644 index 1f3d85fa9c..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/seedance2pro/execute_seedance2pro_seedance2p0_fast.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::client::router_seedance2pro_client::RouterSeedance2ProClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::errors::provider_error::ProviderError; -use crate::generate::generate_video::execute::seedance2pro::execute_seedance2pro_seedance2p0::{ - upload_optional_url, upload_optional_url_list, -}; -use crate::generate::generate_video::generate_video_response::{ - GenerateVideoResponse, Seedance2proVideoResponsePayload, -}; -use crate::generate::generate_video::plan::seedance2pro::plan_generate_video_seedance2pro_seedance2p0_fast::PlanSeedance2proSeedance2p0Fast; -use seedance2pro_client::requests::generate_video::generate_video::{ - generate_video, GenerateVideoArgs, -}; - -/// Execute Seedance 2.0 Fast via the Seedance2Pro/Kinovi provider. -/// -/// Identical to the Seedance 2.0 Pro executor except it uses -/// `ModelType::Seedance2Fast` instead of `ModelType::Seedance2Pro`. -pub async fn execute_seedance2pro_seedance2p0_fast( - plan: &PlanSeedance2proSeedance2p0Fast, - seedance2pro_client: &RouterSeedance2ProClient, -) -> Result { - let session = &seedance2pro_client.session; - - // Upload media files to seedance2pro CDN - let start_frame_url = upload_optional_url(session, plan.request.start_frame_url.as_deref()).await?; - let end_frame_url = upload_optional_url(session, plan.request.end_frame_url.as_deref()).await?; - let reference_image_urls = upload_optional_url_list(session, plan.request.reference_image_urls.as_deref()).await?; - let reference_video_urls = upload_optional_url_list(session, plan.request.reference_video_urls.as_deref()).await?; - let reference_audio_urls = upload_optional_url_list(session, plan.request.reference_audio_urls.as_deref()).await?; - - let mut request = plan.request.clone(); - request.start_frame_url = start_frame_url; - request.end_frame_url = end_frame_url; - request.reference_image_urls = reference_image_urls; - request.reference_video_urls = reference_video_urls; - request.reference_audio_urls = reference_audio_urls; - - let args = GenerateVideoArgs { - session, - host_override: None, - request, - }; - - let response = generate_video(args) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Seedance2Pro(err)))?; - - Ok(GenerateVideoResponse::Seedance2Pro(Seedance2proVideoResponsePayload { - order_id: response.order_id, - task_id: response.task_id, - maybe_order_ids: response.order_ids, - maybe_task_ids: response.task_ids, - })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/seedance2pro/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/seedance2pro/mod.rs deleted file mode 100644 index 35e435c85d..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/execute/seedance2pro/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod execute_seedance2pro_seedance2p0; -pub mod execute_seedance2pro_seedance2p0_fast; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/generate_video_request_builder.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/generate_video_request_builder.rs index 81cb6fd0e8..438e020c19 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/generate_video_request_builder.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/generate_video_request_builder.rs @@ -9,44 +9,6 @@ use crate::api::provider::Provider; use crate::api::video_list_ref::VideoListRef; use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy; use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling3p0_pro::plan_generate_video_artcraft_kling3p0_pro; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling3p0_standard::plan_generate_video_artcraft_kling3p0_standard; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_1_6_pro::plan_generate_video_artcraft_kling_1_6_pro; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_1_master::plan_generate_video_artcraft_kling_2_1_master; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_1_pro::plan_generate_video_artcraft_kling_2_1_pro; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_5_turbo_pro::plan_generate_video_artcraft_kling_2_5_turbo_pro; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_6_pro::plan_generate_video_artcraft_kling_2_6_pro; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance1p5_pro::plan_generate_video_artcraft_seedance1p5_pro; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance2p0::plan_generate_video_artcraft_seedance2p0; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance2p0_fast::plan_generate_video_artcraft_seedance2p0_fast; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance_1_0_lite::plan_generate_video_artcraft_seedance_1_0_lite; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_sora_2::plan_generate_video_artcraft_sora_2; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_sora_2_pro::plan_generate_video_artcraft_sora_2_pro; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_2::plan_generate_video_artcraft_veo_2; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_3::plan_generate_video_artcraft_veo_3; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_3_fast::plan_generate_video_artcraft_veo_3_fast; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_3p1::plan_generate_video_artcraft_veo_3p1; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_3p1_fast::plan_generate_video_artcraft_veo_3p1_fast; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_1_6_pro::plan_generate_video_fal_kling_1_6_pro; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_2_1_master::plan_generate_video_fal_kling_2_1_master; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_2_1_pro::plan_generate_video_fal_kling_2_1_pro; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_2_5_turbo_pro::plan_generate_video_fal_kling_2_5_turbo_pro; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_2_6_pro::plan_generate_video_fal_kling_2_6_pro; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_3p0_pro::plan_generate_video_fal_kling_3p0_pro; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_3p0_standard::plan_generate_video_fal_kling_3p0_standard; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_seedance_1_0_lite::plan_generate_video_fal_seedance_1_0_lite; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_seedance_1p5_pro::plan_generate_video_fal_seedance_1p5_pro; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_sora_2::plan_generate_video_fal_sora_2; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_sora_2_pro::plan_generate_video_fal_sora_2_pro; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_2::plan_generate_video_fal_veo_2; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3::plan_generate_video_fal_veo_3; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3_fast::plan_generate_video_fal_veo_3_fast; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1::plan_generate_video_fal_veo_3p1; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1_fast::plan_generate_video_fal_veo_3p1_fast; -use crate::generate::generate_video::plan::muapi::plan_generate_video_muapi_seedance2p0::plan_generate_video_muapi_seedance2p0; -use crate::generate::generate_video::plan::seedance2pro::plan_generate_video_seedance2pro_seedance2p0::plan_generate_video_seedance2pro_seedance2p0; -use crate::generate::generate_video::plan::seedance2pro::plan_generate_video_seedance2pro_seedance2p0_fast::plan_generate_video_seedance2pro_seedance2p0_fast; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; use crate::generate::generate_video_v2::providers::artcraft::grok_imagine_video::build::build_artcraft_grok_imagine_video; use crate::generate::generate_video_v2::providers::artcraft::happy_horse_1p0::build::build_artcraft_happy_horse_1p0; use crate::generate::generate_video_v2::providers::artcraft::kling_1_6_pro::build::build_artcraft_kling_1_6_pro; @@ -58,6 +20,8 @@ use crate::generate::generate_video_v2::providers::artcraft::kling_3p0_pro::buil use crate::generate::generate_video_v2::providers::artcraft::kling_3p0_standard::build::build_artcraft_kling_3p0_standard; use crate::generate::generate_video_v2::providers::artcraft::preview_model::build::build_artcraft_preview_model; use crate::generate::generate_video_v2::providers::artcraft::preview_model_fast::build::build_artcraft_preview_model_fast; +use crate::generate::generate_video_v2::providers::artcraft::seedance_1p0_lite::build::build_artcraft_seedance_1p0_lite; +use crate::generate::generate_video_v2::providers::artcraft::seedance_1p5_pro::build::build_artcraft_seedance_1p5_pro; use crate::generate::generate_video_v2::providers::artcraft::seedance_2p0::build::build_artcraft_seedance_2p0; use crate::generate::generate_video_v2::providers::artcraft::seedance_2p0_fast::build::build_artcraft_seedance_2p0_fast; use crate::generate::generate_video_v2::providers::artcraft::seedance_2p0_u::build::build_artcraft_seedance_2p0_u; @@ -95,9 +59,8 @@ use crate::generate::generate_video_v2::providers::fal::veo_3p1_fast::build::bui use crate::generate::generate_video_v2::providers::kinovi::seedance_2p0_fast::build::build_kinovi_seedance_2p0_fast; use crate::generate::generate_video_v2::video_generation_draft_or_request::VideoGenerationDraftOrRequest; -/// Plan to either (1) generate a video or (2) determine how much it costs to generate that video. -/// This works across multiple providers by shaping a generic "GenerateVideoRequest" into a provider-specific plan. -/// That plan can then be used to return a cost estimate for that given provider or return a struct that can be used to send a real generation request. +/// Provider-agnostic video generation request. Distilled by `build2()` into a +/// `VideoGenerationDraftOrRequest` for the selected (provider, model) pair. #[derive(Clone, Debug)] pub struct GenerateVideoRequestBuilder { /// Which model to use. @@ -182,64 +145,6 @@ impl Default for GenerateVideoRequestBuilder { impl GenerateVideoRequestBuilder { - pub fn use_new_builder(&self) -> bool { - match (self.provider, self.model) { - // Artcraft - (Provider::Artcraft, CommonVideoModel::GrokImagineVideo) => true, - (Provider::Artcraft, CommonVideoModel::HappyHorse1p0) => true, - (Provider::Artcraft, CommonVideoModel::Kling16Pro) => true, - (Provider::Artcraft, CommonVideoModel::Kling21Master) => true, - (Provider::Artcraft, CommonVideoModel::Kling21Pro) => true, - (Provider::Artcraft, CommonVideoModel::Kling2p5TurboPro) => true, - (Provider::Artcraft, CommonVideoModel::Kling2p6Pro) => true, - (Provider::Artcraft, CommonVideoModel::Kling3p0Pro) => true, - (Provider::Artcraft, CommonVideoModel::Kling3p0Standard) => true, - (Provider::Artcraft, CommonVideoModel::Seedance2p0) => true, - (Provider::Artcraft, CommonVideoModel::Seedance2p0Fast) => true, - (Provider::Artcraft, CommonVideoModel::Seedance2p0Ultra) => true, - (Provider::Artcraft, CommonVideoModel::Seedance2p0UltraFast) => true, - (Provider::Artcraft, CommonVideoModel::Seedance2p0BytePlus) => true, - (Provider::Artcraft, CommonVideoModel::Seedance2p0BytePlusFast) => true, - (Provider::Artcraft, CommonVideoModel::PreviewModel) => true, - (Provider::Artcraft, CommonVideoModel::PreviewModelFast) => true, - (Provider::Artcraft, CommonVideoModel::Sora2) => true, - (Provider::Artcraft, CommonVideoModel::Sora2Pro) => true, - (Provider::Artcraft, CommonVideoModel::Veo2) => true, - (Provider::Artcraft, CommonVideoModel::Veo3) => true, - (Provider::Artcraft, CommonVideoModel::Veo3Fast) => true, - (Provider::Artcraft, CommonVideoModel::Veo3p1) => true, - (Provider::Artcraft, CommonVideoModel::Veo3p1Fast) => true, - // Fal - (Provider::Fal, CommonVideoModel::Kling16Pro) => true, - (Provider::Fal, CommonVideoModel::Kling21Master) => true, - (Provider::Fal, CommonVideoModel::Kling21Pro) => true, - (Provider::Fal, CommonVideoModel::Kling2p5TurboPro) => true, - (Provider::Fal, CommonVideoModel::Kling2p6Pro) => true, - (Provider::Fal, CommonVideoModel::Kling3p0Pro) => true, - (Provider::Fal, CommonVideoModel::Kling3p0Standard) => true, - (Provider::Fal, CommonVideoModel::Seedance10Lite) => true, - (Provider::Fal, CommonVideoModel::Seedance1p5Pro) => true, - (Provider::Fal, CommonVideoModel::Sora2) => true, - (Provider::Fal, CommonVideoModel::Sora2Pro) => true, - (Provider::Fal, CommonVideoModel::Veo2) => true, - (Provider::Fal, CommonVideoModel::Veo3) => true, - (Provider::Fal, CommonVideoModel::Veo3Fast) => true, - (Provider::Fal, CommonVideoModel::Veo3p1) => true, - (Provider::Fal, CommonVideoModel::Veo3p1Fast) => true, - // GmiCloud - (Provider::GmiCloud, CommonVideoModel::Seedance2p0Ultra) => true, - (Provider::GmiCloud, CommonVideoModel::Seedance2p0UltraFast) => true, - // Grok - (Provider::GrokApi, CommonVideoModel::GrokImagineVideo) => true, - // Kinovi - (Provider::Seedance2Pro, CommonVideoModel::HappyHorse1p0) => true, - (Provider::Seedance2Pro, CommonVideoModel::Seedance2p0) => true, - (Provider::Seedance2Pro, CommonVideoModel::Seedance2p0Fast) => true, - _ => false, - } - } - - // New builder (transitional state) pub fn build2(self) -> Result { match (self.provider, self.model) { // Artcraft @@ -260,6 +165,8 @@ impl GenerateVideoRequestBuilder { (Provider::Artcraft, CommonVideoModel::Seedance2p0BytePlusFast) => build_artcraft_seedance_2p0_bp_fast(self), (Provider::Artcraft, CommonVideoModel::PreviewModel) => build_artcraft_preview_model(self), (Provider::Artcraft, CommonVideoModel::PreviewModelFast) => build_artcraft_preview_model_fast(self), + (Provider::Artcraft, CommonVideoModel::Seedance10Lite) => build_artcraft_seedance_1p0_lite(self), + (Provider::Artcraft, CommonVideoModel::Seedance1p5Pro) => build_artcraft_seedance_1p5_pro(self), (Provider::Artcraft, CommonVideoModel::Sora2) => build_artcraft_sora_2(self), (Provider::Artcraft, CommonVideoModel::Sora2Pro) => build_artcraft_sora_2_pro(self), (Provider::Artcraft, CommonVideoModel::Veo2) => build_artcraft_veo_2(self), @@ -297,88 +204,9 @@ impl GenerateVideoRequestBuilder { } } - /// Read the video generation request, construct a plan, then yield a means to execute it. - pub fn build(&self) -> Result { - match self.provider { - Provider::Artcraft => self.build_artcraft(), - Provider::Fal => self.build_fal(), - Provider::GmiCloud => self.unsupported_provider(), // GmiCloud uses build2() only - Provider::GrokApi => self.unsupported_provider(), // Grok uses build2() only - Provider::Muapi => self.build_muapi(), - Provider::Seedance2Pro => self.build_seedance2pro(), - } - } - - fn build_artcraft(&self) -> Result { - match self.model { - CommonVideoModel::Kling16Pro => plan_generate_video_artcraft_kling_1_6_pro(self), - CommonVideoModel::Kling21Master => plan_generate_video_artcraft_kling_2_1_master(self), - CommonVideoModel::Kling21Pro => plan_generate_video_artcraft_kling_2_1_pro(self), - CommonVideoModel::Kling2p5TurboPro => plan_generate_video_artcraft_kling_2_5_turbo_pro(self), - CommonVideoModel::Kling2p6Pro => plan_generate_video_artcraft_kling_2_6_pro(self), - CommonVideoModel::Kling3p0Pro => plan_generate_video_artcraft_kling3p0_pro(self), - CommonVideoModel::Kling3p0Standard => plan_generate_video_artcraft_kling3p0_standard(self), - CommonVideoModel::Seedance10Lite => plan_generate_video_artcraft_seedance_1_0_lite(self), - CommonVideoModel::Seedance1p5Pro => plan_generate_video_artcraft_seedance1p5_pro(self), - CommonVideoModel::Seedance2p0 => plan_generate_video_artcraft_seedance2p0(self), - CommonVideoModel::Seedance2p0Fast => plan_generate_video_artcraft_seedance2p0_fast(self), - CommonVideoModel::Sora2 => plan_generate_video_artcraft_sora_2(self), - CommonVideoModel::Sora2Pro => plan_generate_video_artcraft_sora_2_pro(self), - CommonVideoModel::Veo2 => plan_generate_video_artcraft_veo_2(self), - CommonVideoModel::Veo3 => plan_generate_video_artcraft_veo_3(self), - CommonVideoModel::Veo3Fast => plan_generate_video_artcraft_veo_3_fast(self), - CommonVideoModel::Veo3p1 => plan_generate_video_artcraft_veo_3p1(self), - CommonVideoModel::Veo3p1Fast => plan_generate_video_artcraft_veo_3p1_fast(self), - _ => Err(ArtcraftRouterError::UnsupportedModel(format!("{:?}", self.model))), - } - } - - fn build_fal(&self) -> Result { - match self.model { - CommonVideoModel::Veo2 => plan_generate_video_fal_veo_2(self), - CommonVideoModel::Veo3 => plan_generate_video_fal_veo_3(self), - CommonVideoModel::Veo3Fast => plan_generate_video_fal_veo_3_fast(self), - CommonVideoModel::Veo3p1 => plan_generate_video_fal_veo_3p1(self), - CommonVideoModel::Veo3p1Fast => plan_generate_video_fal_veo_3p1_fast(self), - CommonVideoModel::Kling16Pro => plan_generate_video_fal_kling_1_6_pro(self), - CommonVideoModel::Kling21Pro => plan_generate_video_fal_kling_2_1_pro(self), - CommonVideoModel::Kling21Master => plan_generate_video_fal_kling_2_1_master(self), - CommonVideoModel::Kling2p5TurboPro => plan_generate_video_fal_kling_2_5_turbo_pro(self), - CommonVideoModel::Kling2p6Pro => plan_generate_video_fal_kling_2_6_pro(self), - CommonVideoModel::Kling3p0Pro => plan_generate_video_fal_kling_3p0_pro(self), - CommonVideoModel::Kling3p0Standard => plan_generate_video_fal_kling_3p0_standard(self), - CommonVideoModel::Seedance10Lite => plan_generate_video_fal_seedance_1_0_lite(self), - CommonVideoModel::Seedance1p5Pro => plan_generate_video_fal_seedance_1p5_pro(self), - CommonVideoModel::Sora2 => plan_generate_video_fal_sora_2(self), - CommonVideoModel::Sora2Pro => plan_generate_video_fal_sora_2_pro(self), - _ => Err(ArtcraftRouterError::UnsupportedModel(format!("{:?}", self.model))), - } - } - - fn build_muapi(&self) -> Result { - match self.model { - CommonVideoModel::Seedance2p0 => plan_generate_video_muapi_seedance2p0(self), - _ => Err(ArtcraftRouterError::UnsupportedModel(format!("{:?}", self.model))), - } - } - - fn build_seedance2pro(&self) -> Result { - match self.model { - CommonVideoModel::Seedance2p0 => plan_generate_video_seedance2pro_seedance2p0(self), - CommonVideoModel::Seedance2p0Fast => plan_generate_video_seedance2pro_seedance2p0_fast(self), - _ => Err(ArtcraftRouterError::UnsupportedModel(format!("{:?}", self.model))), - } - } - - fn unsupported_provider(&self) -> Result { - Err(ArtcraftRouterError::UnsupportedModel( - format!("Video generation for model `{:?}` is not supported for provider {:?}", self.model, self.provider) - )) - } - fn unsupported_provider_and_model(&self) -> Result { Err(ArtcraftRouterError::UnsupportedProviderAndModelForNewApi( - format!("Video generation for model `{:?}` is not supported for provider {:?} using the new API", self.model, self.provider) + format!("Video generation for model `{:?}` is not supported for provider {:?}", self.model, self.provider) )) } diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/generate_video_response.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/generate_video_response.rs index d5ed3da153..95dac85b13 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/generate_video_response.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/generate_video_response.rs @@ -1,7 +1,6 @@ use std::fmt::Debug; use std::sync::Arc; -use muapi_client::api_types::request_id::RequestId as MuapiRequestId; use tokens::tokens::generic_inference_jobs::InferenceJobToken; #[derive(Clone, Debug)] @@ -10,11 +9,6 @@ pub struct ArtcraftVideoResponsePayload { pub all_inference_job_tokens: Vec, } -#[derive(Clone, Debug)] -pub struct MuapiVideoResponsePayload { - pub request_id: MuapiRequestId, -} - #[derive(Clone, Debug)] pub struct Seedance2proVideoResponsePayload { pub order_id: String, @@ -56,7 +50,6 @@ pub enum GenerateVideoResponse { Artcraft(ArtcraftVideoResponsePayload), GmiCloud(GmiCloudVideoResponsePayload), Grok(GrokVideoResponsePayload), - Muapi(MuapiVideoResponsePayload), Seedance2Pro(Seedance2proVideoResponsePayload), Fal(FalVideoResponsePayload), } @@ -69,13 +62,6 @@ impl GenerateVideoResponse { } } - pub fn get_muapi_payload(&self) -> Option { - match self { - Self::Muapi(p) => Some(p.clone()), - _ => None, - } - } - pub fn get_seedance2pro_payload(&self) -> Option { match self { Self::Seedance2Pro(p) => Some(p.clone()), diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/mod.rs index a631f59199..ff33f334f6 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/mod.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/mod.rs @@ -1,7 +1,3 @@ -pub mod cost; -pub mod execute; pub mod generate_video_request_builder; pub mod generate_video_response; -pub mod plan; pub mod video_generation_cost_estimate; -pub mod video_generation_plan; \ No newline at end of file diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/mod.rs deleted file mode 100644 index 0c8a683e1b..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -pub mod plan_generate_video_artcraft_kling_1_6_pro; -pub mod plan_generate_video_artcraft_kling_2_1_master; -pub mod plan_generate_video_artcraft_kling_2_1_pro; -pub mod plan_generate_video_artcraft_kling_2_5_turbo_pro; -pub mod plan_generate_video_artcraft_kling_2_6_pro; -pub mod plan_generate_video_artcraft_kling3p0_pro; -pub mod plan_generate_video_artcraft_kling3p0_standard; -pub mod plan_generate_video_artcraft_seedance_1_0_lite; -pub mod plan_generate_video_artcraft_seedance1p5_pro; -pub mod plan_generate_video_artcraft_seedance2p0; -pub mod plan_generate_video_artcraft_seedance2p0_fast; -pub mod plan_generate_video_artcraft_sora_2; -pub mod plan_generate_video_artcraft_sora_2_pro; -pub mod plan_generate_video_artcraft_veo_2; -pub mod plan_generate_video_artcraft_veo_3; -pub mod plan_generate_video_artcraft_veo_3_fast; -pub mod plan_generate_video_artcraft_veo_3p1; -pub mod plan_generate_video_artcraft_veo_3p1_fast; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling3p0_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling3p0_pro.rs deleted file mode 100644 index b057a35eeb..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling3p0_pro.rs +++ /dev/null @@ -1,276 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::multi_function::kling_3p0_pro_multi_function_video_gen::{ - Kling3p0ProMultiFunctionVideoGenAspectRatio, - Kling3p0ProMultiFunctionVideoGenDuration, -}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Debug, Clone)] -pub struct PlanArtcraftKling3p0Pro { - pub prompt: Option, - pub negative_prompt: Option, - pub start_frame: Option, - pub end_frame: Option, - pub aspect_ratio: Option, - pub duration: Option, - pub generate_audio: Option, - pub idempotency_token: String, -} - -pub fn plan_generate_video_artcraft_kling3p0_pro( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = resolve_image_ref(request.start_frame.clone())?; - let end_frame = resolve_image_ref(request.end_frame.clone())?; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::ArtcraftKling3p0Pro(PlanArtcraftKling3p0Pro { - prompt: request.prompt.clone(), - negative_prompt: request.negative_prompt.clone(), - start_frame, - end_frame, - aspect_ratio, - duration, - generate_audio: request.generate_audio, - idempotency_token: request.get_or_generate_idempotency_token(), - })) -} - -fn resolve_image_ref( - image_ref: Option, -) -> Result, ArtcraftRouterError> { - match image_ref { - None => Ok(None), - Some(ImageRef::MediaFileToken(t)) => Ok(Some(t)), - Some(ImageRef::Url(_)) => { - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - } -} - -// Kling 3.0 Pro supports: Square (1:1), SixteenByNine (16:9), NineBySixteen (9:16) -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - match aspect_ratio { - None => Ok(None), - - // Direct mappings - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => { - Ok(Some(Kling3p0ProMultiFunctionVideoGenAspectRatio::SixteenByNine)) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(Some(Kling3p0ProMultiFunctionVideoGenAspectRatio::NineBySixteen)) - } - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => { - Ok(Some(Kling3p0ProMultiFunctionVideoGenAspectRatio::Square)) - } - - // Auto defaults to 16:9 - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => { - Ok(Some(Kling3p0ProMultiFunctionVideoGenAspectRatio::SixteenByNine)) - } - - // Mismatches - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade - | RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(Some(nearest_aspect_ratio(unsupported))) - } - }, - } -} - -fn nearest_aspect_ratio(aspect_ratio: CommonAspectRatio) -> Kling3p0ProMultiFunctionVideoGenAspectRatio { - match aspect_ratio { - // Wide-ish → 16:9 - CommonAspectRatio::WideFourByThree - | CommonAspectRatio::WideFiveByFour - | CommonAspectRatio::WideThreeByTwo - | CommonAspectRatio::WideTwentyOneByNine => Kling3p0ProMultiFunctionVideoGenAspectRatio::SixteenByNine, - // Tall-ish → 9:16 - CommonAspectRatio::TallThreeByFour - | CommonAspectRatio::TallFourByFive - | CommonAspectRatio::TallTwoByThree - | CommonAspectRatio::TallNineByTwentyOne => Kling3p0ProMultiFunctionVideoGenAspectRatio::NineBySixteen, - // Fallback - _ => Kling3p0ProMultiFunctionVideoGenAspectRatio::Square, - } -} - -// Kling 3.0 Pro supports durations of 3–15 seconds. -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - const MIN: u16 = 3; - const MAX: u16 = 15; - match duration_seconds { - None => Ok(None), - Some(d) if d >= MIN && d <= MAX => Ok(Some(seconds_to_duration(d))), - Some(d) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", d), - })) - } - _ => Ok(Some(seconds_to_duration(d.clamp(MIN, MAX)))), - }, - } -} - -fn seconds_to_duration(seconds: u16) -> Kling3p0ProMultiFunctionVideoGenDuration { - match seconds { - 3 => Kling3p0ProMultiFunctionVideoGenDuration::ThreeSeconds, - 4 => Kling3p0ProMultiFunctionVideoGenDuration::FourSeconds, - 5 => Kling3p0ProMultiFunctionVideoGenDuration::FiveSeconds, - 6 => Kling3p0ProMultiFunctionVideoGenDuration::SixSeconds, - 7 => Kling3p0ProMultiFunctionVideoGenDuration::SevenSeconds, - 8 => Kling3p0ProMultiFunctionVideoGenDuration::EightSeconds, - 9 => Kling3p0ProMultiFunctionVideoGenDuration::NineSeconds, - 10 => Kling3p0ProMultiFunctionVideoGenDuration::TenSeconds, - 11 => Kling3p0ProMultiFunctionVideoGenDuration::ElevenSeconds, - 12 => Kling3p0ProMultiFunctionVideoGenDuration::TwelveSeconds, - 13 => Kling3p0ProMultiFunctionVideoGenDuration::ThirteenSeconds, - 14 => Kling3p0ProMultiFunctionVideoGenDuration::FourteenSeconds, - _ => Kling3p0ProMultiFunctionVideoGenDuration::FifteenSeconds, - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::api::common_aspect_ratio::CommonAspectRatio; - use crate::api::common_video_model::CommonVideoModel; - use crate::api::image_ref::ImageRef; - use crate::api::provider::Provider; - use crate::errors::artcraft_router_error::ArtcraftRouterError; - use crate::errors::client_error::ClientError; - use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; - use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; - - fn base_request() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling3p0Pro, - provider: Provider::Artcraft, - prompt: Some("a cat in space".to_string()), - negative_prompt: None, - start_frame: None, - end_frame: None, - reference_images: None, - reference_videos: None, - reference_audio: None, - reference_character_tokens: None, - resolution: None, - aspect_ratio: None, - duration_seconds: None, - video_batch_count: None, - generate_audio: None, - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut, - idempotency_token: None, - } - } - - #[test] - fn aspect_ratio_direct_16x9() { - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine), - ..base_request() - }; - let VideoGenerationPlan::ArtcraftKling3p0Pro(plan) = request.build().unwrap() else { panic!("wrong variant") }; - assert!(matches!(plan.aspect_ratio, Some(Kling3p0ProMultiFunctionVideoGenAspectRatio::SixteenByNine))); - } - - #[test] - fn aspect_ratio_direct_9x16() { - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::TallNineBySixteen), - ..base_request() - }; - let VideoGenerationPlan::ArtcraftKling3p0Pro(plan) = request.build().unwrap() else { panic!("wrong variant") }; - assert!(matches!(plan.aspect_ratio, Some(Kling3p0ProMultiFunctionVideoGenAspectRatio::NineBySixteen))); - } - - #[test] - fn aspect_ratio_direct_square() { - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::Square), - ..base_request() - }; - let VideoGenerationPlan::ArtcraftKling3p0Pro(plan) = request.build().unwrap() else { panic!("wrong variant") }; - assert!(matches!(plan.aspect_ratio, Some(Kling3p0ProMultiFunctionVideoGenAspectRatio::Square))); - } - - #[test] - fn aspect_ratio_error_out_on_unsupported() { - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::WideThreeByTwo), - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut, - ..base_request() - }; - let result = request.build(); - assert!(matches!( - result, - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { .. })) - )); - } - - #[test] - fn duration_valid_range() { - for d in 3..=15 { - let request = GenerateVideoRequestBuilder { - duration_seconds: Some(d), - ..base_request() - }; - let result = request.build(); - assert!(result.is_ok(), "duration {} should be valid", d); - } - } - - #[test] - fn duration_out_of_range_error_out() { - let request = GenerateVideoRequestBuilder { - duration_seconds: Some(16), - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut, - ..base_request() - }; - let result = request.build(); - assert!(matches!( - result, - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { .. })) - )); - } - - #[test] - fn url_image_ref_returns_error() { - let request = GenerateVideoRequestBuilder { - start_frame: Some(ImageRef::Url("https://example.com/image.jpg".to_string())), - ..base_request() - }; - let result = request.build(); - assert!(matches!( - result, - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - )); - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling3p0_standard.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling3p0_standard.rs deleted file mode 100644 index 16c42a6afa..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling3p0_standard.rs +++ /dev/null @@ -1,276 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::multi_function::kling_3p0_standard_multi_function_video_gen::{ - Kling3p0StandardMultiFunctionVideoGenAspectRatio, - Kling3p0StandardMultiFunctionVideoGenDuration, -}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Debug, Clone)] -pub struct PlanArtcraftKling3p0Standard { - pub prompt: Option, - pub negative_prompt: Option, - pub start_frame: Option, - pub end_frame: Option, - pub aspect_ratio: Option, - pub duration: Option, - pub generate_audio: Option, - pub idempotency_token: String, -} - -pub fn plan_generate_video_artcraft_kling3p0_standard( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = resolve_image_ref(request.start_frame.clone())?; - let end_frame = resolve_image_ref(request.end_frame.clone())?; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::ArtcraftKling3p0Standard(PlanArtcraftKling3p0Standard { - prompt: request.prompt.clone(), - negative_prompt: request.negative_prompt.clone(), - start_frame, - end_frame, - aspect_ratio, - duration, - generate_audio: request.generate_audio, - idempotency_token: request.get_or_generate_idempotency_token(), - })) -} - -fn resolve_image_ref( - image_ref: Option, -) -> Result, ArtcraftRouterError> { - match image_ref { - None => Ok(None), - Some(ImageRef::MediaFileToken(t)) => Ok(Some(t)), - Some(ImageRef::Url(_)) => { - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - } -} - -// Kling 3.0 Standard supports: Square (1:1), SixteenByNine (16:9), NineBySixteen (9:16) -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - match aspect_ratio { - None => Ok(None), - - // Direct mappings - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => { - Ok(Some(Kling3p0StandardMultiFunctionVideoGenAspectRatio::SixteenByNine)) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(Some(Kling3p0StandardMultiFunctionVideoGenAspectRatio::NineBySixteen)) - } - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => { - Ok(Some(Kling3p0StandardMultiFunctionVideoGenAspectRatio::Square)) - } - - // Auto defaults to 16:9 - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => { - Ok(Some(Kling3p0StandardMultiFunctionVideoGenAspectRatio::SixteenByNine)) - } - - // Mismatches - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade - | RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(Some(nearest_aspect_ratio(unsupported))) - } - }, - } -} - -fn nearest_aspect_ratio(aspect_ratio: CommonAspectRatio) -> Kling3p0StandardMultiFunctionVideoGenAspectRatio { - match aspect_ratio { - // Wide-ish → 16:9 - CommonAspectRatio::WideFourByThree - | CommonAspectRatio::WideFiveByFour - | CommonAspectRatio::WideThreeByTwo - | CommonAspectRatio::WideTwentyOneByNine => Kling3p0StandardMultiFunctionVideoGenAspectRatio::SixteenByNine, - // Tall-ish → 9:16 - CommonAspectRatio::TallThreeByFour - | CommonAspectRatio::TallFourByFive - | CommonAspectRatio::TallTwoByThree - | CommonAspectRatio::TallNineByTwentyOne => Kling3p0StandardMultiFunctionVideoGenAspectRatio::NineBySixteen, - // Fallback - _ => Kling3p0StandardMultiFunctionVideoGenAspectRatio::Square, - } -} - -// Kling 3.0 Standard supports durations of 3–15 seconds. -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - const MIN: u16 = 3; - const MAX: u16 = 15; - match duration_seconds { - None => Ok(None), - Some(d) if d >= MIN && d <= MAX => Ok(Some(seconds_to_duration(d))), - Some(d) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", d), - })) - } - _ => Ok(Some(seconds_to_duration(d.clamp(MIN, MAX)))), - }, - } -} - -fn seconds_to_duration(seconds: u16) -> Kling3p0StandardMultiFunctionVideoGenDuration { - match seconds { - 3 => Kling3p0StandardMultiFunctionVideoGenDuration::ThreeSeconds, - 4 => Kling3p0StandardMultiFunctionVideoGenDuration::FourSeconds, - 5 => Kling3p0StandardMultiFunctionVideoGenDuration::FiveSeconds, - 6 => Kling3p0StandardMultiFunctionVideoGenDuration::SixSeconds, - 7 => Kling3p0StandardMultiFunctionVideoGenDuration::SevenSeconds, - 8 => Kling3p0StandardMultiFunctionVideoGenDuration::EightSeconds, - 9 => Kling3p0StandardMultiFunctionVideoGenDuration::NineSeconds, - 10 => Kling3p0StandardMultiFunctionVideoGenDuration::TenSeconds, - 11 => Kling3p0StandardMultiFunctionVideoGenDuration::ElevenSeconds, - 12 => Kling3p0StandardMultiFunctionVideoGenDuration::TwelveSeconds, - 13 => Kling3p0StandardMultiFunctionVideoGenDuration::ThirteenSeconds, - 14 => Kling3p0StandardMultiFunctionVideoGenDuration::FourteenSeconds, - _ => Kling3p0StandardMultiFunctionVideoGenDuration::FifteenSeconds, - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::api::common_aspect_ratio::CommonAspectRatio; - use crate::api::common_video_model::CommonVideoModel; - use crate::api::image_ref::ImageRef; - use crate::api::provider::Provider; - use crate::errors::artcraft_router_error::ArtcraftRouterError; - use crate::errors::client_error::ClientError; - use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; - use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; - - fn base_request() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling3p0Standard, - provider: Provider::Artcraft, - prompt: Some("a cat in space".to_string()), - negative_prompt: None, - start_frame: None, - end_frame: None, - reference_images: None, - reference_videos: None, - reference_audio: None, - reference_character_tokens: None, - resolution: None, - aspect_ratio: None, - duration_seconds: None, - video_batch_count: None, - generate_audio: None, - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut, - idempotency_token: None, - } - } - - #[test] - fn aspect_ratio_direct_16x9() { - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine), - ..base_request() - }; - let VideoGenerationPlan::ArtcraftKling3p0Standard(plan) = request.build().unwrap() else { panic!("wrong variant") }; - assert!(matches!(plan.aspect_ratio, Some(Kling3p0StandardMultiFunctionVideoGenAspectRatio::SixteenByNine))); - } - - #[test] - fn aspect_ratio_direct_9x16() { - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::TallNineBySixteen), - ..base_request() - }; - let VideoGenerationPlan::ArtcraftKling3p0Standard(plan) = request.build().unwrap() else { panic!("wrong variant") }; - assert!(matches!(plan.aspect_ratio, Some(Kling3p0StandardMultiFunctionVideoGenAspectRatio::NineBySixteen))); - } - - #[test] - fn aspect_ratio_direct_square() { - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::Square), - ..base_request() - }; - let VideoGenerationPlan::ArtcraftKling3p0Standard(plan) = request.build().unwrap() else { panic!("wrong variant") }; - assert!(matches!(plan.aspect_ratio, Some(Kling3p0StandardMultiFunctionVideoGenAspectRatio::Square))); - } - - #[test] - fn aspect_ratio_error_out_on_unsupported() { - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::WideThreeByTwo), - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut, - ..base_request() - }; - let result = request.build(); - assert!(matches!( - result, - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { .. })) - )); - } - - #[test] - fn duration_valid_range() { - for d in 3..=15 { - let request = GenerateVideoRequestBuilder { - duration_seconds: Some(d), - ..base_request() - }; - let result = request.build(); - assert!(result.is_ok(), "duration {} should be valid", d); - } - } - - #[test] - fn duration_out_of_range_error_out() { - let request = GenerateVideoRequestBuilder { - duration_seconds: Some(16), - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut, - ..base_request() - }; - let result = request.build(); - assert!(matches!( - result, - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { .. })) - )); - } - - #[test] - fn url_image_ref_returns_error() { - let request = GenerateVideoRequestBuilder { - start_frame: Some(ImageRef::Url("https://example.com/image.jpg".to_string())), - ..base_request() - }; - let result = request.build(); - assert!(matches!( - result, - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - )); - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling_1_6_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling_1_6_pro.rs deleted file mode 100644 index f8efcb6008..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling_1_6_pro.rs +++ /dev/null @@ -1,136 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::generate_kling_1_6_pro_image_to_video::{ - GenerateKling16ProAspectRatio, GenerateKling16ProDuration, -}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Debug, Clone)] -pub struct PlanArtcraftKling16Pro { - pub prompt: Option, - pub start_frame: MediaFileToken, - pub end_frame: Option, - pub aspect_ratio: Option, - pub duration: Option, - pub idempotency_token: String, -} - -pub fn plan_generate_video_artcraft_kling_1_6_pro( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = match request.start_frame.clone() { - Some(ImageRef::MediaFileToken(t)) => t, - Some(ImageRef::Url(_)) => { - return Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - None => { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "start_frame", - value: "Kling 1.6 Pro requires a starting frame".to_string(), - })) - } - }; - let end_frame = resolve_end_frame(request.end_frame.clone())?; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::ArtcraftKling16Pro(PlanArtcraftKling16Pro { - prompt: request.prompt.clone(), - start_frame, - end_frame, - aspect_ratio, - duration, - idempotency_token: request.get_or_generate_idempotency_token(), - })) -} - -fn resolve_end_frame( - image_ref: Option, -) -> Result, ArtcraftRouterError> { - match image_ref { - None => Ok(None), - Some(ImageRef::MediaFileToken(t)) => Ok(Some(t)), - Some(ImageRef::Url(_)) => { - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - } -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use GenerateKling16ProAspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Ar::Square)), - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::WideSixteenNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::TallNineSixteen)), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::WideSixteenNine)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(nearest_aspect_ratio(unsupported))), - }, - } -} - -fn nearest_aspect_ratio(ar: CommonAspectRatio) -> GenerateKling16ProAspectRatio { - use GenerateKling16ProAspectRatio as Ar; - match ar { - CommonAspectRatio::WideFourByThree - | CommonAspectRatio::WideFiveByFour - | CommonAspectRatio::WideThreeByTwo - | CommonAspectRatio::WideTwentyOneByNine => Ar::WideSixteenNine, - CommonAspectRatio::TallThreeByFour - | CommonAspectRatio::TallFourByFive - | CommonAspectRatio::TallTwoByThree - | CommonAspectRatio::TallNineByTwentyOne => Ar::TallNineSixteen, - _ => Ar::Square, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use GenerateKling16ProDuration as D; - match duration_seconds { - None => Ok(None), - Some(5) => Ok(Some(D::FiveSeconds)), - Some(10) => Ok(Some(D::TenSeconds)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::TenSeconds)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::FiveSeconds)), - }, - } -} - -impl PlanArtcraftKling16Pro { - pub fn is_ten_seconds(&self) -> bool { - matches!(self.duration, Some(GenerateKling16ProDuration::TenSeconds)) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling_2_1_master.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling_2_1_master.rs deleted file mode 100644 index f5988bce41..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling_2_1_master.rs +++ /dev/null @@ -1,128 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::generate_kling_2_1_master_image_to_video::{ - GenerateKling21MasterAspectRatio, GenerateKling21MasterDuration, -}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Debug, Clone)] -pub struct PlanArtcraftKling21Master { - pub prompt: Option, - pub start_frame: MediaFileToken, - pub aspect_ratio: Option, - pub duration: Option, - pub idempotency_token: String, -} - -pub fn plan_generate_video_artcraft_kling_2_1_master( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = match request.start_frame.clone() { - Some(ImageRef::MediaFileToken(t)) => t, - Some(ImageRef::Url(_)) => { - return Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - None => { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "start_frame", - value: "Kling 2.1 Master requires a starting frame".to_string(), - })) - } - }; - - if request.end_frame.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "end_frame", - value: "Kling 2.1 Master does not support an ending frame".to_string(), - })); - } - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::ArtcraftKling21Master(PlanArtcraftKling21Master { - prompt: request.prompt.clone(), - start_frame, - aspect_ratio, - duration, - idempotency_token: request.get_or_generate_idempotency_token(), - })) -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use GenerateKling21MasterAspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Ar::Square)), - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::WideSixteenNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::TallNineSixteen)), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::WideSixteenNine)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(nearest_aspect_ratio(unsupported))), - }, - } -} - -fn nearest_aspect_ratio(ar: CommonAspectRatio) -> GenerateKling21MasterAspectRatio { - use GenerateKling21MasterAspectRatio as Ar; - match ar { - CommonAspectRatio::WideFourByThree - | CommonAspectRatio::WideFiveByFour - | CommonAspectRatio::WideThreeByTwo - | CommonAspectRatio::WideTwentyOneByNine => Ar::WideSixteenNine, - CommonAspectRatio::TallThreeByFour - | CommonAspectRatio::TallFourByFive - | CommonAspectRatio::TallTwoByThree - | CommonAspectRatio::TallNineByTwentyOne => Ar::TallNineSixteen, - _ => Ar::Square, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use GenerateKling21MasterDuration as D; - match duration_seconds { - None => Ok(None), - Some(5) => Ok(Some(D::FiveSeconds)), - Some(10) => Ok(Some(D::TenSeconds)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::TenSeconds)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::FiveSeconds)), - }, - } -} - -impl PlanArtcraftKling21Master { - pub fn is_ten_seconds(&self) -> bool { - matches!(self.duration, Some(GenerateKling21MasterDuration::TenSeconds)) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling_2_1_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling_2_1_pro.rs deleted file mode 100644 index 94acbadb49..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling_2_1_pro.rs +++ /dev/null @@ -1,136 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::generate_kling_2_1_pro_image_to_video::{ - GenerateKling21ProAspectRatio, GenerateKling21ProDuration, -}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Debug, Clone)] -pub struct PlanArtcraftKling21Pro { - pub prompt: Option, - pub start_frame: MediaFileToken, - pub end_frame: Option, - pub aspect_ratio: Option, - pub duration: Option, - pub idempotency_token: String, -} - -pub fn plan_generate_video_artcraft_kling_2_1_pro( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = match request.start_frame.clone() { - Some(ImageRef::MediaFileToken(t)) => t, - Some(ImageRef::Url(_)) => { - return Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - None => { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "start_frame", - value: "Kling 2.1 Pro requires a starting frame".to_string(), - })) - } - }; - let end_frame = resolve_end_frame(request.end_frame.clone())?; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::ArtcraftKling21Pro(PlanArtcraftKling21Pro { - prompt: request.prompt.clone(), - start_frame, - end_frame, - aspect_ratio, - duration, - idempotency_token: request.get_or_generate_idempotency_token(), - })) -} - -fn resolve_end_frame( - image_ref: Option, -) -> Result, ArtcraftRouterError> { - match image_ref { - None => Ok(None), - Some(ImageRef::MediaFileToken(t)) => Ok(Some(t)), - Some(ImageRef::Url(_)) => { - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - } -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use GenerateKling21ProAspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Ar::Square)), - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::WideSixteenNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::TallNineSixteen)), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::WideSixteenNine)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(nearest_aspect_ratio(unsupported))), - }, - } -} - -fn nearest_aspect_ratio(ar: CommonAspectRatio) -> GenerateKling21ProAspectRatio { - use GenerateKling21ProAspectRatio as Ar; - match ar { - CommonAspectRatio::WideFourByThree - | CommonAspectRatio::WideFiveByFour - | CommonAspectRatio::WideThreeByTwo - | CommonAspectRatio::WideTwentyOneByNine => Ar::WideSixteenNine, - CommonAspectRatio::TallThreeByFour - | CommonAspectRatio::TallFourByFive - | CommonAspectRatio::TallTwoByThree - | CommonAspectRatio::TallNineByTwentyOne => Ar::TallNineSixteen, - _ => Ar::Square, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use GenerateKling21ProDuration as D; - match duration_seconds { - None => Ok(None), - Some(5) => Ok(Some(D::FiveSeconds)), - Some(10) => Ok(Some(D::TenSeconds)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::TenSeconds)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::FiveSeconds)), - }, - } -} - -impl PlanArtcraftKling21Pro { - pub fn is_ten_seconds(&self) -> bool { - matches!(self.duration, Some(GenerateKling21ProDuration::TenSeconds)) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling_2_5_turbo_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling_2_5_turbo_pro.rs deleted file mode 100644 index 7c5f16042a..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling_2_5_turbo_pro.rs +++ /dev/null @@ -1,127 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::multi_function::kling_2_5_turbo_multi_function_video_gen::{ - Kling2p5TurboProMultiFunctionVideoGenAspectRatio, Kling2p5TurboProMultiFunctionVideoGenDuration, -}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Debug, Clone)] -pub struct PlanArtcraftKling2p5TurboPro { - pub prompt: Option, - pub negative_prompt: Option, - pub start_frame: Option, - pub end_frame: Option, - pub aspect_ratio: Option, - pub duration: Option, - pub idempotency_token: String, -} - -pub fn plan_generate_video_artcraft_kling_2_5_turbo_pro( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = resolve_image_ref(request.start_frame.clone())?; - let end_frame = resolve_image_ref(request.end_frame.clone())?; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::ArtcraftKling2p5TurboPro(PlanArtcraftKling2p5TurboPro { - prompt: request.prompt.clone(), - negative_prompt: request.negative_prompt.clone(), - start_frame, - end_frame, - aspect_ratio, - duration, - idempotency_token: request.get_or_generate_idempotency_token(), - })) -} - -fn resolve_image_ref( - image_ref: Option, -) -> Result, ArtcraftRouterError> { - match image_ref { - None => Ok(None), - Some(ImageRef::MediaFileToken(t)) => Ok(Some(t)), - Some(ImageRef::Url(_)) => { - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - } -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use Kling2p5TurboProMultiFunctionVideoGenAspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Ar::Square)), - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::SixteenByNine)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(nearest_aspect_ratio(unsupported))), - }, - } -} - -fn nearest_aspect_ratio(ar: CommonAspectRatio) -> Kling2p5TurboProMultiFunctionVideoGenAspectRatio { - use Kling2p5TurboProMultiFunctionVideoGenAspectRatio as Ar; - match ar { - CommonAspectRatio::WideFourByThree - | CommonAspectRatio::WideFiveByFour - | CommonAspectRatio::WideThreeByTwo - | CommonAspectRatio::WideTwentyOneByNine => Ar::SixteenByNine, - CommonAspectRatio::TallThreeByFour - | CommonAspectRatio::TallFourByFive - | CommonAspectRatio::TallTwoByThree - | CommonAspectRatio::TallNineByTwentyOne => Ar::NineBySixteen, - _ => Ar::Square, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use Kling2p5TurboProMultiFunctionVideoGenDuration as D; - match duration_seconds { - None => Ok(None), - Some(5) => Ok(Some(D::FiveSeconds)), - Some(10) => Ok(Some(D::TenSeconds)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::TenSeconds)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::FiveSeconds)), - }, - } -} - -impl PlanArtcraftKling2p5TurboPro { - pub fn is_ten_seconds(&self) -> bool { - matches!(self.duration, Some(Kling2p5TurboProMultiFunctionVideoGenDuration::TenSeconds)) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling_2_6_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling_2_6_pro.rs deleted file mode 100644 index b123d97411..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_kling_2_6_pro.rs +++ /dev/null @@ -1,133 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::multi_function::kling_2_6_multi_function_video_gen::{ - Kling2p6ProMultiFunctionVideoGenAspectRatio, Kling2p6ProMultiFunctionVideoGenDuration, -}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Debug, Clone)] -pub struct PlanArtcraftKling2p6Pro { - pub prompt: Option, - pub negative_prompt: Option, - pub start_frame: Option, - pub aspect_ratio: Option, - pub duration: Option, - pub generate_audio: Option, - pub idempotency_token: String, -} - -pub fn plan_generate_video_artcraft_kling_2_6_pro( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = match request.start_frame.clone() { - None => None, - Some(ImageRef::MediaFileToken(t)) => Some(t), - Some(ImageRef::Url(_)) => { - return Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - }; - - if request.end_frame.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "end_frame", - value: "Kling 2.6 Pro does not support an ending frame".to_string(), - })); - } - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::ArtcraftKling2p6Pro(PlanArtcraftKling2p6Pro { - prompt: request.prompt.clone(), - negative_prompt: request.negative_prompt.clone(), - start_frame, - aspect_ratio, - duration, - generate_audio: request.generate_audio, - idempotency_token: request.get_or_generate_idempotency_token(), - })) -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use Kling2p6ProMultiFunctionVideoGenAspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Ar::Square)), - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::SixteenByNine)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(nearest_aspect_ratio(unsupported))), - }, - } -} - -fn nearest_aspect_ratio(ar: CommonAspectRatio) -> Kling2p6ProMultiFunctionVideoGenAspectRatio { - use Kling2p6ProMultiFunctionVideoGenAspectRatio as Ar; - match ar { - CommonAspectRatio::WideFourByThree - | CommonAspectRatio::WideFiveByFour - | CommonAspectRatio::WideThreeByTwo - | CommonAspectRatio::WideTwentyOneByNine => Ar::SixteenByNine, - CommonAspectRatio::TallThreeByFour - | CommonAspectRatio::TallFourByFive - | CommonAspectRatio::TallTwoByThree - | CommonAspectRatio::TallNineByTwentyOne => Ar::NineBySixteen, - _ => Ar::Square, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use Kling2p6ProMultiFunctionVideoGenDuration as D; - match duration_seconds { - None => Ok(None), - Some(5) => Ok(Some(D::FiveSeconds)), - Some(10) => Ok(Some(D::TenSeconds)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::TenSeconds)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::FiveSeconds)), - }, - } -} - -impl PlanArtcraftKling2p6Pro { - pub fn is_ten_seconds(&self) -> bool { - matches!(self.duration, Some(Kling2p6ProMultiFunctionVideoGenDuration::TenSeconds)) - } - - /// Legacy Kling 2.6 Pro generate handler forwards `request.generate_audio` as-is - /// to the Fal client, which defaults to `true`. - pub fn generate_audio_for_cost(&self) -> bool { - self.generate_audio.unwrap_or(true) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_seedance1p5_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_seedance1p5_pro.rs deleted file mode 100644 index f800e68b1a..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_seedance1p5_pro.rs +++ /dev/null @@ -1,294 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::multi_function::seedance_1p5_pro_multi_function_video_gen::{ - Seedance1p5ProMultiFunctionVideoGenAspectRatio, - Seedance1p5ProMultiFunctionVideoGenDuration, - Seedance1p5ProMultiFunctionVideoGenResolution, -}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Debug, Clone)] -pub struct PlanArtcraftSeedance1p5Pro { - pub prompt: Option, - pub start_frame: Option, - pub end_frame: Option, - pub aspect_ratio: Option, - pub duration: Option, - pub resolution: Option, - pub generate_audio: Option, - pub idempotency_token: String, -} - -pub fn plan_generate_video_artcraft_seedance1p5_pro( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = resolve_image_ref(request.start_frame.clone())?; - let end_frame = resolve_image_ref(request.end_frame.clone())?; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - let resolution = plan_resolution(request.resolution, strategy)?; - - Ok(VideoGenerationPlan::ArtcraftSeedance1p5Pro(PlanArtcraftSeedance1p5Pro { - prompt: request.prompt.clone(), - start_frame, - end_frame, - aspect_ratio, - duration, - resolution, - generate_audio: request.generate_audio, - idempotency_token: request.get_or_generate_idempotency_token(), - })) -} - -fn resolve_image_ref( - image_ref: Option, -) -> Result, ArtcraftRouterError> { - match image_ref { - None => Ok(None), - Some(ImageRef::MediaFileToken(t)) => Ok(Some(t)), - // Omni-gen distillation hydrates media tokens to URLs before running the - // Artcraft cost path. Cost doesn't depend on image content, so URL-form - // refs are accepted and dropped. - Some(ImageRef::Url(_)) => Ok(None), - } -} - -// Supported aspect ratios and their AR values (width / height): -// NineBySixteen = 0.5625, ThreeByFour = 0.75, Square = 1.0, FourByThree = 1.33, -// SixteenByNine = 1.78, TwentyOneByNine = 2.33, Auto = auto -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - match aspect_ratio { - None - | Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Seedance1p5ProMultiFunctionVideoGenAspectRatio::Auto)), - - // Direct mappings - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => { - Ok(Some(Seedance1p5ProMultiFunctionVideoGenAspectRatio::SixteenByNine)) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(Some(Seedance1p5ProMultiFunctionVideoGenAspectRatio::NineBySixteen)) - } - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => { - Ok(Some(Seedance1p5ProMultiFunctionVideoGenAspectRatio::Square)) - } - Some(CommonAspectRatio::WideFourByThree) => { - Ok(Some(Seedance1p5ProMultiFunctionVideoGenAspectRatio::FourByThree)) - } - Some(CommonAspectRatio::TallThreeByFour) => { - Ok(Some(Seedance1p5ProMultiFunctionVideoGenAspectRatio::ThreeByFour)) - } - Some(CommonAspectRatio::WideTwentyOneByNine) => { - Ok(Some(Seedance1p5ProMultiFunctionVideoGenAspectRatio::TwentyOneByNine)) - } - - // Mismatches — apply strategy - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade - | RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(Some(nearest_aspect_ratio(unsupported))) - } - }, - } -} - -fn nearest_aspect_ratio(aspect_ratio: CommonAspectRatio) -> Seedance1p5ProMultiFunctionVideoGenAspectRatio { - match aspect_ratio { - CommonAspectRatio::WideFiveByFour => Seedance1p5ProMultiFunctionVideoGenAspectRatio::FourByThree, // 1.25, nearest 1.33 - CommonAspectRatio::WideThreeByTwo => Seedance1p5ProMultiFunctionVideoGenAspectRatio::FourByThree, // 1.50, nearest 1.33 - CommonAspectRatio::TallFourByFive => Seedance1p5ProMultiFunctionVideoGenAspectRatio::ThreeByFour, // 0.80, nearest 0.75 - CommonAspectRatio::TallTwoByThree => Seedance1p5ProMultiFunctionVideoGenAspectRatio::ThreeByFour, // 0.67, nearest 0.75 - CommonAspectRatio::TallNineByTwentyOne => Seedance1p5ProMultiFunctionVideoGenAspectRatio::NineBySixteen, // 0.43, nearest 0.56 - _ => Seedance1p5ProMultiFunctionVideoGenAspectRatio::Square, - } -} - -// Seedance 1.5 Pro supports durations of 4–12 seconds. -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - const MIN: u16 = 4; - const MAX: u16 = 12; - match duration_seconds { - None => Ok(None), - Some(d) if d >= MIN && d <= MAX => Ok(Some(seconds_to_duration(d))), - Some(d) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", d), - })) - } - _ => Ok(Some(seconds_to_duration(d.clamp(MIN, MAX)))), - }, - } -} - -fn seconds_to_duration(seconds: u16) -> Seedance1p5ProMultiFunctionVideoGenDuration { - match seconds { - 4 => Seedance1p5ProMultiFunctionVideoGenDuration::FourSeconds, - 5 => Seedance1p5ProMultiFunctionVideoGenDuration::FiveSeconds, - 6 => Seedance1p5ProMultiFunctionVideoGenDuration::SixSeconds, - 7 => Seedance1p5ProMultiFunctionVideoGenDuration::SevenSeconds, - 8 => Seedance1p5ProMultiFunctionVideoGenDuration::EightSeconds, - 9 => Seedance1p5ProMultiFunctionVideoGenDuration::NineSeconds, - 10 => Seedance1p5ProMultiFunctionVideoGenDuration::TenSeconds, - 11 => Seedance1p5ProMultiFunctionVideoGenDuration::ElevenSeconds, - _ => Seedance1p5ProMultiFunctionVideoGenDuration::TwelveSeconds, - } -} - -fn plan_resolution( - resolution: Option, - _strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use crate::api::common_resolution::CommonResolution; - match resolution { - None => Ok(None), - Some(CommonResolution::OneK) => Ok(Some(Seedance1p5ProMultiFunctionVideoGenResolution::SevenTwentyP)), - Some(CommonResolution::TwoK) => Ok(Some(Seedance1p5ProMultiFunctionVideoGenResolution::TenEightyP)), - Some(CommonResolution::ThreeK) => Ok(Some(Seedance1p5ProMultiFunctionVideoGenResolution::TenEightyP)), - Some(CommonResolution::FourK) => Ok(Some(Seedance1p5ProMultiFunctionVideoGenResolution::TenEightyP)), - // HalfK and FourEightyP map to the lowest supported resolution - Some(CommonResolution::HalfK | CommonResolution::FourEightyP) => Ok(Some(Seedance1p5ProMultiFunctionVideoGenResolution::FourEightyP)), - Some(CommonResolution::SevenTwentyP) => Ok(Some(Seedance1p5ProMultiFunctionVideoGenResolution::SevenTwentyP)), - Some(CommonResolution::TenEightyP) => Ok(Some(Seedance1p5ProMultiFunctionVideoGenResolution::TenEightyP)), - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::api::common_aspect_ratio::CommonAspectRatio; - use crate::api::common_video_model::CommonVideoModel; - use crate::api::image_ref::ImageRef; - use crate::api::provider::Provider; - use crate::errors::artcraft_router_error::ArtcraftRouterError; - use crate::errors::client_error::ClientError; - use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; - use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; - - fn base_seedance_1p5_pro_request() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Seedance1p5Pro, - provider: Provider::Artcraft, - prompt: Some("a cat in space".to_string()), - negative_prompt: None, - start_frame: None, - end_frame: None, - reference_images: None, - reference_videos: None, - reference_audio: None, - reference_character_tokens: None, - resolution: None, - aspect_ratio: None, - duration_seconds: None, - video_batch_count: None, - generate_audio: None, - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut, - idempotency_token: None, - } - } - - #[test] - fn aspect_ratio_direct_16x9() { - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine), - ..base_seedance_1p5_pro_request() - }; - let VideoGenerationPlan::ArtcraftSeedance1p5Pro(plan) = request.build().unwrap() else { panic!("wrong variant") }; - assert!(matches!(plan.aspect_ratio, Some(Seedance1p5ProMultiFunctionVideoGenAspectRatio::SixteenByNine))); - } - - #[test] - fn aspect_ratio_direct_9x16() { - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::TallNineBySixteen), - ..base_seedance_1p5_pro_request() - }; - let VideoGenerationPlan::ArtcraftSeedance1p5Pro(plan) = request.build().unwrap() else { panic!("wrong variant") }; - assert!(matches!(plan.aspect_ratio, Some(Seedance1p5ProMultiFunctionVideoGenAspectRatio::NineBySixteen))); - } - - #[test] - fn aspect_ratio_direct_21x9() { - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::WideTwentyOneByNine), - ..base_seedance_1p5_pro_request() - }; - let VideoGenerationPlan::ArtcraftSeedance1p5Pro(plan) = request.build().unwrap() else { panic!("wrong variant") }; - assert!(matches!(plan.aspect_ratio, Some(Seedance1p5ProMultiFunctionVideoGenAspectRatio::TwentyOneByNine))); - } - - #[test] - fn aspect_ratio_error_out_on_unsupported() { - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::WideThreeByTwo), - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut, - ..base_seedance_1p5_pro_request() - }; - let result = request.build(); - assert!(matches!( - result, - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { .. })) - )); - } - - #[test] - fn duration_valid_range() { - for d in 4..=12 { - let request = GenerateVideoRequestBuilder { - duration_seconds: Some(d), - ..base_seedance_1p5_pro_request() - }; - let result = request.build(); - assert!(result.is_ok(), "duration {} should be valid", d); - } - } - - #[test] - fn duration_out_of_range_error_out() { - let request = GenerateVideoRequestBuilder { - duration_seconds: Some(13), - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut, - ..base_seedance_1p5_pro_request() - }; - let result = request.build(); - assert!(matches!( - result, - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { .. })) - )); - } - - #[test] - fn url_image_ref_accepted_for_cost_path() { - let request = GenerateVideoRequestBuilder { - start_frame: Some(ImageRef::Url("https://example.com/image.jpg".to_string())), - ..base_seedance_1p5_pro_request() - }; - let VideoGenerationPlan::ArtcraftSeedance1p5Pro(plan) = request.build().unwrap() else { - panic!("expected ArtcraftSeedance1p5Pro") - }; - // URL is dropped; start_frame resolves to None on the artcraft plan. - assert!(plan.start_frame.is_none()); - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_seedance2p0.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_seedance2p0.rs deleted file mode 100644 index b240f52491..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_seedance2p0.rs +++ /dev/null @@ -1,420 +0,0 @@ -use crate::api::audio_list_ref::AudioListRef; -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -use crate::api::image_list_ref::ImageListRef; -use crate::api::image_ref::ImageRef; -use crate::api::video_list_ref::VideoListRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::multi_function::seedance_2p0_multi_function_video_gen::{ - Seedance2p0AspectRatio, Seedance2p0BatchCount, -}; -use tokens::tokens::characters::CharacterToken; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Debug, Clone)] -pub struct PlanArtcraftSeedance2p0 { - pub prompt: Option, - pub start_frame: Option, - pub end_frame: Option, - pub reference_images: Option>, - pub reference_videos: Option>, - pub reference_audio: Option>, - pub reference_characters: Option>, - pub aspect_ratio: Option, - pub resolution: Option, - pub duration_seconds: Option, - pub batch_count: Seedance2p0BatchCount, - pub idempotency_token: String, -} - -pub fn plan_generate_video_artcraft_seedance2p0( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = resolve_image_ref(request.start_frame.clone())?; - let end_frame = resolve_image_ref(request.end_frame.clone())?; - let reference_images = resolve_image_list_ref(request.reference_images.clone())?; - let reference_videos = resolve_video_list_ref(request.reference_videos.clone())?; - let reference_audio = resolve_audio_list_ref(request.reference_audio.clone())?; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let resolution = plan_output_resolution(request.resolution, strategy)?; - let batch_count = plan_batch_count(request.video_batch_count, strategy)?; - let duration_seconds = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::ArtcraftSeedance2p0(PlanArtcraftSeedance2p0 { - prompt: request.prompt.clone(), - start_frame, - end_frame, - reference_images, - reference_videos, - reference_audio, - reference_characters: resolve_character_list_ref(request.reference_character_tokens.clone()), - aspect_ratio, - resolution, - duration_seconds, - batch_count, - idempotency_token: request.get_or_generate_idempotency_token(), - })) -} - -fn resolve_character_list_ref( - character_list_ref: Option, -) -> Option> { - match character_list_ref { - None => None, - Some(crate::api::character_list_ref::CharacterListRef::CharacterTokens(tokens)) => Some(tokens), - } -} - -fn resolve_image_ref( - image_ref: Option, -) -> Result, ArtcraftRouterError> { - match image_ref { - None => Ok(None), - Some(ImageRef::MediaFileToken(t)) => Ok(Some(t)), - Some(ImageRef::Url(_)) => { - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - } -} - -fn resolve_image_list_ref( - image_list_ref: Option, -) -> Result>, ArtcraftRouterError> { - match image_list_ref { - None => Ok(None), - Some(ImageListRef::MediaFileTokens(tokens)) => Ok(Some(tokens)), - Some(ImageListRef::Urls(_)) => { - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - } -} - -fn resolve_video_list_ref( - video_list_ref: Option, -) -> Result>, ArtcraftRouterError> { - match video_list_ref { - None => Ok(None), - Some(VideoListRef::MediaFileTokens(tokens)) => Ok(Some(tokens)), - Some(VideoListRef::Urls(_)) => { - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - } -} - -fn resolve_audio_list_ref( - audio_list_ref: Option, -) -> Result>, ArtcraftRouterError> { - match audio_list_ref { - None => Ok(None), - Some(AudioListRef::MediaFileTokens(tokens)) => Ok(Some(tokens)), - Some(AudioListRef::Urls(_)) => { - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - } -} - -// Supported aspect ratios and their AR values (width / height): -// Portrait9x16 = 0.5625, Portrait3x4 = 0.75, Square1x1 = 1.0, Standard4x3 = 1.33, Landscape16x9 = 1.78 -// -// All supported ratios cost the same, so PayMoreUpgrade and PayLessDowngrade both -// select the nearest match rather than rounding in a specific direction. -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - match aspect_ratio { - // No preference or auto — let the model decide - None - | Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(None), - - // Direct mappings - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => { - Ok(Some(Seedance2p0AspectRatio::Landscape16x9)) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(Some(Seedance2p0AspectRatio::Portrait9x16)) - } - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => { - Ok(Some(Seedance2p0AspectRatio::Square1x1)) - } - Some(CommonAspectRatio::WideFourByThree) => Ok(Some(Seedance2p0AspectRatio::Standard4x3)), - Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(Seedance2p0AspectRatio::Portrait3x4)), - - // Mismatches — apply strategy - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade - | RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(Some(nearest_aspect_ratio(unsupported))) - } - }, - } -} - -/// Pick the nearest supported aspect ratio by AR value (width / height). -/// All Seedance2p0 aspect ratios cost the same, so this is used for both upgrade and downgrade. -fn nearest_aspect_ratio(aspect_ratio: CommonAspectRatio) -> Seedance2p0AspectRatio { - match aspect_ratio { - CommonAspectRatio::WideFiveByFour => Seedance2p0AspectRatio::Standard4x3, // 1.25, nearest 1.33 - CommonAspectRatio::WideThreeByTwo => Seedance2p0AspectRatio::Standard4x3, // 1.50, nearest 1.33 - CommonAspectRatio::WideTwentyOneByNine => Seedance2p0AspectRatio::Landscape16x9, // 2.33, nearest 1.78 - CommonAspectRatio::TallFourByFive => Seedance2p0AspectRatio::Portrait3x4, // 0.80, nearest 0.75 - CommonAspectRatio::TallTwoByThree => Seedance2p0AspectRatio::Portrait3x4, // 0.67, nearest 0.75 - CommonAspectRatio::TallNineByTwentyOne => Seedance2p0AspectRatio::Portrait9x16, // 0.43, nearest 0.56 - _ => Seedance2p0AspectRatio::Square1x1, - } -} - -// Seedance2p0 supports batch counts of 1, 2, and 4 only. -fn plan_batch_count( - video_batch_count: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - let count = video_batch_count.unwrap_or(1); - match count { - 0 => Err(ArtcraftRouterError::Client(ClientError::UserRequestedZeroGenerations)), - 1 => Ok(Seedance2p0BatchCount::One), - 2 => Ok(Seedance2p0BatchCount::Two), - 4 => Ok(Seedance2p0BatchCount::Four), - _ => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "video_batch_count", - value: format!("{}", count), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => { - // Round up: 3 → Four; anything > 4 clamps to Four - Ok(if count < 4 { Seedance2p0BatchCount::Four } else { Seedance2p0BatchCount::Four }) - } - RequestMismatchMitigationStrategy::PayLessDowngrade => { - // Round down: 3 → Two; anything > 4 clamps to Four (max available) - Ok(if count < 4 { Seedance2p0BatchCount::Two } else { Seedance2p0BatchCount::Four }) - } - }, - } -} - -// Seedance2p0 supports duration of 4–15 seconds. - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - const MIN: u16 = 4; - const MAX: u16 = 15; - match duration_seconds { - None => Ok(None), - Some(d) if d >= MIN && d <= MAX => Ok(Some(d as u8)), - Some(d) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", d), - })) - } - _ => Ok(Some(d.clamp(MIN, MAX) as u8)), - }, - } -} - -// Seedance 2.0 Pro supports output resolutions: 480p, 720p, 1080p. -fn plan_output_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - match resolution { - None => Ok(None), - - // Direct mappings - Some(CommonResolution::FourEightyP) - | Some(CommonResolution::SevenTwentyP) - | Some(CommonResolution::TenEightyP) => Ok(resolution), - - // Mismatches - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => { - // HalfK → 480p (up); OneK/TwoK/ThreeK/FourK → 1080p (max) - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolution::FourEightyP, - _ => CommonResolution::TenEightyP, - })) - } - RequestMismatchMitigationStrategy::PayLessDowngrade => { - // HalfK → 480p (min); OneK/TwoK/ThreeK/FourK → 1080p (closest below) - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolution::FourEightyP, - _ => CommonResolution::TenEightyP, - })) - } - }, - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::api::common_aspect_ratio::CommonAspectRatio; - use crate::api::image_ref::ImageRef; - use crate::errors::artcraft_router_error::ArtcraftRouterError; - use crate::errors::client_error::ClientError; - use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; - use crate::test_helpers::base_video_request; - use artcraft_api_defs::generate::video::multi_function::seedance_2p0_multi_function_video_gen::{ - Seedance2p0AspectRatio, Seedance2p0BatchCount, - }; - - #[test] - fn aspect_ratio_direct_16x9() { - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine), - ..base_video_request() - }; - let VideoGenerationPlan::ArtcraftSeedance2p0(plan) = request.build().unwrap() else { panic!("wrong variant") }; - assert!(matches!(plan.aspect_ratio, Some(Seedance2p0AspectRatio::Landscape16x9))); - } - - #[test] - fn aspect_ratio_direct_9x16() { - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::TallNineBySixteen), - ..base_video_request() - }; - let VideoGenerationPlan::ArtcraftSeedance2p0(plan) = request.build().unwrap() else { panic!("wrong variant") }; - assert!(matches!(plan.aspect_ratio, Some(Seedance2p0AspectRatio::Portrait9x16))); - } - - #[test] - fn aspect_ratio_direct_square() { - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::Square), - ..base_video_request() - }; - let VideoGenerationPlan::ArtcraftSeedance2p0(plan) = request.build().unwrap() else { panic!("wrong variant") }; - assert!(matches!(plan.aspect_ratio, Some(Seedance2p0AspectRatio::Square1x1))); - } - - #[test] - fn aspect_ratio_nearest_match_both_strategies() { - // WideThreeByTwo (AR 1.5) is nearest to Standard4x3 (1.33), not Landscape16x9 (1.78) - for strategy in [ - RequestMismatchMitigationStrategy::PayMoreUpgrade, - RequestMismatchMitigationStrategy::PayLessDowngrade, - ] { - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::WideThreeByTwo), - request_mismatch_mitigation_strategy: strategy, - ..base_video_request() - }; - let VideoGenerationPlan::ArtcraftSeedance2p0(plan) = request.build().unwrap() else { panic!("wrong variant") }; - assert!( - matches!(plan.aspect_ratio, Some(Seedance2p0AspectRatio::Standard4x3)), - "Expected Standard4x3 for WideThreeByTwo with {:?}", strategy, - ); - } - } - - #[test] - fn aspect_ratio_error_out_on_unsupported() { - let request = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::WideThreeByTwo), - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut, - ..base_video_request() - }; - let result = request.build(); - assert!(matches!( - result, - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { .. })) - )); - } - - #[test] - fn batch_count_zero_is_always_error() { - for strategy in [ - RequestMismatchMitigationStrategy::ErrorOut, - RequestMismatchMitigationStrategy::PayMoreUpgrade, - RequestMismatchMitigationStrategy::PayLessDowngrade, - ] { - let request = GenerateVideoRequestBuilder { - video_batch_count: Some(0), - request_mismatch_mitigation_strategy: strategy, - ..base_video_request() - }; - let result = request.build(); - assert!( - matches!(result, Err(ArtcraftRouterError::Client(ClientError::UserRequestedZeroGenerations))), - "Expected UserRequestedZeroGenerations with {:?}", strategy, - ); - } - } - - #[test] - fn batch_count_direct_mapping() { - let req = GenerateVideoRequestBuilder { video_batch_count: Some(1), ..base_video_request() }; - let VideoGenerationPlan::ArtcraftSeedance2p0(plan) = req.build().unwrap() else { panic!("wrong variant") }; - assert!(matches!(plan.batch_count, Seedance2p0BatchCount::One)); - - let req = GenerateVideoRequestBuilder { video_batch_count: Some(2), ..base_video_request() }; - let VideoGenerationPlan::ArtcraftSeedance2p0(plan) = req.build().unwrap() else { panic!("wrong variant") }; - assert!(matches!(plan.batch_count, Seedance2p0BatchCount::Two)); - - let req = GenerateVideoRequestBuilder { video_batch_count: Some(4), ..base_video_request() }; - let VideoGenerationPlan::ArtcraftSeedance2p0(plan) = req.build().unwrap() else { panic!("wrong variant") }; - assert!(matches!(plan.batch_count, Seedance2p0BatchCount::Four)); - } - - #[test] - fn batch_count_three_upgrade_rounds_to_four() { - let request = GenerateVideoRequestBuilder { - video_batch_count: Some(3), - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade, - ..base_video_request() - }; - let VideoGenerationPlan::ArtcraftSeedance2p0(plan) = request.build().unwrap() else { panic!("wrong variant") }; - assert!(matches!(plan.batch_count, Seedance2p0BatchCount::Four)); - } - - #[test] - fn batch_count_three_downgrade_rounds_to_two() { - let request = GenerateVideoRequestBuilder { - video_batch_count: Some(3), - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayLessDowngrade, - ..base_video_request() - }; - let VideoGenerationPlan::ArtcraftSeedance2p0(plan) = request.build().unwrap() else { panic!("wrong variant") }; - assert!(matches!(plan.batch_count, Seedance2p0BatchCount::Two)); - } - - #[test] - fn url_image_ref_returns_error() { - let request = GenerateVideoRequestBuilder { - start_frame: Some(ImageRef::Url("https://example.com/image.jpg".to_string())), - ..base_video_request() - }; - let result = request.build(); - assert!(matches!( - result, - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - )); - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_seedance2p0_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_seedance2p0_fast.rs deleted file mode 100644 index ccaf40759b..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_seedance2p0_fast.rs +++ /dev/null @@ -1,380 +0,0 @@ -use crate::api::audio_list_ref::AudioListRef; -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -use crate::api::image_list_ref::ImageListRef; -use crate::api::image_ref::ImageRef; -use crate::api::video_list_ref::VideoListRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance2p0::PlanArtcraftSeedance2p0; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::multi_function::seedance_2p0_multi_function_video_gen::{ - Seedance2p0AspectRatio, Seedance2p0BatchCount, -}; -use tokens::tokens::characters::CharacterToken; -use tokens::tokens::media_files::MediaFileToken; - -pub fn plan_generate_video_artcraft_seedance2p0_fast( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = resolve_image_ref(request.start_frame.clone())?; - let end_frame = resolve_image_ref(request.end_frame.clone())?; - let reference_images = resolve_image_list_ref(request.reference_images.clone())?; - let reference_videos = resolve_video_list_ref(request.reference_videos.clone())?; - let reference_audio = resolve_audio_list_ref(request.reference_audio.clone())?; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let resolution = plan_output_resolution(request.resolution, strategy)?; - let batch_count = plan_batch_count(request.video_batch_count, strategy)?; - let duration_seconds = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::ArtcraftSeedance2p0Fast(PlanArtcraftSeedance2p0 { - prompt: request.prompt.clone(), - start_frame, - end_frame, - reference_images, - reference_videos, - reference_audio, - reference_characters: resolve_character_list_ref(request.reference_character_tokens.clone()), - aspect_ratio, - resolution, - duration_seconds, - batch_count, - idempotency_token: request.get_or_generate_idempotency_token(), - })) -} - -fn resolve_character_list_ref( - character_list_ref: Option, -) -> Option> { - match character_list_ref { - None => None, - Some(crate::api::character_list_ref::CharacterListRef::CharacterTokens(tokens)) => Some(tokens), - } -} - -fn resolve_image_ref( - image_ref: Option, -) -> Result, ArtcraftRouterError> { - match image_ref { - None => Ok(None), - Some(ImageRef::MediaFileToken(t)) => Ok(Some(t)), - Some(ImageRef::Url(_)) => { - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - } -} - -fn resolve_image_list_ref( - image_list_ref: Option, -) -> Result>, ArtcraftRouterError> { - match image_list_ref { - None => Ok(None), - Some(ImageListRef::MediaFileTokens(tokens)) => Ok(Some(tokens)), - Some(ImageListRef::Urls(_)) => { - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - } -} - -fn resolve_video_list_ref( - video_list_ref: Option, -) -> Result>, ArtcraftRouterError> { - match video_list_ref { - None => Ok(None), - Some(VideoListRef::MediaFileTokens(tokens)) => Ok(Some(tokens)), - Some(VideoListRef::Urls(_)) => { - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - } -} - -fn resolve_audio_list_ref( - audio_list_ref: Option, -) -> Result>, ArtcraftRouterError> { - match audio_list_ref { - None => Ok(None), - Some(AudioListRef::MediaFileTokens(tokens)) => Ok(Some(tokens)), - Some(AudioListRef::Urls(_)) => { - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - } -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - match aspect_ratio { - None - | Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(None), - - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => { - Ok(Some(Seedance2p0AspectRatio::Landscape16x9)) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(Some(Seedance2p0AspectRatio::Portrait9x16)) - } - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => { - Ok(Some(Seedance2p0AspectRatio::Square1x1)) - } - Some(CommonAspectRatio::WideFourByThree) => Ok(Some(Seedance2p0AspectRatio::Standard4x3)), - Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(Seedance2p0AspectRatio::Portrait3x4)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade - | RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(Some(nearest_aspect_ratio(unsupported))) - } - }, - } -} - -fn nearest_aspect_ratio(aspect_ratio: CommonAspectRatio) -> Seedance2p0AspectRatio { - match aspect_ratio { - CommonAspectRatio::WideFiveByFour => Seedance2p0AspectRatio::Standard4x3, - CommonAspectRatio::WideThreeByTwo => Seedance2p0AspectRatio::Standard4x3, - CommonAspectRatio::WideTwentyOneByNine => Seedance2p0AspectRatio::Landscape16x9, - CommonAspectRatio::TallFourByFive => Seedance2p0AspectRatio::Portrait3x4, - CommonAspectRatio::TallTwoByThree => Seedance2p0AspectRatio::Portrait3x4, - CommonAspectRatio::TallNineByTwentyOne => Seedance2p0AspectRatio::Portrait9x16, - _ => Seedance2p0AspectRatio::Square1x1, - } -} - -fn plan_batch_count( - video_batch_count: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - let count = video_batch_count.unwrap_or(1); - match count { - 0 => Err(ArtcraftRouterError::Client(ClientError::UserRequestedZeroGenerations)), - 1 => Ok(Seedance2p0BatchCount::One), - 2 => Ok(Seedance2p0BatchCount::Two), - 4 => Ok(Seedance2p0BatchCount::Four), - _ => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "video_batch_count", - value: format!("{}", count), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => { - Ok(if count < 4 { Seedance2p0BatchCount::Four } else { Seedance2p0BatchCount::Four }) - } - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(if count < 4 { Seedance2p0BatchCount::Two } else { Seedance2p0BatchCount::Four }) - } - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - const MIN: u16 = 4; - const MAX: u16 = 15; - match duration_seconds { - None => Ok(None), - Some(d) if d >= MIN && d <= MAX => Ok(Some(d as u8)), - Some(d) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", d), - })) - } - _ => Ok(Some(d.clamp(MIN, MAX) as u8)), - }, - } -} - -// Seedance 2.0 Fast supports output resolutions: 480p and 720p only. -fn plan_output_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - match resolution { - None => Ok(None), - - // Direct mappings - Some(CommonResolution::FourEightyP) - | Some(CommonResolution::SevenTwentyP) => Ok(resolution), - - // Mismatches - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => { - // HalfK → 480p (up); TenEightyP/OneK+ → 720p (max) - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolution::FourEightyP, - _ => CommonResolution::SevenTwentyP, - })) - } - RequestMismatchMitigationStrategy::PayLessDowngrade => { - // HalfK → 480p (min); TenEightyP/OneK+ → 720p (closest below) - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolution::FourEightyP, - _ => CommonResolution::SevenTwentyP, - })) - } - }, - } -} - -#[cfg(test)] -mod tests { - use crate::api::common_aspect_ratio::CommonAspectRatio; - use crate::api::common_video_model::CommonVideoModel; - use crate::api::image_ref::ImageRef; - use crate::api::provider::Provider; - 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_video::generate_video_request_builder::GenerateVideoRequestBuilder; - use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; - use artcraft_api_defs::generate::video::multi_function::seedance_2p0_multi_function_video_gen::{ - Seedance2p0AspectRatio, Seedance2p0BatchCount, - }; - - fn base_request() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Seedance2p0Fast, - provider: Provider::Artcraft, - prompt: Some("a cat in space".to_string()), - negative_prompt: None, - start_frame: None, - end_frame: None, - reference_images: None, - reference_videos: None, - reference_audio: None, - reference_character_tokens: None, - resolution: None, - aspect_ratio: None, - duration_seconds: None, - video_batch_count: None, - generate_audio: None, - request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade, - idempotency_token: None, - } - } - - #[test] - fn produces_fast_variant() { - let req = base_request(); - let plan = req.build().unwrap(); - assert!(matches!(plan, VideoGenerationPlan::ArtcraftSeedance2p0Fast(_))); - } - - #[test] - fn prompt_is_passed_through() { - let req = base_request(); - let plan = req.build().unwrap(); - if let VideoGenerationPlan::ArtcraftSeedance2p0Fast(p) = plan { - assert_eq!(p.prompt, Some("a cat in space".to_string())); - } else { panic!("wrong variant"); } - } - - #[test] - fn aspect_ratio_16x9() { - let req = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::WideSixteenByNine), - ..base_request() - }; - let plan = req.build().unwrap(); - let VideoGenerationPlan::ArtcraftSeedance2p0Fast(p) = plan else { panic!("wrong variant") }; - assert!(matches!(p.aspect_ratio, Some(Seedance2p0AspectRatio::Landscape16x9))); - } - - #[test] - fn aspect_ratio_9x16() { - let req = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::TallNineBySixteen), - ..base_request() - }; - let plan = req.build().unwrap(); - let VideoGenerationPlan::ArtcraftSeedance2p0Fast(p) = plan else { panic!("wrong variant") }; - assert!(matches!(p.aspect_ratio, Some(Seedance2p0AspectRatio::Portrait9x16))); - } - - #[test] - fn aspect_ratio_square() { - let req = GenerateVideoRequestBuilder { - aspect_ratio: Some(CommonAspectRatio::Square), - ..base_request() - }; - let plan = req.build().unwrap(); - let VideoGenerationPlan::ArtcraftSeedance2p0Fast(p) = plan else { panic!("wrong variant") }; - assert!(matches!(p.aspect_ratio, Some(Seedance2p0AspectRatio::Square1x1))); - } - - #[test] - fn batch_count_defaults_to_one() { - let req = base_request(); - let plan = req.build().unwrap(); - let VideoGenerationPlan::ArtcraftSeedance2p0Fast(p) = plan else { panic!("wrong variant") }; - assert!(matches!(p.batch_count, Seedance2p0BatchCount::One)); - } - - #[test] - fn batch_count_2() { - let req = GenerateVideoRequestBuilder { video_batch_count: Some(2), ..base_request() }; - let plan = req.build().unwrap(); - let VideoGenerationPlan::ArtcraftSeedance2p0Fast(p) = plan else { panic!("wrong variant") }; - assert!(matches!(p.batch_count, Seedance2p0BatchCount::Two)); - } - - #[test] - fn batch_count_4() { - let req = GenerateVideoRequestBuilder { video_batch_count: Some(4), ..base_request() }; - let plan = req.build().unwrap(); - let VideoGenerationPlan::ArtcraftSeedance2p0Fast(p) = plan else { panic!("wrong variant") }; - assert!(matches!(p.batch_count, Seedance2p0BatchCount::Four)); - } - - #[test] - fn duration_in_range() { - let req = GenerateVideoRequestBuilder { duration_seconds: Some(10), ..base_request() }; - let plan = req.build().unwrap(); - let VideoGenerationPlan::ArtcraftSeedance2p0Fast(p) = plan else { panic!("wrong variant") }; - assert_eq!(p.duration_seconds, Some(10)); - } - - #[test] - fn duration_clamped_to_max() { - let req = GenerateVideoRequestBuilder { duration_seconds: Some(99), ..base_request() }; - let plan = req.build().unwrap(); - let VideoGenerationPlan::ArtcraftSeedance2p0Fast(p) = plan else { panic!("wrong variant") }; - assert_eq!(p.duration_seconds, Some(15)); - } - - #[test] - fn url_image_ref_returns_error() { - let req = GenerateVideoRequestBuilder { - start_frame: Some(ImageRef::Url("https://example.com/image.jpg".to_string())), - ..base_request() - }; - assert!(matches!( - req.build(), - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - )); - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_seedance_1_0_lite.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_seedance_1_0_lite.rs deleted file mode 100644 index 3b3ad01f7e..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_seedance_1_0_lite.rs +++ /dev/null @@ -1,161 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::generate_seedance_1_0_lite_image_to_video::{ - GenerateSeedance10LiteAspectRatio, GenerateSeedance10LiteDuration, - GenerateSeedance10LiteResolution, -}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Debug, Clone)] -pub struct PlanArtcraftSeedance10Lite { - pub prompt: Option, - pub start_frame: MediaFileToken, - pub end_frame: Option, - pub aspect_ratio: Option, - pub resolution: Option, - pub duration: Option, - pub idempotency_token: String, -} - -pub fn plan_generate_video_artcraft_seedance_1_0_lite( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = match request.start_frame.clone() { - Some(ImageRef::MediaFileToken(t)) => t, - Some(ImageRef::Url(_)) => { - return Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - None => { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "start_frame", - value: "Seedance 1.0 Lite requires a starting frame".to_string(), - })) - } - }; - let end_frame = resolve_end_frame(request.end_frame.clone())?; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let resolution = plan_resolution(request.resolution, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::ArtcraftSeedance10Lite(PlanArtcraftSeedance10Lite { - prompt: request.prompt.clone(), - start_frame, - end_frame, - aspect_ratio, - resolution, - duration, - idempotency_token: request.get_or_generate_idempotency_token(), - })) -} - -fn resolve_end_frame( - image_ref: Option, -) -> Result, ArtcraftRouterError> { - match image_ref { - None => Ok(None), - Some(ImageRef::MediaFileToken(t)) => Ok(Some(t)), - Some(ImageRef::Url(_)) => { - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - } -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use GenerateSeedance10LiteAspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::Auto)), - - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Ar::Square)), - Some(CommonAspectRatio::WideFourByThree) => Ok(Some(Ar::FourByThree)), - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)), - Some(CommonAspectRatio::WideTwentyOneByNine) => Ok(Some(Ar::TwentyOneByNine)), - Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(Ar::ThreeByFour)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(Ar::Auto)), - }, - } -} - -fn plan_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use GenerateSeedance10LiteResolution as R; - // Legacy endpoint exposes only 480p and 720p. - match resolution { - None => Ok(None), - Some(CommonResolution::FourEightyP) => Ok(Some(R::FourEightyP)), - Some(CommonResolution::SevenTwentyP) => Ok(Some(R::SevenTwentyP)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(R::SevenTwentyP)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(R::FourEightyP)), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use GenerateSeedance10LiteDuration as D; - match duration_seconds { - None => Ok(None), - Some(5) => Ok(Some(D::FiveSeconds)), - Some(10) => Ok(Some(D::TenSeconds)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::TenSeconds)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::FiveSeconds)), - }, - } -} - -impl PlanArtcraftSeedance10Lite { - /// Legacy handler default: 5 seconds. - pub fn duration_seconds_for_cost(&self) -> u64 { - match self.duration { - None | Some(GenerateSeedance10LiteDuration::FiveSeconds) => 5, - Some(GenerateSeedance10LiteDuration::TenSeconds) => 10, - } - } - - /// Legacy handler default: 720p. - pub fn resolution_for_cost(&self) -> GenerateSeedance10LiteResolution { - self.resolution.unwrap_or(GenerateSeedance10LiteResolution::SevenTwentyP) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_sora_2.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_sora_2.rs deleted file mode 100644 index 37f341d02b..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_sora_2.rs +++ /dev/null @@ -1,139 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::multi_function::sora_2_multi_function_video_gen::{ - Sora2MultiFunctionVideoGenAspectRatio, Sora2MultiFunctionVideoGenDuration, - Sora2MultiFunctionVideoGenResolution, -}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Debug, Clone)] -pub struct PlanArtcraftSora2 { - pub prompt: Option, - pub start_frame: Option, - pub aspect_ratio: Option, - pub resolution: Option, - pub duration: Option, - pub idempotency_token: String, -} - -pub fn plan_generate_video_artcraft_sora_2( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = match request.start_frame.clone() { - None => None, - Some(ImageRef::MediaFileToken(t)) => Some(t), - Some(ImageRef::Url(_)) => { - return Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - }; - - if request.end_frame.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "end_frame", - value: "Sora 2 does not support an ending frame".to_string(), - })); - } - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let resolution = plan_resolution(request.resolution, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::ArtcraftSora2(PlanArtcraftSora2 { - prompt: request.prompt.clone(), - start_frame, - aspect_ratio, - resolution, - duration, - idempotency_token: request.get_or_generate_idempotency_token(), - })) -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use Sora2MultiFunctionVideoGenAspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::Auto)), - - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(Ar::Auto)), - }, - } -} - -fn plan_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use Sora2MultiFunctionVideoGenResolution as R; - match resolution { - None => Ok(None), - Some(CommonResolution::SevenTwentyP) => Ok(Some(R::SevenTwentyP)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", other), - })) - } - _ => Ok(Some(R::SevenTwentyP)), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use Sora2MultiFunctionVideoGenDuration as D; - match duration_seconds { - None => Ok(None), - Some(4) => Ok(Some(D::FourSeconds)), - Some(8) => Ok(Some(D::EightSeconds)), - Some(12) => Ok(Some(D::TwelveSeconds)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::TwelveSeconds)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::FourSeconds)), - }, - } -} - -impl PlanArtcraftSora2 { - /// Fal client default: 4 seconds when None. - pub fn duration_seconds_for_cost(&self) -> u64 { - use Sora2MultiFunctionVideoGenDuration as D; - match self.duration { - None | Some(D::FourSeconds) => 4, - Some(D::EightSeconds) => 8, - Some(D::TwelveSeconds) => 12, - } - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_sora_2_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_sora_2_pro.rs deleted file mode 100644 index 59b99cb38b..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_sora_2_pro.rs +++ /dev/null @@ -1,151 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::multi_function::sora_2_pro_multi_function_video_gen::{ - Sora2ProMultiFunctionVideoGenAspectRatio, Sora2ProMultiFunctionVideoGenDuration, - Sora2ProMultiFunctionVideoGenResolution, -}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Debug, Clone)] -pub struct PlanArtcraftSora2Pro { - pub prompt: Option, - pub start_frame: Option, - pub aspect_ratio: Option, - pub resolution: Option, - pub duration: Option, - pub idempotency_token: String, -} - -pub fn plan_generate_video_artcraft_sora_2_pro( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = match request.start_frame.clone() { - None => None, - Some(ImageRef::MediaFileToken(t)) => Some(t), - Some(ImageRef::Url(_)) => { - return Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - }; - - if request.end_frame.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "end_frame", - value: "Sora 2 Pro does not support an ending frame".to_string(), - })); - } - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let resolution = plan_resolution(request.resolution, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::ArtcraftSora2Pro(PlanArtcraftSora2Pro { - prompt: request.prompt.clone(), - start_frame, - aspect_ratio, - resolution, - duration, - idempotency_token: request.get_or_generate_idempotency_token(), - })) -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use Sora2ProMultiFunctionVideoGenAspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::Auto)), - - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(Ar::Auto)), - }, - } -} - -fn plan_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use Sora2ProMultiFunctionVideoGenResolution as R; - match resolution { - None => Ok(None), - Some(CommonResolution::SevenTwentyP) => Ok(Some(R::SevenTwentyP)), - Some(CommonResolution::TenEightyP) => Ok(Some(R::TenEightyP)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(R::TenEightyP)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(R::SevenTwentyP)), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use Sora2ProMultiFunctionVideoGenDuration as D; - match duration_seconds { - None => Ok(None), - Some(4) => Ok(Some(D::FourSeconds)), - Some(8) => Ok(Some(D::EightSeconds)), - Some(12) => Ok(Some(D::TwelveSeconds)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::TwelveSeconds)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::FourSeconds)), - }, - } -} - -impl PlanArtcraftSora2Pro { - /// Fal client default: 4 seconds when None. - pub fn duration_seconds_for_cost(&self) -> u64 { - use Sora2ProMultiFunctionVideoGenDuration as D; - match self.duration { - None | Some(D::FourSeconds) => 4, - Some(D::EightSeconds) => 8, - Some(D::TwelveSeconds) => 12, - } - } - - /// Fal client defaults: text-to-video → 1080p; image-to-video → Auto (priced as 720p). - pub fn is_ten_eighty_p_for_cost(&self) -> bool { - use Sora2ProMultiFunctionVideoGenResolution as R; - match self.resolution { - Some(R::TenEightyP) => true, - Some(R::SevenTwentyP) | Some(R::Auto) => false, - None => self.start_frame.is_none(), - } - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_veo_2.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_veo_2.rs deleted file mode 100644 index 4fe85ed08b..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_veo_2.rs +++ /dev/null @@ -1,128 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::generate_veo_2_image_to_video::{ - GenerateVeo2AspectRatio, GenerateVeo2Duration, -}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Debug, Clone)] -pub struct PlanArtcraftVeo2 { - pub prompt: Option, - /// Required for execution. May be None on the cost path when the omni-gen - /// distillation hydrated the media token to a URL (which the Artcraft - /// provider can't use but cost estimation doesn't need). - pub start_frame: Option, - pub aspect_ratio: Option, - pub duration: Option, - pub idempotency_token: String, -} - -pub fn plan_generate_video_artcraft_veo_2( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = match request.start_frame.clone() { - Some(ImageRef::MediaFileToken(t)) => Some(t), - // Omni-gen distillation hydrates media tokens to URLs before running the - // Artcraft cost path. Cost only depends on duration, so URL-form refs are - // accepted and dropped. - Some(ImageRef::Url(_)) => None, - // No start_frame = text-to-video mode. - None => None, - }; - - if request.end_frame.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "end_frame", - value: "Veo 2 does not support an ending frame".to_string(), - })); - } - - // Aspect ratio only applies to text-to-video; image-to-video inherits - // the source frame's aspect ratio. - let is_image_mode = request.start_frame.is_some(); - let aspect_ratio = if is_image_mode { - None - } else { - plan_aspect_ratio(request.aspect_ratio, strategy)? - }; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::ArtcraftVeo2(PlanArtcraftVeo2 { - prompt: request.prompt.clone(), - start_frame, - aspect_ratio, - duration, - idempotency_token: request.get_or_generate_idempotency_token(), - })) -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use GenerateVeo2AspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::Auto)), - - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::WideSixteenNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::TallNineSixteen)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(Ar::Auto)), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use GenerateVeo2Duration as D; - match duration_seconds { - None => Ok(None), - Some(5) => Ok(Some(D::FiveSeconds)), - Some(6) => Ok(Some(D::SixSeconds)), - Some(7) => Ok(Some(D::SevenSeconds)), - Some(8) => Ok(Some(D::EightSeconds)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::EightSeconds)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::FiveSeconds)), - }, - } -} - -impl PlanArtcraftVeo2 { - /// Mirrors the Fal client's default-resolved duration used for billing. - pub fn duration_seconds_for_cost(&self) -> u64 { - match self.duration { - // Legacy generate handler defaults `None` to FiveSeconds. - None | Some(GenerateVeo2Duration::FiveSeconds) => 5, - Some(GenerateVeo2Duration::SixSeconds) => 6, - Some(GenerateVeo2Duration::SevenSeconds) => 7, - Some(GenerateVeo2Duration::EightSeconds) => 8, - } - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_veo_3.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_veo_3.rs deleted file mode 100644 index 1a13763ee1..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_veo_3.rs +++ /dev/null @@ -1,168 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::generate_veo_3_image_to_video::{ - GenerateVeo3AspectRatio, GenerateVeo3Duration, GenerateVeo3Resolution, -}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Debug, Clone)] -pub struct PlanArtcraftVeo3 { - pub prompt: Option, - /// Required for image-to-video. None for text-to-video or when the - /// omni-gen distillation hydrated the token to a URL. - pub start_frame: Option, - pub aspect_ratio: Option, - pub resolution: Option, - pub duration: Option, - /// The raw requested duration in seconds, preserved for cost estimation. - /// The `duration` field above maps everything to `EightSeconds` for the - /// legacy endpoint, but cost should reflect the actual requested value. - pub duration_seconds_raw: Option, - pub generate_audio: Option, - pub idempotency_token: String, -} - -pub fn plan_generate_video_artcraft_veo_3( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = match request.start_frame.clone() { - Some(ImageRef::MediaFileToken(t)) => Some(t), - // Omni-gen distillation hydrates media tokens to URLs before running the - // Artcraft cost path. Cost only depends on duration/audio, so URL-form - // refs are accepted and dropped. - Some(ImageRef::Url(_)) => None, - // No start_frame = text-to-video mode. - None => None, - }; - - if request.end_frame.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "end_frame", - value: "Veo 3 does not support an ending frame".to_string(), - })); - } - - // Aspect ratio only applies to text-to-video; image-to-video inherits - // the source frame's aspect ratio. - let is_image_mode = request.start_frame.is_some(); - let aspect_ratio = if is_image_mode { - None - } else { - plan_aspect_ratio(request.aspect_ratio, strategy)? - }; - let resolution = plan_resolution(request.resolution, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::ArtcraftVeo3(PlanArtcraftVeo3 { - prompt: request.prompt.clone(), - start_frame, - aspect_ratio, - resolution, - duration, - duration_seconds_raw: request.duration_seconds, - generate_audio: request.generate_audio, - idempotency_token: request.get_or_generate_idempotency_token(), - })) -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use GenerateVeo3AspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::WideSixteenNine)), - - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Ar::Square)), - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::WideSixteenNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::TallNineSixteen)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(Ar::WideSixteenNine)), - }, - } -} - -fn plan_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use GenerateVeo3Resolution as R; - match resolution { - None => Ok(None), - Some(CommonResolution::SevenTwentyP) => Ok(Some(R::SevenTwentyP)), - Some(CommonResolution::TenEightyP) => Ok(Some(R::TenEightyP)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(R::TenEightyP)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(R::SevenTwentyP)), - }, - } -} - -// The legacy storyteller endpoint for Veo 3 only exposes EightSeconds, but -// the artcraft plan stores the raw duration_seconds from the omni request so -// that cost estimation works for all supported durations (4/6/8). -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - match duration_seconds { - None => Ok(None), - // The api_defs enum only has EightSeconds; all durations map to it for - // the legacy endpoint. The actual seconds are tracked via - // `duration_seconds_raw` below for cost estimation. - Some(4) | Some(6) | Some(8) => Ok(Some(GenerateVeo3Duration::EightSeconds)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(GenerateVeo3Duration::EightSeconds)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(GenerateVeo3Duration::EightSeconds)), - }, - } -} - -impl PlanArtcraftVeo3 { - /// Duration in seconds for cost estimation. Uses the raw requested - /// duration, clamped to {4, 6, 8}, defaulting to 8s. - pub fn duration_seconds_for_cost(&self) -> u64 { - match self.duration_seconds_raw { - Some(s) if s <= 4 => 4, - Some(s) if s <= 6 => 6, - _ => 8, // None, 7, 8, or above → 8s - } - } - - /// Legacy Veo 3 generate handler defaults `generate_audio` to false. - /// The omni path defaults to true (matching the fal plan builder). - pub fn generate_audio_for_cost(&self) -> bool { - self.generate_audio.unwrap_or(false) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_veo_3_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_veo_3_fast.rs deleted file mode 100644 index b3e0c985a1..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_veo_3_fast.rs +++ /dev/null @@ -1,136 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::generate_veo_3_fast_image_to_video::{ - GenerateVeo3FastAspectRatio, GenerateVeo3FastDuration, GenerateVeo3FastResolution, -}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Debug, Clone)] -pub struct PlanArtcraftVeo3Fast { - pub prompt: Option, - pub start_frame: Option, - pub aspect_ratio: Option, - pub resolution: Option, - pub duration: Option, - pub generate_audio: Option, - pub idempotency_token: String, -} - -pub fn plan_generate_video_artcraft_veo_3_fast( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = match request.start_frame.clone() { - Some(ImageRef::MediaFileToken(t)) => Some(t), - Some(ImageRef::Url(_)) => None, - None => None, - }; - - if request.end_frame.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "end_frame", - value: "Veo 3 Fast does not support an ending frame".to_string(), - })); - } - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let resolution = plan_resolution(request.resolution, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::ArtcraftVeo3Fast(PlanArtcraftVeo3Fast { - prompt: request.prompt.clone(), - start_frame, - aspect_ratio, - resolution, - duration, - generate_audio: request.generate_audio, - idempotency_token: request.get_or_generate_idempotency_token(), - })) -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use GenerateVeo3FastAspectRatio as Ar; - match aspect_ratio { - None - | Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto3k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::Auto)), - - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(Ar::Auto)), - }, - } -} - -fn plan_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use GenerateVeo3FastResolution as R; - match resolution { - None => Ok(None), - Some(CommonResolution::SevenTwentyP) => Ok(Some(R::SevenTwentyP)), - Some(CommonResolution::TenEightyP) => Ok(Some(R::TenEightyP)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(R::TenEightyP)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(R::SevenTwentyP)), - }, - } -} - -// Legacy storyteller Veo 3 Fast endpoint only exposes EightSeconds. -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - match duration_seconds { - None => Ok(None), - Some(8) => Ok(Some(GenerateVeo3FastDuration::EightSeconds)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - _ => Ok(Some(GenerateVeo3FastDuration::EightSeconds)), - }, - } -} - -impl PlanArtcraftVeo3Fast { - pub fn duration_seconds_for_cost(&self) -> u64 { - 8 - } - - /// Legacy Veo 3 Fast generate handler defaults `generate_audio` to false. - pub fn generate_audio_for_cost(&self) -> bool { - self.generate_audio.unwrap_or(false) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_veo_3p1.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_veo_3p1.rs deleted file mode 100644 index 8e989c65c0..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_veo_3p1.rs +++ /dev/null @@ -1,159 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::multi_function::veo_3p1_multi_function_video_gen::{ - Veo3p1MultiFunctionVideoGenAspectRatio, Veo3p1MultiFunctionVideoGenDuration, - Veo3p1MultiFunctionVideoGenResolution, -}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Debug, Clone)] -pub struct PlanArtcraftVeo3p1 { - pub prompt: Option, - pub negative_prompt: Option, - pub start_frame: Option, - pub end_frame: Option, - pub aspect_ratio: Option, - pub resolution: Option, - pub duration: Option, - pub generate_audio: Option, - pub idempotency_token: String, -} - -pub fn plan_generate_video_artcraft_veo_3p1( - request: &GenerateVideoRequestBuilder, -) -> Result { - let plan = build_plan_artcraft_veo_3p1(request)?; - Ok(VideoGenerationPlan::ArtcraftVeo3p1(plan)) -} - -pub(crate) fn build_plan_artcraft_veo_3p1( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = resolve_image_ref(request.start_frame.clone())?; - let end_frame = resolve_image_ref(request.end_frame.clone())?; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let resolution = plan_resolution(request.resolution, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(PlanArtcraftVeo3p1 { - prompt: request.prompt.clone(), - negative_prompt: request.negative_prompt.clone(), - start_frame, - end_frame, - aspect_ratio, - resolution, - duration, - generate_audio: request.generate_audio, - idempotency_token: request.get_or_generate_idempotency_token(), - }) -} - -fn resolve_image_ref( - image_ref: Option, -) -> Result, ArtcraftRouterError> { - match image_ref { - None => Ok(None), - Some(ImageRef::MediaFileToken(t)) => Ok(Some(t)), - Some(ImageRef::Url(_)) => { - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - } -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use Veo3p1MultiFunctionVideoGenAspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::Auto)), - - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(Ar::Auto)), - }, - } -} - -fn plan_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use Veo3p1MultiFunctionVideoGenResolution as R; - match resolution { - None => Ok(None), - Some(CommonResolution::SevenTwentyP) => Ok(Some(R::SevenTwentyP)), - Some(CommonResolution::TenEightyP) => Ok(Some(R::TenEightyP)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(R::TenEightyP)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(R::SevenTwentyP)), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use Veo3p1MultiFunctionVideoGenDuration as D; - match duration_seconds { - None => Ok(None), - Some(4) => Ok(Some(D::FourSeconds)), - Some(6) => Ok(Some(D::SixSeconds)), - Some(8) => Ok(Some(D::EightSeconds)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::EightSeconds)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::FourSeconds)), - }, - } -} - -impl PlanArtcraftVeo3p1 { - /// Legacy Veo 3.1 multi-function handler defaults `None` to SixSeconds. - pub fn duration_seconds_for_cost(&self) -> u64 { - use Veo3p1MultiFunctionVideoGenDuration as D; - match self.duration { - None | Some(D::SixSeconds) => 6, - Some(D::FourSeconds) => 4, - Some(D::EightSeconds) => 8, - } - } - - /// Legacy Veo 3.1 multi-function handler defaults `generate_audio` to true. - pub fn generate_audio_for_cost(&self) -> bool { - self.generate_audio.unwrap_or(true) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_veo_3p1_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_veo_3p1_fast.rs deleted file mode 100644 index 0dd4e7c8f5..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/artcraft/plan_generate_video_artcraft_veo_3p1_fast.rs +++ /dev/null @@ -1,152 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use artcraft_api_defs::generate::video::multi_function::veo_3p1_fast_multi_function_video_gen::{ - Veo3p1FastMultiFunctionVideoGenAspectRatio, Veo3p1FastMultiFunctionVideoGenDuration, - Veo3p1FastMultiFunctionVideoGenResolution, -}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Debug, Clone)] -pub struct PlanArtcraftVeo3p1Fast { - pub prompt: Option, - pub negative_prompt: Option, - pub start_frame: Option, - pub end_frame: Option, - pub aspect_ratio: Option, - pub resolution: Option, - pub duration: Option, - pub generate_audio: Option, - pub idempotency_token: String, -} - -pub fn plan_generate_video_artcraft_veo_3p1_fast( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame = resolve_image_ref(request.start_frame.clone())?; - let end_frame = resolve_image_ref(request.end_frame.clone())?; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let resolution = plan_resolution(request.resolution, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::ArtcraftVeo3p1Fast(PlanArtcraftVeo3p1Fast { - prompt: request.prompt.clone(), - negative_prompt: request.negative_prompt.clone(), - start_frame, - end_frame, - aspect_ratio, - resolution, - duration, - generate_audio: request.generate_audio, - idempotency_token: request.get_or_generate_idempotency_token(), - })) -} - -fn resolve_image_ref( - image_ref: Option, -) -> Result, ArtcraftRouterError> { - match image_ref { - None => Ok(None), - Some(ImageRef::MediaFileToken(t)) => Ok(Some(t)), - Some(ImageRef::Url(_)) => { - Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens)) - } - } -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use Veo3p1FastMultiFunctionVideoGenAspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::Auto)), - - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(Ar::Auto)), - }, - } -} - -fn plan_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use Veo3p1FastMultiFunctionVideoGenResolution as R; - match resolution { - None => Ok(None), - Some(CommonResolution::SevenTwentyP) => Ok(Some(R::SevenTwentyP)), - Some(CommonResolution::TenEightyP) => Ok(Some(R::TenEightyP)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(R::TenEightyP)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(R::SevenTwentyP)), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use Veo3p1FastMultiFunctionVideoGenDuration as D; - match duration_seconds { - None => Ok(None), - Some(4) => Ok(Some(D::FourSeconds)), - Some(6) => Ok(Some(D::SixSeconds)), - Some(8) => Ok(Some(D::EightSeconds)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::EightSeconds)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::FourSeconds)), - }, - } -} - -impl PlanArtcraftVeo3p1Fast { - /// Legacy Veo 3.1 Fast multi-function handler defaults `None` to SixSeconds. - pub fn duration_seconds_for_cost(&self) -> u64 { - use Veo3p1FastMultiFunctionVideoGenDuration as D; - match self.duration { - None | Some(D::SixSeconds) => 6, - Some(D::FourSeconds) => 4, - Some(D::EightSeconds) => 8, - } - } - - /// Legacy Veo 3.1 Fast multi-function handler defaults `generate_audio` to true. - pub fn generate_audio_for_cost(&self) -> bool { - self.generate_audio.unwrap_or(true) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/mod.rs deleted file mode 100644 index 0466d75047..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -pub mod plan_generate_video_fal_kling_1_6_pro; -pub mod plan_generate_video_fal_kling_2_1_master; -pub mod plan_generate_video_fal_kling_2_1_pro; -pub mod plan_generate_video_fal_kling_2_5_turbo_pro; -pub mod plan_generate_video_fal_kling_2_6_pro; -pub mod plan_generate_video_fal_kling_3p0_pro; -pub mod plan_generate_video_fal_kling_3p0_standard; -pub mod plan_generate_video_fal_seedance_1_0_lite; -pub mod plan_generate_video_fal_seedance_1p5_pro; -pub mod plan_generate_video_fal_sora_2; -pub mod plan_generate_video_fal_sora_2_pro; -pub mod plan_generate_video_fal_veo_2; -pub mod plan_generate_video_fal_veo_3; -pub mod plan_generate_video_fal_veo_3_fast; -pub mod plan_generate_video_fal_veo_3p1; -pub mod plan_generate_video_fal_veo_3p1_fast; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_1_6_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_1_6_pro.rs deleted file mode 100644 index a870f00172..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_1_6_pro.rs +++ /dev/null @@ -1,122 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use fal_client::requests::webhook::video::image::enqueue_kling_v1p6_pro_image_to_video_webhook::{ - Kling1p6ProAspectRatio, Kling1p6ProDuration, -}; - -#[derive(Debug, Clone)] -pub struct PlanFalKling16Pro { - pub prompt: String, - pub image_url: String, - pub end_image_url: Option, - pub aspect_ratio: Kling1p6ProAspectRatio, - pub duration: Kling1p6ProDuration, -} - -pub fn plan_generate_video_fal_kling_1_6_pro( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let image_url = require_url(request.start_frame.clone(), "start_frame", "Kling 1.6 Pro requires a starting frame")?; - let end_image_url = optional_url(request.end_frame.clone())?; - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::FalKling16Pro(PlanFalKling16Pro { - prompt: request.prompt.clone().unwrap_or_default(), - image_url, - end_image_url, - aspect_ratio, - duration, - })) -} - -pub(crate) fn require_url( - image_ref: Option, - field: &'static str, - reason: &str, -) -> Result { - match image_ref { - Some(ImageRef::Url(url)) => Ok(url.to_string()), - Some(ImageRef::MediaFileToken(_)) => { - Err(ArtcraftRouterError::Client(ClientError::FalOnlySupportsUrls)) - } - None => Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field, - value: reason.to_string(), - })), - } -} - -pub(crate) fn optional_url( - image_ref: Option, -) -> Result, ArtcraftRouterError> { - match image_ref { - None => Ok(None), - Some(ImageRef::Url(url)) => Ok(Some(url.to_string())), - Some(ImageRef::MediaFileToken(_)) => { - Err(ArtcraftRouterError::Client(ClientError::FalOnlySupportsUrls)) - } - } -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - use Kling1p6ProAspectRatio as Ar; - match aspect_ratio { - None => Ok(Ar::WideSixteenNine), - - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Ar::Square), - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Ar::WideSixteenNine), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Ar::TallNineSixteen), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Ar::WideSixteenNine), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Ar::WideSixteenNine), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - match duration_seconds { - None => Ok(Kling1p6ProDuration::Default), - Some(5) => Ok(Kling1p6ProDuration::FiveSeconds), - Some(10) => Ok(Kling1p6ProDuration::TenSeconds), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Kling1p6ProDuration::TenSeconds), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Kling1p6ProDuration::FiveSeconds), - }, - } -} - -impl PlanFalKling16Pro { - pub fn is_ten_seconds(&self) -> bool { - matches!(self.duration, Kling1p6ProDuration::TenSeconds) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_2_1_master.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_2_1_master.rs deleted file mode 100644 index aecdcdd681..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_2_1_master.rs +++ /dev/null @@ -1,97 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_1_6_pro::require_url; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use fal_client::requests::webhook::video::image::enqueue_kling_v2p1_master_image_to_video_webhook::{ - Kling2p1MasterAspectRatio, Kling2p1MasterDuration, -}; - -#[derive(Debug, Clone)] -pub struct PlanFalKling21Master { - pub prompt: String, - pub image_url: String, - pub aspect_ratio: Kling2p1MasterAspectRatio, - pub duration: Kling2p1MasterDuration, -} - -pub fn plan_generate_video_fal_kling_2_1_master( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let image_url = require_url(request.start_frame.clone(), "start_frame", "Kling 2.1 Master requires a starting frame")?; - if request.end_frame.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "end_frame", - value: "Kling 2.1 Master does not support an ending frame".to_string(), - })); - } - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::FalKling21Master(PlanFalKling21Master { - prompt: request.prompt.clone().unwrap_or_default(), - image_url, - aspect_ratio, - duration, - })) -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - use Kling2p1MasterAspectRatio as Ar; - match aspect_ratio { - None => Ok(Ar::WideSixteenNine), - - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Ar::Square), - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Ar::WideSixteenNine), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Ar::TallNineSixteen), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Ar::WideSixteenNine), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Ar::WideSixteenNine), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - match duration_seconds { - None => Ok(Kling2p1MasterDuration::Default), - Some(5) => Ok(Kling2p1MasterDuration::FiveSeconds), - Some(10) => Ok(Kling2p1MasterDuration::TenSeconds), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Kling2p1MasterDuration::TenSeconds), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Kling2p1MasterDuration::FiveSeconds), - }, - } -} - -impl PlanFalKling21Master { - pub fn is_ten_seconds(&self) -> bool { - matches!(self.duration, Kling2p1MasterDuration::TenSeconds) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_2_1_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_2_1_pro.rs deleted file mode 100644 index 29c82dcd91..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_2_1_pro.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_1_6_pro::{optional_url, require_url}; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use fal_client::requests::webhook::video::image::enqueue_kling_v2p1_pro_image_to_video_webhook::{ - Kling2p1ProAspectRatio, Kling2p1ProDuration, -}; - -#[derive(Debug, Clone)] -pub struct PlanFalKling21Pro { - pub prompt: String, - pub image_url: String, - pub end_image_url: Option, - pub aspect_ratio: Kling2p1ProAspectRatio, - pub duration: Kling2p1ProDuration, -} - -pub fn plan_generate_video_fal_kling_2_1_pro( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let image_url = require_url(request.start_frame.clone(), "start_frame", "Kling 2.1 Pro requires a starting frame")?; - let end_image_url = optional_url(request.end_frame.clone())?; - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::FalKling21Pro(PlanFalKling21Pro { - prompt: request.prompt.clone().unwrap_or_default(), - image_url, - end_image_url, - aspect_ratio, - duration, - })) -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - use Kling2p1ProAspectRatio as Ar; - match aspect_ratio { - None => Ok(Ar::WideSixteenNine), - - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Ar::Square), - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Ar::WideSixteenNine), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Ar::TallNineSixteen), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Ar::WideSixteenNine), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Ar::WideSixteenNine), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - match duration_seconds { - None => Ok(Kling2p1ProDuration::Default), - Some(5) => Ok(Kling2p1ProDuration::FiveSeconds), - Some(10) => Ok(Kling2p1ProDuration::TenSeconds), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Kling2p1ProDuration::TenSeconds), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Kling2p1ProDuration::FiveSeconds), - }, - } -} - -impl PlanFalKling21Pro { - pub fn is_ten_seconds(&self) -> bool { - matches!(self.duration, Kling2p1ProDuration::TenSeconds) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_2_5_turbo_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_2_5_turbo_pro.rs deleted file mode 100644 index 1dc6f21435..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_2_5_turbo_pro.rs +++ /dev/null @@ -1,126 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_1_6_pro::optional_url; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; - -#[derive(Debug, Clone, Copy)] -pub enum FalKling2p5TurboProAspectRatio { - Square, - SixteenByNine, - NineBySixteen, -} - -#[derive(Debug, Clone, Copy)] -pub enum FalKling2p5TurboProDuration { - Five, - Ten, -} - -#[derive(Debug, Clone)] -pub enum FalKling2p5TurboProMode { - TextToVideo, - ImageToVideo { - image_url: String, - end_image_url: Option, - }, -} - -#[derive(Debug, Clone)] -pub struct PlanFalKling2p5TurboPro { - pub prompt: String, - pub negative_prompt: Option, - pub mode: FalKling2p5TurboProMode, - pub aspect_ratio: Option, - pub duration: Option, -} - -pub fn plan_generate_video_fal_kling_2_5_turbo_pro( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let mode = match optional_url(request.start_frame.clone())? { - None => { - if request.end_frame.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "end_frame", - value: "Kling 2.5 Turbo Pro requires a start_frame when end_frame is provided".to_string(), - })); - } - FalKling2p5TurboProMode::TextToVideo - } - Some(image_url) => FalKling2p5TurboProMode::ImageToVideo { - image_url, - end_image_url: optional_url(request.end_frame.clone())?, - }, - }; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::FalKling2p5TurboPro(PlanFalKling2p5TurboPro { - prompt: request.prompt.clone().unwrap_or_default(), - negative_prompt: request.negative_prompt.clone(), - mode, - aspect_ratio, - duration, - })) -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use FalKling2p5TurboProAspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Ar::Square)), - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::SixteenByNine)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(Ar::SixteenByNine)), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - match duration_seconds { - None => Ok(None), - Some(5) => Ok(Some(FalKling2p5TurboProDuration::Five)), - Some(10) => Ok(Some(FalKling2p5TurboProDuration::Ten)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(FalKling2p5TurboProDuration::Ten)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(FalKling2p5TurboProDuration::Five)), - }, - } -} - -impl PlanFalKling2p5TurboPro { - pub fn is_ten_seconds(&self) -> bool { - matches!(self.duration, Some(FalKling2p5TurboProDuration::Ten)) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_2_6_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_2_6_pro.rs deleted file mode 100644 index aab4a2c704..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_2_6_pro.rs +++ /dev/null @@ -1,126 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_1_6_pro::optional_url; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; - -#[derive(Debug, Clone, Copy)] -pub enum FalKling2p6ProAspectRatio { - Square, - SixteenByNine, - NineBySixteen, -} - -#[derive(Debug, Clone, Copy)] -pub enum FalKling2p6ProDuration { - Five, - Ten, -} - -#[derive(Debug, Clone)] -pub enum FalKling2p6ProMode { - TextToVideo, - ImageToVideo { image_url: String }, -} - -#[derive(Debug, Clone)] -pub struct PlanFalKling2p6Pro { - pub prompt: String, - pub negative_prompt: Option, - pub mode: FalKling2p6ProMode, - pub aspect_ratio: Option, - pub duration: Option, - pub generate_audio: Option, -} - -pub fn plan_generate_video_fal_kling_2_6_pro( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - if request.end_frame.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "end_frame", - value: "Kling 2.6 Pro does not support an ending frame".to_string(), - })); - } - - let mode = match optional_url(request.start_frame.clone())? { - None => FalKling2p6ProMode::TextToVideo, - Some(image_url) => FalKling2p6ProMode::ImageToVideo { image_url }, - }; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::FalKling2p6Pro(PlanFalKling2p6Pro { - prompt: request.prompt.clone().unwrap_or_default(), - negative_prompt: request.negative_prompt.clone(), - mode, - aspect_ratio, - duration, - generate_audio: request.generate_audio, - })) -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use FalKling2p6ProAspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Ar::Square)), - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::SixteenByNine)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(Ar::SixteenByNine)), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - match duration_seconds { - None => Ok(None), - Some(5) => Ok(Some(FalKling2p6ProDuration::Five)), - Some(10) => Ok(Some(FalKling2p6ProDuration::Ten)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(FalKling2p6ProDuration::Ten)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(FalKling2p6ProDuration::Five)), - }, - } -} - -impl PlanFalKling2p6Pro { - pub fn is_ten_seconds(&self) -> bool { - matches!(self.duration, Some(FalKling2p6ProDuration::Ten)) - } - - /// Legacy / Fal client default for `generate_audio` is `true`. - pub fn generate_audio_for_cost(&self) -> bool { - self.generate_audio.unwrap_or(true) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_3p0_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_3p0_pro.rs deleted file mode 100644 index 751457cf2b..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_3p0_pro.rs +++ /dev/null @@ -1,156 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_1_6_pro::optional_url; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; - -#[derive(Debug, Clone, Copy)] -pub enum FalKling3p0AspectRatio { - Square, - SixteenByNine, - NineBySixteen, -} - -/// 3-15 seconds inclusive. -#[derive(Debug, Clone, Copy)] -pub struct FalKling3p0Duration(pub u8); - -#[derive(Debug, Clone)] -pub enum FalKling3p0Mode { - TextToVideo, - ImageToVideo { - image_url: String, - end_image_url: Option, - }, -} - -#[derive(Debug, Clone)] -pub struct PlanFalKling3p0Pro { - pub prompt: String, - pub negative_prompt: Option, - pub mode: FalKling3p0Mode, - pub aspect_ratio: Option, - pub duration: Option, - pub generate_audio: Option, -} - -pub fn plan_generate_video_fal_kling_3p0_pro( - request: &GenerateVideoRequestBuilder, -) -> Result { - let inner = build_kling_3p0_plan(request, "Kling 3.0 Pro")?; - Ok(VideoGenerationPlan::FalKling3p0Pro(PlanFalKling3p0Pro { - prompt: inner.prompt, - negative_prompt: inner.negative_prompt, - mode: inner.mode, - aspect_ratio: inner.aspect_ratio, - duration: inner.duration, - generate_audio: inner.generate_audio, - })) -} - -pub(crate) struct Kling3p0Common { - pub prompt: String, - pub negative_prompt: Option, - pub mode: FalKling3p0Mode, - pub aspect_ratio: Option, - pub duration: Option, - pub generate_audio: Option, -} - -pub(crate) fn build_kling_3p0_plan( - request: &GenerateVideoRequestBuilder, - _model_label: &'static str, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let mode = match optional_url(request.start_frame.clone())? { - None => { - if request.end_frame.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "end_frame", - value: "Kling 3.0 requires a start_frame when end_frame is provided".to_string(), - })); - } - FalKling3p0Mode::TextToVideo - } - Some(image_url) => FalKling3p0Mode::ImageToVideo { - image_url, - end_image_url: optional_url(request.end_frame.clone())?, - }, - }; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(Kling3p0Common { - prompt: request.prompt.clone().unwrap_or_default(), - negative_prompt: request.negative_prompt.clone(), - mode, - aspect_ratio, - duration, - generate_audio: request.generate_audio, - }) -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use FalKling3p0AspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Ar::Square)), - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::SixteenByNine)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(Ar::SixteenByNine)), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - const MIN: u16 = 3; - const MAX: u16 = 15; - match duration_seconds { - None => Ok(None), - Some(d) if (MIN..=MAX).contains(&d) => Ok(Some(FalKling3p0Duration(d as u8))), - Some(d) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", d), - })) - } - _ => Ok(Some(FalKling3p0Duration(d.clamp(MIN, MAX) as u8))), - }, - } -} - -impl PlanFalKling3p0Pro { - /// Default duration is 5s when None per Fal client. - pub fn duration_seconds_for_cost(&self) -> u64 { - self.duration.map(|d| d.0 as u64).unwrap_or(5) - } - - /// Default `generate_audio` is true per Fal client. - pub fn generate_audio_for_cost(&self) -> bool { - self.generate_audio.unwrap_or(true) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_3p0_standard.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_3p0_standard.rs deleted file mode 100644 index eb98ea56f0..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_kling_3p0_standard.rs +++ /dev/null @@ -1,40 +0,0 @@ -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_3p0_pro::{ - build_kling_3p0_plan, FalKling3p0AspectRatio, FalKling3p0Duration, FalKling3p0Mode, -}; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; - -#[derive(Debug, Clone)] -pub struct PlanFalKling3p0Standard { - pub prompt: String, - pub negative_prompt: Option, - pub mode: FalKling3p0Mode, - pub aspect_ratio: Option, - pub duration: Option, - pub generate_audio: Option, -} - -pub fn plan_generate_video_fal_kling_3p0_standard( - request: &GenerateVideoRequestBuilder, -) -> Result { - let inner = build_kling_3p0_plan(request, "Kling 3.0 Standard")?; - Ok(VideoGenerationPlan::FalKling3p0Standard(PlanFalKling3p0Standard { - prompt: inner.prompt, - negative_prompt: inner.negative_prompt, - mode: inner.mode, - aspect_ratio: inner.aspect_ratio, - duration: inner.duration, - generate_audio: inner.generate_audio, - })) -} - -impl PlanFalKling3p0Standard { - pub fn duration_seconds_for_cost(&self) -> u64 { - self.duration.map(|d| d.0 as u64).unwrap_or(5) - } - - pub fn generate_audio_for_cost(&self) -> bool { - self.generate_audio.unwrap_or(true) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_seedance_1_0_lite.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_seedance_1_0_lite.rs deleted file mode 100644 index 332788f5ee..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_seedance_1_0_lite.rs +++ /dev/null @@ -1,121 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_1_6_pro::{optional_url, require_url}; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use fal_client::requests::webhook::video::image::enqueue_seedance_1_lite_image_to_video_webhook::{ - Seedance1LiteAspectRatio, Seedance1LiteDuration, Seedance1LiteResolution, -}; - -#[derive(Debug, Clone)] -pub struct PlanFalSeedance10Lite { - pub prompt: String, - pub image_url: String, - pub end_image_url: Option, - pub aspect_ratio: Option, - pub resolution: Seedance1LiteResolution, - pub duration: Seedance1LiteDuration, -} - -pub fn plan_generate_video_fal_seedance_1_0_lite( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let image_url = require_url( - request.start_frame.clone(), - "start_frame", - "Seedance 1.0 Lite requires a starting frame", - )?; - let end_image_url = optional_url(request.end_frame.clone())?; - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let resolution = plan_resolution(request.resolution, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::FalSeedance10Lite(PlanFalSeedance10Lite { - prompt: request.prompt.clone().unwrap_or_default(), - image_url, - end_image_url, - aspect_ratio, - resolution, - duration, - })) -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use Seedance1LiteAspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::Auto)), - - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Ar::Square)), - Some(CommonAspectRatio::WideFourByThree) => Ok(Some(Ar::FourByThree)), - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)), - Some(CommonAspectRatio::WideTwentyOneByNine) => Ok(Some(Ar::TwentyOneByNine)), - Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(Ar::ThreeByFour)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(Ar::Auto)), - }, - } -} - -fn plan_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - use Seedance1LiteResolution as R; - match resolution { - None => Ok(R::SevenTwentyP), - Some(CommonResolution::FourEightyP) => Ok(R::FourEightyP), - Some(CommonResolution::SevenTwentyP) => Ok(R::SevenTwentyP), - Some(CommonResolution::TenEightyP) => Ok(R::TenEightyP), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(R::TenEightyP), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(R::FourEightyP), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - match duration_seconds { - None => Ok(Seedance1LiteDuration::FiveSeconds), - Some(5) => Ok(Seedance1LiteDuration::FiveSeconds), - Some(10) => Ok(Seedance1LiteDuration::TenSeconds), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Seedance1LiteDuration::TenSeconds), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Seedance1LiteDuration::FiveSeconds), - }, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_seedance_1p5_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_seedance_1p5_pro.rs deleted file mode 100644 index b5b0ffe91c..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_seedance_1p5_pro.rs +++ /dev/null @@ -1,192 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_1_6_pro::optional_url; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; - -#[derive(Debug, Clone, Copy)] -pub enum FalSeedance1p5ProAspectRatio { - Auto, - TwentyOneByNine, - SixteenByNine, - FourByThree, - Square, - ThreeByFour, - NineBySixteen, -} - -#[derive(Debug, Clone, Copy)] -pub enum FalSeedance1p5ProResolution { - FourEightyP, - SevenTwentyP, - TenEightyP, -} - -#[derive(Debug, Clone, Copy)] -pub enum FalSeedance1p5ProDuration { - Four, - Five, - Six, - Seven, - Eight, - Nine, - Ten, - Eleven, - Twelve, -} - -#[derive(Debug, Clone)] -pub enum FalSeedance1p5ProMode { - TextToVideo, - ImageToVideo { - image_url: String, - end_image_url: Option, - }, -} - -#[derive(Debug, Clone)] -pub struct PlanFalSeedance1p5Pro { - pub prompt: String, - pub mode: FalSeedance1p5ProMode, - pub aspect_ratio: Option, - pub resolution: Option, - pub duration: Option, - pub generate_audio: Option, -} - -pub fn plan_generate_video_fal_seedance_1p5_pro( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let mode = match optional_url(request.start_frame.clone())? { - None => { - if request.end_frame.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "end_frame", - value: "Seedance 1.5 Pro requires a start_frame when end_frame is provided".to_string(), - })); - } - FalSeedance1p5ProMode::TextToVideo - } - Some(image_url) => FalSeedance1p5ProMode::ImageToVideo { - image_url, - end_image_url: optional_url(request.end_frame.clone())?, - }, - }; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let resolution = plan_resolution(request.resolution, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::FalSeedance1p5Pro(PlanFalSeedance1p5Pro { - prompt: request.prompt.clone().unwrap_or_default(), - mode, - aspect_ratio, - resolution, - duration, - generate_audio: request.generate_audio, - })) -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use FalSeedance1p5ProAspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::Auto)), - - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Ar::Square)), - Some(CommonAspectRatio::WideFourByThree) => Ok(Some(Ar::FourByThree)), - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)), - Some(CommonAspectRatio::WideTwentyOneByNine) => Ok(Some(Ar::TwentyOneByNine)), - Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(Ar::ThreeByFour)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(nearest_aspect_ratio(unsupported))), - }, - } -} - -/// Pick the nearest supported aspect ratio for unsupported inputs. -fn nearest_aspect_ratio(aspect_ratio: CommonAspectRatio) -> FalSeedance1p5ProAspectRatio { - use FalSeedance1p5ProAspectRatio as Ar; - match aspect_ratio { - // Wide unsupported → nearest wide - CommonAspectRatio::WideFiveByFour => Ar::FourByThree, // 1.25 → 1.33 - CommonAspectRatio::WideThreeByTwo => Ar::FourByThree, // 1.50 → 1.33 - // Tall unsupported → nearest tall - CommonAspectRatio::TallFourByFive => Ar::ThreeByFour, // 0.80 → 0.75 - CommonAspectRatio::TallTwoByThree => Ar::ThreeByFour, // 0.67 → 0.75 - CommonAspectRatio::TallNineByTwentyOne => Ar::NineBySixteen, // 0.43 → 0.56 - // Anything else → Square - _ => Ar::Square, - } -} - -fn plan_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use FalSeedance1p5ProResolution as R; - match resolution { - None => Ok(None), - Some(CommonResolution::FourEightyP) => Ok(Some(R::FourEightyP)), - Some(CommonResolution::SevenTwentyP) => Ok(Some(R::SevenTwentyP)), - Some(CommonResolution::TenEightyP) => Ok(Some(R::TenEightyP)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(R::TenEightyP)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(R::FourEightyP)), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use FalSeedance1p5ProDuration as D; - match duration_seconds { - None => Ok(None), - Some(4) => Ok(Some(D::Four)), - Some(5) => Ok(Some(D::Five)), - Some(6) => Ok(Some(D::Six)), - Some(7) => Ok(Some(D::Seven)), - Some(8) => Ok(Some(D::Eight)), - Some(9) => Ok(Some(D::Nine)), - Some(10) => Ok(Some(D::Ten)), - Some(11) => Ok(Some(D::Eleven)), - Some(12) => Ok(Some(D::Twelve)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::Twelve)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::Four)), - }, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_sora_2.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_sora_2.rs deleted file mode 100644 index da59c49719..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_sora_2.rs +++ /dev/null @@ -1,156 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_1_6_pro::optional_url; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; - -#[derive(Debug, Clone, Copy)] -pub enum FalSora2AspectRatio { - Auto, - SixteenByNine, - NineBySixteen, -} - -/// Sora 2 supports 720p (and `auto` on image-to-video). -#[derive(Debug, Clone, Copy)] -pub enum FalSora2Resolution { - Auto, - SevenTwentyP, -} - -#[derive(Debug, Clone, Copy)] -pub enum FalSora2Duration { - Four, - Eight, - Twelve, -} - -#[derive(Debug, Clone)] -pub enum FalSora2Mode { - TextToVideo, - ImageToVideo { image_url: String }, -} - -#[derive(Debug, Clone)] -pub struct PlanFalSora2 { - pub prompt: String, - pub mode: FalSora2Mode, - pub aspect_ratio: Option, - pub resolution: Option, - pub duration: Option, -} - -pub fn plan_generate_video_fal_sora_2( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - if request.end_frame.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "end_frame", - value: "Sora 2 does not support an ending frame".to_string(), - })); - } - - let mode = match optional_url(request.start_frame.clone())? { - None => FalSora2Mode::TextToVideo, - Some(image_url) => FalSora2Mode::ImageToVideo { image_url }, - }; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let resolution = plan_resolution(request.resolution, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::FalSora2(PlanFalSora2 { - prompt: request.prompt.clone().unwrap_or_default(), - mode, - aspect_ratio, - resolution, - duration, - })) -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use FalSora2AspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::Auto)), - - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(Ar::SixteenByNine)), - }, - } -} - -fn plan_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use FalSora2Resolution as R; - match resolution { - None => Ok(None), - Some(CommonResolution::SevenTwentyP) => Ok(Some(R::SevenTwentyP)), - // Only 720p is supported; everything else falls back or errors. - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", other), - })) - } - _ => Ok(Some(R::SevenTwentyP)), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use FalSora2Duration as D; - match duration_seconds { - None => Ok(None), - Some(4) => Ok(Some(D::Four)), - Some(8) => Ok(Some(D::Eight)), - Some(12) => Ok(Some(D::Twelve)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::Twelve)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::Four)), - }, - } -} - -impl PlanFalSora2 { - /// Fal client default: 4s. - pub fn duration_seconds_for_cost(&self) -> u64 { - match self.duration { - Some(FalSora2Duration::Four) | None => 4, - Some(FalSora2Duration::Eight) => 8, - Some(FalSora2Duration::Twelve) => 12, - } - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_sora_2_pro.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_sora_2_pro.rs deleted file mode 100644 index 2ed683e7d9..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_sora_2_pro.rs +++ /dev/null @@ -1,167 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_1_6_pro::optional_url; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; - -#[derive(Debug, Clone, Copy)] -pub enum FalSora2ProAspectRatio { - Auto, - SixteenByNine, - NineBySixteen, -} - -#[derive(Debug, Clone, Copy)] -pub enum FalSora2ProResolution { - Auto, - SevenTwentyP, - TenEightyP, -} - -#[derive(Debug, Clone, Copy)] -pub enum FalSora2ProDuration { - Four, - Eight, - Twelve, -} - -#[derive(Debug, Clone)] -pub enum FalSora2ProMode { - TextToVideo, - ImageToVideo { image_url: String }, -} - -#[derive(Debug, Clone)] -pub struct PlanFalSora2Pro { - pub prompt: String, - pub mode: FalSora2ProMode, - pub aspect_ratio: Option, - pub resolution: Option, - pub duration: Option, -} - -pub fn plan_generate_video_fal_sora_2_pro( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - if request.end_frame.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "end_frame", - value: "Sora 2 Pro does not support an ending frame".to_string(), - })); - } - - let mode = match optional_url(request.start_frame.clone())? { - None => FalSora2ProMode::TextToVideo, - Some(image_url) => FalSora2ProMode::ImageToVideo { image_url }, - }; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let resolution = plan_resolution(request.resolution, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::FalSora2Pro(PlanFalSora2Pro { - prompt: request.prompt.clone().unwrap_or_default(), - mode, - aspect_ratio, - resolution, - duration, - })) -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use FalSora2ProAspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::Auto)), - - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - _ => Ok(Some(Ar::SixteenByNine)), - }, - } -} - -fn plan_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use FalSora2ProResolution as R; - match resolution { - None => Ok(None), - Some(CommonResolution::SevenTwentyP) => Ok(Some(R::SevenTwentyP)), - Some(CommonResolution::TenEightyP) => Ok(Some(R::TenEightyP)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(R::TenEightyP)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(R::SevenTwentyP)), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use FalSora2ProDuration as D; - match duration_seconds { - None => Ok(None), - Some(4) => Ok(Some(D::Four)), - Some(8) => Ok(Some(D::Eight)), - Some(12) => Ok(Some(D::Twelve)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", other), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::Twelve)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::Four)), - }, - } -} - -impl PlanFalSora2Pro { - /// Fal client default: 4s. - pub fn duration_seconds_for_cost(&self) -> u64 { - match self.duration { - Some(FalSora2ProDuration::Four) | None => 4, - Some(FalSora2ProDuration::Eight) => 8, - Some(FalSora2ProDuration::Twelve) => 12, - } - } - - /// Fal client default varies by mode: text-to-video defaults to 1080p; image-to-video - /// defaults to auto (priced as 720p). - pub fn is_ten_eighty_p_for_cost(&self) -> bool { - match self.resolution { - Some(FalSora2ProResolution::TenEightyP) => true, - Some(FalSora2ProResolution::SevenTwentyP) | Some(FalSora2ProResolution::Auto) => false, - None => matches!(self.mode, FalSora2ProMode::TextToVideo), - } - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_veo_2.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_veo_2.rs deleted file mode 100644 index d3978b5a4b..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_veo_2.rs +++ /dev/null @@ -1,127 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use fal_client::requests::webhook::video::image::enqueue_veo_2_image_to_video_webhook::{ - Veo2AspectRatio, Veo2Duration, -}; - -#[derive(Debug, Clone)] -pub enum FalVeo2Mode { - TextToVideo, - ImageToVideo { - image_url: String, - }, -} - -#[derive(Debug, Clone)] -pub struct PlanFalVeo2 { - pub prompt: String, - pub negative_prompt: Option, - pub mode: FalVeo2Mode, - /// Only set for text-to-video. Image-to-video inherits the source frame's - /// aspect ratio and doesn't accept this parameter. - pub aspect_ratio: Option, - pub duration: Veo2Duration, -} - -pub fn plan_generate_video_fal_veo_2( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - if request.end_frame.is_some() { - return Err(unsupported("end_frame", "Veo 2 does not support an ending frame")); - } - - let mode = match request.start_frame.clone() { - Some(ImageRef::Url(url)) => FalVeo2Mode::ImageToVideo { - image_url: url.to_string(), - }, - Some(ImageRef::MediaFileToken(_)) => { - return Err(ArtcraftRouterError::Client(ClientError::FalOnlySupportsUrls)); - } - None => FalVeo2Mode::TextToVideo, - }; - - // Aspect ratio only applies to text-to-video; image-to-video inherits - // the source frame's aspect ratio. - let aspect_ratio = match &mode { - FalVeo2Mode::TextToVideo => Some(plan_aspect_ratio(request.aspect_ratio, strategy)?), - FalVeo2Mode::ImageToVideo { .. } => None, - }; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(VideoGenerationPlan::FalVeo2(PlanFalVeo2 { - prompt: request.prompt.clone().unwrap_or_default(), - negative_prompt: request.negative_prompt.clone(), - mode, - aspect_ratio, - duration, - })) -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - use Veo2AspectRatio as Ar; - match aspect_ratio { - None - | Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto3k) - | Some(CommonAspectRatio::Auto4k) => Ok(Ar::Auto), - - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Ar::WideSixteenNine), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Ar::TallNineSixteen), - - Some(unsupported_ar) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(unsupported("aspect_ratio", &format!("{:?}", unsupported_ar))) - } - _ => Ok(Ar::Auto), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - match duration_seconds { - None => Ok(Veo2Duration::Default), - Some(5) => Ok(Veo2Duration::FiveSeconds), - Some(6) => Ok(Veo2Duration::SixSeconds), - Some(7) => Ok(Veo2Duration::SevenSeconds), - Some(8) => Ok(Veo2Duration::EightSeconds), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(unsupported("duration_seconds", &format!("{}", other))) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Veo2Duration::EightSeconds), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Veo2Duration::FiveSeconds), - }, - } -} - -fn unsupported(field: &'static str, value: &str) -> ArtcraftRouterError { - ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field, - value: value.to_string(), - }) -} - -impl PlanFalVeo2 { - pub fn duration_seconds_for_cost(&self) -> u64 { - match self.duration { - Veo2Duration::Default | Veo2Duration::FiveSeconds => 5, - Veo2Duration::SixSeconds => 6, - Veo2Duration::SevenSeconds => 7, - Veo2Duration::EightSeconds => 8, - } - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_veo_3.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_veo_3.rs deleted file mode 100644 index 0f8f7c297c..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_veo_3.rs +++ /dev/null @@ -1,216 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use fal_client::requests::webhook::video::image::enqueue_veo_3_image_to_video_webhook::{ - Veo3I2vAspectRatio, Veo3I2vDuration, Veo3I2vResolution, -}; -use fal_client::requests::webhook::video::text::enqueue_veo_3_text_to_video_webhook::{ - Veo3T2vAspectRatio, Veo3T2vDuration, Veo3T2vResolution, -}; - -#[derive(Debug, Clone)] -pub enum FalVeo3Mode { - TextToVideo, - ImageToVideo { - image_url: String, - }, -} - -/// Router-level duration shared between both modes. -#[derive(Debug, Clone, Copy)] -pub enum FalVeo3Duration { - Default, - FourSeconds, - SixSeconds, - EightSeconds, -} - -/// Router-level resolution shared between both modes. -#[derive(Debug, Clone, Copy)] -pub enum FalVeo3Resolution { - Default, - SevenTwentyP, - TenEightyP, -} - -/// Router-level aspect ratio for text-to-video only (no Auto, no Square). -#[derive(Debug, Clone, Copy)] -pub enum FalVeo3T2vAspectRatio { - Default, - WideSixteenNine, - TallNineSixteen, -} - -/// Router-level aspect ratio for image-to-video only (has Auto, no Square). -#[derive(Debug, Clone, Copy)] -pub enum FalVeo3I2vAspectRatio { - Auto, - WideSixteenNine, - TallNineSixteen, -} - -#[derive(Debug, Clone)] -pub struct PlanFalVeo3 { - pub prompt: String, - pub negative_prompt: Option, - pub mode: FalVeo3Mode, - /// Only set for text-to-video. Image-to-video inherits the source frame's - /// aspect ratio and uses `i2v_aspect_ratio` instead. - pub t2v_aspect_ratio: Option, - /// Only set for image-to-video. - pub i2v_aspect_ratio: Option, - pub resolution: FalVeo3Resolution, - pub duration: FalVeo3Duration, - pub generate_audio: bool, -} - -pub fn plan_generate_video_fal_veo_3( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - if request.end_frame.is_some() { - return Err(unsupported("end_frame", "Veo 3 does not support an ending frame")); - } - - let mode = match request.start_frame.clone() { - Some(ImageRef::Url(url)) => FalVeo3Mode::ImageToVideo { - image_url: url.to_string(), - }, - Some(ImageRef::MediaFileToken(_)) => { - return Err(ArtcraftRouterError::Client(ClientError::FalOnlySupportsUrls)); - } - None => FalVeo3Mode::TextToVideo, - }; - - let (t2v_aspect_ratio, i2v_aspect_ratio) = match &mode { - FalVeo3Mode::TextToVideo => { - (Some(plan_t2v_aspect_ratio(request.aspect_ratio, strategy)?), None) - } - FalVeo3Mode::ImageToVideo { .. } => { - (None, Some(plan_i2v_aspect_ratio(request.aspect_ratio, strategy)?)) - } - }; - let resolution = plan_resolution(request.resolution, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - let generate_audio = request.generate_audio.unwrap_or(true); - - Ok(VideoGenerationPlan::FalVeo3(PlanFalVeo3 { - prompt: request.prompt.clone().unwrap_or_default(), - negative_prompt: request.negative_prompt.clone(), - mode, - t2v_aspect_ratio, - i2v_aspect_ratio, - resolution, - duration, - generate_audio, - })) -} - -/// Text-to-video: only 16:9 and 9:16 (no Auto, no Square). -fn plan_t2v_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - use FalVeo3T2vAspectRatio as Ar; - match aspect_ratio { - None => Ok(Ar::Default), - - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Ar::WideSixteenNine), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Ar::TallNineSixteen), - - // Everything else (Auto*, Square, unsupported) → Default (16:9). - Some(_) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(unsupported("aspect_ratio", &format!("{:?}", aspect_ratio.unwrap()))) - } - _ => Ok(Ar::Default), - }, - } -} - -/// Image-to-video: Auto, 16:9, 9:16 (no Square). -fn plan_i2v_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - use FalVeo3I2vAspectRatio as Ar; - match aspect_ratio { - None - | Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto3k) - | Some(CommonAspectRatio::Auto4k) => Ok(Ar::Auto), - - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Ar::WideSixteenNine), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Ar::TallNineSixteen), - - // Everything else (Square, unsupported) → Auto. - Some(_) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(unsupported("aspect_ratio", &format!("{:?}", aspect_ratio.unwrap()))) - } - _ => Ok(Ar::Auto), - }, - } -} - -fn plan_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - use FalVeo3Resolution as R; - match resolution { - None => Ok(R::Default), - Some(CommonResolution::SevenTwentyP) => Ok(R::SevenTwentyP), - Some(CommonResolution::TenEightyP) => Ok(R::TenEightyP), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(unsupported("resolution", &format!("{:?}", other))) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(R::TenEightyP), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(R::SevenTwentyP), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - match duration_seconds { - None => Ok(FalVeo3Duration::Default), - Some(4) => Ok(FalVeo3Duration::FourSeconds), - Some(6) => Ok(FalVeo3Duration::SixSeconds), - Some(8) => Ok(FalVeo3Duration::EightSeconds), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(unsupported("duration_seconds", &format!("{}", other))) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(FalVeo3Duration::EightSeconds), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(FalVeo3Duration::FourSeconds), - }, - } -} - -fn unsupported(field: &'static str, value: &str) -> ArtcraftRouterError { - ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field, - value: value.to_string(), - }) -} - -impl PlanFalVeo3 { - pub fn duration_seconds_for_cost(&self) -> u64 { - match self.duration { - FalVeo3Duration::Default | FalVeo3Duration::EightSeconds => 8, - FalVeo3Duration::SixSeconds => 6, - FalVeo3Duration::FourSeconds => 4, - } - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_veo_3_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_veo_3_fast.rs deleted file mode 100644 index 6766dfa8e7..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_veo_3_fast.rs +++ /dev/null @@ -1,137 +0,0 @@ -use crate::api::common_resolution::CommonResolution; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use crate::api::common_aspect_ratio::CommonAspectRatio; -use fal_client::requests::webhook::video::image::enqueue_veo_3_fast_image_to_video_webhook::{ - Veo3FastAspectRatio, Veo3FastDuration, Veo3FastResolution, -}; - -#[derive(Debug, Clone)] -pub struct PlanFalVeo3Fast { - pub prompt: String, - pub start_frame_url: String, - pub aspect_ratio: Veo3FastAspectRatio, - pub resolution: Veo3FastResolution, - pub duration: Veo3FastDuration, - pub generate_audio: bool, -} - -pub fn plan_generate_video_fal_veo_3_fast( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame_url = resolve_required_image_url(request.start_frame.clone())?; - if request.end_frame.is_some() { - return Err(unsupported("end_frame", "Veo 3 Fast does not support an ending frame")); - } - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let resolution = plan_resolution(request.resolution, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - let generate_audio = request.generate_audio.unwrap_or(true); - - Ok(VideoGenerationPlan::FalVeo3Fast(PlanFalVeo3Fast { - prompt: request.prompt.clone().unwrap_or_default(), - start_frame_url, - aspect_ratio, - resolution, - duration, - generate_audio, - })) -} - -fn resolve_required_image_url( - image_ref: Option, -) -> Result { - match image_ref { - Some(ImageRef::Url(url)) => Ok(url.to_string()), - Some(ImageRef::MediaFileToken(_)) => { - Err(ArtcraftRouterError::Client(ClientError::FalOnlySupportsUrls)) - } - None => Err(unsupported("start_frame", "Veo 3 Fast requires a starting frame")), - } -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - use Veo3FastAspectRatio as Ar; - match aspect_ratio { - None - | Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto3k) - | Some(CommonAspectRatio::Auto4k) => Ok(Ar::Auto), - - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Ar::WideSixteenNine), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Ar::TallNineSixteen), - - Some(unsupported_ar) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(unsupported("aspect_ratio", &format!("{:?}", unsupported_ar))) - } - _ => Ok(Ar::Auto), - }, - } -} - -fn plan_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - use Veo3FastResolution as R; - match resolution { - None => Ok(R::Default), - Some(CommonResolution::SevenTwentyP) => Ok(R::SevenTwentyP), - Some(CommonResolution::TenEightyP) => Ok(R::TenEightyP), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(unsupported("resolution", &format!("{:?}", other))) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(R::TenEightyP), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(R::SevenTwentyP), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - match duration_seconds { - None => Ok(Veo3FastDuration::Default), - Some(4) => Ok(Veo3FastDuration::FourSeconds), - Some(6) => Ok(Veo3FastDuration::SixSeconds), - Some(8) => Ok(Veo3FastDuration::EightSeconds), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(unsupported("duration_seconds", &format!("{}", other))) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Veo3FastDuration::EightSeconds), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Veo3FastDuration::FourSeconds), - }, - } -} - -fn unsupported(field: &'static str, value: &str) -> ArtcraftRouterError { - ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field, - value: value.to_string(), - }) -} - -impl PlanFalVeo3Fast { - pub fn duration_seconds_for_cost(&self) -> u64 { - match self.duration { - Veo3FastDuration::Default | Veo3FastDuration::EightSeconds => 8, - Veo3FastDuration::SixSeconds => 6, - Veo3FastDuration::FourSeconds => 4, - } - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_veo_3p1.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_veo_3p1.rs deleted file mode 100644 index 846bf306a9..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_veo_3p1.rs +++ /dev/null @@ -1,194 +0,0 @@ -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -use crate::api::image_ref::ImageRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; - -/// Three-way internal selection of which Fal Veo 3.1 endpoint to call. -/// Veo 3.1 / 3.1 Fast each expose distinct (but parallel) types per endpoint — -/// we resolve those at execute time. -#[derive(Debug, Clone)] -pub enum FalVeo3p1Mode { - TextToVideo, - ImageToVideo { start_frame_url: String }, - FirstLastFrame { first_frame_url: String, last_frame_url: String }, -} - -#[derive(Debug, Clone, Copy)] -pub enum FalVeo3p1AspectRatio { - Auto, - SixteenByNine, - NineBySixteen, -} - -#[derive(Debug, Clone, Copy)] -pub enum FalVeo3p1Resolution { - SevenTwentyP, - TenEightyP, -} - -#[derive(Debug, Clone, Copy)] -pub enum FalVeo3p1Duration { - Four, - Six, - Eight, -} - -#[derive(Debug, Clone)] -pub struct PlanFalVeo3p1 { - pub prompt: String, - pub negative_prompt: Option, - pub mode: FalVeo3p1Mode, - pub aspect_ratio: Option, - pub resolution: Option, - pub duration: Option, - pub generate_audio: Option, -} - -pub fn plan_generate_video_fal_veo_3p1( - request: &GenerateVideoRequestBuilder, -) -> Result { - let plan = build_plan_fal_veo_3p1(request, "Veo 3.1")?; - Ok(VideoGenerationPlan::FalVeo3p1(plan)) -} - -pub(crate) fn build_plan_fal_veo_3p1( - request: &GenerateVideoRequestBuilder, - model_label: &'static str, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let mode = resolve_mode(request.start_frame.clone(), request.end_frame.clone(), model_label)?; - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let resolution = plan_resolution(request.resolution, strategy)?; - let duration = plan_duration(request.duration_seconds, strategy)?; - - Ok(PlanFalVeo3p1 { - prompt: request.prompt.clone().unwrap_or_default(), - negative_prompt: request.negative_prompt.clone(), - mode, - aspect_ratio, - resolution, - duration, - generate_audio: request.generate_audio, - }) -} - -fn resolve_mode( - start_frame: Option, - end_frame: Option, - model_label: &'static str, -) -> Result { - let start = resolve_optional_image_url(start_frame)?; - let end = resolve_optional_image_url(end_frame)?; - match (start, end) { - (None, None) => Ok(FalVeo3p1Mode::TextToVideo), - (Some(s), None) => Ok(FalVeo3p1Mode::ImageToVideo { start_frame_url: s }), - (Some(s), Some(e)) => Ok(FalVeo3p1Mode::FirstLastFrame { - first_frame_url: s, - last_frame_url: e, - }), - (None, Some(_)) => Err(unsupported( - "end_frame", - &format!("{} requires a start_frame when end_frame is provided", model_label), - )), - } -} - -fn resolve_optional_image_url( - image_ref: Option, -) -> Result, ArtcraftRouterError> { - match image_ref { - None => Ok(None), - Some(ImageRef::Url(url)) => Ok(Some(url.to_string())), - Some(ImageRef::MediaFileToken(_)) => { - Err(ArtcraftRouterError::Client(ClientError::FalOnlySupportsUrls)) - } - } -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use FalVeo3p1AspectRatio as Ar; - match aspect_ratio { - None => Ok(None), - - Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::Auto)), - - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)), - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)), - - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(unsupported("aspect_ratio", &format!("{:?}", other))) - } - _ => Ok(Some(Ar::Auto)), - }, - } -} - -fn plan_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - use FalVeo3p1Resolution as R; - match resolution { - None => Ok(None), - Some(CommonResolution::SevenTwentyP) => Ok(Some(R::SevenTwentyP)), - Some(CommonResolution::TenEightyP) => Ok(Some(R::TenEightyP)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(unsupported("resolution", &format!("{:?}", other))) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(R::TenEightyP)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(R::SevenTwentyP)), - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - match duration_seconds { - None => Ok(None), - Some(4) => Ok(Some(FalVeo3p1Duration::Four)), - Some(6) => Ok(Some(FalVeo3p1Duration::Six)), - Some(8) => Ok(Some(FalVeo3p1Duration::Eight)), - Some(other) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(unsupported("duration_seconds", &format!("{}", other))) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(FalVeo3p1Duration::Eight)), - RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(FalVeo3p1Duration::Four)), - }, - } -} - -fn unsupported(field: &'static str, value: &str) -> ArtcraftRouterError { - ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field, - value: value.to_string(), - }) -} - -impl PlanFalVeo3p1 { - pub fn duration_seconds_for_cost(&self) -> u64 { - match self.duration { - Some(FalVeo3p1Duration::Four) => 4, - Some(FalVeo3p1Duration::Six) => 6, - Some(FalVeo3p1Duration::Eight) | None => 8, - } - } - - pub fn generate_audio_for_cost(&self) -> bool { - self.generate_audio.unwrap_or(true) - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_veo_3p1_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_veo_3p1_fast.rs deleted file mode 100644 index 6bbd6d1e22..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/fal/plan_generate_video_fal_veo_3p1_fast.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1::{ - build_plan_fal_veo_3p1, PlanFalVeo3p1, -}; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; - -/// Veo 3.1 Fast shares the exact same input shape as Veo 3.1 — only the -/// downstream Fal endpoint and pricing differ. We reuse the planner and tag the -/// resulting plan as the Fast variant for execute/cost dispatch. -#[derive(Debug, Clone)] -pub struct PlanFalVeo3p1Fast { - pub inner: PlanFalVeo3p1, -} - -pub fn plan_generate_video_fal_veo_3p1_fast( - request: &GenerateVideoRequestBuilder, -) -> Result { - let inner = build_plan_fal_veo_3p1(request, "Veo 3.1 Fast")?; - Ok(VideoGenerationPlan::FalVeo3p1Fast(PlanFalVeo3p1Fast { inner })) -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/mod.rs deleted file mode 100644 index 0674492f66..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod artcraft; -pub mod fal; -pub mod muapi; -pub mod seedance2pro; \ No newline at end of file diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/muapi/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/muapi/mod.rs deleted file mode 100644 index 0b4ec0acba..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/muapi/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod plan_generate_video_muapi_seedance2p0; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/muapi/plan_generate_video_muapi_seedance2p0.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/muapi/plan_generate_video_muapi_seedance2p0.rs deleted file mode 100644 index 692576b373..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/muapi/plan_generate_video_muapi_seedance2p0.rs +++ /dev/null @@ -1,259 +0,0 @@ -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use muapi_client::requests::seedance_2p0_image_to_video::seedance_2p0_image_to_video::{ - AspectRatio as I2vAspectRatio, - Duration as I2vDuration, - Quality as I2vQuality, -}; -use muapi_client::requests::seedance_2p0_text_to_video::seedance_2p0_text_to_video::{ - AspectRatio as T2vAspectRatio, - Duration as T2vDuration, - Quality as T2vQuality, -}; - -/// The generation mode determined at plan time. -/// Muapi has separate text-to-video and image-to-video endpoints. -/// If reference images are present, we use image-to-video; otherwise text-to-video. -#[derive(Debug, Clone)] -pub enum MuapiSeedance2p0Mode { - TextToVideo { - aspect_ratio: T2vAspectRatio, - duration: T2vDuration, - quality: T2vQuality, - }, - ImageToVideo { - image_urls: Vec, - aspect_ratio: I2vAspectRatio, - duration: I2vDuration, - quality: I2vQuality, - }, -} - -#[derive(Debug, Clone)] -pub struct PlanMuapiSeedance2p0 { - pub prompt: String, - pub mode: MuapiSeedance2p0Mode, -} - -pub fn plan_generate_video_muapi_seedance2p0( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - // Muapi does not support start/end frames, video references, or audio references. - if request.start_frame.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "start_frame", - value: "Muapi does not support start frame keyframes".to_string(), - })); - } - if request.end_frame.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "end_frame", - value: "Muapi does not support end frame keyframes".to_string(), - })); - } - if request.reference_videos.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "reference_videos", - value: "Muapi does not support video references".to_string(), - })); - } - if request.reference_audio.is_some() { - return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "reference_audio", - value: "Muapi does not support audio references".to_string(), - })); - } - - let image_urls = resolve_image_urls(request.reference_images.clone())?; - - let prompt = request.prompt.clone().unwrap_or_default(); - - let mode = match image_urls { - Some(urls) => { - MuapiSeedance2p0Mode::ImageToVideo { - image_urls: urls, - aspect_ratio: plan_i2v_aspect_ratio(request.aspect_ratio, strategy)?, - duration: plan_i2v_duration(request.duration_seconds, strategy)?, - quality: I2vQuality::High, // NB: "Low" is a "fast" mode, I think - } - } - None => { - MuapiSeedance2p0Mode::TextToVideo { - aspect_ratio: plan_t2v_aspect_ratio(request.aspect_ratio, strategy)?, - duration: plan_t2v_duration(request.duration_seconds, strategy)?, - quality: T2vQuality::High, // NB: "Low" is a "fast" mode, I think - } - } - }; - - Ok(VideoGenerationPlan::MuapiSeedance2p0(PlanMuapiSeedance2p0 { - prompt, - mode, - })) -} - -fn resolve_image_urls( - reference_images: Option, -) -> Result>, ArtcraftRouterError> { - match reference_images { - None => Ok(None), - Some(ImageListRef::Urls(urls)) => { - if urls.is_empty() { - Ok(None) - } else { - Ok(Some(urls.clone())) - } - } - Some(ImageListRef::MediaFileTokens(_)) => { - Err(ArtcraftRouterError::Client(ClientError::MuapiOnlySupportsUrls)) - } - } -} - -// Muapi supports: 16:9, 9:16, 4:3, 3:4 (no square, no 1:1) -fn plan_t2v_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - match aspect_ratio { - None - | Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(T2vAspectRatio::Landscape16x9), - - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => { - Ok(T2vAspectRatio::Landscape16x9) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(T2vAspectRatio::Portrait9x16) - } - Some(CommonAspectRatio::WideFourByThree) => Ok(T2vAspectRatio::Standard4x3), - Some(CommonAspectRatio::TallThreeByFour) => Ok(T2vAspectRatio::Portrait3x4), - - // Square and others are not supported by Muapi - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade - | RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(nearest_t2v_aspect_ratio(unsupported)) - } - }, - } -} - -fn nearest_t2v_aspect_ratio(aspect_ratio: CommonAspectRatio) -> T2vAspectRatio { - match aspect_ratio { - // Wide ratios → nearest wide - CommonAspectRatio::Square | CommonAspectRatio::SquareHd - | CommonAspectRatio::WideFiveByFour => T2vAspectRatio::Standard4x3, - CommonAspectRatio::WideThreeByTwo => T2vAspectRatio::Landscape16x9, - CommonAspectRatio::WideTwentyOneByNine => T2vAspectRatio::Landscape16x9, - // Tall ratios → nearest tall - CommonAspectRatio::TallFourByFive => T2vAspectRatio::Portrait3x4, - CommonAspectRatio::TallTwoByThree => T2vAspectRatio::Portrait9x16, - CommonAspectRatio::TallNineByTwentyOne => T2vAspectRatio::Portrait9x16, - _ => T2vAspectRatio::Landscape16x9, - } -} - -fn plan_i2v_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - match aspect_ratio { - None - | Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(I2vAspectRatio::Landscape16x9), - - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => { - Ok(I2vAspectRatio::Landscape16x9) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(I2vAspectRatio::Portrait9x16) - } - Some(CommonAspectRatio::WideFourByThree) => Ok(I2vAspectRatio::Standard4x3), - Some(CommonAspectRatio::TallThreeByFour) => Ok(I2vAspectRatio::Portrait3x4), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade - | RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(nearest_i2v_aspect_ratio(unsupported)) - } - }, - } -} - -fn nearest_i2v_aspect_ratio(aspect_ratio: CommonAspectRatio) -> I2vAspectRatio { - match aspect_ratio { - CommonAspectRatio::Square | CommonAspectRatio::SquareHd - | CommonAspectRatio::WideFiveByFour => I2vAspectRatio::Standard4x3, - CommonAspectRatio::WideThreeByTwo => I2vAspectRatio::Landscape16x9, - CommonAspectRatio::WideTwentyOneByNine => I2vAspectRatio::Landscape16x9, - CommonAspectRatio::TallFourByFive => I2vAspectRatio::Portrait3x4, - CommonAspectRatio::TallTwoByThree => I2vAspectRatio::Portrait9x16, - CommonAspectRatio::TallNineByTwentyOne => I2vAspectRatio::Portrait9x16, - _ => I2vAspectRatio::Landscape16x9, - } -} - -// Muapi supports durations of 5, 10, and 15 seconds. -fn plan_t2v_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - let d = duration_seconds.unwrap_or(5); - match d { - 0..=5 => Ok(T2vDuration::FiveSeconds), - 6..=10 => Ok(T2vDuration::TenSeconds), - 11..=15 => Ok(T2vDuration::FifteenSeconds), - _ => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", d), - })) - } - _ => Ok(T2vDuration::FifteenSeconds), // clamp to max - }, - } -} - -fn plan_i2v_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - let d = duration_seconds.unwrap_or(5); - match d { - 0..=5 => Ok(I2vDuration::FiveSeconds), - 6..=10 => Ok(I2vDuration::TenSeconds), - 11..=15 => Ok(I2vDuration::FifteenSeconds), - _ => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", d), - })) - } - _ => Ok(I2vDuration::FifteenSeconds), - }, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/seedance2pro/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/seedance2pro/mod.rs deleted file mode 100644 index 3413f094c5..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/seedance2pro/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod plan_generate_video_seedance2pro_seedance2p0; -pub mod plan_generate_video_seedance2pro_seedance2p0_fast; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/seedance2pro/plan_generate_video_seedance2pro_seedance2p0.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/seedance2pro/plan_generate_video_seedance2pro_seedance2p0.rs deleted file mode 100644 index c425a0b8f6..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/seedance2pro/plan_generate_video_seedance2pro_seedance2p0.rs +++ /dev/null @@ -1,223 +0,0 @@ -use crate::api::audio_list_ref::AudioListRef; -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::image_list_ref::ImageListRef; -use crate::api::image_ref::ImageRef; -use crate::api::video_list_ref::VideoListRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use seedance2pro_client::requests::generate_video::generate_video::{ - KinoviGenerateVideoRequest as SeedanceGenerateVideoRequest, - KinoviBatchCount, KinoviModelType, KinoviOutputResolution, KinoviAspectRatio, -}; - -use crate::api::common_resolution::CommonResolution; - -#[derive(Debug, Clone)] -pub struct PlanSeedance2proSeedance2p0 { - pub request: SeedanceGenerateVideoRequest, -} - -pub fn plan_generate_video_seedance2pro_seedance2p0( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame_url = resolve_image_ref_url(request.start_frame.clone())?; - let end_frame_url = resolve_image_ref_url(request.end_frame.clone())?; - let reference_image_urls = resolve_image_list_ref_urls(request.reference_images.clone())?; - let reference_video_urls = resolve_video_list_ref_urls(request.reference_videos.clone())?; - let reference_audio_urls = resolve_audio_list_ref_urls(request.reference_audio.clone())?; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let batch_count = plan_batch_count(request.video_batch_count, strategy)?; - let duration_seconds = plan_duration(request.duration_seconds, strategy)?; - - let output_resolution = request.resolution.map(map_common_resolution_to_kinovi); - - Ok(VideoGenerationPlan::Seedance2proSeedance2p0(PlanSeedance2proSeedance2p0 { - request: SeedanceGenerateVideoRequest { - model_type: KinoviModelType::Seedance2Pro, - prompt: request.prompt.clone().unwrap_or_default(), - aspect_ratio, - output_resolution, - duration_seconds, - batch_count, - start_frame_url, - end_frame_url, - reference_image_urls, - reference_video_urls, - reference_audio_urls, - character_ids: None, - use_face_blur_hack: None, - }, - })) -} - -fn map_common_resolution_to_kinovi(resolution: CommonResolution) -> KinoviOutputResolution { - match resolution { - CommonResolution::FourEightyP => KinoviOutputResolution::FourEightyP, - CommonResolution::SevenTwentyP => KinoviOutputResolution::SevenTwentyP, - CommonResolution::TenEightyP => KinoviOutputResolution::TenEightyP, - _ => KinoviOutputResolution::SevenTwentyP, - } -} - -fn resolve_image_ref_url( - image_ref: Option, -) -> Result, ArtcraftRouterError> { - match image_ref { - None => Ok(None), - Some(ImageRef::Url(url)) => Ok(Some(url.to_string())), - Some(ImageRef::MediaFileToken(_)) => { - Err(ArtcraftRouterError::Client(ClientError::Seedance2ProOnlySupportsUrls)) - } - } -} - -fn resolve_image_list_ref_urls( - image_list_ref: Option, -) -> Result>, ArtcraftRouterError> { - match image_list_ref { - None => Ok(None), - Some(ImageListRef::Urls(urls)) => Ok(Some(urls.clone())), - Some(ImageListRef::MediaFileTokens(_)) => { - Err(ArtcraftRouterError::Client(ClientError::Seedance2ProOnlySupportsUrls)) - } - } -} - -fn resolve_video_list_ref_urls( - video_list_ref: Option, -) -> Result>, ArtcraftRouterError> { - match video_list_ref { - None => Ok(None), - Some(VideoListRef::Urls(urls)) => Ok(Some(urls.clone())), - Some(VideoListRef::MediaFileTokens(_)) => { - Err(ArtcraftRouterError::Client(ClientError::Seedance2ProOnlySupportsUrls)) - } - } -} - -fn resolve_audio_list_ref_urls( - audio_list_ref: Option, -) -> Result>, ArtcraftRouterError> { - match audio_list_ref { - None => Ok(None), - Some(AudioListRef::Urls(urls)) => Ok(Some(urls.clone())), - Some(AudioListRef::MediaFileTokens(_)) => { - Err(ArtcraftRouterError::Client(ClientError::Seedance2ProOnlySupportsUrls)) - } - } -} - -// Supported aspect ratios and their AR values (width / height): -// Portrait9x16 = 0.5625, Portrait3x4 = 0.75, Square1x1 = 1.0, Standard4x3 = 1.33, Landscape16x9 = 1.78 -// -// All supported ratios cost the same, so PayMoreUpgrade and PayLessDowngrade both -// select the nearest match rather than rounding in a specific direction. -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - match aspect_ratio { - // No preference or auto — default to landscape - None - | Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(KinoviAspectRatio::Landscape16x9), - - // Direct mappings - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => { - Ok(KinoviAspectRatio::Landscape16x9) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(KinoviAspectRatio::Portrait9x16) - } - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => { - Ok(KinoviAspectRatio::Square1x1) - } - Some(CommonAspectRatio::WideFourByThree) => Ok(KinoviAspectRatio::Standard4x3), - Some(CommonAspectRatio::TallThreeByFour) => Ok(KinoviAspectRatio::Portrait3x4), - - // Mismatches — apply strategy - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade - | RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(nearest_resolution(unsupported)) - } - }, - } -} - -/// Pick the nearest supported resolution by AR value (width / height). -fn nearest_resolution(aspect_ratio: CommonAspectRatio) -> KinoviAspectRatio { - match aspect_ratio { - CommonAspectRatio::WideFiveByFour => KinoviAspectRatio::Standard4x3, // 1.25, nearest 1.33 - CommonAspectRatio::WideThreeByTwo => KinoviAspectRatio::Standard4x3, // 1.50, nearest 1.33 - CommonAspectRatio::WideTwentyOneByNine => KinoviAspectRatio::Landscape16x9, // 2.33, nearest 1.78 - CommonAspectRatio::TallFourByFive => KinoviAspectRatio::Portrait3x4, // 0.80, nearest 0.75 - CommonAspectRatio::TallTwoByThree => KinoviAspectRatio::Portrait3x4, // 0.67, nearest 0.75 - CommonAspectRatio::TallNineByTwentyOne => KinoviAspectRatio::Portrait9x16, // 0.43, nearest 0.56 - _ => KinoviAspectRatio::Square1x1, - } -} - -// Seedance2p0 supports batch counts of 1, 2, and 4 only. -fn plan_batch_count( - video_batch_count: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - let count = video_batch_count.unwrap_or(1); - match count { - 0 => Err(ArtcraftRouterError::Client(ClientError::UserRequestedZeroGenerations)), - 1 => Ok(KinoviBatchCount::One), - 2 => Ok(KinoviBatchCount::Two), - 4 => Ok(KinoviBatchCount::Four), - _ => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "video_batch_count", - value: format!("{}", count), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => { - Ok(if count < 4 { KinoviBatchCount::Four } else { KinoviBatchCount::Four }) - } - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(if count < 4 { KinoviBatchCount::Two } else { KinoviBatchCount::Four }) - } - }, - } -} - -// Seedance2p0 supports duration of 4–15 seconds. -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - const MIN: u16 = 4; - const MAX: u16 = 15; - const DEFAULT: u8 = 5; - match duration_seconds { - None => Ok(DEFAULT), - Some(d) if d >= MIN && d <= MAX => Ok(d as u8), - Some(d) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", d), - })) - } - _ => Ok(d.clamp(MIN, MAX) as u8), - }, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/seedance2pro/plan_generate_video_seedance2pro_seedance2p0_fast.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/seedance2pro/plan_generate_video_seedance2pro_seedance2p0_fast.rs deleted file mode 100644 index 9824ace6a7..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/plan/seedance2pro/plan_generate_video_seedance2pro_seedance2p0_fast.rs +++ /dev/null @@ -1,212 +0,0 @@ -use crate::api::audio_list_ref::AudioListRef; -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::image_list_ref::ImageListRef; -use crate::api::image_ref::ImageRef; -use crate::api::video_list_ref::VideoListRef; -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_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use seedance2pro_client::requests::generate_video::generate_video::{ - KinoviGenerateVideoRequest as SeedanceGenerateVideoRequest, - KinoviBatchCount, KinoviModelType, KinoviOutputResolution, KinoviAspectRatio, -}; - -use crate::api::common_resolution::CommonResolution; - -#[derive(Debug, Clone)] -pub struct PlanSeedance2proSeedance2p0Fast { - pub request: SeedanceGenerateVideoRequest, -} - -pub fn plan_generate_video_seedance2pro_seedance2p0_fast( - request: &GenerateVideoRequestBuilder, -) -> Result { - let strategy = request.request_mismatch_mitigation_strategy; - - let start_frame_url = resolve_image_ref_url(request.start_frame.clone())?; - let end_frame_url = resolve_image_ref_url(request.end_frame.clone())?; - let reference_image_urls = resolve_image_list_ref_urls(request.reference_images.clone())?; - let reference_video_urls = resolve_video_list_ref_urls(request.reference_videos.clone())?; - let reference_audio_urls = resolve_audio_list_ref_urls(request.reference_audio.clone())?; - - let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?; - let batch_count = plan_batch_count(request.video_batch_count, strategy)?; - let duration_seconds = plan_duration(request.duration_seconds, strategy)?; - - let output_resolution = request.resolution.map(map_common_resolution_to_kinovi); - - Ok(VideoGenerationPlan::Seedance2proSeedance2p0Fast(PlanSeedance2proSeedance2p0Fast { - request: SeedanceGenerateVideoRequest { - model_type: KinoviModelType::Seedance2Fast, - prompt: request.prompt.clone().unwrap_or_default(), - aspect_ratio, - output_resolution, - duration_seconds, - batch_count, - start_frame_url, - end_frame_url, - reference_image_urls, - reference_video_urls, - reference_audio_urls, - character_ids: None, - use_face_blur_hack: None, - }, - })) -} - -fn map_common_resolution_to_kinovi(resolution: CommonResolution) -> KinoviOutputResolution { - match resolution { - CommonResolution::FourEightyP => KinoviOutputResolution::FourEightyP, - CommonResolution::SevenTwentyP => KinoviOutputResolution::SevenTwentyP, - CommonResolution::TenEightyP => KinoviOutputResolution::SevenTwentyP, // NB: Kinovi doesn't have 1080p fast currently - _ => KinoviOutputResolution::SevenTwentyP, - } -} - -fn resolve_image_ref_url( - image_ref: Option, -) -> Result, ArtcraftRouterError> { - match image_ref { - None => Ok(None), - Some(ImageRef::Url(url)) => Ok(Some(url.to_string())), - Some(ImageRef::MediaFileToken(_)) => { - Err(ArtcraftRouterError::Client(ClientError::Seedance2ProOnlySupportsUrls)) - } - } -} - -fn resolve_image_list_ref_urls( - image_list_ref: Option, -) -> Result>, ArtcraftRouterError> { - match image_list_ref { - None => Ok(None), - Some(ImageListRef::Urls(urls)) => Ok(Some(urls.clone())), - Some(ImageListRef::MediaFileTokens(_)) => { - Err(ArtcraftRouterError::Client(ClientError::Seedance2ProOnlySupportsUrls)) - } - } -} - -fn resolve_video_list_ref_urls( - video_list_ref: Option, -) -> Result>, ArtcraftRouterError> { - match video_list_ref { - None => Ok(None), - Some(VideoListRef::Urls(urls)) => Ok(Some(urls.clone())), - Some(VideoListRef::MediaFileTokens(_)) => { - Err(ArtcraftRouterError::Client(ClientError::Seedance2ProOnlySupportsUrls)) - } - } -} - -fn resolve_audio_list_ref_urls( - audio_list_ref: Option, -) -> Result>, ArtcraftRouterError> { - match audio_list_ref { - None => Ok(None), - Some(AudioListRef::Urls(urls)) => Ok(Some(urls.clone())), - Some(AudioListRef::MediaFileTokens(_)) => { - Err(ArtcraftRouterError::Client(ClientError::Seedance2ProOnlySupportsUrls)) - } - } -} - -fn plan_aspect_ratio( - aspect_ratio: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - match aspect_ratio { - None - | Some(CommonAspectRatio::Auto) - | Some(CommonAspectRatio::Auto2k) - | Some(CommonAspectRatio::Auto4k) => Ok(KinoviAspectRatio::Landscape16x9), - - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => { - Ok(KinoviAspectRatio::Landscape16x9) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(KinoviAspectRatio::Portrait9x16) - } - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => { - Ok(KinoviAspectRatio::Square1x1) - } - Some(CommonAspectRatio::WideFourByThree) => Ok(KinoviAspectRatio::Standard4x3), - Some(CommonAspectRatio::TallThreeByFour) => Ok(KinoviAspectRatio::Portrait3x4), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "aspect_ratio", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade - | RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(nearest_resolution(unsupported)) - } - }, - } -} - -fn nearest_resolution(aspect_ratio: CommonAspectRatio) -> KinoviAspectRatio { - match aspect_ratio { - CommonAspectRatio::WideFiveByFour => KinoviAspectRatio::Standard4x3, - CommonAspectRatio::WideThreeByTwo => KinoviAspectRatio::Standard4x3, - CommonAspectRatio::WideTwentyOneByNine => KinoviAspectRatio::Landscape16x9, - CommonAspectRatio::TallFourByFive => KinoviAspectRatio::Portrait3x4, - CommonAspectRatio::TallTwoByThree => KinoviAspectRatio::Portrait3x4, - CommonAspectRatio::TallNineByTwentyOne => KinoviAspectRatio::Portrait9x16, - _ => KinoviAspectRatio::Square1x1, - } -} - -fn plan_batch_count( - video_batch_count: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - let count = video_batch_count.unwrap_or(1); - match count { - 0 => Err(ArtcraftRouterError::Client(ClientError::UserRequestedZeroGenerations)), - 1 => Ok(KinoviBatchCount::One), - 2 => Ok(KinoviBatchCount::Two), - 4 => Ok(KinoviBatchCount::Four), - _ => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "video_batch_count", - value: format!("{}", count), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => { - Ok(if count < 4 { KinoviBatchCount::Four } else { KinoviBatchCount::Four }) - } - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(if count < 4 { KinoviBatchCount::Two } else { KinoviBatchCount::Four }) - } - }, - } -} - -fn plan_duration( - duration_seconds: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result { - const MIN: u16 = 4; - const MAX: u16 = 15; - const DEFAULT: u8 = 5; - match duration_seconds { - None => Ok(DEFAULT), - Some(d) if d >= MIN && d <= MAX => Ok(d as u8), - Some(d) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "duration_seconds", - value: format!("{}", d), - })) - } - _ => Ok(d.clamp(MIN, MAX) as u8), - }, - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/video_generation_plan.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/video_generation_plan.rs deleted file mode 100644 index 3bee61abce..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/video_generation_plan.rs +++ /dev/null @@ -1,377 +0,0 @@ -use crate::client::router_client::RouterClient; -use crate::errors::artcraft_router_error::ArtcraftRouterError; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_kling_1_6_pro::estimate_video_cost_artcraft_kling_1_6_pro; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_kling_2_1_master::estimate_video_cost_artcraft_kling_2_1_master; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_kling_2_1_pro::estimate_video_cost_artcraft_kling_2_1_pro; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_kling_2_5_turbo_pro::estimate_video_cost_artcraft_kling_2_5_turbo_pro; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_kling_2_6_pro::estimate_video_cost_artcraft_kling_2_6_pro; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_kling3p0_pro::estimate_video_cost_artcraft_kling3p0_pro; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_kling3p0_standard::estimate_video_cost_artcraft_kling3p0_standard; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_seedance_1_0_lite::estimate_video_cost_artcraft_seedance_1_0_lite; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_seedance1p5_pro::estimate_video_cost_artcraft_seedance1p5_pro; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_seedance2p0::estimate_video_cost_artcraft_seedance2p0; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_seedance2p0_fast::estimate_video_cost_artcraft_seedance2p0_fast; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_sora_2::estimate_video_cost_artcraft_sora_2; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_sora_2_pro::estimate_video_cost_artcraft_sora_2_pro; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_veo_2::estimate_video_cost_artcraft_veo_2; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_veo_3::estimate_video_cost_artcraft_veo_3; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_veo_3_fast::estimate_video_cost_artcraft_veo_3_fast; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_veo_3p1::estimate_video_cost_artcraft_veo_3p1; -use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_veo_3p1_fast::estimate_video_cost_artcraft_veo_3p1_fast; -use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_kling_1_6_pro::estimate_video_cost_fal_kling_1_6_pro; -use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_kling_2_1_master::estimate_video_cost_fal_kling_2_1_master; -use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_kling_2_1_pro::estimate_video_cost_fal_kling_2_1_pro; -use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_kling_2_5_turbo_pro::estimate_video_cost_fal_kling_2_5_turbo_pro; -use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_kling_2_6_pro::estimate_video_cost_fal_kling_2_6_pro; -use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_kling_3p0_pro::estimate_video_cost_fal_kling_3p0_pro; -use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_kling_3p0_standard::estimate_video_cost_fal_kling_3p0_standard; -use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_seedance_1_0_lite::estimate_video_cost_fal_seedance_1_0_lite; -use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_seedance_1p5_pro::estimate_video_cost_fal_seedance_1p5_pro; -use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_sora_2::estimate_video_cost_fal_sora_2; -use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_sora_2_pro::estimate_video_cost_fal_sora_2_pro; -use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_veo_2::estimate_video_cost_fal_veo_2; -use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_veo_3::estimate_video_cost_fal_veo_3; -use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_veo_3_fast::estimate_video_cost_fal_veo_3_fast; -use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_veo_3p1::estimate_video_cost_fal_veo_3p1; -use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_veo_3p1_fast::estimate_video_cost_fal_veo_3p1_fast; -use crate::generate::generate_video::cost::muapi::estimate_video_cost_muapi_seedance2p0::estimate_video_cost_muapi_seedance2p0; -use crate::generate::generate_video::cost::seedance2pro::estimate_video_cost_seedance2pro_seedance2p0::estimate_video_cost_seedance2pro_seedance2p0; -use crate::generate::generate_video::cost::seedance2pro::estimate_video_cost_seedance2pro_seedance2p0_fast::estimate_video_cost_seedance2pro_seedance2p0_fast; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_kling_1_6_pro::execute_artcraft_kling_1_6_pro; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_kling_2_1_master::execute_artcraft_kling_2_1_master; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_kling_2_1_pro::execute_artcraft_kling_2_1_pro; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_kling_2_5_turbo_pro::execute_artcraft_kling_2_5_turbo_pro; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_kling_2_6_pro::execute_artcraft_kling_2_6_pro; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_kling3p0_pro::execute_artcraft_kling3p0_pro; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_kling3p0_standard::execute_artcraft_kling3p0_standard; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_seedance_1_0_lite::execute_artcraft_seedance_1_0_lite; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_seedance1p5_pro::execute_artcraft_seedance1p5_pro; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_seedance2p0::execute_artcraft_seedance2p0; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_seedance2p0_fast::execute_artcraft_seedance2p0_fast; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_sora_2::execute_artcraft_sora_2; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_sora_2_pro::execute_artcraft_sora_2_pro; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_veo_2::execute_artcraft_veo_2; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_veo_3::execute_artcraft_veo_3; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_veo_3_fast::execute_artcraft_veo_3_fast; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_veo_3p1::execute_artcraft_veo_3p1; -use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_veo_3p1_fast::execute_artcraft_veo_3p1_fast; -use crate::generate::generate_video::execute::fal::generate_video_fal_kling_1_6_pro::execute_fal_kling_1_6_pro; -use crate::generate::generate_video::execute::fal::generate_video_fal_kling_2_1_master::execute_fal_kling_2_1_master; -use crate::generate::generate_video::execute::fal::generate_video_fal_kling_2_1_pro::execute_fal_kling_2_1_pro; -use crate::generate::generate_video::execute::fal::generate_video_fal_kling_2_5_turbo_pro::execute_fal_kling_2_5_turbo_pro; -use crate::generate::generate_video::execute::fal::generate_video_fal_kling_2_6_pro::execute_fal_kling_2_6_pro; -use crate::generate::generate_video::execute::fal::generate_video_fal_kling_3p0_pro::execute_fal_kling_3p0_pro; -use crate::generate::generate_video::execute::fal::generate_video_fal_kling_3p0_standard::execute_fal_kling_3p0_standard; -use crate::generate::generate_video::execute::fal::generate_video_fal_seedance_1_0_lite::execute_fal_seedance_1_0_lite; -use crate::generate::generate_video::execute::fal::generate_video_fal_seedance_1p5_pro::execute_fal_seedance_1p5_pro; -use crate::generate::generate_video::execute::fal::generate_video_fal_sora_2::execute_fal_sora_2; -use crate::generate::generate_video::execute::fal::generate_video_fal_sora_2_pro::execute_fal_sora_2_pro; -use crate::generate::generate_video::execute::fal::generate_video_fal_veo_2::execute_fal_veo_2; -use crate::generate::generate_video::execute::fal::generate_video_fal_veo_3::execute_fal_veo_3; -use crate::generate::generate_video::execute::fal::generate_video_fal_veo_3_fast::execute_fal_veo_3_fast; -use crate::generate::generate_video::execute::fal::generate_video_fal_veo_3p1::execute_fal_veo_3p1; -use crate::generate::generate_video::execute::fal::generate_video_fal_veo_3p1_fast::execute_fal_veo_3p1_fast; -use crate::generate::generate_video::execute::muapi::execute_muapi_seedance2p0::execute_muapi_seedance2p0; -use crate::generate::generate_video::execute::seedance2pro::execute_seedance2pro_seedance2p0::execute_seedance2pro_seedance2p0; -use crate::generate::generate_video::execute::seedance2pro::execute_seedance2pro_seedance2p0_fast::execute_seedance2pro_seedance2p0_fast; -use crate::generate::generate_video::generate_video_response::GenerateVideoResponse; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_1_6_pro::PlanArtcraftKling16Pro; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_1_master::PlanArtcraftKling21Master; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_1_pro::PlanArtcraftKling21Pro; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_5_turbo_pro::PlanArtcraftKling2p5TurboPro; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_6_pro::PlanArtcraftKling2p6Pro; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling3p0_pro::PlanArtcraftKling3p0Pro; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling3p0_standard::PlanArtcraftKling3p0Standard; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance_1_0_lite::PlanArtcraftSeedance10Lite; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance1p5_pro::PlanArtcraftSeedance1p5Pro; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance2p0::PlanArtcraftSeedance2p0; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_sora_2::PlanArtcraftSora2; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_sora_2_pro::PlanArtcraftSora2Pro; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_2::PlanArtcraftVeo2; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_3::PlanArtcraftVeo3; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_3_fast::PlanArtcraftVeo3Fast; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_3p1::PlanArtcraftVeo3p1; -use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_veo_3p1_fast::PlanArtcraftVeo3p1Fast; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_1_6_pro::PlanFalKling16Pro; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_2_1_master::PlanFalKling21Master; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_2_1_pro::PlanFalKling21Pro; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_2_5_turbo_pro::PlanFalKling2p5TurboPro; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_2_6_pro::PlanFalKling2p6Pro; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_3p0_pro::PlanFalKling3p0Pro; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_kling_3p0_standard::PlanFalKling3p0Standard; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_seedance_1_0_lite::PlanFalSeedance10Lite; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_seedance_1p5_pro::PlanFalSeedance1p5Pro; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_sora_2::PlanFalSora2; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_sora_2_pro::PlanFalSora2Pro; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_2::PlanFalVeo2; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3::PlanFalVeo3; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3_fast::PlanFalVeo3Fast; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1::PlanFalVeo3p1; -use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1_fast::PlanFalVeo3p1Fast; -use crate::generate::generate_video::plan::muapi::plan_generate_video_muapi_seedance2p0::PlanMuapiSeedance2p0; -use crate::generate::generate_video::plan::seedance2pro::plan_generate_video_seedance2pro_seedance2p0::PlanSeedance2proSeedance2p0; -use crate::generate::generate_video::plan::seedance2pro::plan_generate_video_seedance2pro_seedance2p0_fast::PlanSeedance2proSeedance2p0Fast; -use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; - -#[derive(Debug)] -pub enum VideoGenerationPlan { - ArtcraftKling16Pro(PlanArtcraftKling16Pro), - ArtcraftKling21Master(PlanArtcraftKling21Master), - ArtcraftKling21Pro(PlanArtcraftKling21Pro), - ArtcraftKling2p5TurboPro(PlanArtcraftKling2p5TurboPro), - ArtcraftKling2p6Pro(PlanArtcraftKling2p6Pro), - ArtcraftKling3p0Pro(PlanArtcraftKling3p0Pro), - ArtcraftKling3p0Standard(PlanArtcraftKling3p0Standard), - ArtcraftSeedance10Lite(PlanArtcraftSeedance10Lite), - ArtcraftSeedance1p5Pro(PlanArtcraftSeedance1p5Pro), - ArtcraftSeedance2p0(PlanArtcraftSeedance2p0), - ArtcraftSeedance2p0Fast(PlanArtcraftSeedance2p0), - ArtcraftSora2(PlanArtcraftSora2), - ArtcraftSora2Pro(PlanArtcraftSora2Pro), - ArtcraftVeo2(PlanArtcraftVeo2), - ArtcraftVeo3(PlanArtcraftVeo3), - ArtcraftVeo3Fast(PlanArtcraftVeo3Fast), - ArtcraftVeo3p1(PlanArtcraftVeo3p1), - ArtcraftVeo3p1Fast(PlanArtcraftVeo3p1Fast), - MuapiSeedance2p0(PlanMuapiSeedance2p0), - Seedance2proSeedance2p0(PlanSeedance2proSeedance2p0), - Seedance2proSeedance2p0Fast(PlanSeedance2proSeedance2p0Fast), - FalVeo2(PlanFalVeo2), - FalVeo3(PlanFalVeo3), - FalVeo3Fast(PlanFalVeo3Fast), - FalVeo3p1(PlanFalVeo3p1), - FalVeo3p1Fast(PlanFalVeo3p1Fast), - FalKling16Pro(PlanFalKling16Pro), - FalKling21Pro(PlanFalKling21Pro), - FalKling21Master(PlanFalKling21Master), - FalKling2p5TurboPro(PlanFalKling2p5TurboPro), - FalKling2p6Pro(PlanFalKling2p6Pro), - FalKling3p0Pro(PlanFalKling3p0Pro), - FalKling3p0Standard(PlanFalKling3p0Standard), - FalSeedance10Lite(PlanFalSeedance10Lite), - FalSeedance1p5Pro(PlanFalSeedance1p5Pro), - FalSora2(PlanFalSora2), - FalSora2Pro(PlanFalSora2Pro), -} - -impl VideoGenerationPlan { - pub async fn generate_video( - &self, - client: &RouterClient, - ) -> Result { - match self { - VideoGenerationPlan::ArtcraftKling16Pro(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_kling_1_6_pro(plan, artcraft_client).await - } - VideoGenerationPlan::ArtcraftKling21Master(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_kling_2_1_master(plan, artcraft_client).await - } - VideoGenerationPlan::ArtcraftKling21Pro(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_kling_2_1_pro(plan, artcraft_client).await - } - VideoGenerationPlan::ArtcraftKling2p5TurboPro(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_kling_2_5_turbo_pro(plan, artcraft_client).await - } - VideoGenerationPlan::ArtcraftKling2p6Pro(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_kling_2_6_pro(plan, artcraft_client).await - } - VideoGenerationPlan::ArtcraftKling3p0Pro(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_kling3p0_pro(plan, artcraft_client).await - } - VideoGenerationPlan::ArtcraftKling3p0Standard(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_kling3p0_standard(plan, artcraft_client).await - } - VideoGenerationPlan::ArtcraftSeedance10Lite(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_seedance_1_0_lite(plan, artcraft_client).await - } - VideoGenerationPlan::ArtcraftSeedance1p5Pro(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_seedance1p5_pro(plan, artcraft_client).await - } - VideoGenerationPlan::ArtcraftSeedance2p0(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_seedance2p0(plan, artcraft_client).await - } - VideoGenerationPlan::ArtcraftSeedance2p0Fast(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_seedance2p0_fast(plan, artcraft_client).await - } - VideoGenerationPlan::ArtcraftSora2(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_sora_2(plan, artcraft_client).await - } - VideoGenerationPlan::ArtcraftSora2Pro(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_sora_2_pro(plan, artcraft_client).await - } - VideoGenerationPlan::ArtcraftVeo2(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_veo_2(plan, artcraft_client).await - } - VideoGenerationPlan::ArtcraftVeo3(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_veo_3(plan, artcraft_client).await - } - VideoGenerationPlan::ArtcraftVeo3Fast(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_veo_3_fast(plan, artcraft_client).await - } - VideoGenerationPlan::ArtcraftVeo3p1(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_veo_3p1(plan, artcraft_client).await - } - VideoGenerationPlan::ArtcraftVeo3p1Fast(plan) => { - let artcraft_client = client.get_artcraft_client_ref()?; - execute_artcraft_veo_3p1_fast(plan, artcraft_client).await - } - VideoGenerationPlan::MuapiSeedance2p0(plan) => { - let muapi_client = client.get_muapi_client_ref()?; - execute_muapi_seedance2p0(plan, muapi_client).await - } - VideoGenerationPlan::Seedance2proSeedance2p0(plan) => { - let seedance2pro_client = client.get_seedance2pro_client_ref()?; - execute_seedance2pro_seedance2p0(plan, seedance2pro_client).await - } - VideoGenerationPlan::Seedance2proSeedance2p0Fast(plan) => { - let seedance2pro_client = client.get_seedance2pro_client_ref()?; - execute_seedance2pro_seedance2p0_fast(plan, seedance2pro_client).await - } - VideoGenerationPlan::FalVeo2(plan) => { - let fal_client = client.get_fal_client_ref()?; - execute_fal_veo_2(plan, fal_client).await - } - VideoGenerationPlan::FalVeo3(plan) => { - let fal_client = client.get_fal_client_ref()?; - execute_fal_veo_3(plan, fal_client).await - } - VideoGenerationPlan::FalVeo3Fast(plan) => { - let fal_client = client.get_fal_client_ref()?; - execute_fal_veo_3_fast(plan, fal_client).await - } - VideoGenerationPlan::FalVeo3p1(plan) => { - let fal_client = client.get_fal_client_ref()?; - execute_fal_veo_3p1(plan, fal_client).await - } - VideoGenerationPlan::FalVeo3p1Fast(plan) => { - let fal_client = client.get_fal_client_ref()?; - execute_fal_veo_3p1_fast(plan, fal_client).await - } - VideoGenerationPlan::FalKling16Pro(plan) => { - let fal_client = client.get_fal_client_ref()?; - execute_fal_kling_1_6_pro(plan, fal_client).await - } - VideoGenerationPlan::FalKling21Pro(plan) => { - let fal_client = client.get_fal_client_ref()?; - execute_fal_kling_2_1_pro(plan, fal_client).await - } - VideoGenerationPlan::FalKling21Master(plan) => { - let fal_client = client.get_fal_client_ref()?; - execute_fal_kling_2_1_master(plan, fal_client).await - } - VideoGenerationPlan::FalKling2p5TurboPro(plan) => { - let fal_client = client.get_fal_client_ref()?; - execute_fal_kling_2_5_turbo_pro(plan, fal_client).await - } - VideoGenerationPlan::FalKling2p6Pro(plan) => { - let fal_client = client.get_fal_client_ref()?; - execute_fal_kling_2_6_pro(plan, fal_client).await - } - VideoGenerationPlan::FalKling3p0Pro(plan) => { - let fal_client = client.get_fal_client_ref()?; - execute_fal_kling_3p0_pro(plan, fal_client).await - } - VideoGenerationPlan::FalKling3p0Standard(plan) => { - let fal_client = client.get_fal_client_ref()?; - execute_fal_kling_3p0_standard(plan, fal_client).await - } - VideoGenerationPlan::FalSeedance10Lite(plan) => { - let fal_client = client.get_fal_client_ref()?; - execute_fal_seedance_1_0_lite(plan, fal_client).await - } - VideoGenerationPlan::FalSeedance1p5Pro(plan) => { - let fal_client = client.get_fal_client_ref()?; - execute_fal_seedance_1p5_pro(plan, fal_client).await - } - VideoGenerationPlan::FalSora2(plan) => { - let fal_client = client.get_fal_client_ref()?; - execute_fal_sora_2(plan, fal_client).await - } - VideoGenerationPlan::FalSora2Pro(plan) => { - let fal_client = client.get_fal_client_ref()?; - execute_fal_sora_2_pro(plan, fal_client).await - } - } - } - - pub fn estimate_costs(&self) -> VideoGenerationCostEstimate { - match self { - VideoGenerationPlan::ArtcraftKling16Pro(plan) => estimate_video_cost_artcraft_kling_1_6_pro(plan), - VideoGenerationPlan::ArtcraftKling21Master(plan) => estimate_video_cost_artcraft_kling_2_1_master(plan), - VideoGenerationPlan::ArtcraftKling21Pro(plan) => estimate_video_cost_artcraft_kling_2_1_pro(plan), - VideoGenerationPlan::ArtcraftKling2p5TurboPro(plan) => estimate_video_cost_artcraft_kling_2_5_turbo_pro(plan), - VideoGenerationPlan::ArtcraftKling2p6Pro(plan) => estimate_video_cost_artcraft_kling_2_6_pro(plan), - VideoGenerationPlan::ArtcraftKling3p0Pro(plan) => { - estimate_video_cost_artcraft_kling3p0_pro(plan) - } - VideoGenerationPlan::ArtcraftKling3p0Standard(plan) => { - estimate_video_cost_artcraft_kling3p0_standard(plan) - } - VideoGenerationPlan::ArtcraftSeedance10Lite(plan) => { - estimate_video_cost_artcraft_seedance_1_0_lite(plan) - } - VideoGenerationPlan::ArtcraftSeedance1p5Pro(plan) => { - estimate_video_cost_artcraft_seedance1p5_pro(plan) - } - VideoGenerationPlan::ArtcraftSeedance2p0(plan) => { - estimate_video_cost_artcraft_seedance2p0(plan) - } - VideoGenerationPlan::ArtcraftSeedance2p0Fast(plan) => { - estimate_video_cost_artcraft_seedance2p0_fast(plan) - } - VideoGenerationPlan::ArtcraftSora2(plan) => { - estimate_video_cost_artcraft_sora_2(plan) - } - VideoGenerationPlan::ArtcraftSora2Pro(plan) => { - estimate_video_cost_artcraft_sora_2_pro(plan) - } - VideoGenerationPlan::ArtcraftVeo2(plan) => estimate_video_cost_artcraft_veo_2(plan), - VideoGenerationPlan::ArtcraftVeo3(plan) => estimate_video_cost_artcraft_veo_3(plan), - VideoGenerationPlan::ArtcraftVeo3Fast(plan) => estimate_video_cost_artcraft_veo_3_fast(plan), - VideoGenerationPlan::ArtcraftVeo3p1(plan) => estimate_video_cost_artcraft_veo_3p1(plan), - VideoGenerationPlan::ArtcraftVeo3p1Fast(plan) => estimate_video_cost_artcraft_veo_3p1_fast(plan), - VideoGenerationPlan::MuapiSeedance2p0(plan) => { - estimate_video_cost_muapi_seedance2p0(plan) - } - VideoGenerationPlan::Seedance2proSeedance2p0(plan) => { - estimate_video_cost_seedance2pro_seedance2p0(plan) - } - VideoGenerationPlan::Seedance2proSeedance2p0Fast(plan) => { - estimate_video_cost_seedance2pro_seedance2p0_fast(plan) - } - VideoGenerationPlan::FalVeo2(plan) => estimate_video_cost_fal_veo_2(plan), - VideoGenerationPlan::FalVeo3(plan) => estimate_video_cost_fal_veo_3(plan), - VideoGenerationPlan::FalVeo3Fast(plan) => estimate_video_cost_fal_veo_3_fast(plan), - VideoGenerationPlan::FalVeo3p1(plan) => estimate_video_cost_fal_veo_3p1(plan), - VideoGenerationPlan::FalVeo3p1Fast(plan) => estimate_video_cost_fal_veo_3p1_fast(plan), - VideoGenerationPlan::FalKling16Pro(plan) => estimate_video_cost_fal_kling_1_6_pro(plan), - VideoGenerationPlan::FalKling21Pro(plan) => estimate_video_cost_fal_kling_2_1_pro(plan), - VideoGenerationPlan::FalKling21Master(plan) => estimate_video_cost_fal_kling_2_1_master(plan), - VideoGenerationPlan::FalKling2p5TurboPro(plan) => estimate_video_cost_fal_kling_2_5_turbo_pro(plan), - VideoGenerationPlan::FalKling2p6Pro(plan) => estimate_video_cost_fal_kling_2_6_pro(plan), - VideoGenerationPlan::FalKling3p0Pro(plan) => estimate_video_cost_fal_kling_3p0_pro(plan), - VideoGenerationPlan::FalKling3p0Standard(plan) => estimate_video_cost_fal_kling_3p0_standard(plan), - VideoGenerationPlan::FalSeedance10Lite(plan) => estimate_video_cost_fal_seedance_1_0_lite(plan), - VideoGenerationPlan::FalSeedance1p5Pro(plan) => estimate_video_cost_fal_seedance_1p5_pro(plan), - VideoGenerationPlan::FalSora2(plan) => estimate_video_cost_fal_sora_2(plan), - VideoGenerationPlan::FalSora2Pro(plan) => estimate_video_cost_fal_sora_2_pro(plan), - } - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/kling_cost_parity_tests.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/kling_cost_parity_tests.rs deleted file mode 100644 index a1c1aef60b..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/kling_cost_parity_tests.rs +++ /dev/null @@ -1,343 +0,0 @@ -//! Combinatorial cost-parity tests between v1 (`build().estimate_costs()`) and v2 -//! (`build2().estimate_cost()`) for the Artcraft-hosted Kling video models. -//! -//! All 7 Kling variants run on the v2 omni-gen path, but each owns its own -//! pricing formula in v2 (mirroring the v1 plan-based price). These tests -//! prove the new formula reproduces v1 prices across every shape we expect -//! routers to send. - -#![cfg(test)] - -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_video_model::CommonVideoModel; -use crate::api::image_ref::ImageRef; -use crate::api::provider::Provider; -use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy; -use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use tokens::tokens::media_files::MediaFileToken; - -fn v1_cost(builder: &GenerateVideoRequestBuilder) -> Option { - builder.build().ok().and_then(|plan| plan.estimate_costs().cost_in_usd_cents) -} - -fn v2_cost(builder: GenerateVideoRequestBuilder) -> Option { - builder - .build2() - .ok() - .and_then(|dor| dor.estimate_cost().ok()) - .and_then(|estimate| estimate.cost_in_usd_cents) -} - -fn dummy_token() -> MediaFileToken { - MediaFileToken::new("mf_dummy".to_string()) -} - -fn supported_aspect_ratios() -> &'static [Option] { - &[ - None, - Some(CommonAspectRatio::Square), - Some(CommonAspectRatio::WideSixteenByNine), - Some(CommonAspectRatio::TallNineBySixteen), - Some(CommonAspectRatio::Auto), - // Unsupported — falls back to nearest_aspect_ratio per omni-gen helper. - Some(CommonAspectRatio::WideFourByThree), - ] -} - -// ── Kling 1.6 Pro ── - -mod kling_1_6_pro { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling16Pro, - provider: Provider::Artcraft, - start_frame: Some(ImageRef::MediaFileToken(dummy_token())), - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(5u16), Some(10)]; - let mut combos = 0; - for &aspect_ratio in supported_aspect_ratios() { - for &duration in &durations { - for include_end_frame in [false, true] { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.duration_seconds = duration; - if include_end_frame { - builder.end_frame = Some(ImageRef::MediaFileToken(dummy_token())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "artcraft kling_1_6_pro: ar={:?} dur={:?} end={} → v1={:?} v2={:?}", - aspect_ratio, duration, include_end_frame, v1, v2); - combos += 1; - } - } - } - assert_eq!(combos, 6 * 3 * 2); - } -} - -// ── Kling 2.1 Pro ── - -mod kling_2_1_pro { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling21Pro, - provider: Provider::Artcraft, - start_frame: Some(ImageRef::MediaFileToken(dummy_token())), - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(5u16), Some(10)]; - let mut combos = 0; - for &aspect_ratio in supported_aspect_ratios() { - for &duration in &durations { - for include_end_frame in [false, true] { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.duration_seconds = duration; - if include_end_frame { - builder.end_frame = Some(ImageRef::MediaFileToken(dummy_token())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "artcraft kling_2_1_pro: ar={:?} dur={:?} end={} → v1={:?} v2={:?}", - aspect_ratio, duration, include_end_frame, v1, v2); - combos += 1; - } - } - } - assert_eq!(combos, 6 * 3 * 2); - } -} - -// ── Kling 2.1 Master ── - -mod kling_2_1_master { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling21Master, - provider: Provider::Artcraft, - start_frame: Some(ImageRef::MediaFileToken(dummy_token())), - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(5u16), Some(10)]; - let mut combos = 0; - for &aspect_ratio in supported_aspect_ratios() { - for &duration in &durations { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.duration_seconds = duration; - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "artcraft kling_2_1_master: ar={:?} dur={:?} → v1={:?} v2={:?}", - aspect_ratio, duration, v1, v2); - combos += 1; - } - } - assert_eq!(combos, 6 * 3); - } -} - -// ── Kling 2.5 Turbo Pro ── - -mod kling_2_5_turbo_pro { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling2p5TurboPro, - provider: Provider::Artcraft, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(5u16), Some(10)]; - let mut combos = 0; - for &aspect_ratio in supported_aspect_ratios() { - for &duration in &durations { - for has_start in [false, true] { - for include_end in [false, true] { - if include_end && !has_start { continue; } - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.duration_seconds = duration; - if has_start { - builder.start_frame = Some(ImageRef::MediaFileToken(dummy_token())); - } - if include_end { - builder.end_frame = Some(ImageRef::MediaFileToken(dummy_token())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "artcraft kling_2_5_turbo_pro: ar={:?} dur={:?} start={} end={} → v1={:?} v2={:?}", - aspect_ratio, duration, has_start, include_end, v1, v2); - combos += 1; - } - } - } - } - assert!(combos >= 50, "expected ≥50 combos, got {}", combos); - } -} - -// ── Kling 2.6 Pro ── - -mod kling_2_6_pro { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling2p6Pro, - provider: Provider::Artcraft, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(5u16), Some(10)]; - let audios = [None, Some(true), Some(false)]; - let mut combos = 0; - for &aspect_ratio in supported_aspect_ratios() { - for &duration in &durations { - for &generate_audio in &audios { - for has_start in [false, true] { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.duration_seconds = duration; - builder.generate_audio = generate_audio; - if has_start { - builder.start_frame = Some(ImageRef::MediaFileToken(dummy_token())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "artcraft kling_2_6_pro: ar={:?} dur={:?} audio={:?} start={} → v1={:?} v2={:?}", - aspect_ratio, duration, generate_audio, has_start, v1, v2); - combos += 1; - } - } - } - } - assert_eq!(combos, 6 * 3 * 3 * 2); - } -} - -// ── Kling 3.0 Pro ── - -mod kling_3p0_pro { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling3p0Pro, - provider: Provider::Artcraft, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(3u16), Some(5), Some(10), Some(15)]; - let audios = [None, Some(true), Some(false)]; - let mut combos = 0; - for &aspect_ratio in supported_aspect_ratios() { - for &duration in &durations { - for &generate_audio in &audios { - for has_start in [false, true] { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.duration_seconds = duration; - builder.generate_audio = generate_audio; - if has_start { - builder.start_frame = Some(ImageRef::MediaFileToken(dummy_token())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "artcraft kling_3p0_pro: ar={:?} dur={:?} audio={:?} start={} → v1={:?} v2={:?}", - aspect_ratio, duration, generate_audio, has_start, v1, v2); - combos += 1; - } - } - } - } - assert!(combos >= 150, "expected ≥150 combos, got {}", combos); - } - - #[test] - fn cost_parity_out_of_range_durations() { - for &(d, strategy) in &[ - (2, RequestMismatchMitigationStrategy::PayLessDowngrade), - (16, RequestMismatchMitigationStrategy::PayMoreUpgrade), - (20, RequestMismatchMitigationStrategy::PayLessDowngrade), - ] { - let mut builder = base_builder(); - builder.duration_seconds = Some(d); - builder.request_mismatch_mitigation_strategy = strategy; - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "artcraft kling_3p0_pro out-of-range: d={} strat={:?} → v1={:?} v2={:?}", d, strategy, v1, v2); - } - } -} - -// ── Kling 3.0 Standard ── - -mod kling_3p0_standard { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling3p0Standard, - provider: Provider::Artcraft, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(3u16), Some(5), Some(10), Some(15)]; - let audios = [None, Some(true), Some(false)]; - let mut combos = 0; - for &aspect_ratio in supported_aspect_ratios() { - for &duration in &durations { - for &generate_audio in &audios { - for has_start in [false, true] { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.duration_seconds = duration; - builder.generate_audio = generate_audio; - if has_start { - builder.start_frame = Some(ImageRef::MediaFileToken(dummy_token())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "artcraft kling_3p0_standard: ar={:?} dur={:?} audio={:?} start={} → v1={:?} v2={:?}", - aspect_ratio, duration, generate_audio, has_start, v1, v2); - combos += 1; - } - } - } - } - assert!(combos >= 150, "expected ≥150 combos, got {}", combos); - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/mod.rs index 4514de5204..abfc4775dd 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/mod.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/mod.rs @@ -12,6 +12,8 @@ pub mod preview_model; pub mod preview_model_fast; pub(crate) mod request_common; pub(crate) mod resolve; +pub mod seedance_1p0_lite; +pub mod seedance_1p5_pro; pub mod seedance_2p0; pub mod seedance_2p0_fast; pub mod seedance_2p0_u_fast; @@ -26,11 +28,3 @@ pub mod veo_3_fast; pub mod veo_3p1; pub mod veo_3p1_fast; -#[cfg(test)] -mod kling_cost_parity_tests; - -#[cfg(test)] -mod veo_cost_parity_tests; - -#[cfg(test)] -mod sora_cost_parity_tests; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p0_lite/build.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p0_lite/build.rs new file mode 100644 index 0000000000..94f38f4f6c --- /dev/null +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p0_lite/build.rs @@ -0,0 +1,48 @@ +use enums::common::generation::common_video_model::CommonVideoModel as CommonVideoModelEnum; + +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_video::generate_video_request_builder::GenerateVideoRequestBuilder; +use crate::generate::generate_video_v2::providers::artcraft::build_common::{ + build_artcraft_omni_request, SupportedResolutions, UltraWideSupport, +}; +use crate::generate::generate_video_v2::providers::artcraft::seedance_1p0_lite::request::ArtcraftSeedance10LiteRequestState; +use crate::generate::generate_video_v2::video_generation_draft_or_request::VideoGenerationDraftOrRequest; +use crate::generate::generate_video_v2::video_generation_request::VideoGenerationRequest; + +pub fn build_artcraft_seedance_1p0_lite(mut builder: GenerateVideoRequestBuilder) -> Result { + // Seedance 1.0 Lite accepts only {5, 10} seconds; pre-plan so cost parity holds. + let strategy = builder.request_mismatch_mitigation_strategy; + let final_duration = plan_seedance_1p0_lite_duration(builder.duration_seconds, strategy)?; + builder.duration_seconds = final_duration; + + let request = build_artcraft_omni_request( + builder, + CommonVideoModelEnum::Seedance10Lite, + SupportedResolutions::Fast, + UltraWideSupport::Supported, + )?; + let state = ArtcraftSeedance10LiteRequestState { request }; + Ok(VideoGenerationDraftOrRequest::Request(VideoGenerationRequest::ArtcraftSeedance10Lite(state))) +} + +fn plan_seedance_1p0_lite_duration( + duration_seconds: Option, + strategy: RequestMismatchMitigationStrategy, +) -> Result, ArtcraftRouterError> { + match duration_seconds { + None => Ok(None), + Some(5) | Some(10) => Ok(duration_seconds), + Some(other) => match strategy { + RequestMismatchMitigationStrategy::ErrorOut => { + Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { + field: "duration_seconds", + value: format!("{}", other), + })) + } + RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(10)), + RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(5)), + }, + } +} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p0_lite/cost.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p0_lite/cost.rs new file mode 100644 index 0000000000..e3c71523ea --- /dev/null +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p0_lite/cost.rs @@ -0,0 +1,102 @@ +use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; +use fal_client::requests::traits::fal_request_cost_calculator_trait::FalRequestCostCalculator; +use fal_client::requests::webhook::video::image::enqueue_seedance_1_lite_image_to_video_webhook::{ + Seedance1LiteDuration, Seedance1LiteRequest, Seedance1LiteResolution, +}; + +use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; +use crate::generate::generate_video_v2::providers::artcraft::seedance_1p0_lite::request::ArtcraftSeedance10LiteRequestState; + +#[derive(Clone, Debug)] +pub struct ArtcraftSeedance10LiteCostState { + pub duration: Seedance1LiteDuration, + pub resolution: Seedance1LiteResolution, +} + +impl ArtcraftSeedance10LiteCostState { + pub fn from_request(request: &ArtcraftSeedance10LiteRequestState) -> Self { + // Legacy handler defaults: 5 seconds, 720p. + let duration = if request.request.duration_seconds == Some(10) { + Seedance1LiteDuration::TenSeconds + } else { + Seedance1LiteDuration::FiveSeconds + }; + let resolution = match request.request.resolution { + Some(CommonResolutionEnum::FourEightyP) => Seedance1LiteResolution::FourEightyP, + _ => Seedance1LiteResolution::SevenTwentyP, + }; + Self { duration, resolution } + } + + pub fn estimate_cost(&self) -> VideoGenerationCostEstimate { + // Delegate to the Fal client's cost calculator to guarantee parity with + // what we charge through the underlying provider. + let req = Seedance1LiteRequest { + image_url: String::new(), + end_frame_image_url: None, + prompt: String::new(), + duration: self.duration, + resolution: self.resolution, + aspect_ratio: None, + camera_fixed: false, + seed: None, + }; + let cost_in_usd_cents = req.calculate_cost_in_cents(); + + VideoGenerationCostEstimate { + 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, + failures_are_refunded: None, + } + } +} + +#[cfg(test)] +mod tests { + use crate::api::common_resolution::CommonResolution; + use crate::api::common_video_model::CommonVideoModel; + use crate::api::provider::Provider; + use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; + + fn cost_cents(duration_seconds: Option, resolution: Option) -> u64 { + let b = GenerateVideoRequestBuilder { + model: CommonVideoModel::Seedance10Lite, + provider: Provider::Artcraft, + prompt: Some("test".to_string()), + duration_seconds, + resolution, + ..Default::default() + }; + b.build2().unwrap().estimate_cost().unwrap().cost_in_usd_cents.unwrap() + } + + #[test] + fn default_is_720p_5s_priced_at_18() { + // 720p + 5s is the special-cased price from the fal calculator: 18¢. + assert_eq!(cost_cents(None, None), 18); + } + + #[test] + fn p720_5s_is_18() { assert_eq!(cost_cents(Some(5), Some(CommonResolution::SevenTwentyP)), 18); } + + #[test] + fn p720_10s_is_95() { + // 1280×720×30×10/1024 = 270000 tokens × $1.8/M = $0.486 → ceil = 49¢ ... + // No wait — fal kling not seedance. The Seedance 1.0 Lite rate is different. + // Trust the fal calculator: assert whatever the actual computed value is. + let v = cost_cents(Some(10), Some(CommonResolution::SevenTwentyP)); + assert!(v > 18, "10s should cost more than 5s, got {}", v); + } + + #[test] + fn p480_5s_cheaper_than_p720_5s() { + assert!( + cost_cents(Some(5), Some(CommonResolution::FourEightyP)) + < cost_cents(Some(5), Some(CommonResolution::SevenTwentyP)) + ); + } +} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p0_lite/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p0_lite/mod.rs new file mode 100644 index 0000000000..98150bd014 --- /dev/null +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p0_lite/mod.rs @@ -0,0 +1,3 @@ +pub mod build; +pub mod cost; +pub mod request; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p0_lite/request.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p0_lite/request.rs new file mode 100644 index 0000000000..80ec47d992 --- /dev/null +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p0_lite/request.rs @@ -0,0 +1,17 @@ +use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; + +use crate::client::router_artcraft_client::RouterArtcraftClient; +use crate::errors::artcraft_router_error::ArtcraftRouterError; +use crate::generate::generate_video::generate_video_response::GenerateVideoResponse; +use crate::generate::generate_video_v2::providers::artcraft::request_common::send_artcraft_omni_request; + +#[derive(Clone, Debug)] +pub struct ArtcraftSeedance10LiteRequestState { + pub request: OmniGenVideoCostAndGenerateRequest, +} + +impl ArtcraftSeedance10LiteRequestState { + pub async fn send(&self, client: &RouterArtcraftClient) -> Result { + send_artcraft_omni_request(&self.request, client).await + } +} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p5_pro/build.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p5_pro/build.rs new file mode 100644 index 0000000000..32303dd674 --- /dev/null +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p5_pro/build.rs @@ -0,0 +1,54 @@ +use enums::common::generation::common_video_model::CommonVideoModel as CommonVideoModelEnum; + +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_video::generate_video_request_builder::GenerateVideoRequestBuilder; +use crate::generate::generate_video_v2::providers::artcraft::build_common::{ + build_artcraft_omni_request, SupportedResolutions, UltraWideSupport, +}; +use crate::generate::generate_video_v2::providers::artcraft::seedance_1p5_pro::request::ArtcraftSeedance1p5ProRequestState; +use crate::generate::generate_video_v2::video_generation_draft_or_request::VideoGenerationDraftOrRequest; +use crate::generate::generate_video_v2::video_generation_request::VideoGenerationRequest; + +pub fn build_artcraft_seedance_1p5_pro(mut builder: GenerateVideoRequestBuilder) -> Result { + // Seedance 1.5 Pro supports 4-12 seconds; omni-gen helper accepts up to 15, + // so we clamp the upper bound ourselves. Preserve generate_audio (omni-gen + // hardcodes None on output). + let strategy = builder.request_mismatch_mitigation_strategy; + let final_duration = plan_seedance_1p5_pro_duration(builder.duration_seconds, strategy)?; + builder.duration_seconds = final_duration; + + let generate_audio = builder.generate_audio; + let mut request = build_artcraft_omni_request( + builder, + CommonVideoModelEnum::Seedance1p5Pro, + SupportedResolutions::Full, + UltraWideSupport::Supported, + )?; + request.generate_audio = generate_audio; + + let state = ArtcraftSeedance1p5ProRequestState { request }; + Ok(VideoGenerationDraftOrRequest::Request(VideoGenerationRequest::ArtcraftSeedance1p5Pro(state))) +} + +fn plan_seedance_1p5_pro_duration( + duration_seconds: Option, + strategy: RequestMismatchMitigationStrategy, +) -> Result, ArtcraftRouterError> { + const MIN: u16 = 4; + const MAX: u16 = 12; + match duration_seconds { + None => Ok(None), + Some(d) if (MIN..=MAX).contains(&d) => Ok(Some(d)), + Some(d) => match strategy { + RequestMismatchMitigationStrategy::ErrorOut => { + Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { + field: "duration_seconds", + value: format!("{}", d), + })) + } + _ => Ok(Some(d.clamp(MIN, MAX))), + }, + } +} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p5_pro/cost.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p5_pro/cost.rs new file mode 100644 index 0000000000..80e471d09b --- /dev/null +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p5_pro/cost.rs @@ -0,0 +1,109 @@ +use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; +use fal_client::requests::traits::fal_request_cost_calculator_trait::FalRequestCostCalculator; +use fal_client::requests::webhook::video::text::enqueue_seedance_1p5_pro_text_to_video_webhook::{ + EnqueueSeedance1p5ProTextToVideoDuration, EnqueueSeedance1p5ProTextToVideoRequest, + EnqueueSeedance1p5ProTextToVideoResolution, +}; + +use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; +use crate::generate::generate_video_v2::providers::artcraft::seedance_1p5_pro::request::ArtcraftSeedance1p5ProRequestState; + +#[derive(Clone, Debug)] +pub struct ArtcraftSeedance1p5ProCostState { + pub duration: Option, + pub resolution: Option, + pub generate_audio: Option, +} + +impl ArtcraftSeedance1p5ProCostState { + pub fn from_request(request: &ArtcraftSeedance1p5ProRequestState) -> Self { + let duration = request.request.duration_seconds.and_then(seconds_to_duration); + let resolution = request.request.resolution.and_then(common_resolution_to_seedance); + Self { + duration, + resolution, + generate_audio: request.request.generate_audio, + } + } + + pub fn estimate_cost(&self) -> VideoGenerationCostEstimate { + // Delegate to the Fal client's cost calculator. Pricing is identical for + // text-to-video and image-to-video at the same resolution+duration+audio, + // so we use the text-to-video request type as a stand-in. + let req = EnqueueSeedance1p5ProTextToVideoRequest { + prompt: String::new(), + duration: self.duration, + resolution: self.resolution, + aspect_ratio: None, + generate_audio: self.generate_audio, + }; + let cost_in_usd_cents = req.calculate_cost_in_cents(); + + VideoGenerationCostEstimate { + 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, + failures_are_refunded: None, + } + } +} + +fn seconds_to_duration(seconds: u16) -> Option { + use EnqueueSeedance1p5ProTextToVideoDuration as D; + match seconds { + 4 => Some(D::FourSeconds), + 5 => Some(D::FiveSeconds), + 6 => Some(D::SixSeconds), + 7 => Some(D::SevenSeconds), + 8 => Some(D::EightSeconds), + 9 => Some(D::NineSeconds), + 10 => Some(D::TenSeconds), + 11 => Some(D::ElevenSeconds), + 12 => Some(D::TwelveSeconds), + _ => None, + } +} + +fn common_resolution_to_seedance(r: CommonResolutionEnum) -> Option { + match r { + CommonResolutionEnum::FourEightyP => Some(EnqueueSeedance1p5ProTextToVideoResolution::FourEightyP), + CommonResolutionEnum::SevenTwentyP => Some(EnqueueSeedance1p5ProTextToVideoResolution::SevenTwentyP), + CommonResolutionEnum::TenEightyP => Some(EnqueueSeedance1p5ProTextToVideoResolution::TenEightyP), + _ => None, + } +} + +#[cfg(test)] +mod tests { + use crate::api::common_video_model::CommonVideoModel; + use crate::api::provider::Provider; + use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; + + fn cost_cents(duration_seconds: Option) -> u64 { + let b = GenerateVideoRequestBuilder { + model: CommonVideoModel::Seedance1p5Pro, + provider: Provider::Artcraft, + prompt: Some("test".to_string()), + duration_seconds, + ..Default::default() + }; + b.build2().unwrap().estimate_cost().unwrap().cost_in_usd_cents.unwrap() + } + + // Numeric literals mirror the v1 Artcraft Seedance 1.5 Pro tests we deleted: + // resolution=None + generate_audio=None → fal client defaults (720p, audio on). + #[test] + fn default_5s_is_26() { assert_eq!(cost_cents(Some(5)), 26); } + + #[test] + fn default_4s_is_26() { assert_eq!(cost_cents(Some(4)), 26); } + + #[test] + fn default_10s_is_65() { assert_eq!(cost_cents(Some(10)), 65); } + + #[test] + fn default_12s_is_78() { assert_eq!(cost_cents(Some(12)), 78); } +} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p5_pro/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p5_pro/mod.rs new file mode 100644 index 0000000000..98150bd014 --- /dev/null +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p5_pro/mod.rs @@ -0,0 +1,3 @@ +pub mod build; +pub mod cost; +pub mod request; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p5_pro/request.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p5_pro/request.rs new file mode 100644 index 0000000000..b5a674e747 --- /dev/null +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_1p5_pro/request.rs @@ -0,0 +1,17 @@ +use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; + +use crate::client::router_artcraft_client::RouterArtcraftClient; +use crate::errors::artcraft_router_error::ArtcraftRouterError; +use crate::generate::generate_video::generate_video_response::GenerateVideoResponse; +use crate::generate::generate_video_v2::providers::artcraft::request_common::send_artcraft_omni_request; + +#[derive(Clone, Debug)] +pub struct ArtcraftSeedance1p5ProRequestState { + pub request: OmniGenVideoCostAndGenerateRequest, +} + +impl ArtcraftSeedance1p5ProRequestState { + pub async fn send(&self, client: &RouterArtcraftClient) -> Result { + send_artcraft_omni_request(&self.request, client).await + } +} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/sora_cost_parity_tests.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/sora_cost_parity_tests.rs deleted file mode 100644 index 52dd610ae8..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/sora_cost_parity_tests.rs +++ /dev/null @@ -1,122 +0,0 @@ -//! Combinatorial cost-parity tests between v1 (`build().estimate_costs()`) and v2 -//! (`build2().estimate_cost()`) for the Artcraft-hosted Sora 2 / Sora 2 Pro models. - -#![cfg(test)] - -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -use crate::api::common_video_model::CommonVideoModel; -use crate::api::image_ref::ImageRef; -use crate::api::provider::Provider; -use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use tokens::tokens::media_files::MediaFileToken; - -fn v1_cost(builder: &GenerateVideoRequestBuilder) -> Option { - builder.build().ok().and_then(|plan| plan.estimate_costs().cost_in_usd_cents) -} - -fn v2_cost(builder: GenerateVideoRequestBuilder) -> Option { - builder - .build2() - .ok() - .and_then(|dor| dor.estimate_cost().ok()) - .and_then(|estimate| estimate.cost_in_usd_cents) -} - -fn dummy_token() -> MediaFileToken { - MediaFileToken::new("mf_dummy".to_string()) -} - -fn supported_aspect_ratios() -> &'static [Option] { - &[ - None, - Some(CommonAspectRatio::Auto), - Some(CommonAspectRatio::WideSixteenByNine), - Some(CommonAspectRatio::TallNineBySixteen), - Some(CommonAspectRatio::Square), - ] -} - -// ── Sora 2 ── - -mod sora_2 { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Sora2, - provider: Provider::Artcraft, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(4u16), Some(8), Some(12)]; - let resolutions = [None, Some(CommonResolution::SevenTwentyP)]; - let mut combos = 0; - for &aspect_ratio in supported_aspect_ratios() { - for &resolution in &resolutions { - for &duration in &durations { - for has_start in [false, true] { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.resolution = resolution; - builder.duration_seconds = duration; - if has_start { - builder.start_frame = Some(ImageRef::MediaFileToken(dummy_token())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "artcraft sora_2: ar={:?} res={:?} dur={:?} start={} → v1={:?} v2={:?}", - aspect_ratio, resolution, duration, has_start, v1, v2); - combos += 1; - } - } - } - } - assert_eq!(combos, 5 * 2 * 4 * 2); - } -} - -// ── Sora 2 Pro ── - -mod sora_2_pro { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Sora2Pro, - provider: Provider::Artcraft, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(4u16), Some(8), Some(12)]; - let resolutions = [None, Some(CommonResolution::SevenTwentyP), Some(CommonResolution::TenEightyP)]; - let mut combos = 0; - for &aspect_ratio in supported_aspect_ratios() { - for &resolution in &resolutions { - for &duration in &durations { - for has_start in [false, true] { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.resolution = resolution; - builder.duration_seconds = duration; - if has_start { - builder.start_frame = Some(ImageRef::MediaFileToken(dummy_token())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "artcraft sora_2_pro: ar={:?} res={:?} dur={:?} start={} → v1={:?} v2={:?}", - aspect_ratio, resolution, duration, has_start, v1, v2); - combos += 1; - } - } - } - } - assert_eq!(combos, 5 * 3 * 4 * 2); - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/veo_cost_parity_tests.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/veo_cost_parity_tests.rs deleted file mode 100644 index 8935b57ffa..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/veo_cost_parity_tests.rs +++ /dev/null @@ -1,266 +0,0 @@ -//! Combinatorial cost-parity tests between v1 (`build().estimate_costs()`) and v2 -//! (`build2().estimate_cost()`) for the Artcraft-hosted Veo video models. -//! -//! All 5 Veo variants run on the v2 omni-gen path, but each owns its own -//! pricing formula in v2 (mirroring the v1 plan-based price). These tests -//! prove the new formula reproduces v1 prices across every shape we expect -//! routers to send. - -#![cfg(test)] - -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -use crate::api::common_video_model::CommonVideoModel; -use crate::api::image_ref::ImageRef; -use crate::api::provider::Provider; -use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use tokens::tokens::media_files::MediaFileToken; - -fn v1_cost(builder: &GenerateVideoRequestBuilder) -> Option { - builder.build().ok().and_then(|plan| plan.estimate_costs().cost_in_usd_cents) -} - -fn v2_cost(builder: GenerateVideoRequestBuilder) -> Option { - builder - .build2() - .ok() - .and_then(|dor| dor.estimate_cost().ok()) - .and_then(|estimate| estimate.cost_in_usd_cents) -} - -fn dummy_token() -> MediaFileToken { - MediaFileToken::new("mf_dummy".to_string()) -} - -fn supported_aspect_ratios() -> &'static [Option] { - &[ - None, - Some(CommonAspectRatio::Auto), - Some(CommonAspectRatio::WideSixteenByNine), - Some(CommonAspectRatio::TallNineBySixteen), - Some(CommonAspectRatio::Square), - ] -} - -fn resolutions() -> &'static [Option] { - &[None, Some(CommonResolution::SevenTwentyP), Some(CommonResolution::TenEightyP)] -} - -// ── Veo 2 ── - -mod veo_2 { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Veo2, - provider: Provider::Artcraft, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(5u16), Some(6), Some(7), Some(8)]; - let mut combos = 0; - for &aspect_ratio in supported_aspect_ratios() { - for &duration in &durations { - for has_start in [false, true] { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.duration_seconds = duration; - if has_start { - builder.start_frame = Some(ImageRef::MediaFileToken(dummy_token())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "artcraft veo_2: ar={:?} dur={:?} start={} → v1={:?} v2={:?}", - aspect_ratio, duration, has_start, v1, v2); - combos += 1; - } - } - } - assert_eq!(combos, 5 * 5 * 2); - } -} - -// ── Veo 3 ── - -mod veo_3 { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Veo3, - provider: Provider::Artcraft, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(4u16), Some(6), Some(8)]; - let audios = [None, Some(true), Some(false)]; - let mut combos = 0; - for &aspect_ratio in supported_aspect_ratios() { - for &resolution in resolutions() { - for &duration in &durations { - for &generate_audio in &audios { - for has_start in [false, true] { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.resolution = resolution; - builder.duration_seconds = duration; - builder.generate_audio = generate_audio; - if has_start { - builder.start_frame = Some(ImageRef::MediaFileToken(dummy_token())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "artcraft veo_3: ar={:?} res={:?} dur={:?} audio={:?} start={} → v1={:?} v2={:?}", - aspect_ratio, resolution, duration, generate_audio, has_start, v1, v2); - combos += 1; - } - } - } - } - } - assert!(combos >= 200, "expected ≥200 combos, got {}", combos); - } -} - -// ── Veo 3 Fast ── - -mod veo_3_fast { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Veo3Fast, - provider: Provider::Artcraft, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - // Veo 3 Fast accepts only Some(8) — anything else with non-ErrorOut clamps to 8. - let durations = [None, Some(8u16)]; - let audios = [None, Some(true), Some(false)]; - let mut combos = 0; - for &aspect_ratio in supported_aspect_ratios() { - for &resolution in resolutions() { - for &duration in &durations { - for &generate_audio in &audios { - for has_start in [false, true] { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.resolution = resolution; - builder.duration_seconds = duration; - builder.generate_audio = generate_audio; - if has_start { - builder.start_frame = Some(ImageRef::MediaFileToken(dummy_token())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "artcraft veo_3_fast: ar={:?} res={:?} dur={:?} audio={:?} start={} → v1={:?} v2={:?}", - aspect_ratio, resolution, duration, generate_audio, has_start, v1, v2); - combos += 1; - } - } - } - } - } - assert!(combos >= 100, "expected ≥100 combos, got {}", combos); - } -} - -// ── Veo 3.1 ── - -mod veo_3p1 { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Veo3p1, - provider: Provider::Artcraft, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(4u16), Some(6), Some(8)]; - let audios = [None, Some(true), Some(false)]; - let mut combos = 0; - for &aspect_ratio in supported_aspect_ratios() { - for &resolution in resolutions() { - for &duration in &durations { - for &generate_audio in &audios { - for has_start in [false, true] { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.resolution = resolution; - builder.duration_seconds = duration; - builder.generate_audio = generate_audio; - if has_start { - builder.start_frame = Some(ImageRef::MediaFileToken(dummy_token())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "artcraft veo_3p1: ar={:?} res={:?} dur={:?} audio={:?} start={} → v1={:?} v2={:?}", - aspect_ratio, resolution, duration, generate_audio, has_start, v1, v2); - combos += 1; - } - } - } - } - } - assert!(combos >= 200, "expected ≥200 combos, got {}", combos); - } -} - -// ── Veo 3.1 Fast ── - -mod veo_3p1_fast { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Veo3p1Fast, - provider: Provider::Artcraft, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(4u16), Some(6), Some(8)]; - let audios = [None, Some(true), Some(false)]; - let mut combos = 0; - for &aspect_ratio in supported_aspect_ratios() { - for &resolution in resolutions() { - for &duration in &durations { - for &generate_audio in &audios { - for has_start in [false, true] { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.resolution = resolution; - builder.duration_seconds = duration; - builder.generate_audio = generate_audio; - if has_start { - builder.start_frame = Some(ImageRef::MediaFileToken(dummy_token())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "artcraft veo_3p1_fast: ar={:?} res={:?} dur={:?} audio={:?} start={} → v1={:?} v2={:?}", - aspect_ratio, resolution, duration, generate_audio, has_start, v1, v2); - combos += 1; - } - } - } - } - } - assert!(combos >= 200, "expected ≥200 combos, got {}", combos); - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/fal/cost_parity_tests.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/fal/cost_parity_tests.rs deleted file mode 100644 index 44cc0d93b0..0000000000 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/fal/cost_parity_tests.rs +++ /dev/null @@ -1,1001 +0,0 @@ -//! Combinatorial cost-parity tests between v1 (`build().estimate_cost()`) and v2 -//! (`build2().estimate_cost()`) for the Fal-hosted Seedance video models. -//! -//! The goal: every request that produces a price in v1 must produce the -//! identical price in v2. If any callsite picks a different price after the -//! port, billing diverges. These tests close that gap. -//! -//! Both pipelines ultimately delegate to the same `FalRequestCostCalculator` -//! impls in `fal_client`, so parity should hold by construction — but we -//! exercise a wide variety of inputs anyway to catch any drift in the request -//! plumbing (e.g. resolution/duration mapping errors, default-value mismatches, -//! aspect-ratio fallthroughs). - -#![cfg(test)] - -use crate::api::common_aspect_ratio::CommonAspectRatio; -use crate::api::common_resolution::CommonResolution; -use crate::api::common_video_model::CommonVideoModel; -use crate::api::image_ref::ImageRef; -use crate::api::provider::Provider; -use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy; -use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; - -const DUMMY_IMAGE: &str = "https://example.com/dummy.png"; -const DUMMY_END_FRAME: &str = "https://example.com/dummy_end.png"; - -// ── seedance 1.0 lite ── - -mod seedance_1p0_lite { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Seedance10Lite, - provider: Provider::Fal, - // 1.0 lite is image-to-video only — a start_frame is required. - start_frame: Some(ImageRef::Url(DUMMY_IMAGE.to_string())), - ..Default::default() - } - } - - fn all_resolutions() -> &'static [Option] { - &[ - None, - Some(CommonResolution::FourEightyP), - Some(CommonResolution::SevenTwentyP), - Some(CommonResolution::TenEightyP), - ] - } - - fn all_durations() -> &'static [Option] { - &[None, Some(5), Some(10)] - } - - fn supported_aspect_ratios() -> &'static [Option] { - &[ - None, - Some(CommonAspectRatio::Auto), - Some(CommonAspectRatio::Square), - Some(CommonAspectRatio::WideFourByThree), - Some(CommonAspectRatio::WideSixteenByNine), - Some(CommonAspectRatio::Wide), - Some(CommonAspectRatio::WideTwentyOneByNine), - Some(CommonAspectRatio::TallThreeByFour), - Some(CommonAspectRatio::TallNineBySixteen), - Some(CommonAspectRatio::Tall), - ] - } - - #[test] - fn cost_parity_full_combinatorial() { - let mut combos_checked = 0; - let mut combos_with_end_frame = 0; - - for &resolution in all_resolutions() { - for &duration in all_durations() { - for &aspect_ratio in supported_aspect_ratios() { - for include_end_frame in [false, true] { - let mut builder = base_builder(); - builder.resolution = resolution; - builder.duration_seconds = duration; - builder.aspect_ratio = aspect_ratio; - if include_end_frame { - builder.end_frame = Some(ImageRef::Url(DUMMY_END_FRAME.to_string())); - combos_with_end_frame += 1; - } - - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!( - v1, v2, - "1.0 lite cost mismatch: res={:?} dur={:?} ar={:?} end={} → v1={:?} v2={:?}", - resolution, duration, aspect_ratio, include_end_frame, v1, v2, - ); - combos_checked += 1; - } - } - } - } - - // Sanity: we should be checking a meaningful number of combinations. - assert!(combos_checked >= 240, "expected ≥240 combos, got {}", combos_checked); - assert!(combos_with_end_frame > 0, "expected at least one with end_frame"); - } -} - -// ── seedance 1.5 pro ── - -mod seedance_1p5_pro { - use super::*; - - fn t2v_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Seedance1p5Pro, - provider: Provider::Fal, - // No start_frame → text-to-video mode. - ..Default::default() - } - } - - fn i2v_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Seedance1p5Pro, - provider: Provider::Fal, - start_frame: Some(ImageRef::Url(DUMMY_IMAGE.to_string())), - ..Default::default() - } - } - - fn all_resolutions() -> &'static [Option] { - &[ - None, - Some(CommonResolution::FourEightyP), - Some(CommonResolution::SevenTwentyP), - Some(CommonResolution::TenEightyP), - ] - } - - fn all_durations() -> &'static [Option] { - &[None, Some(4), Some(5), Some(6), Some(7), Some(8), Some(9), Some(10), Some(11), Some(12)] - } - - fn supported_aspect_ratios() -> &'static [Option] { - &[ - None, - Some(CommonAspectRatio::Auto), - Some(CommonAspectRatio::Square), - Some(CommonAspectRatio::WideFourByThree), - Some(CommonAspectRatio::WideSixteenByNine), - Some(CommonAspectRatio::Wide), - Some(CommonAspectRatio::WideTwentyOneByNine), - Some(CommonAspectRatio::TallThreeByFour), - Some(CommonAspectRatio::TallNineBySixteen), - Some(CommonAspectRatio::Tall), - ] - } - - fn audio_options() -> &'static [Option] { - &[None, Some(true), Some(false)] - } - - #[test] - fn cost_parity_t2v_combinatorial() { - let mut combos_checked = 0; - for &resolution in all_resolutions() { - for &duration in all_durations() { - for &aspect_ratio in supported_aspect_ratios() { - for &generate_audio in audio_options() { - let mut builder = t2v_builder(); - builder.resolution = resolution; - builder.duration_seconds = duration; - builder.aspect_ratio = aspect_ratio; - builder.generate_audio = generate_audio; - - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!( - v1, v2, - "1.5 pro t2v cost mismatch: res={:?} dur={:?} ar={:?} audio={:?} → v1={:?} v2={:?}", - resolution, duration, aspect_ratio, generate_audio, v1, v2, - ); - combos_checked += 1; - } - } - } - } - assert!(combos_checked >= 1000, "expected ≥1000 combos, got {}", combos_checked); - } - - #[test] - fn cost_parity_i2v_combinatorial() { - let mut combos_checked = 0; - let mut combos_with_end_frame = 0; - for &resolution in all_resolutions() { - for &duration in all_durations() { - for &aspect_ratio in supported_aspect_ratios() { - for &generate_audio in audio_options() { - for include_end_frame in [false, true] { - let mut builder = i2v_builder(); - builder.resolution = resolution; - builder.duration_seconds = duration; - builder.aspect_ratio = aspect_ratio; - builder.generate_audio = generate_audio; - if include_end_frame { - builder.end_frame = Some(ImageRef::Url(DUMMY_END_FRAME.to_string())); - combos_with_end_frame += 1; - } - - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!( - v1, v2, - "1.5 pro i2v cost mismatch: res={:?} dur={:?} ar={:?} audio={:?} end={} → v1={:?} v2={:?}", - resolution, duration, aspect_ratio, generate_audio, include_end_frame, v1, v2, - ); - combos_checked += 1; - } - } - } - } - } - assert!(combos_checked >= 2000, "expected ≥2000 combos, got {}", combos_checked); - assert!(combos_with_end_frame > 0, "expected at least one with end_frame"); - } - - #[test] - fn cost_parity_with_pay_less_downgrade_strategy() { - // Sanity: even when the mismatch strategy downgrades unsupported - // resolutions/durations, v1 and v2 should pick the same fallback. - let oddities: &[(Option, Option)] = &[ - (Some(CommonResolution::OneK), None), - (Some(CommonResolution::TwoK), Some(5)), - (Some(CommonResolution::FourK), Some(12)), - (None, Some(13)), - ]; - for &(resolution, duration) in oddities { - let mut builder = t2v_builder(); - builder.resolution = resolution; - builder.duration_seconds = duration; - builder.request_mismatch_mitigation_strategy = - RequestMismatchMitigationStrategy::PayLessDowngrade; - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "PayLessDowngrade mismatch at res={:?} dur={:?}", resolution, duration); - } - } - - #[test] - fn cost_parity_with_pay_more_upgrade_strategy() { - let oddities: &[(Option, Option)] = &[ - (Some(CommonResolution::OneK), None), - (Some(CommonResolution::TwoK), Some(5)), - (Some(CommonResolution::FourK), Some(13)), - (None, Some(20)), - ]; - for &(resolution, duration) in oddities { - let mut builder = t2v_builder(); - builder.resolution = resolution; - builder.duration_seconds = duration; - builder.request_mismatch_mitigation_strategy = - RequestMismatchMitigationStrategy::PayMoreUpgrade; - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "PayMoreUpgrade mismatch at res={:?} dur={:?}", resolution, duration); - } - } -} - -// ── helpers ── - -/// Returns `Some(cost_in_usd_cents)` from the v1 pipeline. If v1 errors out -/// (e.g. for an unsupported resolution with `ErrorOut` strategy), returns `None` -/// so the parity test can compare apples to apples. -fn v1_cost(builder: &GenerateVideoRequestBuilder) -> Option { - builder - .build() - .ok() - .and_then(|plan| plan.estimate_costs().cost_in_usd_cents) -} - -/// Same as `v1_cost`, but for the v2 pipeline. -fn v2_cost(builder: GenerateVideoRequestBuilder) -> Option { - builder - .build2() - .ok() - .and_then(|dor| dor.estimate_cost().ok()) - .and_then(|estimate| estimate.cost_in_usd_cents) -} - -// ── Kling shared helpers ── - -mod kling_helpers { - use super::*; - - pub fn kling_aspect_ratios() -> &'static [Option] { - &[ - None, - Some(CommonAspectRatio::Square), - Some(CommonAspectRatio::WideSixteenByNine), - Some(CommonAspectRatio::TallNineBySixteen), - Some(CommonAspectRatio::Auto), - // Unsupported — falls back to 16:9 for non-ErrorOut. - Some(CommonAspectRatio::WideFourByThree), - ] - } -} - -// ── Kling 1.6 Pro ── - -mod kling_1_6_pro { - use super::*; - use super::kling_helpers::kling_aspect_ratios; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling16Pro, - provider: Provider::Fal, - start_frame: Some(ImageRef::Url(DUMMY_IMAGE.to_string())), - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(5u16), Some(10)]; - let mut combos = 0; - for &aspect_ratio in kling_aspect_ratios() { - for &duration in &durations { - for include_end_frame in [false, true] { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.duration_seconds = duration; - if include_end_frame { - builder.end_frame = Some(ImageRef::Url(DUMMY_END_FRAME.to_string())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "kling_1_6_pro: ar={:?} dur={:?} end={} → v1={:?} v2={:?}", - aspect_ratio, duration, include_end_frame, v1, v2); - combos += 1; - } - } - } - assert_eq!(combos, 6 * 3 * 2); - } -} - -// ── Kling 2.1 Pro ── - -mod kling_2_1_pro { - use super::*; - use super::kling_helpers::kling_aspect_ratios; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling21Pro, - provider: Provider::Fal, - start_frame: Some(ImageRef::Url(DUMMY_IMAGE.to_string())), - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(5u16), Some(10)]; - let mut combos = 0; - for &aspect_ratio in kling_aspect_ratios() { - for &duration in &durations { - for include_end_frame in [false, true] { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.duration_seconds = duration; - if include_end_frame { - builder.end_frame = Some(ImageRef::Url(DUMMY_END_FRAME.to_string())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "kling_2_1_pro: ar={:?} dur={:?} end={} → v1={:?} v2={:?}", - aspect_ratio, duration, include_end_frame, v1, v2); - combos += 1; - } - } - } - assert_eq!(combos, 6 * 3 * 2); - } -} - -// ── Kling 2.1 Master ── - -mod kling_2_1_master { - use super::*; - use super::kling_helpers::kling_aspect_ratios; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling21Master, - provider: Provider::Fal, - start_frame: Some(ImageRef::Url(DUMMY_IMAGE.to_string())), - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(5u16), Some(10)]; - let mut combos = 0; - for &aspect_ratio in kling_aspect_ratios() { - for &duration in &durations { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.duration_seconds = duration; - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "kling_2_1_master: ar={:?} dur={:?} → v1={:?} v2={:?}", - aspect_ratio, duration, v1, v2); - combos += 1; - } - } - assert_eq!(combos, 6 * 3); - } -} - -// ── Kling 2.5 Turbo Pro ── - -mod kling_2_5_turbo_pro { - use super::*; - use super::kling_helpers::kling_aspect_ratios; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling2p5TurboPro, - provider: Provider::Fal, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(5u16), Some(10)]; - let mut combos = 0; - for &aspect_ratio in kling_aspect_ratios() { - for &duration in &durations { - for has_start in [false, true] { - for include_end in [false, true] { - if include_end && !has_start { continue; } - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.duration_seconds = duration; - if has_start { - builder.start_frame = Some(ImageRef::Url(DUMMY_IMAGE.to_string())); - } - if include_end { - builder.end_frame = Some(ImageRef::Url(DUMMY_END_FRAME.to_string())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "kling_2_5_turbo_pro: ar={:?} dur={:?} start={} end={} → v1={:?} v2={:?}", - aspect_ratio, duration, has_start, include_end, v1, v2); - combos += 1; - } - } - } - } - assert!(combos >= 50, "expected ≥50 combos, got {}", combos); - } -} - -// ── Kling 2.6 Pro ── - -mod kling_2_6_pro { - use super::*; - use super::kling_helpers::kling_aspect_ratios; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling2p6Pro, - provider: Provider::Fal, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(5u16), Some(10)]; - let audios = [None, Some(true), Some(false)]; - let mut combos = 0; - for &aspect_ratio in kling_aspect_ratios() { - for &duration in &durations { - for &generate_audio in &audios { - for has_start in [false, true] { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.duration_seconds = duration; - builder.generate_audio = generate_audio; - if has_start { - builder.start_frame = Some(ImageRef::Url(DUMMY_IMAGE.to_string())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "kling_2_6_pro: ar={:?} dur={:?} audio={:?} start={} → v1={:?} v2={:?}", - aspect_ratio, duration, generate_audio, has_start, v1, v2); - combos += 1; - } - } - } - } - assert_eq!(combos, 6 * 3 * 3 * 2); - } -} - -// ── Kling 3.0 Pro ── - -mod kling_3p0_pro { - use super::*; - use super::kling_helpers::kling_aspect_ratios; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling3p0Pro, - provider: Provider::Fal, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - // 3-15s inclusive, plus None and out-of-range. - let durations = [None, Some(3u16), Some(5), Some(10), Some(15), Some(2), Some(16)]; - let audios = [None, Some(true), Some(false)]; - let mut combos = 0; - for &aspect_ratio in kling_aspect_ratios() { - for &duration in &durations { - for &generate_audio in &audios { - for has_start in [false, true] { - for include_end in [false, true] { - if include_end && !has_start { continue; } - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.duration_seconds = duration; - builder.generate_audio = generate_audio; - if has_start { - builder.start_frame = Some(ImageRef::Url(DUMMY_IMAGE.to_string())); - } - if include_end { - builder.end_frame = Some(ImageRef::Url(DUMMY_END_FRAME.to_string())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "kling_3p0_pro: ar={:?} dur={:?} audio={:?} start={} end={} → v1={:?} v2={:?}", - aspect_ratio, duration, generate_audio, has_start, include_end, v1, v2); - combos += 1; - } - } - } - } - } - assert!(combos >= 300, "expected ≥300 combos, got {}", combos); - } -} - -// ── Kling 3.0 Standard ── - -mod kling_3p0_standard { - use super::*; - use super::kling_helpers::kling_aspect_ratios; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Kling3p0Standard, - provider: Provider::Fal, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let durations = [None, Some(3u16), Some(5), Some(10), Some(15), Some(2), Some(16)]; - let audios = [None, Some(true), Some(false)]; - let mut combos = 0; - for &aspect_ratio in kling_aspect_ratios() { - for &duration in &durations { - for &generate_audio in &audios { - for has_start in [false, true] { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.duration_seconds = duration; - builder.generate_audio = generate_audio; - if has_start { - builder.start_frame = Some(ImageRef::Url(DUMMY_IMAGE.to_string())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "kling_3p0_standard: ar={:?} dur={:?} audio={:?} start={} → v1={:?} v2={:?}", - aspect_ratio, duration, generate_audio, has_start, v1, v2); - combos += 1; - } - } - } - } - assert!(combos >= 200, "expected ≥200 combos, got {}", combos); - } -} - -// ── Sora 2 ── - -mod sora_2 { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Sora2, - provider: Provider::Fal, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let resolutions = [None, Some(CommonResolution::SevenTwentyP), Some(CommonResolution::TenEightyP)]; - let durations = [None, Some(4u16), Some(8), Some(12)]; - let aspect_ratios = [ - None, - Some(CommonAspectRatio::Auto), - Some(CommonAspectRatio::WideSixteenByNine), - Some(CommonAspectRatio::TallNineBySixteen), - Some(CommonAspectRatio::Square), - ]; - let mut combos = 0; - for &resolution in &resolutions { - for &duration in &durations { - for &aspect_ratio in &aspect_ratios { - for has_start in [false, true] { - let mut builder = base_builder(); - builder.resolution = resolution; - builder.duration_seconds = duration; - builder.aspect_ratio = aspect_ratio; - if has_start { - builder.start_frame = Some(ImageRef::Url(DUMMY_IMAGE.to_string())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "sora_2: res={:?} dur={:?} ar={:?} start={} → v1={:?} v2={:?}", - resolution, duration, aspect_ratio, has_start, v1, v2); - combos += 1; - } - } - } - } - assert_eq!(combos, 3 * 4 * 5 * 2); - } -} - -// ── Sora 2 Pro ── - -mod sora_2_pro { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Sora2Pro, - provider: Provider::Fal, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let resolutions = [None, Some(CommonResolution::SevenTwentyP), Some(CommonResolution::TenEightyP)]; - let durations = [None, Some(4u16), Some(8), Some(12)]; - let aspect_ratios = [ - None, - Some(CommonAspectRatio::Auto), - Some(CommonAspectRatio::WideSixteenByNine), - Some(CommonAspectRatio::TallNineBySixteen), - Some(CommonAspectRatio::Square), - ]; - let mut combos = 0; - for &resolution in &resolutions { - for &duration in &durations { - for &aspect_ratio in &aspect_ratios { - for has_start in [false, true] { - let mut builder = base_builder(); - builder.resolution = resolution; - builder.duration_seconds = duration; - builder.aspect_ratio = aspect_ratio; - if has_start { - builder.start_frame = Some(ImageRef::Url(DUMMY_IMAGE.to_string())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!(v1, v2, "sora_2_pro: res={:?} dur={:?} ar={:?} start={} → v1={:?} v2={:?}", - resolution, duration, aspect_ratio, has_start, v1, v2); - combos += 1; - } - } - } - } - assert_eq!(combos, 3 * 4 * 5 * 2); - } -} - -// ── Veo 2 ── - -mod veo_2 { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Veo2, - provider: Provider::Fal, - ..Default::default() - } - } - - fn supported_aspect_ratios() -> &'static [Option] { - &[ - None, - Some(CommonAspectRatio::Auto), - Some(CommonAspectRatio::WideSixteenByNine), - Some(CommonAspectRatio::TallNineBySixteen), - // Unsupported (router falls back to Auto for non-ErrorOut strategy). - Some(CommonAspectRatio::Square), - ] - } - - fn all_durations() -> &'static [Option] { - &[None, Some(5), Some(6), Some(7), Some(8)] - } - - #[test] - fn cost_parity_full_combinatorial() { - let mut combos = 0; - for &aspect_ratio in supported_aspect_ratios() { - for &duration in all_durations() { - for has_start_frame in [false, true] { - let mut builder = base_builder(); - builder.aspect_ratio = aspect_ratio; - builder.duration_seconds = duration; - if has_start_frame { - builder.start_frame = Some(ImageRef::Url(DUMMY_IMAGE.to_string())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!( - v1, v2, - "veo_2 cost mismatch: ar={:?} dur={:?} start={} → v1={:?} v2={:?}", - aspect_ratio, duration, has_start_frame, v1, v2, - ); - combos += 1; - } - } - } - assert_eq!(combos, 5 * 5 * 2); - } -} - -// ── Veo 3 ── - -mod veo_3 { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Veo3, - provider: Provider::Fal, - ..Default::default() - } - } - - fn all_resolutions() -> &'static [Option] { - &[None, Some(CommonResolution::SevenTwentyP), Some(CommonResolution::TenEightyP)] - } - - fn all_durations() -> &'static [Option] { - &[None, Some(4), Some(6), Some(8)] - } - - fn supported_aspect_ratios() -> &'static [Option] { - &[ - None, - Some(CommonAspectRatio::Auto), - Some(CommonAspectRatio::WideSixteenByNine), - Some(CommonAspectRatio::TallNineBySixteen), - Some(CommonAspectRatio::Square), - ] - } - - fn audio_options() -> &'static [Option] { - &[None, Some(true), Some(false)] - } - - #[test] - fn cost_parity_full_combinatorial() { - let mut combos = 0; - for &resolution in all_resolutions() { - for &duration in all_durations() { - for &aspect_ratio in supported_aspect_ratios() { - for &generate_audio in audio_options() { - for has_start_frame in [false, true] { - let mut builder = base_builder(); - builder.resolution = resolution; - builder.duration_seconds = duration; - builder.aspect_ratio = aspect_ratio; - builder.generate_audio = generate_audio; - if has_start_frame { - builder.start_frame = Some(ImageRef::Url(DUMMY_IMAGE.to_string())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!( - v1, v2, - "veo_3 cost mismatch: res={:?} dur={:?} ar={:?} audio={:?} start={} → v1={:?} v2={:?}", - resolution, duration, aspect_ratio, generate_audio, has_start_frame, v1, v2, - ); - combos += 1; - } - } - } - } - } - assert_eq!(combos, 3 * 4 * 5 * 3 * 2); - } -} - -// ── Veo 3 Fast (image-to-video only) ── - -mod veo_3_fast { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Veo3Fast, - provider: Provider::Fal, - start_frame: Some(ImageRef::Url(DUMMY_IMAGE.to_string())), - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let resolutions = [None, Some(CommonResolution::SevenTwentyP), Some(CommonResolution::TenEightyP)]; - let durations = [None, Some(4u16), Some(6), Some(8)]; - let audios = [None, Some(true), Some(false)]; - - let mut combos = 0; - for &resolution in &resolutions { - for &duration in &durations { - for &generate_audio in &audios { - let mut builder = base_builder(); - builder.resolution = resolution; - builder.duration_seconds = duration; - builder.generate_audio = generate_audio; - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!( - v1, v2, - "veo_3_fast cost mismatch: res={:?} dur={:?} audio={:?} → v1={:?} v2={:?}", - resolution, duration, generate_audio, v1, v2, - ); - combos += 1; - } - } - } - assert_eq!(combos, 3 * 4 * 3); - } -} - -// ── Veo 3.1 ── - -mod veo_3p1 { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Veo3p1, - provider: Provider::Fal, - ..Default::default() - } - } - - fn all_resolutions() -> &'static [Option] { - &[None, Some(CommonResolution::SevenTwentyP), Some(CommonResolution::TenEightyP)] - } - - fn all_durations() -> &'static [Option] { - &[None, Some(4), Some(6), Some(8)] - } - - fn supported_aspect_ratios() -> &'static [Option] { - &[None, Some(CommonAspectRatio::Auto), Some(CommonAspectRatio::WideSixteenByNine), Some(CommonAspectRatio::TallNineBySixteen)] - } - - fn audio_options() -> &'static [Option] { - &[None, Some(true), Some(false)] - } - - /// Three modes: text-to-video (no frames), image-to-video (start only), - /// first/last-frame (both). All three must price identically. - #[derive(Clone, Copy)] - enum FrameSetup { - None_, - StartOnly, - StartAndEnd, - } - - #[test] - fn cost_parity_full_combinatorial() { - let mut combos = 0; - for &resolution in all_resolutions() { - for &duration in all_durations() { - for &aspect_ratio in supported_aspect_ratios() { - for &generate_audio in audio_options() { - for frames in [FrameSetup::None_, FrameSetup::StartOnly, FrameSetup::StartAndEnd] { - let mut builder = base_builder(); - builder.resolution = resolution; - builder.duration_seconds = duration; - builder.aspect_ratio = aspect_ratio; - builder.generate_audio = generate_audio; - match frames { - FrameSetup::None_ => {} - FrameSetup::StartOnly => { - builder.start_frame = Some(ImageRef::Url(DUMMY_IMAGE.to_string())); - } - FrameSetup::StartAndEnd => { - builder.start_frame = Some(ImageRef::Url(DUMMY_IMAGE.to_string())); - builder.end_frame = Some(ImageRef::Url(DUMMY_END_FRAME.to_string())); - } - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!( - v1, v2, - "veo_3p1 cost mismatch: res={:?} dur={:?} ar={:?} audio={:?} → v1={:?} v2={:?}", - resolution, duration, aspect_ratio, generate_audio, v1, v2, - ); - combos += 1; - } - } - } - } - } - assert_eq!(combos, 3 * 4 * 4 * 3 * 3); - } -} - -// ── Veo 3.1 Fast ── - -mod veo_3p1_fast { - use super::*; - - fn base_builder() -> GenerateVideoRequestBuilder { - GenerateVideoRequestBuilder { - model: CommonVideoModel::Veo3p1Fast, - provider: Provider::Fal, - ..Default::default() - } - } - - #[test] - fn cost_parity_full_combinatorial() { - let resolutions = [None, Some(CommonResolution::SevenTwentyP), Some(CommonResolution::TenEightyP)]; - let durations = [None, Some(4u16), Some(6), Some(8)]; - let aspect_ratios = [ - None, - Some(CommonAspectRatio::Auto), - Some(CommonAspectRatio::WideSixteenByNine), - Some(CommonAspectRatio::TallNineBySixteen), - ]; - let audios = [None, Some(true), Some(false)]; - - let mut combos = 0; - for &resolution in &resolutions { - for &duration in &durations { - for &aspect_ratio in &aspect_ratios { - for &generate_audio in &audios { - for include_end_frame in [false, true] { - let mut builder = base_builder(); - builder.resolution = resolution; - builder.duration_seconds = duration; - builder.aspect_ratio = aspect_ratio; - builder.generate_audio = generate_audio; - builder.start_frame = Some(ImageRef::Url(DUMMY_IMAGE.to_string())); - if include_end_frame { - builder.end_frame = Some(ImageRef::Url(DUMMY_END_FRAME.to_string())); - } - let v1 = v1_cost(&builder); - let v2 = v2_cost(builder.clone()); - assert_eq!( - v1, v2, - "veo_3p1_fast cost mismatch: res={:?} dur={:?} ar={:?} audio={:?} end={} → v1={:?} v2={:?}", - resolution, duration, aspect_ratio, generate_audio, include_end_frame, v1, v2, - ); - combos += 1; - } - } - } - } - } - assert_eq!(combos, 3 * 4 * 4 * 3 * 2); - } -} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/fal/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/fal/mod.rs index 9190dbd7b8..02e43ed38c 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/fal/mod.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/fal/mod.rs @@ -14,6 +14,3 @@ pub mod veo_3; pub mod veo_3_fast; pub mod veo_3p1; pub mod veo_3p1_fast; - -#[cfg(test)] -mod cost_parity_tests; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/video_generation_request.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/video_generation_request.rs index a36f295a70..63b0f30cb2 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/video_generation_request.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/video_generation_request.rs @@ -25,6 +25,10 @@ use crate::generate::generate_video_v2::providers::artcraft::preview_model::cost use crate::generate::generate_video_v2::providers::artcraft::preview_model::request::ArtcraftPreviewModelRequestState; use crate::generate::generate_video_v2::providers::artcraft::preview_model_fast::cost::ArtcraftPreviewModelFastCostState; use crate::generate::generate_video_v2::providers::artcraft::preview_model_fast::request::ArtcraftPreviewModelFastRequestState; +use crate::generate::generate_video_v2::providers::artcraft::seedance_1p0_lite::cost::ArtcraftSeedance10LiteCostState; +use crate::generate::generate_video_v2::providers::artcraft::seedance_1p0_lite::request::ArtcraftSeedance10LiteRequestState; +use crate::generate::generate_video_v2::providers::artcraft::seedance_1p5_pro::cost::ArtcraftSeedance1p5ProCostState; +use crate::generate::generate_video_v2::providers::artcraft::seedance_1p5_pro::request::ArtcraftSeedance1p5ProRequestState; use crate::generate::generate_video_v2::providers::artcraft::seedance_2p0::cost::ArtcraftSeedance2p0CostState; use crate::generate::generate_video_v2::providers::artcraft::seedance_2p0::request::ArtcraftSeedance2p0RequestState; use crate::generate::generate_video_v2::providers::artcraft::seedance_2p0_fast::cost::ArtcraftSeedance2p0FastCostState; @@ -109,6 +113,8 @@ pub enum VideoGenerationRequest { ArtcraftKling3p0Standard(ArtcraftKling3p0StandardRequestState), ArtcraftPreviewModel(ArtcraftPreviewModelRequestState), ArtcraftPreviewModelFast(ArtcraftPreviewModelFastRequestState), + ArtcraftSeedance10Lite(ArtcraftSeedance10LiteRequestState), + ArtcraftSeedance1p5Pro(ArtcraftSeedance1p5ProRequestState), ArtcraftSeedance2p0(ArtcraftSeedance2p0RequestState), ArtcraftSeedance2p0Fast(ArtcraftSeedance2p0FastRequestState), ArtcraftSeedance2p0Ultra(ArtcraftSeedance2p0UltraRequestState), @@ -161,6 +167,8 @@ impl VideoGenerationRequest { Self::ArtcraftKling3p0Standard(_) => Provider::Artcraft, Self::ArtcraftPreviewModel(_) => Provider::Artcraft, Self::ArtcraftPreviewModelFast(_) => Provider::Artcraft, + Self::ArtcraftSeedance10Lite(_) => Provider::Artcraft, + Self::ArtcraftSeedance1p5Pro(_) => Provider::Artcraft, Self::ArtcraftSeedance2p0(_) => Provider::Artcraft, Self::ArtcraftSeedance2p0Fast(_) => Provider::Artcraft, Self::ArtcraftSeedance2p0Ultra(_) => Provider::Artcraft, @@ -213,6 +221,8 @@ impl VideoGenerationRequest { VideoGenerationRequest::ArtcraftKling3p0Standard(request) => Ok(ArtcraftKling3p0StandardCostState::from_request(request).estimate_cost()), VideoGenerationRequest::ArtcraftPreviewModel(request) => Ok(ArtcraftPreviewModelCostState::from_request(request).estimate_cost()), VideoGenerationRequest::ArtcraftPreviewModelFast(request) => Ok(ArtcraftPreviewModelFastCostState::from_request(request).estimate_cost()), + VideoGenerationRequest::ArtcraftSeedance10Lite(request) => Ok(ArtcraftSeedance10LiteCostState::from_request(request).estimate_cost()), + VideoGenerationRequest::ArtcraftSeedance1p5Pro(request) => Ok(ArtcraftSeedance1p5ProCostState::from_request(request).estimate_cost()), VideoGenerationRequest::ArtcraftSeedance2p0(request) => Ok(ArtcraftSeedance2p0CostState::from_request(request).estimate_cost()), VideoGenerationRequest::ArtcraftSeedance2p0Fast(request) => Ok(ArtcraftSeedance2p0FastCostState::from_request(request).estimate_cost()), VideoGenerationRequest::ArtcraftSeedance2p0Ultra(request) => Ok(ArtcraftSeedance2p0UltraCostState::from_request(request).estimate_cost()), @@ -299,6 +309,14 @@ impl VideoGenerationRequest { let client_ref = client.get_artcraft_client_ref()?; request.send(client_ref).await }, + VideoGenerationRequest::ArtcraftSeedance10Lite(request) => { + let client_ref = client.get_artcraft_client_ref()?; + request.send(client_ref).await + }, + VideoGenerationRequest::ArtcraftSeedance1p5Pro(request) => { + let client_ref = client.get_artcraft_client_ref()?; + request.send(client_ref).await + }, VideoGenerationRequest::ArtcraftSeedance2p0(request) => { let client_ref = client.get_artcraft_client_ref()?; request.send(client_ref).await diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/common/maybe_notify_frontend_of_billing_errors.rs b/crates/desktop/artcraft/src/core/commands/enqueue/common/maybe_notify_frontend_of_billing_errors.rs index f74b47f509..5259fefdcf 100644 --- a/crates/desktop/artcraft/src/core/commands/enqueue/common/maybe_notify_frontend_of_billing_errors.rs +++ b/crates/desktop/artcraft/src/core/commands/enqueue/common/maybe_notify_frontend_of_billing_errors.rs @@ -32,7 +32,6 @@ fn billing_error( BillingProvider::Fal => GenerationProvider::Fal, BillingProvider::Kinovi => GenerationProvider::Artcraft, // NB: We don't support Kinovi yet. BillingProvider::Midjourney => GenerationProvider::Midjourney, - BillingProvider::Muapi=> GenerationProvider::Artcraft, // NB: We don't support Muapi yet. BillingProvider::Sora => GenerationProvider::Sora, }; warn!("Billing issue with: {:?}", provider); diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/generate_error.rs b/crates/desktop/artcraft/src/core/commands/enqueue/generate_error.rs index bc286a87ef..8d65ef1c97 100644 --- a/crates/desktop/artcraft/src/core/commands/enqueue/generate_error.rs +++ b/crates/desktop/artcraft/src/core/commands/enqueue/generate_error.rs @@ -97,7 +97,6 @@ pub enum BillingProvider { Fal, Kinovi, Midjourney, - Muapi, Sora, } @@ -235,7 +234,6 @@ impl From for GenerateError { ArtcraftRouterError::ProviderBillingError(err) => { let provider = match err { ProviderError::Fal(_) => BillingProvider::Fal, - ProviderError::Muapi(_) => BillingProvider::Muapi, ProviderError::Seedance2Pro(_) => BillingProvider::Kinovi, ProviderError::Storyteller(_) => BillingProvider::Artcraft, ProviderError::GmiCloud(_) => BillingProvider::Artcraft, @@ -247,7 +245,6 @@ impl From for GenerateError { ArtcraftRouterError::Provider(ProviderError::Fal(_)) => Self::FalNoLongerSupported, ArtcraftRouterError::Provider(ProviderError::GmiCloud(_)) => Self::ArtcraftRouterNotYetSupportedProvider("gmicloud"), ArtcraftRouterError::Provider(ProviderError::Grok(_)) => Self::ArtcraftRouterNotYetSupportedProvider("grok_api"), - ArtcraftRouterError::Provider(ProviderError::Muapi(_)) => Self::ArtcraftRouterNotYetSupportedProvider("muapi"), ArtcraftRouterError::Provider(ProviderError::Seedance2Pro(_)) => Self::ArtcraftRouterNotYetSupportedProvider("seedance2pro"), ArtcraftRouterError::UnsupportedModel(model) => Self::NotYetImplemented(format!("Unsupported model: {}", model)), ArtcraftRouterError::UnsupportedProviderAndModelForNewApi(message) => Self::ArtcraftRouterNotYetSupportedProvider("unsupported model for new router API"), diff --git a/crates/desktop/artcraft/src/core/commands/generate/common/router_image_request_to_artcraft_prompt.rs b/crates/desktop/artcraft/src/core/commands/generate/common/router_image_request_to_artcraft_prompt.rs index 772746ee80..0a3efba6df 100644 --- a/crates/desktop/artcraft/src/core/commands/generate/common/router_image_request_to_artcraft_prompt.rs +++ b/crates/desktop/artcraft/src/core/commands/generate/common/router_image_request_to_artcraft_prompt.rs @@ -66,7 +66,6 @@ fn provider_to_generation_provider(provider: Provider) -> GenerationProvider { Provider::Artcraft => GenerationProvider::Artcraft, Provider::Fal => GenerationProvider::Fal, // Unused providers -> ArtCraft - Provider::Muapi => GenerationProvider::Artcraft, Provider::Seedance2Pro => GenerationProvider::Artcraft , Provider::GmiCloud => GenerationProvider::Artcraft, Provider::GrokApi => GenerationProvider::Artcraft, diff --git a/crates/desktop/artcraft/src/core/commands/generate/common/router_video_request_to_artcraft_prompt.rs b/crates/desktop/artcraft/src/core/commands/generate/common/router_video_request_to_artcraft_prompt.rs index 406637604a..5733313a4a 100644 --- a/crates/desktop/artcraft/src/core/commands/generate/common/router_video_request_to_artcraft_prompt.rs +++ b/crates/desktop/artcraft/src/core/commands/generate/common/router_video_request_to_artcraft_prompt.rs @@ -83,7 +83,6 @@ fn provider_to_generation_provider(provider: Provider) -> GenerationProvider { Provider::Artcraft => GenerationProvider::Artcraft, Provider::Fal => GenerationProvider::Fal, // Unused providers -> ArtCraft - Provider::Muapi => GenerationProvider::Artcraft, Provider::Seedance2Pro => GenerationProvider::Artcraft , Provider::GmiCloud => GenerationProvider::Artcraft, Provider::GrokApi => GenerationProvider::Artcraft, diff --git a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_kling_1p6_pro.rs b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_kling_1p6_pro.rs deleted file mode 100644 index 8de4402c60..0000000000 --- a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_kling_1p6_pro.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::core::commands::enqueue::generate_error::GenerateError; -use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error; -use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation}; -use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess; -use crate::core::events::basic_sendable_event_trait::BasicSendableEvent; -use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent; -use crate::core::events::generation_events::common::{GenerationAction, GenerationModel}; -use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent; -use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs; -use crate::core::state::data_dir::app_data_root::AppDataRoot; -use crate::services::sora::state::sora_credential_manager::SoraCredentialManager; -use crate::services::sora::state::sora_task_queue::SoraTaskQueue; -use crate::services::sora::utils::upload_images_to_sora::{upload_images_to_sora, UploadImagesToSoraArgs, UploadImagesToSoraResult}; -use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager; -use artcraft_api_defs::generate::video::generate_kling_1_6_pro_image_to_video::{GenerateKling16ProAspectRatio, GenerateKling16ProDuration, GenerateKling16ProImageToVideoRequest}; -use enums::common::generation_provider::GenerationProvider; -use enums::tauri::tasks::task_type::TaskType; -use uuid_utils::uuid::generate_random_uuid; -use log::{error, info}; -use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet; -use artcraft_client::endpoints::generate::video::generate_kling_16_pro_image_to_video::generate_kling_16_pro_image_to_video; -use artcraft_client::endpoints::generate::video::generate_kling_21_pro_image_to_video::generate_kling_21_pro_image_to_video; -use artcraft_client::endpoints::generate::video::multi_function::kling_2p5_turbo_pro_multi_function_video_gen::kling_2p5_turbo_pro_multi_function_video_gen; -use artcraft_client::endpoints::generate::video::multi_function::sora_2_multi_function_video_gen::sora_2_multi_function_video_gen; -use tauri::AppHandle; -use tokens::tokens::media_files::MediaFileToken; - -pub (super) async fn handle_artcraft_kling_1p6_pro( - request: &TauriGenerateVideoRequest, - app_env_configs: &AppEnvConfigs, - creds: &StorytellerCredentialSet, -) -> Result { - - let uuid_idempotency_token = generate_random_uuid(); - - // TODO: Fix this parameter - let aspect_ratio = match request.sora_orientation { - Some(SoraOrientation::Portrait) => GenerateKling16ProAspectRatio::TallNineSixteen, - Some(SoraOrientation::Landscape) => GenerateKling16ProAspectRatio::WideSixteenNine, - None => GenerateKling16ProAspectRatio::WideSixteenNine, - }; - - let request = GenerateKling16ProImageToVideoRequest { - uuid_idempotency_token, - prompt: request.prompt.clone(), - media_file_token: request.image_media_token.clone(), - end_frame_image_media_token: request.end_frame_image_media_token.clone(), - aspect_ratio: Some(aspect_ratio), - duration: Some(GenerateKling16ProDuration::TenSeconds), // TODO: Parameterize - }; - - let result = generate_kling_16_pro_image_to_video( - &app_env_configs.storyteller_host, - Some(&creds), - request, - ).await; - - let job_token = match result { - Ok(enqueued) => { - info!("Successfully enqueued."); - enqueued.inference_job_token - } - Err(err) => { - error!("Failed to enqueue: {:?}", err); - return Err(GenerateError::from(err)); - } - }; - - Ok(TaskEnqueueSuccess { - task_type: TaskType::VideoGeneration, - model: Some(GenerationModel::Kling1_6), - provider: GenerationProvider::Artcraft, - provider_job_id: Some(job_token.to_string()), - maybe_queue_status_url: None, - maybe_prompt_token: None, - maybe_queue_response_url: None, - }) -} diff --git a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_kling_2p1_master.rs b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_kling_2p1_master.rs deleted file mode 100644 index 12a63181e8..0000000000 --- a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_kling_2p1_master.rs +++ /dev/null @@ -1,77 +0,0 @@ -use crate::core::commands::enqueue::generate_error::GenerateError; -use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error; -use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation}; -use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess; -use crate::core::events::basic_sendable_event_trait::BasicSendableEvent; -use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent; -use crate::core::events::generation_events::common::{GenerationAction, GenerationModel}; -use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent; -use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs; -use crate::core::state::data_dir::app_data_root::AppDataRoot; -use crate::services::sora::state::sora_credential_manager::SoraCredentialManager; -use crate::services::sora::state::sora_task_queue::SoraTaskQueue; -use crate::services::sora::utils::upload_images_to_sora::{upload_images_to_sora, UploadImagesToSoraArgs, UploadImagesToSoraResult}; -use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager; -use artcraft_api_defs::generate::video::generate_kling_2_1_master_image_to_video::{GenerateKling21MasterAspectRatio, GenerateKling21MasterDuration, GenerateKling21MasterImageToVideoRequest}; -use enums::common::generation_provider::GenerationProvider; -use enums::tauri::tasks::task_type::TaskType; -use uuid_utils::uuid::generate_random_uuid; -use log::{error, info}; -use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet; -use artcraft_client::endpoints::generate::video::generate_kling_21_master_image_to_video::generate_kling_21_master_image_to_video; -use artcraft_client::endpoints::generate::video::generate_kling_21_pro_image_to_video::generate_kling_21_pro_image_to_video; -use artcraft_client::endpoints::generate::video::multi_function::kling_2p5_turbo_pro_multi_function_video_gen::kling_2p5_turbo_pro_multi_function_video_gen; -use artcraft_client::endpoints::generate::video::multi_function::sora_2_multi_function_video_gen::sora_2_multi_function_video_gen; -use tauri::AppHandle; -use tokens::tokens::media_files::MediaFileToken; - -pub (super) async fn handle_artcraft_kling_2p1_master( - request: &TauriGenerateVideoRequest, - app_env_configs: &AppEnvConfigs, - creds: &StorytellerCredentialSet, -) -> Result { - - let uuid_idempotency_token = generate_random_uuid(); - - // TODO: Fix this parameter - let aspect_ratio = match request.sora_orientation { - Some(SoraOrientation::Portrait) => GenerateKling21MasterAspectRatio::TallNineSixteen, - Some(SoraOrientation::Landscape) => GenerateKling21MasterAspectRatio::WideSixteenNine, - None => GenerateKling21MasterAspectRatio::WideSixteenNine, - }; - - let request = GenerateKling21MasterImageToVideoRequest { - uuid_idempotency_token, - prompt: request.prompt.clone(), - media_file_token: request.image_media_token.clone(), - aspect_ratio: Some(aspect_ratio), - duration: Some(GenerateKling21MasterDuration::TenSeconds), // TODO: Parameterize - }; - - let result = generate_kling_21_master_image_to_video( - &app_env_configs.storyteller_host, - Some(&creds), - request, - ).await; - - let job_token = match result { - Ok(enqueued) => { - info!("Successfully enqueued."); - enqueued.inference_job_token - } - Err(err) => { - error!("Failed to enqueue: {:?}", err); - return Err(GenerateError::from(err)); - } - }; - - Ok(TaskEnqueueSuccess { - task_type: TaskType::VideoGeneration, - model: Some(GenerationModel::Kling21Master), - provider: GenerationProvider::Artcraft, - provider_job_id: Some(job_token.to_string()), - maybe_queue_status_url: None, - maybe_prompt_token: None, - maybe_queue_response_url: None, - }) -} diff --git a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_kling_2p1_pro.rs b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_kling_2p1_pro.rs deleted file mode 100644 index fb5a30043c..0000000000 --- a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_kling_2p1_pro.rs +++ /dev/null @@ -1,77 +0,0 @@ -use crate::core::commands::enqueue::generate_error::GenerateError; -use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error; -use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation}; -use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess; -use crate::core::events::basic_sendable_event_trait::BasicSendableEvent; -use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent; -use crate::core::events::generation_events::common::{GenerationAction, GenerationModel}; -use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent; -use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs; -use crate::core::state::data_dir::app_data_root::AppDataRoot; -use crate::services::sora::state::sora_credential_manager::SoraCredentialManager; -use crate::services::sora::state::sora_task_queue::SoraTaskQueue; -use crate::services::sora::utils::upload_images_to_sora::{upload_images_to_sora, UploadImagesToSoraArgs, UploadImagesToSoraResult}; -use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager; -use artcraft_api_defs::generate::video::generate_kling_2_1_pro_image_to_video::{GenerateKling21ProAspectRatio, GenerateKling21ProDuration, GenerateKling21ProImageToVideoRequest}; -use enums::common::generation_provider::GenerationProvider; -use enums::tauri::tasks::task_type::TaskType; -use uuid_utils::uuid::generate_random_uuid; -use log::{error, info}; -use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet; -use artcraft_client::endpoints::generate::video::generate_kling_21_pro_image_to_video::generate_kling_21_pro_image_to_video; -use artcraft_client::endpoints::generate::video::multi_function::kling_2p5_turbo_pro_multi_function_video_gen::kling_2p5_turbo_pro_multi_function_video_gen; -use artcraft_client::endpoints::generate::video::multi_function::sora_2_multi_function_video_gen::sora_2_multi_function_video_gen; -use tauri::AppHandle; -use tokens::tokens::media_files::MediaFileToken; - -pub (super) async fn handle_artcraft_kling_2p1_pro( - request: &TauriGenerateVideoRequest, - app_env_configs: &AppEnvConfigs, - creds: &StorytellerCredentialSet, -) -> Result { - - let uuid_idempotency_token = generate_random_uuid(); - - // TODO: Fix this parameter - let aspect_ratio = match request.sora_orientation { - Some(SoraOrientation::Portrait) => GenerateKling21ProAspectRatio::TallNineSixteen, - Some(SoraOrientation::Landscape) => GenerateKling21ProAspectRatio::WideSixteenNine, - None => GenerateKling21ProAspectRatio::WideSixteenNine, - }; - - let request = GenerateKling21ProImageToVideoRequest { - uuid_idempotency_token, - prompt: request.prompt.clone(), - media_file_token: request.image_media_token.clone(), - end_frame_image_media_token: request.end_frame_image_media_token.clone(), - aspect_ratio: Some(aspect_ratio), - duration: Some(GenerateKling21ProDuration::TenSeconds), // TODO: Parameterize - }; - - let result = generate_kling_21_pro_image_to_video( - &app_env_configs.storyteller_host, - Some(&creds), - request, - ).await; - - let job_token = match result { - Ok(enqueued) => { - info!("Successfully enqueued."); - enqueued.inference_job_token - } - Err(err) => { - error!("Failed to enqueue: {:?}", err); - return Err(GenerateError::from(err)); - } - }; - - Ok(TaskEnqueueSuccess { - task_type: TaskType::VideoGeneration, - model: Some(GenerationModel::Kling21Pro), - provider: GenerationProvider::Artcraft, - provider_job_id: Some(job_token.to_string()), - maybe_queue_status_url: None, - maybe_prompt_token: None, - maybe_queue_response_url: None, - }) -} diff --git a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_kling_2p5_turbo_pro.rs b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_kling_2p5_turbo_pro.rs deleted file mode 100644 index 1475b3fb15..0000000000 --- a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_kling_2p5_turbo_pro.rs +++ /dev/null @@ -1,77 +0,0 @@ -use crate::core::commands::enqueue::generate_error::GenerateError; -use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error; -use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation}; -use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess; -use crate::core::events::basic_sendable_event_trait::BasicSendableEvent; -use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent; -use crate::core::events::generation_events::common::{GenerationAction, GenerationModel}; -use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent; -use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs; -use crate::core::state::data_dir::app_data_root::AppDataRoot; -use crate::services::sora::state::sora_credential_manager::SoraCredentialManager; -use crate::services::sora::state::sora_task_queue::SoraTaskQueue; -use crate::services::sora::utils::upload_images_to_sora::{upload_images_to_sora, UploadImagesToSoraArgs, UploadImagesToSoraResult}; -use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager; -use artcraft_api_defs::generate::video::multi_function::kling_2_5_turbo_multi_function_video_gen::{Kling2p5TurboProMultiFunctionVideoGenAspectRatio, Kling2p5TurboProMultiFunctionVideoGenDuration, Kling2p5TurboProMultiFunctionVideoGenRequest}; -use enums::common::generation_provider::GenerationProvider; -use enums::tauri::tasks::task_type::TaskType; -use uuid_utils::uuid::generate_random_uuid; -use log::{error, info}; -use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet; -use artcraft_client::endpoints::generate::video::multi_function::kling_2p5_turbo_pro_multi_function_video_gen::kling_2p5_turbo_pro_multi_function_video_gen; -use artcraft_client::endpoints::generate::video::multi_function::sora_2_multi_function_video_gen::sora_2_multi_function_video_gen; -use tauri::AppHandle; -use tokens::tokens::media_files::MediaFileToken; - -pub (super) async fn handle_artcraft_kling_2p5_turbo_pro( - request: &TauriGenerateVideoRequest, - app_env_configs: &AppEnvConfigs, - creds: &StorytellerCredentialSet, -) -> Result { - - let uuid_idempotency_token = generate_random_uuid(); - - // TODO: Fix this parameter - let aspect_ratio = match request.sora_orientation { - Some(SoraOrientation::Portrait) => Kling2p5TurboProMultiFunctionVideoGenAspectRatio::NineBySixteen, - Some(SoraOrientation::Landscape) => Kling2p5TurboProMultiFunctionVideoGenAspectRatio::SixteenByNine, - None => Kling2p5TurboProMultiFunctionVideoGenAspectRatio::SixteenByNine, - }; - - let request = Kling2p5TurboProMultiFunctionVideoGenRequest { - uuid_idempotency_token, - prompt: request.prompt.clone(), - negative_prompt: None, // TODO: Parameterize - start_frame_image_media_token: request.image_media_token.clone(), - end_frame_image_media_token: request.end_frame_image_media_token.clone(), - aspect_ratio: Some(aspect_ratio), - duration: Some(Kling2p5TurboProMultiFunctionVideoGenDuration::TenSeconds), // TODO: Parameterize - }; - - let result = kling_2p5_turbo_pro_multi_function_video_gen( - &app_env_configs.storyteller_host, - Some(&creds), - request, - ).await; - - let job_token = match result { - Ok(enqueued) => { - info!("Successfully enqueued."); - enqueued.inference_job_token - } - Err(err) => { - error!("Failed to enqueue: {:?}", err); - return Err(GenerateError::from(err)); - } - }; - - Ok(TaskEnqueueSuccess { - task_type: TaskType::VideoGeneration, - model: Some(GenerationModel::Kling2p5TurboPro), - provider: GenerationProvider::Artcraft, - provider_job_id: Some(job_token.to_string()), - maybe_queue_status_url: None, - maybe_prompt_token: None, - maybe_queue_response_url: None, - }) -} diff --git a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_kling_2p6_pro.rs b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_kling_2p6_pro.rs deleted file mode 100644 index 0c3eb64a38..0000000000 --- a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_kling_2p6_pro.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::core::commands::enqueue::generate_error::GenerateError; -use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error; -use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation}; -use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess; -use crate::core::events::basic_sendable_event_trait::BasicSendableEvent; -use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent; -use crate::core::events::generation_events::common::{GenerationAction, GenerationModel}; -use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent; -use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs; -use crate::core::state::data_dir::app_data_root::AppDataRoot; -use crate::services::sora::state::sora_credential_manager::SoraCredentialManager; -use crate::services::sora::state::sora_task_queue::SoraTaskQueue; -use crate::services::sora::utils::upload_images_to_sora::{upload_images_to_sora, UploadImagesToSoraArgs, UploadImagesToSoraResult}; -use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager; -use artcraft_api_defs::generate::video::generate_kling_1_6_pro_image_to_video::{GenerateKling16ProAspectRatio, GenerateKling16ProImageToVideoRequest}; -use artcraft_api_defs::generate::video::multi_function::kling_2_6_multi_function_video_gen::{Kling2p6ProMultiFunctionVideoGenAspectRatio, Kling2p6ProMultiFunctionVideoGenDuration, Kling2p6ProMultiFunctionVideoGenRequest}; -use enums::common::generation_provider::GenerationProvider; -use enums::tauri::tasks::task_type::TaskType; -use uuid_utils::uuid::generate_random_uuid; -use log::{error, info}; -use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet; -use artcraft_client::endpoints::generate::video::generate_kling_16_pro_image_to_video::generate_kling_16_pro_image_to_video; -use artcraft_client::endpoints::generate::video::multi_function::kling_2p6_pro_multi_function_video_gen::kling_2p6_pro_multi_function_video_gen; -use artcraft_client::endpoints::generate::video::multi_function::sora_2_multi_function_video_gen::sora_2_multi_function_video_gen; -use tauri::AppHandle; -use tokens::tokens::media_files::MediaFileToken; - -pub (super) async fn handle_artcraft_kling_2p6_pro( - request: &TauriGenerateVideoRequest, - app_env_configs: &AppEnvConfigs, - creds: &StorytellerCredentialSet, -) -> Result { - - let uuid_idempotency_token = generate_random_uuid(); - - // TODO: Fix this parameter - let aspect_ratio = match request.sora_orientation { - Some(SoraOrientation::Portrait) => Kling2p6ProMultiFunctionVideoGenAspectRatio::NineBySixteen, - Some(SoraOrientation::Landscape) => Kling2p6ProMultiFunctionVideoGenAspectRatio::SixteenByNine, - None => Kling2p6ProMultiFunctionVideoGenAspectRatio::SixteenByNine, - }; - - let request = Kling2p6ProMultiFunctionVideoGenRequest { - uuid_idempotency_token, - prompt: request.prompt.clone(), - negative_prompt: None, // TODO: Parameterize - start_frame_image_media_token: request.image_media_token.clone(), - aspect_ratio: Some(aspect_ratio), - duration: Some(Kling2p6ProMultiFunctionVideoGenDuration::TenSeconds), // TODO: Parameterize - generate_audio: request.generate_audio, - }; - - let result = kling_2p6_pro_multi_function_video_gen( - &app_env_configs.storyteller_host, - Some(&creds), - request, - ).await; - - let job_token = match result { - Ok(enqueued) => { - info!("Successfully enqueued."); - enqueued.inference_job_token - } - Err(err) => { - error!("Failed to enqueue: {:?}", err); - return Err(GenerateError::from(err)); - } - }; - - Ok(TaskEnqueueSuccess { - task_type: TaskType::VideoGeneration, - model: Some(GenerationModel::Kling2p6Pro), - provider: GenerationProvider::Artcraft, - provider_job_id: Some(job_token.to_string()), - maybe_queue_status_url: None, - maybe_prompt_token: None, - maybe_queue_response_url: None, - }) -} diff --git a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_seedance_1_lite.rs b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_seedance_1_lite.rs deleted file mode 100644 index 3c9826af47..0000000000 --- a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_seedance_1_lite.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::core::commands::enqueue::generate_error::GenerateError; -use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error; -use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation}; -use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess; -use crate::core::events::basic_sendable_event_trait::BasicSendableEvent; -use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent; -use crate::core::events::generation_events::common::{GenerationAction, GenerationModel}; -use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent; -use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs; -use crate::core::state::data_dir::app_data_root::AppDataRoot; -use crate::services::sora::state::sora_credential_manager::SoraCredentialManager; -use crate::services::sora::state::sora_task_queue::SoraTaskQueue; -use crate::services::sora::utils::upload_images_to_sora::{upload_images_to_sora, UploadImagesToSoraArgs, UploadImagesToSoraResult}; -use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager; -use artcraft_api_defs::generate::video::generate_seedance_1_0_lite_image_to_video::{GenerateSeedance10LiteDuration, GenerateSeedance10LiteImageToVideoRequest, GenerateSeedance10LiteResolution}; -use enums::common::generation_provider::GenerationProvider; -use enums::tauri::tasks::task_type::TaskType; -use uuid_utils::uuid::generate_random_uuid; -use log::{error, info}; -use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet; -use artcraft_client::endpoints::generate::video::generate_kling_16_pro_image_to_video::generate_kling_16_pro_image_to_video; -use artcraft_client::endpoints::generate::video::generate_kling_21_pro_image_to_video::generate_kling_21_pro_image_to_video; -use artcraft_client::endpoints::generate::video::generate_seedance_1_0_lite_image_to_video::generate_seedance_1_0_lite_image_to_video; -use artcraft_client::endpoints::generate::video::multi_function::kling_2p5_turbo_pro_multi_function_video_gen::kling_2p5_turbo_pro_multi_function_video_gen; -use artcraft_client::endpoints::generate::video::multi_function::sora_2_multi_function_video_gen::sora_2_multi_function_video_gen; -use tauri::AppHandle; -use tokens::tokens::media_files::MediaFileToken; - -pub (super) async fn handle_artcraft_seedance_1_lite( - request: &TauriGenerateVideoRequest, - app_env_configs: &AppEnvConfigs, - creds: &StorytellerCredentialSet, -) -> Result { - - let uuid_idempotency_token = generate_random_uuid(); - - let request = GenerateSeedance10LiteImageToVideoRequest { - uuid_idempotency_token, - prompt: request.prompt.clone(), - media_file_token: request.image_media_token.clone(), - end_frame_image_media_token: request.end_frame_image_media_token.clone(), - duration: Some(GenerateSeedance10LiteDuration::TenSeconds), // TODO: Parameterize - resolution: Some(GenerateSeedance10LiteResolution::SevenTwentyP), // TODO: Parameterize - aspect_ratio: None, // TODO: Parameterize - }; - - let result = generate_seedance_1_0_lite_image_to_video( - &app_env_configs.storyteller_host, - Some(&creds), - request, - ).await; - - let job_token = match result { - Ok(enqueued) => { - info!("Successfully enqueued."); - enqueued.inference_job_token - } - Err(err) => { - error!("Failed to enqueue: {:?}", err); - return Err(GenerateError::from(err)); - } - }; - - Ok(TaskEnqueueSuccess { - task_type: TaskType::VideoGeneration, - model: Some(GenerationModel::Kling1_6), - provider: GenerationProvider::Artcraft, - provider_job_id: Some(job_token.to_string()), - maybe_queue_status_url: None, - maybe_prompt_token: None, - maybe_queue_response_url: None, - }) -} diff --git a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_sora2.rs b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_sora2.rs deleted file mode 100644 index 846fad6d7d..0000000000 --- a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_sora2.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::core::commands::enqueue::generate_error::GenerateError; -use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error; -use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation}; -use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess; -use crate::core::events::basic_sendable_event_trait::BasicSendableEvent; -use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent; -use crate::core::events::generation_events::common::{GenerationAction, GenerationModel}; -use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent; -use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs; -use crate::core::state::data_dir::app_data_root::AppDataRoot; -use crate::services::sora::state::sora_credential_manager::SoraCredentialManager; -use crate::services::sora::state::sora_task_queue::SoraTaskQueue; -use crate::services::sora::utils::upload_images_to_sora::{upload_images_to_sora, UploadImagesToSoraArgs, UploadImagesToSoraResult}; -use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager; -use artcraft_api_defs::generate::video::generate_kling_1_6_pro_image_to_video::{GenerateKling16ProAspectRatio, GenerateKling16ProImageToVideoRequest}; -use artcraft_api_defs::generate::video::multi_function::sora_2_multi_function_video_gen::{Sora2MultiFunctionVideoGenAspectRatio, Sora2MultiFunctionVideoGenDuration, Sora2MultiFunctionVideoGenRequest, Sora2MultiFunctionVideoGenResolution}; -use enums::common::generation_provider::GenerationProvider; -use enums::tauri::tasks::task_type::TaskType; -use uuid_utils::uuid::generate_random_uuid; -use log::{error, info}; -use openai_sora_client::recipes::generate_sora2_video::generate_sora2_video_with_session_auto_renew::generate_sora2_video_with_session_auto_renew; -use openai_sora_client::recipes::list_sora2_drafts::list_sora2_drafts_with_session_auto_renew::list_sora2_drafts_with_session_auto_renew; -use openai_sora_client::requests::generate_sora2_video::generate_sora2_video::{GenerateSora2VideoArgs, Orientation}; -use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet; -use artcraft_client::endpoints::generate::video::generate_kling_16_pro_image_to_video::generate_kling_16_pro_image_to_video; -use artcraft_client::endpoints::generate::video::multi_function::sora_2_multi_function_video_gen::sora_2_multi_function_video_gen; -use tauri::AppHandle; -use tokens::tokens::media_files::MediaFileToken; - -pub (super) async fn handle_artcraft_sora2( - request: &TauriGenerateVideoRequest, - app_env_configs: &AppEnvConfigs, - creds: &StorytellerCredentialSet, -) -> Result { - - let uuid_idempotency_token = generate_random_uuid(); - - let aspect_ratio = match request.sora_orientation { - Some(SoraOrientation::Portrait) => Sora2MultiFunctionVideoGenAspectRatio::NineBySixteen, - Some(SoraOrientation::Landscape) => Sora2MultiFunctionVideoGenAspectRatio::SixteenByNine, - None => Sora2MultiFunctionVideoGenAspectRatio::SixteenByNine, - }; - - let request = Sora2MultiFunctionVideoGenRequest { - uuid_idempotency_token, - prompt: request.prompt.clone(), - image_media_token: request.image_media_token.clone(), - aspect_ratio: Some(aspect_ratio), - resolution: Some(Sora2MultiFunctionVideoGenResolution::SevenTwentyP), // TODO: Parameterize - duration: Some(Sora2MultiFunctionVideoGenDuration::TwelveSeconds), // TODO: Parameterize - }; - - let result = sora_2_multi_function_video_gen( - &app_env_configs.storyteller_host, - Some(&creds), - request, - ).await; - - let job_token = match result { - Ok(enqueued) => { - info!("Successfully enqueued."); - enqueued.inference_job_token - } - Err(err) => { - error!("Failed to enqueue: {:?}", err); - return Err(GenerateError::from(err)); - } - }; - - Ok(TaskEnqueueSuccess { - task_type: TaskType::VideoGeneration, - model: Some(GenerationModel::Sora2), - provider: GenerationProvider::Artcraft, - provider_job_id: Some(job_token.to_string()), - maybe_queue_status_url: None, - maybe_prompt_token: None, - maybe_queue_response_url: None, - }) -} diff --git a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_sora2_pro.rs b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_sora2_pro.rs deleted file mode 100644 index 8d2393837a..0000000000 --- a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_sora2_pro.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::core::commands::enqueue::generate_error::GenerateError; -use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error; -use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation}; -use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess; -use crate::core::events::basic_sendable_event_trait::BasicSendableEvent; -use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent; -use crate::core::events::generation_events::common::{GenerationAction, GenerationModel}; -use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent; -use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs; -use crate::core::state::data_dir::app_data_root::AppDataRoot; -use crate::services::sora::state::sora_credential_manager::SoraCredentialManager; -use crate::services::sora::state::sora_task_queue::SoraTaskQueue; -use crate::services::sora::utils::upload_images_to_sora::{upload_images_to_sora, UploadImagesToSoraArgs, UploadImagesToSoraResult}; -use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager; -use artcraft_api_defs::generate::video::multi_function::sora_2_pro_multi_function_video_gen::{Sora2ProMultiFunctionVideoGenAspectRatio, Sora2ProMultiFunctionVideoGenDuration, Sora2ProMultiFunctionVideoGenRequest, Sora2ProMultiFunctionVideoGenResolution}; -use enums::common::generation_provider::GenerationProvider; -use enums::tauri::tasks::task_type::TaskType; -use uuid_utils::uuid::generate_random_uuid; -use log::{error, info}; -use openai_sora_client::recipes::generate_sora2_video::generate_sora2_video_with_session_auto_renew::generate_sora2_video_with_session_auto_renew; -use openai_sora_client::recipes::list_sora2_drafts::list_sora2_drafts_with_session_auto_renew::list_sora2_drafts_with_session_auto_renew; -use artcraft_client::endpoints::generate::video::generate_kling_16_pro_image_to_video::generate_kling_16_pro_image_to_video; -use artcraft_client::endpoints::generate::video::multi_function::sora_2_multi_function_video_gen::sora_2_multi_function_video_gen; -use artcraft_client::endpoints::generate::video::multi_function::sora_2_pro_multi_function_video_gen::sora_2_pro_multi_function_video_gen; -use tauri::AppHandle; -use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet; -use tokens::tokens::media_files::MediaFileToken; - -pub (super) async fn handle_artcraft_sora2_pro( - request: &TauriGenerateVideoRequest, - app_env_configs: &AppEnvConfigs, - creds: &StorytellerCredentialSet, -) -> Result { - - let uuid_idempotency_token = generate_random_uuid(); - - let aspect_ratio = match request.sora_orientation { - Some(SoraOrientation::Portrait) => Sora2ProMultiFunctionVideoGenAspectRatio::NineBySixteen, - Some(SoraOrientation::Landscape) => Sora2ProMultiFunctionVideoGenAspectRatio::SixteenByNine, - None => Sora2ProMultiFunctionVideoGenAspectRatio::SixteenByNine, - }; - - let request = Sora2ProMultiFunctionVideoGenRequest { - uuid_idempotency_token, - prompt: request.prompt.clone(), - image_media_token: request.image_media_token.clone(), - aspect_ratio: Some(aspect_ratio), - resolution: Some(Sora2ProMultiFunctionVideoGenResolution::TenEightyP), // TODO: Parameterize - duration: Some(Sora2ProMultiFunctionVideoGenDuration::TwelveSeconds), // TODO: Parameterize - }; - - let result = sora_2_pro_multi_function_video_gen( - &app_env_configs.storyteller_host, - Some(&creds), - request, - ).await; - - let job_token = match result { - Ok(enqueued) => { - info!("Successfully enqueued."); - enqueued.inference_job_token - } - Err(err) => { - error!("Failed to enqueue: {:?}", err); - return Err(GenerateError::from(err)); - } - }; - - Ok(TaskEnqueueSuccess { - task_type: TaskType::VideoGeneration, - model: Some(GenerationModel::Sora2Pro), - provider: GenerationProvider::Artcraft, - provider_job_id: Some(job_token.to_string()), - maybe_queue_status_url: None, - maybe_prompt_token: None, - maybe_queue_response_url: None, - }) -} diff --git a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_veo2.rs b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_veo2.rs deleted file mode 100644 index 7793995946..0000000000 --- a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_veo2.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::core::commands::enqueue::generate_error::GenerateError; -use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error; -use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation}; -use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess; -use crate::core::events::basic_sendable_event_trait::BasicSendableEvent; -use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent; -use crate::core::events::generation_events::common::{GenerationAction, GenerationModel}; -use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent; -use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs; -use crate::core::state::data_dir::app_data_root::AppDataRoot; -use crate::services::sora::state::sora_credential_manager::SoraCredentialManager; -use crate::services::sora::state::sora_task_queue::SoraTaskQueue; -use crate::services::sora::utils::upload_images_to_sora::{upload_images_to_sora, UploadImagesToSoraArgs, UploadImagesToSoraResult}; -use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager; -use artcraft_api_defs::generate::video::generate_veo_2_image_to_video::{GenerateVeo2AspectRatio, GenerateVeo2ImageToVideoRequest}; -use enums::common::generation_provider::GenerationProvider; -use enums::tauri::tasks::task_type::TaskType; -use uuid_utils::uuid::generate_random_uuid; -use log::{error, info}; -use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet; -use artcraft_client::endpoints::generate::video::generate_veo_2_image_to_video::generate_veo_2_image_to_video; -use artcraft_client::endpoints::generate::video::generate_veo_3_image_to_video::generate_veo_3_image_to_video; -use artcraft_client::endpoints::generate::video::multi_function::veo_3p1_multi_function_video_gen::veo_3p1_multi_function_video_gen; -use tauri::AppHandle; -use tokens::tokens::media_files::MediaFileToken; - -pub (super) async fn handle_artcraft_veo2( - request: &TauriGenerateVideoRequest, - app_env_configs: &AppEnvConfigs, - creds: &StorytellerCredentialSet, -) -> Result { - - let uuid_idempotency_token = generate_random_uuid(); - - // TODO: Fix. - let aspect_ratio = match request.sora_orientation { - Some(SoraOrientation::Portrait) => GenerateVeo2AspectRatio::TallNineSixteen, - Some(SoraOrientation::Landscape) => GenerateVeo2AspectRatio::WideSixteenNine, - None => GenerateVeo2AspectRatio::WideSixteenNine, - }; - - let request = GenerateVeo2ImageToVideoRequest { - uuid_idempotency_token, - media_file_token: request.image_media_token.clone(), - prompt: request.prompt.clone(), - aspect_ratio: Some(aspect_ratio), - duration: None, // TODO: Parameterize - }; - - let result = generate_veo_2_image_to_video( - &app_env_configs.storyteller_host, - Some(&creds), - request, - ).await; - - let job_token = match result { - Ok(enqueued) => { - info!("Successfully enqueued."); - enqueued.inference_job_token - } - Err(err) => { - error!("Failed to enqueue: {:?}", err); - return Err(GenerateError::from(err)); - } - }; - - Ok(TaskEnqueueSuccess { - task_type: TaskType::VideoGeneration, - model: Some(GenerationModel::Veo2), - provider: GenerationProvider::Artcraft, - provider_job_id: Some(job_token.to_string()), - maybe_queue_status_url: None, - maybe_prompt_token: None, - maybe_queue_response_url: None, - }) -} diff --git a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_veo3.rs b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_veo3.rs deleted file mode 100644 index b94f5556b3..0000000000 --- a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_veo3.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::core::commands::enqueue::generate_error::GenerateError; -use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error; -use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation}; -use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess; -use crate::core::events::basic_sendable_event_trait::BasicSendableEvent; -use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent; -use crate::core::events::generation_events::common::{GenerationAction, GenerationModel}; -use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent; -use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs; -use crate::core::state::data_dir::app_data_root::AppDataRoot; -use crate::services::sora::state::sora_credential_manager::SoraCredentialManager; -use crate::services::sora::state::sora_task_queue::SoraTaskQueue; -use crate::services::sora::utils::upload_images_to_sora::{upload_images_to_sora, UploadImagesToSoraArgs, UploadImagesToSoraResult}; -use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager; -use artcraft_api_defs::generate::video::generate_kling_1_6_pro_image_to_video::{GenerateKling16ProAspectRatio, GenerateKling16ProImageToVideoRequest}; -use artcraft_api_defs::generate::video::generate_veo_3_image_to_video::{GenerateVeo3AspectRatio, GenerateVeo3ImageToVideoRequest}; -use enums::common::generation_provider::GenerationProvider; -use enums::tauri::tasks::task_type::TaskType; -use uuid_utils::uuid::generate_random_uuid; -use log::{error, info}; -use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet; -use artcraft_client::endpoints::generate::video::generate_veo_3_image_to_video::generate_veo_3_image_to_video; -use artcraft_client::endpoints::generate::video::multi_function::veo_3p1_multi_function_video_gen::veo_3p1_multi_function_video_gen; -use tauri::AppHandle; -use tokens::tokens::media_files::MediaFileToken; - -pub (super) async fn handle_artcraft_veo3( - request: &TauriGenerateVideoRequest, - app_env_configs: &AppEnvConfigs, - creds: &StorytellerCredentialSet, -) -> Result { - - let uuid_idempotency_token = generate_random_uuid(); - - // TODO: Fix. - let aspect_ratio = match request.sora_orientation { - Some(SoraOrientation::Portrait) => GenerateVeo3AspectRatio::TallNineSixteen, - Some(SoraOrientation::Landscape) => GenerateVeo3AspectRatio::WideSixteenNine, - None => GenerateVeo3AspectRatio::WideSixteenNine, - }; - - let request = GenerateVeo3ImageToVideoRequest { - uuid_idempotency_token, - media_file_token: request.image_media_token.clone(), - prompt: request.prompt.clone(), - aspect_ratio: Some(aspect_ratio), - generate_audio: request.generate_audio, - duration: None, // TODO: Parameterize - resolution: None, // TODO: Parameterize - }; - - let result = generate_veo_3_image_to_video( - &app_env_configs.storyteller_host, - Some(&creds), - request, - ).await; - - let job_token = match result { - Ok(enqueued) => { - info!("Successfully enqueued."); - enqueued.inference_job_token - } - Err(err) => { - error!("Failed to enqueue: {:?}", err); - return Err(GenerateError::from(err)); - } - }; - - Ok(TaskEnqueueSuccess { - task_type: TaskType::VideoGeneration, - model: Some(GenerationModel::Veo3), - provider: GenerationProvider::Artcraft, - provider_job_id: Some(job_token.to_string()), - maybe_queue_status_url: None, - maybe_prompt_token: None, - maybe_queue_response_url: None, - }) -} diff --git a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_veo3_fast.rs b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_veo3_fast.rs deleted file mode 100644 index 91647e1ac1..0000000000 --- a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_veo3_fast.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::core::commands::enqueue::generate_error::GenerateError; -use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error; -use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation}; -use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess; -use crate::core::events::basic_sendable_event_trait::BasicSendableEvent; -use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent; -use crate::core::events::generation_events::common::{GenerationAction, GenerationModel}; -use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent; -use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs; -use crate::core::state::data_dir::app_data_root::AppDataRoot; -use crate::services::sora::state::sora_credential_manager::SoraCredentialManager; -use crate::services::sora::state::sora_task_queue::SoraTaskQueue; -use crate::services::sora::utils::upload_images_to_sora::{upload_images_to_sora, UploadImagesToSoraArgs, UploadImagesToSoraResult}; -use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager; -use artcraft_api_defs::generate::video::generate_kling_1_6_pro_image_to_video::{GenerateKling16ProAspectRatio, GenerateKling16ProImageToVideoRequest}; -use artcraft_api_defs::generate::video::generate_veo_3_fast_image_to_video::GenerateVeo3FastImageToVideoRequest; -use enums::common::generation_provider::GenerationProvider; -use enums::tauri::tasks::task_type::TaskType; -use uuid_utils::uuid::generate_random_uuid; -use log::{error, info}; -use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet; -use artcraft_client::endpoints::generate::video::generate_veo_3_fast_image_to_video::generate_veo_3_fast_image_to_video; -use artcraft_client::endpoints::generate::video::generate_veo_3_image_to_video::generate_veo_3_image_to_video; -use artcraft_client::endpoints::generate::video::multi_function::veo_3p1_multi_function_video_gen::veo_3p1_multi_function_video_gen; -use tauri::AppHandle; -use tokens::tokens::media_files::MediaFileToken; - -pub (super) async fn handle_artcraft_veo3_fast( - request: &TauriGenerateVideoRequest, - app_env_configs: &AppEnvConfigs, - creds: &StorytellerCredentialSet, -) -> Result { - - let uuid_idempotency_token = generate_random_uuid(); - - // TODO: No aspect ratio? - let request = GenerateVeo3FastImageToVideoRequest { - uuid_idempotency_token, - media_file_token: request.image_media_token.clone(), - prompt: request.prompt.clone(), - generate_audio: request.generate_audio, - duration: None, // TODO: Parameterize - resolution: None, // TODO: Parameterize - aspect_ratio: None, // TODO: Parameterize - }; - - let result = generate_veo_3_fast_image_to_video( - &app_env_configs.storyteller_host, - Some(&creds), - request, - ).await; - - let job_token = match result { - Ok(enqueued) => { - info!("Successfully enqueued."); - enqueued.inference_job_token - } - Err(err) => { - error!("Failed to enqueue: {:?}", err); - return Err(GenerateError::from(err)); - } - }; - - Ok(TaskEnqueueSuccess { - task_type: TaskType::VideoGeneration, - model: Some(GenerationModel::Veo3Fast), - provider: GenerationProvider::Artcraft, - provider_job_id: Some(job_token.to_string()), - maybe_queue_status_url: None, - maybe_prompt_token: None, - maybe_queue_response_url: None, - }) -} diff --git a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_veo3p1.rs b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_veo3p1.rs deleted file mode 100644 index 7f50d44443..0000000000 --- a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_veo3p1.rs +++ /dev/null @@ -1,81 +0,0 @@ -use crate::core::commands::enqueue::generate_error::GenerateError; -use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error; -use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation}; -use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess; -use crate::core::events::basic_sendable_event_trait::BasicSendableEvent; -use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent; -use crate::core::events::generation_events::common::{GenerationAction, GenerationModel}; -use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent; -use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs; -use crate::core::state::data_dir::app_data_root::AppDataRoot; -use crate::services::sora::state::sora_credential_manager::SoraCredentialManager; -use crate::services::sora::state::sora_task_queue::SoraTaskQueue; -use crate::services::sora::utils::upload_images_to_sora::{upload_images_to_sora, UploadImagesToSoraArgs, UploadImagesToSoraResult}; -use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager; -use artcraft_api_defs::generate::video::generate_kling_1_6_pro_image_to_video::{GenerateKling16ProAspectRatio, GenerateKling16ProImageToVideoRequest}; -use artcraft_api_defs::generate::video::multi_function::veo_3p1_multi_function_video_gen::{Veo3p1MultiFunctionVideoGenAspectRatio, Veo3p1MultiFunctionVideoGenDuration, Veo3p1MultiFunctionVideoGenRequest, Veo3p1MultiFunctionVideoGenResolution}; -use enums::common::generation_provider::GenerationProvider; -use enums::tauri::tasks::task_type::TaskType; -use uuid_utils::uuid::generate_random_uuid; -use log::{error, info}; -use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet; -use artcraft_client::endpoints::generate::video::multi_function::veo_3p1_multi_function_video_gen::veo_3p1_multi_function_video_gen; -use tauri::AppHandle; -use tokens::tokens::media_files::MediaFileToken; - -pub (super) async fn handle_artcraft_veo3p1( - request: &TauriGenerateVideoRequest, - app_env_configs: &AppEnvConfigs, - creds: &StorytellerCredentialSet, -) -> Result { - - let uuid_idempotency_token = generate_random_uuid(); - - let aspect_ratio = match request.sora_orientation { - Some(SoraOrientation::Portrait) => Veo3p1MultiFunctionVideoGenAspectRatio::NineBySixteen, - Some(SoraOrientation::Landscape) => Veo3p1MultiFunctionVideoGenAspectRatio::SixteenByNine, - None => Veo3p1MultiFunctionVideoGenAspectRatio::SixteenByNine, - }; - - let request = Veo3p1MultiFunctionVideoGenRequest { - uuid_idempotency_token, - prompt: request.prompt.clone(), - start_frame_image_media_token: request.image_media_token.clone(), - end_frame_image_media_token: request.end_frame_image_media_token.clone(), - aspect_ratio: Some(aspect_ratio), - generate_audio: request.generate_audio, - resolution: Some(Veo3p1MultiFunctionVideoGenResolution::TenEightyP), // TODO: Parameterize - duration: Some(Veo3p1MultiFunctionVideoGenDuration::EightSeconds), // TODO: Parameterize - negative_prompt: None, // TODO: Parameterize - enhance_prompt: None, // NB: Handled downstream. - auto_fix: None, // NB: Handled downstream. - seed: None, // NB: Handled downstream. - }; - - let result = veo_3p1_multi_function_video_gen( - &app_env_configs.storyteller_host, - Some(&creds), - request, - ).await; - - let job_token = match result { - Ok(enqueued) => { - info!("Successfully enqueued."); - enqueued.inference_job_token - } - Err(err) => { - error!("Failed to enqueue: {:?}", err); - return Err(GenerateError::from(err)); - } - }; - - Ok(TaskEnqueueSuccess { - task_type: TaskType::VideoGeneration, - model: Some(GenerationModel::Veo3p1), - provider: GenerationProvider::Artcraft, - provider_job_id: Some(job_token.to_string()), - maybe_queue_status_url: None, - maybe_prompt_token: None, - maybe_queue_response_url: None, - }) -} diff --git a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_veo3p1_fast.rs b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_veo3p1_fast.rs deleted file mode 100644 index 2bdeb1c906..0000000000 --- a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_veo3p1_fast.rs +++ /dev/null @@ -1,81 +0,0 @@ -use crate::core::commands::enqueue::generate_error::GenerateError; -use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error; -use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation}; -use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess; -use crate::core::events::basic_sendable_event_trait::BasicSendableEvent; -use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent; -use crate::core::events::generation_events::common::{GenerationAction, GenerationModel}; -use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent; -use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs; -use crate::core::state::data_dir::app_data_root::AppDataRoot; -use crate::services::sora::state::sora_credential_manager::SoraCredentialManager; -use crate::services::sora::state::sora_task_queue::SoraTaskQueue; -use crate::services::sora::utils::upload_images_to_sora::{upload_images_to_sora, UploadImagesToSoraArgs, UploadImagesToSoraResult}; -use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager; -use artcraft_api_defs::generate::video::multi_function::veo_3p1_fast_multi_function_video_gen::{Veo3p1FastMultiFunctionVideoGenAspectRatio, Veo3p1FastMultiFunctionVideoGenDuration, Veo3p1FastMultiFunctionVideoGenRequest, Veo3p1FastMultiFunctionVideoGenResolution}; -use enums::common::generation_provider::GenerationProvider; -use enums::tauri::tasks::task_type::TaskType; -use uuid_utils::uuid::generate_random_uuid; -use log::{error, info}; -use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet; -use artcraft_client::endpoints::generate::video::multi_function::veo_3p1_fast_multi_function_video_gen::veo_3p1_fast_multi_function_video_gen; -use artcraft_client::endpoints::generate::video::multi_function::veo_3p1_multi_function_video_gen::veo_3p1_multi_function_video_gen; -use tauri::AppHandle; -use tokens::tokens::media_files::MediaFileToken; - -pub (super) async fn handle_artcraft_veo3p1_fast( - request: &TauriGenerateVideoRequest, - app_env_configs: &AppEnvConfigs, - creds: &StorytellerCredentialSet, -) -> Result { - - let uuid_idempotency_token = generate_random_uuid(); - - let aspect_ratio = match request.sora_orientation { - Some(SoraOrientation::Portrait) => Veo3p1FastMultiFunctionVideoGenAspectRatio::NineBySixteen, - Some(SoraOrientation::Landscape) => Veo3p1FastMultiFunctionVideoGenAspectRatio::SixteenByNine, - None => Veo3p1FastMultiFunctionVideoGenAspectRatio::SixteenByNine, - }; - - let request = Veo3p1FastMultiFunctionVideoGenRequest { - uuid_idempotency_token, - prompt: request.prompt.clone(), - start_frame_image_media_token: request.image_media_token.clone(), - end_frame_image_media_token: request.end_frame_image_media_token.clone(), - aspect_ratio: Some(aspect_ratio), - generate_audio: request.generate_audio, - resolution: Some(Veo3p1FastMultiFunctionVideoGenResolution::TenEightyP), // TODO: Parameterize - duration: Some(Veo3p1FastMultiFunctionVideoGenDuration::EightSeconds), // TODO: Parameterize - negative_prompt: None, // TODO: Parameterize - enhance_prompt: None, // NB: Handled downstream. - auto_fix: None, // NB: Handled downstream. - seed: None, // NB: Handled downstream. - }; - - let result = veo_3p1_fast_multi_function_video_gen( - &app_env_configs.storyteller_host, - Some(&creds), - request, - ).await; - - let job_token = match result { - Ok(enqueued) => { - info!("Successfully enqueued."); - enqueued.inference_job_token - } - Err(err) => { - error!("Failed to enqueue: {:?}", err); - return Err(GenerateError::from(err)); - } - }; - - Ok(TaskEnqueueSuccess { - task_type: TaskType::VideoGeneration, - model: Some(GenerationModel::Veo3p1Fast), - provider: GenerationProvider::Artcraft, - provider_job_id: Some(job_token.to_string()), - maybe_queue_status_url: None, - maybe_prompt_token: None, - maybe_queue_response_url: None, - }) -} diff --git a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_video.rs b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_video.rs index f6688483c9..5bc8e45424 100644 --- a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_video.rs +++ b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_video.rs @@ -1,19 +1,6 @@ use crate::core::commands::enqueue::generate_error::GenerateError; use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess; use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error; -use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_kling_1p6_pro::handle_artcraft_kling_1p6_pro; -use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_kling_2p1_master::handle_artcraft_kling_2p1_master; -use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_kling_2p1_pro::handle_artcraft_kling_2p1_pro; -use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_kling_2p5_turbo_pro::handle_artcraft_kling_2p5_turbo_pro; -use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_kling_2p6_pro::handle_artcraft_kling_2p6_pro; -use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_seedance_1_lite::handle_artcraft_seedance_1_lite; -use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_sora2::handle_artcraft_sora2; -use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_sora2_pro::handle_artcraft_sora2_pro; -use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_veo2::handle_artcraft_veo2; -use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_veo3::handle_artcraft_veo3; -use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_veo3_fast::handle_artcraft_veo3_fast; -use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_veo3p1::handle_artcraft_veo3p1; -use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_veo3p1_fast::handle_artcraft_veo3p1_fast; use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_video_via_router::handle_artcraft_video_via_router; use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, TauriVideoModel}; use crate::core::events::generation_events::common::GenerationModel; @@ -32,34 +19,30 @@ pub async fn handle_video_artcraft( let creds = get_storyteller_creds_or_error(app, storyteller_creds_manager)?; - match request.model { - None => { - Err(GenerateError::no_model_specified()) - }, - // Handled via router - Some(TauriVideoModel::Kling3p0Pro) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonVideoModel::Kling3p0Pro, GenerationModel::Kling3p0Pro).await, - Some(TauriVideoModel::Kling3p0Standard) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonVideoModel::Kling3p0Standard, GenerationModel::Kling3p0Standard).await, - Some(TauriVideoModel::Seedance1p5Pro) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonVideoModel::Seedance1p5Pro, GenerationModel::Seedance1p5Pro).await, - Some(TauriVideoModel::Seedance2p0) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonVideoModel::Seedance2p0, GenerationModel::Seedance2p0).await, - Some(TauriVideoModel::Seedance2p0Fast) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonVideoModel::Seedance2p0Fast, GenerationModel::Seedance2p0Fast).await, - Some(TauriVideoModel::HappyHorse1p0) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonVideoModel::HappyHorse1p0, GenerationModel::HappyHorse1p0).await, - // Legacy endpoints - Some(TauriVideoModel::Kling16Pro) => handle_artcraft_kling_1p6_pro(request, app_env_configs, &creds).await, - Some(TauriVideoModel::Kling21Pro) => handle_artcraft_kling_2p1_pro(request, app_env_configs, &creds).await, - Some(TauriVideoModel::Kling21Master) => handle_artcraft_kling_2p1_master(request, app_env_configs, &creds).await, - Some(TauriVideoModel::Kling2p5TurboPro) => handle_artcraft_kling_2p5_turbo_pro(request, app_env_configs, &creds).await, - Some(TauriVideoModel::Kling2p6Pro) => handle_artcraft_kling_2p6_pro(request, app_env_configs, &creds).await, - Some(TauriVideoModel::Seedance10Lite) => handle_artcraft_seedance_1_lite(request, app_env_configs, &creds).await, - Some(TauriVideoModel::Sora2) => handle_artcraft_sora2(request, app_env_configs, &creds).await, - Some(TauriVideoModel::Sora2Pro) => handle_artcraft_sora2_pro(request, app_env_configs, &creds).await, - Some(TauriVideoModel::Veo2) => handle_artcraft_veo2(request, app_env_configs, &creds).await, - Some(TauriVideoModel::Veo3) => handle_artcraft_veo3(request, app_env_configs, &creds).await, - Some(TauriVideoModel::Veo3Fast) => handle_artcraft_veo3_fast(request, app_env_configs, &creds).await, - Some(TauriVideoModel::Veo3p1) => handle_artcraft_veo3p1(request, app_env_configs, &creds).await, - Some(TauriVideoModel::Veo3p1Fast) => handle_artcraft_veo3p1_fast(request, app_env_configs, &creds).await, - Some(_) => { - Err(GenerateError::AnyhowError( - anyhow!("wrong logic: another branch should handle this: {:?}", request.model))) - }, - } + let (router_model, generation_model) = match request.model { + None => return Err(GenerateError::no_model_specified()), + Some(TauriVideoModel::HappyHorse1p0) => (CommonVideoModel::HappyHorse1p0, GenerationModel::HappyHorse1p0), + Some(TauriVideoModel::Kling16Pro) => (CommonVideoModel::Kling16Pro, GenerationModel::Kling1_6), + Some(TauriVideoModel::Kling21Master) => (CommonVideoModel::Kling21Master, GenerationModel::Kling21Master), + Some(TauriVideoModel::Kling21Pro) => (CommonVideoModel::Kling21Pro, GenerationModel::Kling21Pro), + Some(TauriVideoModel::Kling2p5TurboPro) => (CommonVideoModel::Kling2p5TurboPro, GenerationModel::Kling2p5TurboPro), + Some(TauriVideoModel::Kling2p6Pro) => (CommonVideoModel::Kling2p6Pro, GenerationModel::Kling2p6Pro), + Some(TauriVideoModel::Kling3p0Pro) => (CommonVideoModel::Kling3p0Pro, GenerationModel::Kling3p0Pro), + Some(TauriVideoModel::Kling3p0Standard) => (CommonVideoModel::Kling3p0Standard, GenerationModel::Kling3p0Standard), + Some(TauriVideoModel::Seedance10Lite) => (CommonVideoModel::Seedance10Lite, GenerationModel::Seedance10Lite), + Some(TauriVideoModel::Seedance1p5Pro) => (CommonVideoModel::Seedance1p5Pro, GenerationModel::Seedance1p5Pro), + Some(TauriVideoModel::Seedance2p0) => (CommonVideoModel::Seedance2p0, GenerationModel::Seedance2p0), + Some(TauriVideoModel::Seedance2p0Fast) => (CommonVideoModel::Seedance2p0Fast, GenerationModel::Seedance2p0Fast), + Some(TauriVideoModel::Sora2) => (CommonVideoModel::Sora2, GenerationModel::Sora2), + Some(TauriVideoModel::Sora2Pro) => (CommonVideoModel::Sora2Pro, GenerationModel::Sora2Pro), + Some(TauriVideoModel::Veo2) => (CommonVideoModel::Veo2, GenerationModel::Veo2), + Some(TauriVideoModel::Veo3) => (CommonVideoModel::Veo3, GenerationModel::Veo3), + Some(TauriVideoModel::Veo3Fast) => (CommonVideoModel::Veo3Fast, GenerationModel::Veo3Fast), + Some(TauriVideoModel::Veo3p1) => (CommonVideoModel::Veo3p1, GenerationModel::Veo3p1), + Some(TauriVideoModel::Veo3p1Fast) => (CommonVideoModel::Veo3p1Fast, GenerationModel::Veo3p1Fast), + Some(other) => return Err(GenerateError::AnyhowError( + anyhow!("wrong logic: another branch should handle this: {:?}", other))), + }; + + handle_artcraft_video_via_router(request, app_env_configs, &creds, router_model, generation_model).await } diff --git a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_video_via_router.rs b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_video_via_router.rs index 1ddc01b0c7..d991ec0437 100644 --- a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_video_via_router.rs +++ b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/handle_artcraft_video_via_router.rs @@ -62,13 +62,8 @@ pub(super) async fn handle_artcraft_video_via_router( negative_prompt: None, }; - let response = if router_request.use_new_builder() { - info!("Building request for artcraft_router (v2 pipeline)..."); - generate_via_v2(router_request, &client).await? - } else { - info!("Building request for artcraft_router (v1 pipeline)..."); - generate_via_v1(router_request, &client).await? - }; + info!("Building request for artcraft_router (v2 pipeline)..."); + let response = generate_via_v2(router_request, &client).await?; let job_id = response.get_artcraft_payload() .map(|p| p.inference_job_token.to_string()) @@ -85,22 +80,6 @@ pub(super) async fn handle_artcraft_video_via_router( }) } -/// V1 pipeline: build → plan → generate_video. -async fn generate_via_v1( - router_request: GenerateVideoRequestBuilder, - client: &RouterClient, -) -> Result { - let plan = router_request.build()?; - - let response = plan.generate_video(client).await.map_err(|err| { - error!("V1 failed to enqueue: {:?}", err); - GenerateError::from(err) - })?; - - info!("V1 successfully enqueued."); - Ok(response) -} - /// V2 pipeline: build2 → send_request (Artcraft skips draft phase). async fn generate_via_v2( router_request: GenerateVideoRequestBuilder, diff --git a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/mod.rs b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/mod.rs index af73548dee..5dd8e99770 100644 --- a/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/mod.rs +++ b/crates/desktop/artcraft/src/core/commands/generate/generate_video/artcraft/mod.rs @@ -1,16 +1,3 @@ mod get_storyteller_creds_or_error; -mod handle_artcraft_kling_1p6_pro; -mod handle_artcraft_kling_2p1_master; -mod handle_artcraft_kling_2p1_pro; -mod handle_artcraft_kling_2p5_turbo_pro; -mod handle_artcraft_kling_2p6_pro; mod handle_artcraft_video_via_router; -mod handle_artcraft_seedance_1_lite; -mod handle_artcraft_sora2; -mod handle_artcraft_sora2_pro; -mod handle_artcraft_veo2; -mod handle_artcraft_veo3; -mod handle_artcraft_veo3_fast; -mod handle_artcraft_veo3p1; -mod handle_artcraft_veo3p1_fast; -pub (super) mod handle_artcraft_video; \ No newline at end of file +pub (super) mod handle_artcraft_video; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/generate/cost_estimate/video/estimate_video_cost_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/cost_estimate/video/estimate_video_cost_handler.rs index daba21216c..65e7c0763d 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/generate/cost_estimate/video/estimate_video_cost_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/cost_estimate/video/estimate_video_cost_handler.rs @@ -58,11 +58,11 @@ pub async fn estimate_video_cost_handler( idempotency_token: None, }; - let plan = router_request.build() + let estimate = router_request.build2() + .map_err(|e| HandlerError::InvalidInput(format!("{}", e)))? + .estimate_cost() .map_err(|e| HandlerError::InvalidInput(format!("{}", e)))?; - let estimate = plan.estimate_costs(); - Ok(Json(EstimateVideoCostResponse { success: true, cost_in_credits: estimate.cost_in_credits, diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/cost/video/omni_gen_video_cost_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/cost/video/omni_gen_video_cost_handler.rs index b3598c668f..3d83835012 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/cost/video/omni_gen_video_cost_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/cost/video/omni_gen_video_cost_handler.rs @@ -5,10 +5,7 @@ use actix_web::{web, HttpRequest}; use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; use artcraft_api_defs::omni_gen::cost_response::omni_gen_video_cost_response::OmniGenVideoCostResponse; use artcraft_router::api::provider::Provider; -use artcraft_router::errors::artcraft_router_error::ArtcraftRouterError; -use artcraft_router::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; use log::warn; -use artcraft_router::api::common_video_model::CommonVideoModel; use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::endpoints::omni_gen::generate::video::helpers::hydrate_router_request::hydrate_to_router_request; use crate::state::server_state::ServerState; @@ -34,35 +31,16 @@ pub async fn omni_gen_video_cost_handler( builder.provider = Provider::Artcraft; - let estimate = if builder.use_new_builder() { - builder.build2() - .map_err(|e| { - warn!("Failed to build2 cost estimate: {}", e); - CommonWebError::from_error(e) - })? - .estimate_cost() - .map_err(|e| { - warn!("Failed to estimate cost (v2): {}", e); - CommonWebError::from_error(e) - })? - } else { - let plan = match builder.build() { - Ok(plan) => plan, - Err(ArtcraftRouterError::UnsupportedModel(_)) => { - builder.provider = Provider::Fal; - builder.build() - .map_err(|e| { - warn!("Failed to build Fal cost plan: {}", e); - CommonWebError::from_error(e) - })? - } - Err(e) => { - warn!("Failed to build cost plan: {}", e); - return Err(CommonWebError::from_error(e)); - } - }; - plan.estimate_costs() - }; + let estimate = builder.build2() + .map_err(|e| { + warn!("Failed to build cost estimate: {}", e); + CommonWebError::from_error(e) + })? + .estimate_cost() + .map_err(|e| { + warn!("Failed to estimate cost: {}", e); + CommonWebError::from_error(e) + })?; Ok(Json(OmniGenVideoCostResponse { success: true, diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/mod.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/mod.rs index f4a3071ce1..4cd3b52436 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/mod.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/mod.rs @@ -1,5 +1,4 @@ pub mod omni_gen_video_generate_handler; pub mod helpers; -pub mod pipeline_v1; pub mod pipeline_v2; pub mod insert_db_job; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/omni_gen_video_generate_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/omni_gen_video_generate_handler.rs index d835848c5f..7df088e0b0 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/omni_gen_video_generate_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/omni_gen_video_generate_handler.rs @@ -37,7 +37,6 @@ use crate::http_server::endpoints::omni_gen::generate::video::insert_db_job::ins use crate::http_server::endpoints::omni_gen::generate::video::insert_db_job::insert_grok_api_job::{insert_grok_api_job, InsertGrokApiJobArgs}; use crate::http_server::endpoints::omni_gen::generate::video::insert_db_job::insert_seedance2pro_jobs::{insert_seedance2pro_jobs, InsertSeedance2proJobsArgs}; use crate::http_server::endpoints::omni_gen::generate::video::insert_db_job::shared_job_args::SharedJobArgs; -use crate::http_server::endpoints::omni_gen::generate::video::pipeline_v1::run_pipeline_v1::{run_pipeline_v1, RunPipelineV1Args}; use crate::http_server::endpoints::omni_gen::generate::video::pipeline_v2::run_pipeline_v2::{run_pipeline_v2, RunPipelineV2Args}; use crate::http_server::endpoints::omni_gen::generate::video::helpers::resolve_kinovi_character_ids::resolve_kinovi_character_ids; use crate::http_server::session::lookup::user_session_feature_flags::UserSessionFeatureFlags; @@ -184,20 +183,6 @@ pub async fn omni_gen_video_generate_handler( // ==================== PIPELINE DISPATCH ==================== // - let use_v2 = match request.model { - Some(CommonVideoModel::HappyHorse1p0) => true, - Some(CommonVideoModel::Seedance2p0) => true, - Some(CommonVideoModel::Seedance2p0Fast) => true, - Some(CommonVideoModel::Seedance2p0Ultra) => true, - Some(CommonVideoModel::Seedance2p0UltraFast) => true, - Some(CommonVideoModel::Seedance2p0BytePlus) => true, - Some(CommonVideoModel::Seedance2p0BytePlusFast) => true, - Some(CommonVideoModel::PreviewModel) => true, - Some(CommonVideoModel::PreviewModelFast) => true, - Some(CommonVideoModel::GrokImagineVideo) => true, - _ => false, - }; - let use_alternate_kinovi = match request.model { Some(CommonVideoModel::Seedance2p0BytePlus) => true, Some(CommonVideoModel::Seedance2p0BytePlusFast) => true, @@ -206,29 +191,15 @@ pub async fn omni_gen_video_generate_handler( _ => false, }; - let pipeline_result = if use_v2 { - info!("Using pipeline v2"); - run_pipeline_v2(RunPipelineV2Args { - router_builder: &router_builder, - server_state: &server_state, - mysql_connection: &mut mysql_connection, - user_token, - media_file_to_url_map: &media_file_to_url_map, - kinovi_character_id_map: &kinovi_character_id_map, - use_alternate_kinovi, - }).await? - } else { - info!("Using pipeline v1"); - run_pipeline_v1(RunPipelineV1Args { - request: &request, - router_builder: &router_builder, - server_state: &server_state, - mysql_connection: &mut mysql_connection, - user_token, - media_url_map: &media_file_hydration_map, - kinovi_character_id_map: &kinovi_character_id_map, - }).await? - }; + let pipeline_result = run_pipeline_v2(RunPipelineV2Args { + router_builder: &router_builder, + server_state: &server_state, + mysql_connection: &mut mysql_connection, + user_token, + media_file_to_url_map: &media_file_to_url_map, + kinovi_character_id_map: &kinovi_character_id_map, + use_alternate_kinovi, + }).await?; // ==================== DEBUG LOG: HTTP REQUEST ==================== // diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/distill_helper/mod.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/distill_helper/mod.rs deleted file mode 100644 index ca33f3690d..0000000000 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/distill_helper/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub(crate) mod request_to_costs; -pub(crate) mod request_to_plan; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/distill_helper/request_to_costs.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/distill_helper/request_to_costs.rs deleted file mode 100644 index 848a33e3c0..0000000000 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/distill_helper/request_to_costs.rs +++ /dev/null @@ -1,26 +0,0 @@ -use artcraft_router::api::provider::Provider; -use artcraft_router::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use artcraft_router::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate; -use log::warn; - -use crate::http_server::common_responses::common_web_error::CommonWebError; - -/// Estimate costs for a video generation request. -/// Always uses the Artcraft provider for costing regardless of the execution provider. -/// (Because we're the ones doing the billing.) -pub fn request_to_costs( - request: &GenerateVideoRequestBuilder, -) -> Result { - let cost_request = GenerateVideoRequestBuilder { - provider: Provider::Artcraft, - ..(*request).clone() - }; - - let plan = cost_request.build() - .map_err(|e| { - warn!("Failed to build cost plan: {}", e); - CommonWebError::from_error(e) - })?; - - Ok(plan.estimate_costs()) -} diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/distill_helper/request_to_plan.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/distill_helper/request_to_plan.rs deleted file mode 100644 index cc042b8642..0000000000 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/distill_helper/request_to_plan.rs +++ /dev/null @@ -1,20 +0,0 @@ -use artcraft_router::api::provider::Provider; -use artcraft_router::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use artcraft_router::generate::generate_video::video_generation_plan::VideoGenerationPlan; -use log::warn; - -use crate::http_server::common_responses::common_web_error::CommonWebError; - -/// Build a video generation plan from a transformed request. -/// Overrides the provider to Fal for execution (costing uses Artcraft separately). -pub fn request_to_plan( - request: &mut GenerateVideoRequestBuilder, -) -> Result { - request.provider = Provider::Fal; - - request.build() - .map_err(|e| { - warn!("Failed to build video generation plan: {}", e); - CommonWebError::from_error(e) - }) -} diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/execute/execute_fal.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/execute/execute_fal.rs deleted file mode 100644 index 08169ba956..0000000000 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/execute/execute_fal.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! Fal provider execution path. - -use log::warn; - -use artcraft_router::api::provider::Provider; -use artcraft_router::generate::generate_video::generate_video_response::GenerateVideoResponse; -use artcraft_router::generate::generate_video::video_generation_plan::VideoGenerationPlan; - -use crate::http_server::common_responses::common_web_error::CommonWebError; -use crate::http_server::endpoints::omni_gen::generate::video::helpers::build_router_client::build_router_client; -use crate::state::server_state::ServerState; - -/// Execute generation via Fal (the existing path). -pub(crate) async fn execute_generation_fal( - plan: &VideoGenerationPlan, - server_state: &ServerState, -) -> Result { - const USE_ALTERNATE_KINOVI: bool = false; - - let router_client = build_router_client(Provider::Fal, server_state, USE_ALTERNATE_KINOVI)?; - - let response = plan.generate_video(&router_client) - .await - .map_err(|e| { - warn!("Video generation failed (Fal): {:?}", e); - CommonWebError::from_error(e) - })?; - - Ok(response) -} diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/execute/execute_kinovi.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/execute/execute_kinovi.rs deleted file mode 100644 index 65a94d7aec..0000000000 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/execute/execute_kinovi.rs +++ /dev/null @@ -1,285 +0,0 @@ -//! Seedance2Pro / Kinovi provider execution path. -//! -//! Downloads all referenced media from our CDN, re-uploads to Seedance2Pro's -//! CDN, then calls the Seedance2Pro generate endpoint. - -use std::collections::HashMap; - -use log::{error, info, warn}; -use url::Url; - -use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; -use artcraft_router::generate::generate_video::generate_video_response::{GenerateVideoResponse, Seedance2proVideoResponsePayload}; -use enums::common::generation::common_aspect_ratio::CommonAspectRatio; -use enums::common::generation::common_resolution::CommonResolution; -use enums::common::generation::common_video_model::CommonVideoModel; - -use seedance2pro_client::creds::seedance2pro_session::Seedance2ProSession; -use seedance2pro_client::requests::generate_video::generate_video::{generate_video, GenerateVideoArgs, KinoviGenerateVideoRequest, KinoviBatchCount, KinoviModelType, KinoviAspectRatio, KinoviOutputResolution}; -use seedance2pro_client::requests::prepare_file_upload::prepare_file_upload::{ - prepare_file_upload, PrepareFileUploadArgs, -}; -use seedance2pro_client::requests::upload_file::upload_file::{upload_file, UploadFileArgs}; -use tokens::tokens::media_files::MediaFileToken; -use tokens::tokens::wallet_ledger_entries::WalletLedgerEntryToken; -use url_utils::extension::extract_extension_from_url::{ - extract_extension_from_url, ExtractExtensions, -}; - -use crate::http_server::common_responses::common_web_error::CommonWebError; -use crate::http_server::endpoint_helpers::refund_wallet_after_api_failure::refund_wallet_after_api_failure; -use crate::state::server_state::ServerState; -use crate::util::http_download_url_to_bytes::http_download_url_to_bytes; - -pub(crate) async fn execute_generation_kinovi( - request: &OmniGenVideoCostAndGenerateRequest, - server_state: &ServerState, - media_file_hydration_map: Option<&HashMap>, - kinovi_character_ids: Option>, - maybe_wallet_ledger_entry_token: Option<&WalletLedgerEntryToken>, - mysql_connection: &mut sqlx::pool::PoolConnection, -) -> Result { - let result = execute_generation_kinovi_inner( - request, - server_state, - media_file_hydration_map, - kinovi_character_ids, - ).await; - - if let Err(ref err) = result { - if let Some(ledger_entry_token) = maybe_wallet_ledger_entry_token { - warn!("Kinovi generation failed, issuing refund for ledger entry {}: {:?}", ledger_entry_token.as_str(), err); - if let Err(refund_err) = refund_wallet_after_api_failure(ledger_entry_token, mysql_connection).await { - error!("Failed to refund wallet after Kinovi failure: {:?}", refund_err); - } - } - } - - result -} - -async fn execute_generation_kinovi_inner( - request: &OmniGenVideoCostAndGenerateRequest, - server_state: &ServerState, - media_file_hydration_map: Option<&HashMap>, - kinovi_character_ids: Option>, -) -> Result { - let session = Seedance2ProSession::from_cookies_string( - server_state.seedance2pro.cookies.clone() - ); - - // TODO(bt): Move this logic to `artcraft_router` as an intermediate step between plan and execute. - - let empty_map = HashMap::new(); - let hydration_map = media_file_hydration_map.unwrap_or(&empty_map); - - // Upload each media reference to Seedance2Pro CDN. - let start_frame_url = upload_token_to_seedance2pro( - &session, hydration_map, request.start_frame_image_media_token.as_ref(), - ).await?; - - let end_frame_url = upload_token_to_seedance2pro( - &session, hydration_map, request.end_frame_image_media_token.as_ref(), - ).await?; - - let reference_image_urls = upload_tokens_to_seedance2pro( - &session, hydration_map, request.reference_image_media_tokens.as_deref(), - ).await?; - - let reference_video_urls = upload_tokens_to_seedance2pro( - &session, hydration_map, request.reference_video_media_tokens.as_deref(), - ).await?; - - let reference_audio_urls = upload_tokens_to_seedance2pro( - &session, hydration_map, request.reference_audio_media_tokens.as_deref(), - ).await?; - - // Map aspect ratio / duration / batch from the request. - let aspect_ratio = map_common_aspect_ratio_to_kinovi_resolution(request.aspect_ratio); - - let duration_seconds = request.duration_seconds.unwrap_or(5).clamp(4, 15) as u8; - - let batch_count = match request.video_batch_count { - Some(2) => KinoviBatchCount::Two, - Some(4) => KinoviBatchCount::Four, - _ => KinoviBatchCount::One, - }; - - let prompt = request.prompt.clone().unwrap_or_default(); - - let model_type = match request.model { - Some(CommonVideoModel::Seedance2p0Fast) => KinoviModelType::Seedance2Fast, - _ => KinoviModelType::Seedance2Pro, - }; - - let output_resolution = match model_type { - KinoviModelType::Seedance2Pro => request.resolution.map(|res| map_common_resolution_to_kinovi_pro(res)), - KinoviModelType::Seedance2Fast => request.resolution.map(|res| map_common_resolution_to_kinovi_fast(res)), - }; - - let request = KinoviGenerateVideoRequest { - model_type, - prompt, - aspect_ratio, - duration_seconds, - batch_count, - start_frame_url, - end_frame_url, - reference_image_urls, - reference_video_urls, - reference_audio_urls, - character_ids: kinovi_character_ids, - use_face_blur_hack: None, - output_resolution, - }; - - info!("\n\nKinovi Request: {:?}\n\n", request); - - let video_gen_args = GenerateVideoArgs { - session: &session, - host_override: None, - request, - }; - - let gen_response = generate_video(video_gen_args).await - .map_err(|err| { - warn!("Seedance2Pro generate_video failed: {:?}", err); - CommonWebError::from_error(err) - })?; - - info!( - "Seedance2Pro generation: task_id={}, order_id={}", - gen_response.task_id, gen_response.order_id - ); - - Ok(GenerateVideoResponse::Seedance2Pro(Seedance2proVideoResponsePayload { - order_id: gen_response.order_id, - task_id: gen_response.task_id, - maybe_order_ids: gen_response.order_ids, - maybe_task_ids: gen_response.task_ids, - })) -} - -// --- Upload helpers --- - -/// Upload a single media token (if present) to Seedance2Pro CDN. -async fn upload_token_to_seedance2pro( - session: &Seedance2ProSession, - hydration_map: &HashMap, - maybe_token: Option<&MediaFileToken>, -) -> Result, CommonWebError> { - let token = match maybe_token { - None => return Ok(None), - Some(t) => t, - }; - - let url = hydration_map.get(token).ok_or_else(|| { - CommonWebError::BadInputWithSimpleMessage( - format!("Media token not found in hydration map: {:?}", token)) - })?; - - let uploaded = upload_url_to_seedance2pro(session, url).await?; - Ok(Some(uploaded)) -} - -/// Upload a list of media tokens (if present) to Seedance2Pro CDN. -async fn upload_tokens_to_seedance2pro( - session: &Seedance2ProSession, - hydration_map: &HashMap, - maybe_tokens: Option<&[MediaFileToken]>, -) -> Result>, CommonWebError> { - let tokens = match maybe_tokens { - None => return Ok(None), - Some(tokens) if tokens.is_empty() => return Ok(None), - Some(tokens) => tokens, - }; - - let mut urls = Vec::with_capacity(tokens.len()); - for token in tokens { - let url = hydration_map.get(token).ok_or_else(|| { - CommonWebError::BadInputWithSimpleMessage( - format!("Media token not found in hydration map: {:?}", token)) - })?; - urls.push(upload_url_to_seedance2pro(session, url).await?); - } - Ok(Some(urls)) -} - -/// Download from our CDN and re-upload to Seedance2Pro. -async fn upload_url_to_seedance2pro( - session: &Seedance2ProSession, - our_cdn_url: &Url, -) -> Result { - let extension = extract_extension_from_url(our_cdn_url, &ExtractExtensions::All) - .map(|ext| ext.without_period().to_string()) - .unwrap_or_else(|| "png".to_string()); - - let file_bytes = http_download_url_to_bytes(our_cdn_url.as_str()) - .await - .map_err(|err| { - warn!("Error downloading media from CDN for Seedance2Pro upload: {:?}", err); - CommonWebError::from_error(err) - })? - .to_vec(); - - let prepare_result = prepare_file_upload(PrepareFileUploadArgs { - session, - extension, - host_override: None, - }) - .await - .map_err(|err| { - warn!("Error preparing seedance2pro file upload: {:?}", err); - CommonWebError::from_error(err) - })?; - - let upload_result = upload_file(UploadFileArgs { - upload_url: prepare_result.upload_url, - file_bytes, - host_override: None, - }) - .await - .map_err(|err| { - warn!("Error uploading file to seedance2pro: {:?}", err); - CommonWebError::from_error(err) - })?; - - Ok(upload_result.public_url) -} - -/// Map a CommonAspectRatio to the Seedance2Pro KinoviAspectRatio enum. -fn map_common_aspect_ratio_to_kinovi_resolution(aspect_ratio: Option) -> KinoviAspectRatio { - match aspect_ratio { - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => KinoviAspectRatio::Landscape16x9, - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => KinoviAspectRatio::Portrait9x16, - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => KinoviAspectRatio::Square1x1, - Some(CommonAspectRatio::WideFourByThree) => KinoviAspectRatio::Standard4x3, - Some(CommonAspectRatio::TallThreeByFour) => KinoviAspectRatio::Portrait3x4, - // For unsupported aspect ratios, pick the nearest match. - Some(CommonAspectRatio::WideFiveByFour) | Some(CommonAspectRatio::WideThreeByTwo) => KinoviAspectRatio::Standard4x3, - Some(CommonAspectRatio::WideTwentyOneByNine) => KinoviAspectRatio::Landscape16x9, - Some(CommonAspectRatio::TallFourByFive) | Some(CommonAspectRatio::TallTwoByThree) => KinoviAspectRatio::Portrait3x4, - Some(CommonAspectRatio::TallNineByTwentyOne) => KinoviAspectRatio::Portrait9x16, - // Auto or None — default to landscape. - _ => KinoviAspectRatio::Landscape16x9, - } -} - -// TODO TEMP HACK -fn map_common_resolution_to_kinovi_pro(resolution: CommonResolution) -> KinoviOutputResolution { - match resolution { - CommonResolution::FourEightyP => KinoviOutputResolution::FourEightyP, - CommonResolution::SevenTwentyP => KinoviOutputResolution::SevenTwentyP, - CommonResolution::TenEightyP => KinoviOutputResolution::TenEightyP, - _ => KinoviOutputResolution::SevenTwentyP, - } -} - -// TODO TEMP HACK -fn map_common_resolution_to_kinovi_fast(resolution: CommonResolution) -> KinoviOutputResolution { - match resolution { - CommonResolution::FourEightyP => KinoviOutputResolution::FourEightyP, - CommonResolution::SevenTwentyP => KinoviOutputResolution::SevenTwentyP, - _ => KinoviOutputResolution::SevenTwentyP, - } -} diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/execute/mod.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/execute/mod.rs deleted file mode 100644 index 1fdf742e56..0000000000 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/execute/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub(crate) mod execute_fal; -pub(crate) mod execute_kinovi; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/mod.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/mod.rs deleted file mode 100644 index 297e127e98..0000000000 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod execute; -pub mod run_pipeline_v1; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/run_pipeline_v1.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/run_pipeline_v1.rs deleted file mode 100644 index 3b885d9c01..0000000000 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v1/run_pipeline_v1.rs +++ /dev/null @@ -1,129 +0,0 @@ -use std::collections::HashMap; - -use log::{info, warn}; -use url::Url; - -use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; -use artcraft_router::api::audio_list_ref::AudioListRef; -use artcraft_router::api::image_list_ref::ImageListRef; -use artcraft_router::api::image_ref::ImageRef; -use artcraft_router::api::provider::Provider; -use artcraft_router::api::video_list_ref::VideoListRef; -use artcraft_router::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder; -use enums::common::generation::common_video_model::CommonVideoModel; -use tokens::tokens::characters::CharacterToken; -use tokens::tokens::media_files::MediaFileToken; -use tokens::tokens::users::UserToken; - -use crate::http_server::common_responses::common_web_error::CommonWebError; -use crate::http_server::endpoints::omni_gen::generate::video::helpers::bill_wallet::bill_wallet; -use crate::http_server::endpoints::omni_gen::generate::video::helpers::pipeline_result::PipelineResult; -use crate::http_server::endpoints::omni_gen::generate::video::pipeline_v1::execute::execute_fal::execute_generation_fal; -use crate::http_server::endpoints::omni_gen::generate::video::pipeline_v1::execute::execute_kinovi::execute_generation_kinovi; -use crate::state::server_state::ServerState; - -// ── Pipeline args ── - -pub struct RunPipelineV1Args<'a> { - pub request: &'a OmniGenVideoCostAndGenerateRequest, - pub router_builder: &'a GenerateVideoRequestBuilder, - pub server_state: &'a ServerState, - pub mysql_connection: &'a mut sqlx::pool::PoolConnection, - pub user_token: &'a UserToken, - pub media_url_map: &'a Option>, - pub kinovi_character_id_map: &'a Option>, -} - -// ── Pipeline entrypoint ── - -pub async fn run_pipeline_v1(args: RunPipelineV1Args<'_>) -> Result { - let RunPipelineV1Args { - request, - router_builder, - server_state, - mysql_connection, - user_token, - media_url_map, - kinovi_character_id_map, - } = args; - - // v1 execute_generation expects a flat Vec of kinovi IDs - let kinovi_character_ids: Option> = kinovi_character_id_map - .as_ref() - .map(|map| map.values().cloned().collect()); - - let execution_provider = match request.model { - Some(CommonVideoModel::Seedance2p0) => Provider::Seedance2Pro, - Some(CommonVideoModel::Seedance2p0Fast) => Provider::Seedance2Pro, - _ => Provider::Fal, - }; - - // ── Cost estimate (Artcraft provider — what we bill on) ── - - let cost = { - let cost_request = GenerateVideoRequestBuilder { - provider: Provider::Artcraft, - ..router_builder.clone() - }; - let cost_plan = cost_request.build().map_err(|e| { - warn!("Failed to build cost plan during video distillation: {}", e); - CommonWebError::from_error(e) - })?; - cost_plan.estimate_costs() - }; - - // ── Build the execution request (clone builder, override provider + media URLs) ── - - let empty_map = HashMap::new(); - let url_map = media_url_map.as_ref().unwrap_or(&empty_map); - - let mut exec_request = router_builder.clone(); - exec_request.provider = execution_provider; - - exec_request.start_frame = lookup_url(url_map, request.start_frame_image_media_token.as_ref()).map(ImageRef::Url); - exec_request.end_frame = lookup_url(url_map, request.end_frame_image_media_token.as_ref()).map(ImageRef::Url); - exec_request.reference_images = lookup_urls(url_map, request.reference_image_media_tokens.as_ref()).map(ImageListRef::Urls); - exec_request.reference_videos = lookup_urls(url_map, request.reference_video_media_tokens.as_ref()).map(VideoListRef::Urls); - exec_request.reference_audio = lookup_urls(url_map, request.reference_audio_media_tokens.as_ref()).map(AudioListRef::Urls); - - let plan = exec_request.build().map_err(|e| { - warn!("Failed to build video generation plan during distillation: {}", e); - CommonWebError::from_error(e) - })?; - - info!("v1 distilled plan: {:?}", plan); - - // ── Bill wallet ── - - let cost_in_credits = cost.cost_in_credits.unwrap_or(0); - let billing = bill_wallet(user_token, cost_in_credits, mysql_connection).await?; - - // ── Execute generation via the appropriate provider ── - - let response = match execution_provider { - Provider::Seedance2Pro => { - execute_generation_kinovi( - request, server_state, - media_url_map.as_ref(), kinovi_character_ids, - billing.maybe_wallet_ledger_entry_token.as_ref(), mysql_connection, - ).await? - } - _ => { - execute_generation_fal(&plan, server_state).await? - } - }; - - Ok(PipelineResult { billing, response }) -} - -// ── Helpers ── - -fn lookup_url(map: &HashMap, token: Option<&MediaFileToken>) -> Option { - token.and_then(|t| map.get(t)).map(|u| u.to_string()) -} - -fn lookup_urls(map: &HashMap, tokens: Option<&Vec>) -> Option> { - tokens - .filter(|v| !v.is_empty()) - .map(|tokens| tokens.iter().filter_map(|t| map.get(t).map(|u| u.to_string())).collect()) -} diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v2/run_pipeline_v2.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v2/run_pipeline_v2.rs index 84753967bc..e01c8e964a 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v2/run_pipeline_v2.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/pipeline_v2/run_pipeline_v2.rs @@ -69,9 +69,9 @@ pub async fn run_pipeline_v2(args: RunPipelineV2Args<'_>) -> Result