diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/build_common.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/build_common.rs new file mode 100644 index 0000000000..0bc2289065 --- /dev/null +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/build_common.rs @@ -0,0 +1,257 @@ +use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; +use enums::common::generation::common_aspect_ratio::CommonAspectRatio as CommonAspectRatioEnum; +use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; +use enums::common::generation::common_video_model::CommonVideoModel as CommonVideoModelEnum; + +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_v2::providers::artcraft::resolve::{ + resolve_audio_list_ref, resolve_character_list_ref, resolve_image_list_ref, + resolve_image_ref, resolve_video_list_ref, +}; + +/// Which output resolutions a model supports. +#[derive(Copy, Clone)] +pub enum SupportedResolutions { + /// 480p, 720p, 1080p + Full, + /// 480p, 720p only (1080p downgrades to 720p) + Fast, + /// 720p, 1080p only (480p upgrades) + NoFourEightyP, +} + +/// Which aspect ratios a model supports for the 21:9 ultra-wide slot. +#[derive(Copy, Clone)] +pub enum UltraWideSupport { + /// 21:9 maps directly to WideTwentyOneByNine + Supported, + /// 21:9 is not a direct option; falls through to nearest_aspect_ratio + Unsupported, +} + +/// Build an `OmniGenVideoCostAndGenerateRequest` from the builder, using +/// model-specific configuration for the model enum variant, resolution +/// strategy, and ultra-wide aspect ratio support. +pub fn build_artcraft_omni_request( + mut builder: GenerateVideoRequestBuilder, + model: CommonVideoModelEnum, + resolutions: SupportedResolutions, + ultra_wide: UltraWideSupport, +) -> Result { + let strategy = builder.request_mismatch_mitigation_strategy; + + let aspect_ratio = plan_aspect_ratio(builder.aspect_ratio.take(), strategy, ultra_wide)?; + let resolution = plan_output_resolution(builder.resolution.take(), strategy, resolutions)?; + let batch_count = plan_batch_count(builder.video_batch_count.take(), strategy)?; + let duration_seconds = plan_duration(builder.duration_seconds.take(), strategy)?; + let prompt = builder.prompt.take(); + + let start_frame = resolve_image_ref(builder.start_frame.take())?; + let end_frame = resolve_image_ref(builder.end_frame.take())?; + let reference_images = resolve_image_list_ref(builder.reference_images.take())?; + let reference_videos = resolve_video_list_ref(builder.reference_videos.take())?; + let reference_audio = resolve_audio_list_ref(builder.reference_audio.take())?; + let reference_characters = resolve_character_list_ref(builder.reference_character_tokens.take()); + let idempotency_token = builder.get_or_generate_idempotency_token(); + + Ok(OmniGenVideoCostAndGenerateRequest { + model: Some(model), + idempotency_token: Some(idempotency_token), + prompt, + start_frame_image_media_token: start_frame, + end_frame_image_media_token: end_frame, + reference_image_media_tokens: reference_images, + reference_video_media_tokens: reference_videos, + reference_audio_media_tokens: reference_audio, + reference_character_tokens: reference_characters, + resolution, + aspect_ratio, + duration_seconds: duration_seconds.map(|d| d as u16), + video_batch_count: Some(batch_count), + negative_prompt: None, + generate_audio: None, + quality: None, + }) +} + +// ── Plan helpers ── + +fn plan_aspect_ratio( + aspect_ratio: Option, + strategy: RequestMismatchMitigationStrategy, + ultra_wide: UltraWideSupport, +) -> 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(CommonAspectRatioEnum::WideSixteenByNine)) + } + Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { + Ok(Some(CommonAspectRatioEnum::TallNineBySixteen)) + } + Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => { + Ok(Some(CommonAspectRatioEnum::Square)) + } + Some(CommonAspectRatio::WideFourByThree) => Ok(Some(CommonAspectRatioEnum::WideFourByThree)), + Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(CommonAspectRatioEnum::TallThreeByFour)), + + Some(CommonAspectRatio::WideTwentyOneByNine) => match ultra_wide { + UltraWideSupport::Supported => Ok(Some(CommonAspectRatioEnum::WideTwentyOneByNine)), + UltraWideSupport::Unsupported => match strategy { + RequestMismatchMitigationStrategy::ErrorOut => { + Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { + field: "aspect_ratio", + value: format!("{:?}", CommonAspectRatio::WideTwentyOneByNine), + })) + } + _ => Ok(Some(nearest_aspect_ratio(CommonAspectRatio::WideTwentyOneByNine))), + }, + }, + + 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) -> CommonAspectRatioEnum { + match aspect_ratio { + CommonAspectRatio::WideFiveByFour => CommonAspectRatioEnum::WideFourByThree, + CommonAspectRatio::WideThreeByTwo => CommonAspectRatioEnum::WideFourByThree, + CommonAspectRatio::WideTwentyOneByNine => CommonAspectRatioEnum::WideSixteenByNine, + CommonAspectRatio::TallFourByFive => CommonAspectRatioEnum::TallThreeByFour, + CommonAspectRatio::TallTwoByThree => CommonAspectRatioEnum::TallThreeByFour, + CommonAspectRatio::TallNineByTwentyOne => CommonAspectRatioEnum::TallNineBySixteen, + _ => CommonAspectRatioEnum::Square, + } +} + +fn plan_output_resolution( + resolution: Option, + strategy: RequestMismatchMitigationStrategy, + supported: SupportedResolutions, +) -> Result, ArtcraftRouterError> { + match resolution { + None => Ok(None), + + Some(CommonResolution::FourEightyP) => match supported { + SupportedResolutions::Full | SupportedResolutions::Fast => { + Ok(Some(CommonResolutionEnum::FourEightyP)) + } + SupportedResolutions::NoFourEightyP => match strategy { + RequestMismatchMitigationStrategy::ErrorOut => { + Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { + field: "resolution", + value: format!("{:?}", CommonResolution::FourEightyP), + })) + } + RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(CommonResolutionEnum::TenEightyP)), + RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(CommonResolutionEnum::SevenTwentyP)), + }, + }, + + Some(CommonResolution::SevenTwentyP) => Ok(Some(CommonResolutionEnum::SevenTwentyP)), + + Some(CommonResolution::TenEightyP) => match supported { + SupportedResolutions::Full | SupportedResolutions::NoFourEightyP => { + Ok(Some(CommonResolutionEnum::TenEightyP)) + } + SupportedResolutions::Fast => match strategy { + RequestMismatchMitigationStrategy::ErrorOut => { + Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { + field: "resolution", + value: format!("{:?}", CommonResolution::TenEightyP), + })) + } + _ => Ok(Some(CommonResolutionEnum::SevenTwentyP)), + }, + }, + + Some(unsupported) => match strategy { + RequestMismatchMitigationStrategy::ErrorOut => { + Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { + field: "resolution", + value: format!("{:?}", unsupported), + })) + } + RequestMismatchMitigationStrategy::PayMoreUpgrade => { + Ok(Some(match (unsupported, supported) { + (CommonResolution::HalfK, _) => CommonResolutionEnum::FourEightyP, + (_, SupportedResolutions::Fast) => CommonResolutionEnum::SevenTwentyP, + _ => CommonResolutionEnum::TenEightyP, + })) + } + RequestMismatchMitigationStrategy::PayLessDowngrade => { + Ok(Some(match (unsupported, supported) { + (CommonResolution::HalfK, _) => CommonResolutionEnum::FourEightyP, + (_, SupportedResolutions::Fast) => CommonResolutionEnum::SevenTwentyP, + _ => CommonResolutionEnum::TenEightyP, + })) + } + }, + } +} + +/// Batch counts: 1, 2, 4. +pub 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 | 2 | 4 => Ok(count), + _ => match strategy { + RequestMismatchMitigationStrategy::ErrorOut => { + Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { + field: "video_batch_count", + value: format!("{}", count), + })) + } + RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(4), + RequestMismatchMitigationStrategy::PayLessDowngrade => { + Ok(if count < 4 { 2 } else { 4 }) + } + }, + } +} + +/// Duration: 4-15 seconds. +pub 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)), + }, + } +} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/happy_horse_1p0/build.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/happy_horse_1p0/build.rs index 05df88d994..4dec7ed7ad 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/happy_horse_1p0/build.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/happy_horse_1p0/build.rs @@ -1,185 +1,25 @@ -use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; -use enums::common::generation::common_aspect_ratio::CommonAspectRatio as CommonAspectRatioEnum; -use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; use enums::common::generation::common_video_model::CommonVideoModel as CommonVideoModelEnum; -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_v2::providers::artcraft::resolve::{ - resolve_audio_list_ref, resolve_character_list_ref, resolve_image_list_ref, - resolve_image_ref, resolve_video_list_ref, +use crate::generate::generate_video_v2::providers::artcraft::build_common::{ + build_artcraft_omni_request, SupportedResolutions, UltraWideSupport, }; use crate::generate::generate_video_v2::providers::artcraft::happy_horse_1p0::request::ArtcraftHappyHorse1p0RequestState; 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_happy_horse_1p0(mut builder: GenerateVideoRequestBuilder) -> Result { - let strategy = builder.request_mismatch_mitigation_strategy; - - let aspect_ratio = plan_aspect_ratio(builder.aspect_ratio.take(), strategy)?; - let resolution = plan_output_resolution(builder.resolution.take(), strategy)?; - let batch_count = plan_batch_count(builder.video_batch_count.take(), strategy)?; - let duration_seconds = plan_duration(builder.duration_seconds.take(), strategy)?; - let prompt = builder.prompt.take(); - - let start_frame = resolve_image_ref(builder.start_frame.take())?; - let end_frame = resolve_image_ref(builder.end_frame.take())?; - let reference_images = resolve_image_list_ref(builder.reference_images.take())?; - let reference_videos = resolve_video_list_ref(builder.reference_videos.take())?; - let reference_audio = resolve_audio_list_ref(builder.reference_audio.take())?; - let reference_characters = resolve_character_list_ref(builder.reference_character_tokens.take()); - let idempotency_token = builder.get_or_generate_idempotency_token(); - - let request = OmniGenVideoCostAndGenerateRequest { - model: Some(CommonVideoModelEnum::HappyHorse1p0), - idempotency_token: Some(idempotency_token), - prompt, - start_frame_image_media_token: start_frame, - end_frame_image_media_token: end_frame, - reference_image_media_tokens: reference_images, - reference_video_media_tokens: reference_videos, - reference_audio_media_tokens: reference_audio, - reference_character_tokens: reference_characters, - resolution, - aspect_ratio, - duration_seconds: duration_seconds.map(|d| d as u16), - video_batch_count: Some(batch_count), - negative_prompt: None, - generate_audio: None, - quality: None, - }; - +pub fn build_artcraft_happy_horse_1p0(builder: GenerateVideoRequestBuilder) -> Result { + let request = build_artcraft_omni_request( + builder, + CommonVideoModelEnum::HappyHorse1p0, + SupportedResolutions::NoFourEightyP, + UltraWideSupport::Unsupported, + )?; let state = ArtcraftHappyHorse1p0RequestState { request }; Ok(VideoGenerationDraftOrRequest::Request(VideoGenerationRequest::ArtcraftHappyHorse1p0(state))) } -// ── Plan helpers ── - -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(CommonAspectRatioEnum::WideSixteenByNine)) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(Some(CommonAspectRatioEnum::TallNineBySixteen)) - } - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => { - Ok(Some(CommonAspectRatioEnum::Square)) - } - Some(CommonAspectRatio::WideFourByThree) => Ok(Some(CommonAspectRatioEnum::WideFourByThree)), - Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(CommonAspectRatioEnum::TallThreeByFour)), - - 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) -> CommonAspectRatioEnum { - match aspect_ratio { - CommonAspectRatio::WideFiveByFour => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::WideThreeByTwo => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::WideTwentyOneByNine => CommonAspectRatioEnum::WideSixteenByNine, - CommonAspectRatio::TallFourByFive => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallTwoByThree => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallNineByTwentyOne => CommonAspectRatioEnum::TallNineBySixteen, - _ => CommonAspectRatioEnum::Square, - } -} - -// Happy Horse supports 720p and 1080p only (no 480p). -fn plan_output_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - match resolution { - None => Ok(None), - - Some(CommonResolution::SevenTwentyP) => Ok(Some(CommonResolutionEnum::SevenTwentyP)), - Some(CommonResolution::TenEightyP) => Ok(Some(CommonResolutionEnum::TenEightyP)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => { - Ok(Some(CommonResolutionEnum::TenEightyP)) - } - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(Some(CommonResolutionEnum::SevenTwentyP)) - } - }, - } -} - -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 | 2 | 4 => Ok(count), - _ => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "video_batch_count", - value: format!("{}", count), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(4), - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(if count < 4 { 2 } else { 4 }) - } - }, - } -} - -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)), - }, - } -} - #[cfg(test)] mod tests { use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/happy_horse_1p0/request.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/happy_horse_1p0/request.rs index 8f0bb50f82..36ca4ed99b 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/happy_horse_1p0/request.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/happy_horse_1p0/request.rs @@ -1,12 +1,9 @@ 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 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::generate_video_response::GenerateVideoResponse; +use crate::generate::generate_video_v2::providers::artcraft::request_common::send_artcraft_omni_request; #[derive(Clone, Debug)] pub struct ArtcraftHappyHorse1p0RequestState { @@ -15,18 +12,7 @@ pub struct ArtcraftHappyHorse1p0RequestState { impl ArtcraftHappyHorse1p0RequestState { pub async fn send(&self, client: &RouterArtcraftClient) -> Result { - let response = omni_gen_video_generate( - &client.api_host, - Some(&client.credentials), - self.request.clone(), - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token.clone(), - all_inference_job_tokens: vec![response.inference_job_token], - })) + send_artcraft_omni_request(&self.request, client).await } } 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 0a89c7be29..2f031cee71 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 @@ -1,6 +1,8 @@ +pub(crate) mod build_common; pub mod happy_horse_1p0; pub mod preview_model; pub mod preview_model_fast; +pub(crate) mod request_common; pub(crate) mod resolve; pub mod seedance_2p0; pub mod seedance_2p0_fast; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/preview_model/build.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/preview_model/build.rs index e8b555aaef..856a25cb51 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/preview_model/build.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/preview_model/build.rs @@ -1,194 +1,25 @@ -use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; -use enums::common::generation::common_aspect_ratio::CommonAspectRatio as CommonAspectRatioEnum; -use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; use enums::common::generation::common_video_model::CommonVideoModel as CommonVideoModelEnum; -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_v2::providers::artcraft::resolve::{ - resolve_audio_list_ref, resolve_character_list_ref, resolve_image_list_ref, - resolve_image_ref, resolve_video_list_ref, +use crate::generate::generate_video_v2::providers::artcraft::build_common::{ + build_artcraft_omni_request, SupportedResolutions, UltraWideSupport, }; use crate::generate::generate_video_v2::providers::artcraft::preview_model::request::ArtcraftPreviewModelRequestState; 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_preview_model(mut builder: GenerateVideoRequestBuilder) -> Result { - let strategy = builder.request_mismatch_mitigation_strategy; - - let aspect_ratio = plan_aspect_ratio(builder.aspect_ratio.take(), strategy)?; - let resolution = plan_output_resolution(builder.resolution.take(), strategy)?; - let batch_count = plan_batch_count(builder.video_batch_count.take(), strategy)?; - let duration_seconds = plan_duration(builder.duration_seconds.take(), strategy)?; - let prompt = builder.prompt.take(); - - let start_frame = resolve_image_ref(builder.start_frame.take())?; - let end_frame = resolve_image_ref(builder.end_frame.take())?; - let reference_images = resolve_image_list_ref(builder.reference_images.take())?; - let reference_videos = resolve_video_list_ref(builder.reference_videos.take())?; - let reference_audio = resolve_audio_list_ref(builder.reference_audio.take())?; - let reference_characters = resolve_character_list_ref(builder.reference_character_tokens.take()); - let idempotency_token = builder.get_or_generate_idempotency_token(); - - let request = OmniGenVideoCostAndGenerateRequest { - model: Some(CommonVideoModelEnum::PreviewModel), - idempotency_token: Some(idempotency_token), - prompt, - start_frame_image_media_token: start_frame, - end_frame_image_media_token: end_frame, - reference_image_media_tokens: reference_images, - reference_video_media_tokens: reference_videos, - reference_audio_media_tokens: reference_audio, - reference_character_tokens: reference_characters, - resolution, - aspect_ratio, - duration_seconds: duration_seconds.map(|d| d as u16), - video_batch_count: Some(batch_count), - negative_prompt: None, - generate_audio: None, - quality: None, - }; - +pub fn build_artcraft_preview_model(builder: GenerateVideoRequestBuilder) -> Result { + let request = build_artcraft_omni_request( + builder, + CommonVideoModelEnum::PreviewModel, + SupportedResolutions::Full, + UltraWideSupport::Supported, + )?; let state = ArtcraftPreviewModelRequestState { request }; Ok(VideoGenerationDraftOrRequest::Request(VideoGenerationRequest::ArtcraftPreviewModel(state))) } -// -- Plan helpers -- - -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(CommonAspectRatioEnum::WideSixteenByNine)) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(Some(CommonAspectRatioEnum::TallNineBySixteen)) - } - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => { - Ok(Some(CommonAspectRatioEnum::Square)) - } - Some(CommonAspectRatio::WideFourByThree) => Ok(Some(CommonAspectRatioEnum::WideFourByThree)), - Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(CommonAspectRatioEnum::TallThreeByFour)), - Some(CommonAspectRatio::WideTwentyOneByNine) => Ok(Some(CommonAspectRatioEnum::WideTwentyOneByNine)), - - 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) -> CommonAspectRatioEnum { - match aspect_ratio { - CommonAspectRatio::WideFiveByFour => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::WideThreeByTwo => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::TallFourByFive => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallTwoByThree => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallNineByTwentyOne => CommonAspectRatioEnum::TallNineBySixteen, - _ => CommonAspectRatioEnum::Square, - } -} - -// PreviewModel supports output resolutions: 480p, 720p, 1080p. -fn plan_output_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - match resolution { - None => Ok(None), - - Some(CommonResolution::FourEightyP) => Ok(Some(CommonResolutionEnum::FourEightyP)), - Some(CommonResolution::SevenTwentyP) => Ok(Some(CommonResolutionEnum::SevenTwentyP)), - Some(CommonResolution::TenEightyP) => Ok(Some(CommonResolutionEnum::TenEightyP)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => { - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolutionEnum::FourEightyP, - _ => CommonResolutionEnum::TenEightyP, - })) - } - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolutionEnum::FourEightyP, - _ => CommonResolutionEnum::TenEightyP, - })) - } - }, - } -} - -// Batch counts: 1, 2, 4. -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 | 2 | 4 => Ok(count), - _ => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "video_batch_count", - value: format!("{}", count), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(4), - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(if count < 4 { 2 } else { 4 }) - } - }, - } -} - -// Duration: 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)), - }, - } -} - #[cfg(test)] mod tests { use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/preview_model/request.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/preview_model/request.rs index ebf5a64e67..695d3cb9c8 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/preview_model/request.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/preview_model/request.rs @@ -1,32 +1,17 @@ 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 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::generate_video_response::GenerateVideoResponse; +use crate::generate::generate_video_v2::providers::artcraft::request_common::send_artcraft_omni_request; #[derive(Clone, Debug)] pub struct ArtcraftPreviewModelRequestState { - /// Final materialized request; ready to fire via the omni-gen video endpoint. pub request: OmniGenVideoCostAndGenerateRequest, } impl ArtcraftPreviewModelRequestState { pub async fn send(&self, client: &RouterArtcraftClient) -> Result { - let response = omni_gen_video_generate( - &client.api_host, - Some(&client.credentials), - self.request.clone(), - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token.clone(), - all_inference_job_tokens: vec![response.inference_job_token], - })) + send_artcraft_omni_request(&self.request, client).await } } diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/preview_model_fast/build.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/preview_model_fast/build.rs index 36d9537342..dfcfc28f75 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/preview_model_fast/build.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/preview_model_fast/build.rs @@ -1,204 +1,25 @@ -use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; -use enums::common::generation::common_aspect_ratio::CommonAspectRatio as CommonAspectRatioEnum; -use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; use enums::common::generation::common_video_model::CommonVideoModel as CommonVideoModelEnum; -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_v2::providers::artcraft::resolve::{ - resolve_audio_list_ref, resolve_character_list_ref, resolve_image_list_ref, - resolve_image_ref, resolve_video_list_ref, +use crate::generate::generate_video_v2::providers::artcraft::build_common::{ + build_artcraft_omni_request, SupportedResolutions, UltraWideSupport, }; use crate::generate::generate_video_v2::providers::artcraft::preview_model_fast::request::ArtcraftPreviewModelFastRequestState; 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_preview_model_fast(mut builder: GenerateVideoRequestBuilder) -> Result { - let strategy = builder.request_mismatch_mitigation_strategy; - - let aspect_ratio = plan_aspect_ratio(builder.aspect_ratio.take(), strategy)?; - let resolution = plan_output_resolution(builder.resolution.take(), strategy)?; - let batch_count = plan_batch_count(builder.video_batch_count.take(), strategy)?; - let duration_seconds = plan_duration(builder.duration_seconds.take(), strategy)?; - let prompt = builder.prompt.take(); - - let start_frame = resolve_image_ref(builder.start_frame.take())?; - let end_frame = resolve_image_ref(builder.end_frame.take())?; - let reference_images = resolve_image_list_ref(builder.reference_images.take())?; - let reference_videos = resolve_video_list_ref(builder.reference_videos.take())?; - let reference_audio = resolve_audio_list_ref(builder.reference_audio.take())?; - let reference_characters = resolve_character_list_ref(builder.reference_character_tokens.take()); - let idempotency_token = builder.get_or_generate_idempotency_token(); - - let request = OmniGenVideoCostAndGenerateRequest { - model: Some(CommonVideoModelEnum::PreviewModelFast), - idempotency_token: Some(idempotency_token), - prompt, - start_frame_image_media_token: start_frame, - end_frame_image_media_token: end_frame, - reference_image_media_tokens: reference_images, - reference_video_media_tokens: reference_videos, - reference_audio_media_tokens: reference_audio, - reference_character_tokens: reference_characters, - resolution, - aspect_ratio, - duration_seconds: duration_seconds.map(|d| d as u16), - video_batch_count: Some(batch_count), - negative_prompt: None, - generate_audio: None, - quality: None, - }; - +pub fn build_artcraft_preview_model_fast(builder: GenerateVideoRequestBuilder) -> Result { + let request = build_artcraft_omni_request( + builder, + CommonVideoModelEnum::PreviewModelFast, + SupportedResolutions::Fast, + UltraWideSupport::Supported, + )?; let state = ArtcraftPreviewModelFastRequestState { request }; Ok(VideoGenerationDraftOrRequest::Request(VideoGenerationRequest::ArtcraftPreviewModelFast(state))) } -// -- Plan helpers -- - -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(CommonAspectRatioEnum::WideSixteenByNine)) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(Some(CommonAspectRatioEnum::TallNineBySixteen)) - } - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => { - Ok(Some(CommonAspectRatioEnum::Square)) - } - Some(CommonAspectRatio::WideFourByThree) => Ok(Some(CommonAspectRatioEnum::WideFourByThree)), - Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(CommonAspectRatioEnum::TallThreeByFour)), - Some(CommonAspectRatio::WideTwentyOneByNine) => Ok(Some(CommonAspectRatioEnum::WideTwentyOneByNine)), - - 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) -> CommonAspectRatioEnum { - match aspect_ratio { - CommonAspectRatio::WideFiveByFour => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::WideThreeByTwo => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::TallFourByFive => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallTwoByThree => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallNineByTwentyOne => CommonAspectRatioEnum::TallNineBySixteen, - _ => CommonAspectRatioEnum::Square, - } -} - -// PreviewModelFast supports output resolutions: 480p and 720p only. -fn plan_output_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - match resolution { - None => Ok(None), - - Some(CommonResolution::FourEightyP) => Ok(Some(CommonResolutionEnum::FourEightyP)), - Some(CommonResolution::SevenTwentyP) => Ok(Some(CommonResolutionEnum::SevenTwentyP)), - - // 1080p not supported for Fast - Some(CommonResolution::TenEightyP) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", CommonResolution::TenEightyP), - })) - } - _ => Ok(Some(CommonResolutionEnum::SevenTwentyP)), - }, - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => { - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolutionEnum::FourEightyP, - _ => CommonResolutionEnum::SevenTwentyP, - })) - } - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolutionEnum::FourEightyP, - _ => CommonResolutionEnum::SevenTwentyP, - })) - } - }, - } -} - -// Batch counts: 1, 2, 4. -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 | 2 | 4 => Ok(count), - _ => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "video_batch_count", - value: format!("{}", count), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(4), - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(if count < 4 { 2 } else { 4 }) - } - }, - } -} - -// Duration: 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)), - }, - } -} - #[cfg(test)] mod tests { use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/preview_model_fast/request.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/preview_model_fast/request.rs index 6bfd7a90fa..bc69b66f0f 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/preview_model_fast/request.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/preview_model_fast/request.rs @@ -1,32 +1,17 @@ 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 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::generate_video_response::GenerateVideoResponse; +use crate::generate::generate_video_v2::providers::artcraft::request_common::send_artcraft_omni_request; #[derive(Clone, Debug)] pub struct ArtcraftPreviewModelFastRequestState { - /// Final materialized request; ready to fire via the omni-gen video endpoint. pub request: OmniGenVideoCostAndGenerateRequest, } impl ArtcraftPreviewModelFastRequestState { pub async fn send(&self, client: &RouterArtcraftClient) -> Result { - let response = omni_gen_video_generate( - &client.api_host, - Some(&client.credentials), - self.request.clone(), - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token.clone(), - all_inference_job_tokens: vec![response.inference_job_token], - })) + send_artcraft_omni_request(&self.request, client).await } } diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/request_common.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/request_common.rs new file mode 100644 index 0000000000..6d3bd5482d --- /dev/null +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/request_common.rs @@ -0,0 +1,29 @@ +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 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, +}; + +/// Send a video generation request to the Artcraft omni-gen endpoint. +/// All Artcraft model request states delegate to this function. +pub async fn send_artcraft_omni_request( + request: &OmniGenVideoCostAndGenerateRequest, + client: &RouterArtcraftClient, +) -> Result { + let response = omni_gen_video_generate( + &client.api_host, + Some(&client.credentials), + request.clone(), + ) + .await + .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; + + Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { + inference_job_token: response.inference_job_token.clone(), + all_inference_job_tokens: vec![response.inference_job_token], + })) +} diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0/build.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0/build.rs index 1edd358900..001badfbb8 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0/build.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0/build.rs @@ -1,194 +1,25 @@ -use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; -use enums::common::generation::common_aspect_ratio::CommonAspectRatio as CommonAspectRatioEnum; -use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; use enums::common::generation::common_video_model::CommonVideoModel as CommonVideoModelEnum; -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_v2::providers::artcraft::resolve::{ - resolve_audio_list_ref, resolve_character_list_ref, resolve_image_list_ref, - resolve_image_ref, resolve_video_list_ref, +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_2p0::request::ArtcraftSeedance2p0RequestState; 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_2p0(mut builder: GenerateVideoRequestBuilder) -> Result { - let strategy = builder.request_mismatch_mitigation_strategy; - - let aspect_ratio = plan_aspect_ratio(builder.aspect_ratio.take(), strategy)?; - let resolution = plan_output_resolution(builder.resolution.take(), strategy)?; - let batch_count = plan_batch_count(builder.video_batch_count.take(), strategy)?; - let duration_seconds = plan_duration(builder.duration_seconds.take(), strategy)?; - let prompt = builder.prompt.take(); - - let start_frame = resolve_image_ref(builder.start_frame.take())?; - let end_frame = resolve_image_ref(builder.end_frame.take())?; - let reference_images = resolve_image_list_ref(builder.reference_images.take())?; - let reference_videos = resolve_video_list_ref(builder.reference_videos.take())?; - let reference_audio = resolve_audio_list_ref(builder.reference_audio.take())?; - let reference_characters = resolve_character_list_ref(builder.reference_character_tokens.take()); - let idempotency_token = builder.get_or_generate_idempotency_token(); - - let request = OmniGenVideoCostAndGenerateRequest { - model: Some(CommonVideoModelEnum::Seedance2p0), - idempotency_token: Some(idempotency_token), - prompt, - start_frame_image_media_token: start_frame, - end_frame_image_media_token: end_frame, - reference_image_media_tokens: reference_images, - reference_video_media_tokens: reference_videos, - reference_audio_media_tokens: reference_audio, - reference_character_tokens: reference_characters, - resolution, - aspect_ratio, - duration_seconds: duration_seconds.map(|d| d as u16), - video_batch_count: Some(batch_count), - negative_prompt: None, - generate_audio: None, - quality: None, - }; - +pub fn build_artcraft_seedance_2p0(builder: GenerateVideoRequestBuilder) -> Result { + let request = build_artcraft_omni_request( + builder, + CommonVideoModelEnum::Seedance2p0, + SupportedResolutions::Full, + UltraWideSupport::Supported, + )?; let state = ArtcraftSeedance2p0RequestState { request }; Ok(VideoGenerationDraftOrRequest::Request(VideoGenerationRequest::ArtcraftSeedance2p0(state))) } -// -- Plan helpers -- - -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(CommonAspectRatioEnum::WideSixteenByNine)) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(Some(CommonAspectRatioEnum::TallNineBySixteen)) - } - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => { - Ok(Some(CommonAspectRatioEnum::Square)) - } - Some(CommonAspectRatio::WideFourByThree) => Ok(Some(CommonAspectRatioEnum::WideFourByThree)), - Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(CommonAspectRatioEnum::TallThreeByFour)), - Some(CommonAspectRatio::WideTwentyOneByNine) => Ok(Some(CommonAspectRatioEnum::WideTwentyOneByNine)), - - 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) -> CommonAspectRatioEnum { - match aspect_ratio { - CommonAspectRatio::WideFiveByFour => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::WideThreeByTwo => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::TallFourByFive => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallTwoByThree => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallNineByTwentyOne => CommonAspectRatioEnum::TallNineBySixteen, - _ => CommonAspectRatioEnum::Square, - } -} - -// 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), - - Some(CommonResolution::FourEightyP) => Ok(Some(CommonResolutionEnum::FourEightyP)), - Some(CommonResolution::SevenTwentyP) => Ok(Some(CommonResolutionEnum::SevenTwentyP)), - Some(CommonResolution::TenEightyP) => Ok(Some(CommonResolutionEnum::TenEightyP)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => { - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolutionEnum::FourEightyP, - _ => CommonResolutionEnum::TenEightyP, - })) - } - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolutionEnum::FourEightyP, - _ => CommonResolutionEnum::TenEightyP, - })) - } - }, - } -} - -// Batch counts: 1, 2, 4. -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 | 2 | 4 => Ok(count), - _ => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "video_batch_count", - value: format!("{}", count), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(4), - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(if count < 4 { 2 } else { 4 }) - } - }, - } -} - -// Duration: 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)), - }, - } -} - #[cfg(test)] mod tests { use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0/request.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0/request.rs index c2a91c75a2..ef7f7dc285 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0/request.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0/request.rs @@ -1,33 +1,18 @@ 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 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::generate_video_response::GenerateVideoResponse; +use crate::generate::generate_video_v2::providers::artcraft::request_common::send_artcraft_omni_request; #[derive(Clone, Debug)] pub struct ArtcraftSeedance2p0RequestState { - /// Final materialized request; ready to fire via the omni-gen video endpoint. pub request: OmniGenVideoCostAndGenerateRequest, } impl ArtcraftSeedance2p0RequestState { pub async fn send(&self, client: &RouterArtcraftClient) -> Result { - let response = omni_gen_video_generate( - &client.api_host, - Some(&client.credentials), - self.request.clone(), - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token.clone(), - all_inference_job_tokens: vec![response.inference_job_token], - })) + 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_2p0_fast/build.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_fast/build.rs index 0eb0d8878b..4008014382 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_fast/build.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_fast/build.rs @@ -1,206 +1,25 @@ -use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; -use enums::common::generation::common_aspect_ratio::CommonAspectRatio as CommonAspectRatioEnum; -use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; use enums::common::generation::common_video_model::CommonVideoModel as CommonVideoModelEnum; -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_v2::providers::artcraft::resolve::{ - resolve_audio_list_ref, resolve_character_list_ref, resolve_image_list_ref, - resolve_image_ref, resolve_video_list_ref, +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_2p0_fast::request::ArtcraftSeedance2p0FastRequestState; 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_2p0_fast(mut builder: GenerateVideoRequestBuilder) -> Result { - let strategy = builder.request_mismatch_mitigation_strategy; - - let aspect_ratio = plan_aspect_ratio(builder.aspect_ratio.take(), strategy)?; - let resolution = plan_output_resolution(builder.resolution.take(), strategy)?; - let batch_count = plan_batch_count(builder.video_batch_count.take(), strategy)?; - let duration_seconds = plan_duration(builder.duration_seconds.take(), strategy)?; - let prompt = builder.prompt.take(); - - let start_frame = resolve_image_ref(builder.start_frame.take())?; - let end_frame = resolve_image_ref(builder.end_frame.take())?; - let reference_images = resolve_image_list_ref(builder.reference_images.take())?; - let reference_videos = resolve_video_list_ref(builder.reference_videos.take())?; - let reference_audio = resolve_audio_list_ref(builder.reference_audio.take())?; - let reference_characters = resolve_character_list_ref(builder.reference_character_tokens.take()); - let idempotency_token = builder.get_or_generate_idempotency_token(); - - let request = OmniGenVideoCostAndGenerateRequest { - model: Some(CommonVideoModelEnum::Seedance2p0Fast), - idempotency_token: Some(idempotency_token), - prompt, - start_frame_image_media_token: start_frame, - end_frame_image_media_token: end_frame, - reference_image_media_tokens: reference_images, - reference_video_media_tokens: reference_videos, - reference_audio_media_tokens: reference_audio, - reference_character_tokens: reference_characters, - resolution, - aspect_ratio, - duration_seconds: duration_seconds.map(|d| d as u16), - video_batch_count: Some(batch_count), - negative_prompt: None, - generate_audio: None, - quality: None, - }; - +pub fn build_artcraft_seedance_2p0_fast(builder: GenerateVideoRequestBuilder) -> Result { + let request = build_artcraft_omni_request( + builder, + CommonVideoModelEnum::Seedance2p0Fast, + SupportedResolutions::Fast, + UltraWideSupport::Supported, + )?; let state = ArtcraftSeedance2p0FastRequestState { request }; Ok(VideoGenerationDraftOrRequest::Request(VideoGenerationRequest::ArtcraftSeedance2p0Fast(state))) } -// -- Plan helpers -- - -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), - - // Direct mappings - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => { - Ok(Some(CommonAspectRatioEnum::WideSixteenByNine)) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(Some(CommonAspectRatioEnum::TallNineBySixteen)) - } - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => { - Ok(Some(CommonAspectRatioEnum::Square)) - } - Some(CommonAspectRatio::WideFourByThree) => Ok(Some(CommonAspectRatioEnum::WideFourByThree)), - Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(CommonAspectRatioEnum::TallThreeByFour)), - Some(CommonAspectRatio::WideTwentyOneByNine) => Ok(Some(CommonAspectRatioEnum::WideTwentyOneByNine)), - - // 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) -> CommonAspectRatioEnum { - match aspect_ratio { - CommonAspectRatio::WideFiveByFour => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::WideThreeByTwo => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::TallFourByFive => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallTwoByThree => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallNineByTwentyOne => CommonAspectRatioEnum::TallNineBySixteen, - _ => CommonAspectRatioEnum::Square, - } -} - -// 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), - - Some(CommonResolution::FourEightyP) => Ok(Some(CommonResolutionEnum::FourEightyP)), - Some(CommonResolution::SevenTwentyP) => Ok(Some(CommonResolutionEnum::SevenTwentyP)), - - // 1080p not supported for Fast - Some(CommonResolution::TenEightyP) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", CommonResolution::TenEightyP), - })) - } - _ => Ok(Some(CommonResolutionEnum::SevenTwentyP)), - }, - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => { - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolutionEnum::FourEightyP, - _ => CommonResolutionEnum::SevenTwentyP, - })) - } - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolutionEnum::FourEightyP, - _ => CommonResolutionEnum::SevenTwentyP, - })) - } - }, - } -} - -// Batch counts: 1, 2, 4. -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 | 2 | 4 => Ok(count), - _ => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "video_batch_count", - value: format!("{}", count), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(4), - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(if count < 4 { 2 } else { 4 }) - } - }, - } -} - -// Duration: 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)), - }, - } -} - #[cfg(test)] mod tests { use enums::common::generation::common_aspect_ratio::CommonAspectRatio as CommonAspectRatioEnum; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_fast/request.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_fast/request.rs index 0a8948e761..058bc6a65a 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_fast/request.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_fast/request.rs @@ -1,33 +1,18 @@ 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 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::generate_video_response::GenerateVideoResponse; +use crate::generate::generate_video_v2::providers::artcraft::request_common::send_artcraft_omni_request; #[derive(Clone, Debug)] pub struct ArtcraftSeedance2p0FastRequestState { - /// Final materialized request; ready to fire via the omni-gen video endpoint. pub request: OmniGenVideoCostAndGenerateRequest, } impl ArtcraftSeedance2p0FastRequestState { pub async fn send(&self, client: &RouterArtcraftClient) -> Result { - let response = omni_gen_video_generate( - &client.api_host, - Some(&client.credentials), - self.request.clone(), - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token.clone(), - all_inference_job_tokens: vec![response.inference_job_token], - })) + 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_2p0_fast_g/build.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_fast_g/build.rs index a60c41d6d9..ea4b4e003f 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_fast_g/build.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_fast_g/build.rs @@ -1,206 +1,25 @@ -use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; -use enums::common::generation::common_aspect_ratio::CommonAspectRatio as CommonAspectRatioEnum; -use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; use enums::common::generation::common_video_model::CommonVideoModel as CommonVideoModelEnum; -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_v2::providers::artcraft::resolve::{ - resolve_audio_list_ref, resolve_character_list_ref, resolve_image_list_ref, - resolve_image_ref, resolve_video_list_ref, +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_2p0_fast_g::request::ArtcraftSeedance2p0FastGRequestState; 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_2p0_fast_g(mut builder: GenerateVideoRequestBuilder) -> Result { - let strategy = builder.request_mismatch_mitigation_strategy; - - let aspect_ratio = plan_aspect_ratio(builder.aspect_ratio.take(), strategy)?; - let resolution = plan_output_resolution(builder.resolution.take(), strategy)?; - let batch_count = plan_batch_count(builder.video_batch_count.take(), strategy)?; - let duration_seconds = plan_duration(builder.duration_seconds.take(), strategy)?; - let prompt = builder.prompt.take(); - - let start_frame = resolve_image_ref(builder.start_frame.take())?; - let end_frame = resolve_image_ref(builder.end_frame.take())?; - let reference_images = resolve_image_list_ref(builder.reference_images.take())?; - let reference_videos = resolve_video_list_ref(builder.reference_videos.take())?; - let reference_audio = resolve_audio_list_ref(builder.reference_audio.take())?; - let reference_characters = resolve_character_list_ref(builder.reference_character_tokens.take()); - let idempotency_token = builder.get_or_generate_idempotency_token(); - - let request = OmniGenVideoCostAndGenerateRequest { - model: Some(CommonVideoModelEnum::Seedance2p0FastGlobal), - idempotency_token: Some(idempotency_token), - prompt, - start_frame_image_media_token: start_frame, - end_frame_image_media_token: end_frame, - reference_image_media_tokens: reference_images, - reference_video_media_tokens: reference_videos, - reference_audio_media_tokens: reference_audio, - reference_character_tokens: reference_characters, - resolution, - aspect_ratio, - duration_seconds: duration_seconds.map(|d| d as u16), - video_batch_count: Some(batch_count), - negative_prompt: None, - generate_audio: None, - quality: None, - }; - +pub fn build_artcraft_seedance_2p0_fast_g(builder: GenerateVideoRequestBuilder) -> Result { + let request = build_artcraft_omni_request( + builder, + CommonVideoModelEnum::Seedance2p0FastGlobal, + SupportedResolutions::Fast, + UltraWideSupport::Supported, + )?; let state = ArtcraftSeedance2p0FastGRequestState { request }; Ok(VideoGenerationDraftOrRequest::Request(VideoGenerationRequest::ArtcraftSeedance2p0FastG(state))) } -// -- Plan helpers -- - -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), - - // Direct mappings - Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => { - Ok(Some(CommonAspectRatioEnum::WideSixteenByNine)) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(Some(CommonAspectRatioEnum::TallNineBySixteen)) - } - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => { - Ok(Some(CommonAspectRatioEnum::Square)) - } - Some(CommonAspectRatio::WideFourByThree) => Ok(Some(CommonAspectRatioEnum::WideFourByThree)), - Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(CommonAspectRatioEnum::TallThreeByFour)), - Some(CommonAspectRatio::WideTwentyOneByNine) => Ok(Some(CommonAspectRatioEnum::WideTwentyOneByNine)), - - // 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) -> CommonAspectRatioEnum { - match aspect_ratio { - CommonAspectRatio::WideFiveByFour => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::WideThreeByTwo => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::TallFourByFive => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallTwoByThree => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallNineByTwentyOne => CommonAspectRatioEnum::TallNineBySixteen, - _ => CommonAspectRatioEnum::Square, - } -} - -// 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), - - Some(CommonResolution::FourEightyP) => Ok(Some(CommonResolutionEnum::FourEightyP)), - Some(CommonResolution::SevenTwentyP) => Ok(Some(CommonResolutionEnum::SevenTwentyP)), - - // 1080p not supported for Fast - Some(CommonResolution::TenEightyP) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", CommonResolution::TenEightyP), - })) - } - _ => Ok(Some(CommonResolutionEnum::SevenTwentyP)), - }, - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => { - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolutionEnum::FourEightyP, - _ => CommonResolutionEnum::SevenTwentyP, - })) - } - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolutionEnum::FourEightyP, - _ => CommonResolutionEnum::SevenTwentyP, - })) - } - }, - } -} - -// Batch counts: 1, 2, 4. -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 | 2 | 4 => Ok(count), - _ => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "video_batch_count", - value: format!("{}", count), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(4), - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(if count < 4 { 2 } else { 4 }) - } - }, - } -} - -// Duration: 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)), - }, - } -} - #[cfg(test)] mod tests { use enums::common::generation::common_aspect_ratio::CommonAspectRatio as CommonAspectRatioEnum; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_fast_g/request.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_fast_g/request.rs index 78ef149fc7..12b4cad0e8 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_fast_g/request.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_fast_g/request.rs @@ -1,33 +1,18 @@ 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 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::generate_video_response::GenerateVideoResponse; +use crate::generate::generate_video_v2::providers::artcraft::request_common::send_artcraft_omni_request; #[derive(Clone, Debug)] pub struct ArtcraftSeedance2p0FastGRequestState { - /// Final materialized request; ready to fire via the omni-gen video endpoint. pub request: OmniGenVideoCostAndGenerateRequest, } impl ArtcraftSeedance2p0FastGRequestState { pub async fn send(&self, client: &RouterArtcraftClient) -> Result { - let response = omni_gen_video_generate( - &client.api_host, - Some(&client.credentials), - self.request.clone(), - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token.clone(), - all_inference_job_tokens: vec![response.inference_job_token], - })) + 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_2p0_g/build.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_g/build.rs index a6344e5cff..a4f11f4554 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_g/build.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_g/build.rs @@ -1,194 +1,25 @@ -use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; -use enums::common::generation::common_aspect_ratio::CommonAspectRatio as CommonAspectRatioEnum; -use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; use enums::common::generation::common_video_model::CommonVideoModel as CommonVideoModelEnum; -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_v2::providers::artcraft::resolve::{ - resolve_audio_list_ref, resolve_character_list_ref, resolve_image_list_ref, - resolve_image_ref, resolve_video_list_ref, +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_2p0_g::request::ArtcraftSeedance2p0GRequestState; 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_2p0_g(mut builder: GenerateVideoRequestBuilder) -> Result { - let strategy = builder.request_mismatch_mitigation_strategy; - - let aspect_ratio = plan_aspect_ratio(builder.aspect_ratio.take(), strategy)?; - let resolution = plan_output_resolution(builder.resolution.take(), strategy)?; - let batch_count = plan_batch_count(builder.video_batch_count.take(), strategy)?; - let duration_seconds = plan_duration(builder.duration_seconds.take(), strategy)?; - let prompt = builder.prompt.take(); - - let start_frame = resolve_image_ref(builder.start_frame.take())?; - let end_frame = resolve_image_ref(builder.end_frame.take())?; - let reference_images = resolve_image_list_ref(builder.reference_images.take())?; - let reference_videos = resolve_video_list_ref(builder.reference_videos.take())?; - let reference_audio = resolve_audio_list_ref(builder.reference_audio.take())?; - let reference_characters = resolve_character_list_ref(builder.reference_character_tokens.take()); - let idempotency_token = builder.get_or_generate_idempotency_token(); - - let request = OmniGenVideoCostAndGenerateRequest { - model: Some(CommonVideoModelEnum::Seedance2p0Global), - idempotency_token: Some(idempotency_token), - prompt, - start_frame_image_media_token: start_frame, - end_frame_image_media_token: end_frame, - reference_image_media_tokens: reference_images, - reference_video_media_tokens: reference_videos, - reference_audio_media_tokens: reference_audio, - reference_character_tokens: reference_characters, - resolution, - aspect_ratio, - duration_seconds: duration_seconds.map(|d| d as u16), - video_batch_count: Some(batch_count), - negative_prompt: None, - generate_audio: None, - quality: None, - }; - +pub fn build_artcraft_seedance_2p0_g(builder: GenerateVideoRequestBuilder) -> Result { + let request = build_artcraft_omni_request( + builder, + CommonVideoModelEnum::Seedance2p0Global, + SupportedResolutions::Full, + UltraWideSupport::Supported, + )?; let state = ArtcraftSeedance2p0GRequestState { request }; Ok(VideoGenerationDraftOrRequest::Request(VideoGenerationRequest::ArtcraftSeedance2p0G(state))) } -// -- Plan helpers -- - -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(CommonAspectRatioEnum::WideSixteenByNine)) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(Some(CommonAspectRatioEnum::TallNineBySixteen)) - } - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => { - Ok(Some(CommonAspectRatioEnum::Square)) - } - Some(CommonAspectRatio::WideFourByThree) => Ok(Some(CommonAspectRatioEnum::WideFourByThree)), - Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(CommonAspectRatioEnum::TallThreeByFour)), - Some(CommonAspectRatio::WideTwentyOneByNine) => Ok(Some(CommonAspectRatioEnum::WideTwentyOneByNine)), - - 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) -> CommonAspectRatioEnum { - match aspect_ratio { - CommonAspectRatio::WideFiveByFour => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::WideThreeByTwo => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::TallFourByFive => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallTwoByThree => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallNineByTwentyOne => CommonAspectRatioEnum::TallNineBySixteen, - _ => CommonAspectRatioEnum::Square, - } -} - -// 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), - - Some(CommonResolution::FourEightyP) => Ok(Some(CommonResolutionEnum::FourEightyP)), - Some(CommonResolution::SevenTwentyP) => Ok(Some(CommonResolutionEnum::SevenTwentyP)), - Some(CommonResolution::TenEightyP) => Ok(Some(CommonResolutionEnum::TenEightyP)), - - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => { - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolutionEnum::FourEightyP, - _ => CommonResolutionEnum::TenEightyP, - })) - } - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolutionEnum::FourEightyP, - _ => CommonResolutionEnum::TenEightyP, - })) - } - }, - } -} - -// Batch counts: 1, 2, 4. -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 | 2 | 4 => Ok(count), - _ => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "video_batch_count", - value: format!("{}", count), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(4), - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(if count < 4 { 2 } else { 4 }) - } - }, - } -} - -// Duration: 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)), - }, - } -} - #[cfg(test)] mod tests { use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_g/request.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_g/request.rs index 9af4690d5b..f655a32851 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_g/request.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_g/request.rs @@ -1,33 +1,18 @@ 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 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::generate_video_response::GenerateVideoResponse; +use crate::generate::generate_video_v2::providers::artcraft::request_common::send_artcraft_omni_request; #[derive(Clone, Debug)] pub struct ArtcraftSeedance2p0GRequestState { - /// Final materialized request; ready to fire via the omni-gen video endpoint. pub request: OmniGenVideoCostAndGenerateRequest, } impl ArtcraftSeedance2p0GRequestState { pub async fn send(&self, client: &RouterArtcraftClient) -> Result { - let response = omni_gen_video_generate( - &client.api_host, - Some(&client.credentials), - self.request.clone(), - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token.clone(), - all_inference_job_tokens: vec![response.inference_job_token], - })) + 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_2p0_p/build.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_p/build.rs index 2e6b80beda..5f6d1535fd 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_p/build.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_p/build.rs @@ -1,185 +1,25 @@ -use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; -use enums::common::generation::common_aspect_ratio::CommonAspectRatio as CommonAspectRatioEnum; -use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; use enums::common::generation::common_video_model::CommonVideoModel as CommonVideoModelEnum; -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_v2::providers::artcraft::resolve::{ - resolve_audio_list_ref, resolve_character_list_ref, resolve_image_list_ref, - resolve_image_ref, resolve_video_list_ref, +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_2p0_p::request::ArtcraftSeedance2p0PlusRequestState; 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_2p0_p(mut builder: GenerateVideoRequestBuilder) -> Result { - let strategy = builder.request_mismatch_mitigation_strategy; - - let aspect_ratio = plan_aspect_ratio(builder.aspect_ratio.take(), strategy)?; - let resolution = plan_output_resolution(builder.resolution.take(), strategy)?; - let batch_count = plan_batch_count(builder.video_batch_count.take(), strategy)?; - let duration_seconds = plan_duration(builder.duration_seconds.take(), strategy)?; - let prompt = builder.prompt.take(); - - let start_frame = resolve_image_ref(builder.start_frame.take())?; - let end_frame = resolve_image_ref(builder.end_frame.take())?; - let reference_images = resolve_image_list_ref(builder.reference_images.take())?; - let reference_videos = resolve_video_list_ref(builder.reference_videos.take())?; - let reference_audio = resolve_audio_list_ref(builder.reference_audio.take())?; - let reference_characters = resolve_character_list_ref(builder.reference_character_tokens.take()); - let idempotency_token = builder.get_or_generate_idempotency_token(); - - let request = OmniGenVideoCostAndGenerateRequest { - model: Some(CommonVideoModelEnum::Seedance2p0Plus), - idempotency_token: Some(idempotency_token), - prompt, - start_frame_image_media_token: start_frame, - end_frame_image_media_token: end_frame, - reference_image_media_tokens: reference_images, - reference_video_media_tokens: reference_videos, - reference_audio_media_tokens: reference_audio, - reference_character_tokens: reference_characters, - resolution, - aspect_ratio, - duration_seconds: duration_seconds.map(|d| d as u16), - video_batch_count: Some(batch_count), - negative_prompt: None, - generate_audio: None, - quality: None, - }; - +pub fn build_artcraft_seedance_2p0_p(builder: GenerateVideoRequestBuilder) -> Result { + let request = build_artcraft_omni_request( + builder, + CommonVideoModelEnum::Seedance2p0Plus, + SupportedResolutions::Full, + UltraWideSupport::Supported, + )?; let state = ArtcraftSeedance2p0PlusRequestState { request }; Ok(VideoGenerationDraftOrRequest::Request(VideoGenerationRequest::ArtcraftSeedance2p0Plus(state))) } -// -- Plan helpers -- - -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(CommonAspectRatioEnum::WideSixteenByNine)) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(Some(CommonAspectRatioEnum::TallNineBySixteen)) - } - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => { - Ok(Some(CommonAspectRatioEnum::Square)) - } - Some(CommonAspectRatio::WideFourByThree) => Ok(Some(CommonAspectRatioEnum::WideFourByThree)), - Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(CommonAspectRatioEnum::TallThreeByFour)), - Some(CommonAspectRatio::WideTwentyOneByNine) => Ok(Some(CommonAspectRatioEnum::WideTwentyOneByNine)), - - 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) -> CommonAspectRatioEnum { - match aspect_ratio { - CommonAspectRatio::WideFiveByFour => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::WideThreeByTwo => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::TallFourByFive => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallTwoByThree => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallNineByTwentyOne => CommonAspectRatioEnum::TallNineBySixteen, - _ => CommonAspectRatioEnum::Square, - } -} - -// Supports output resolutions: 480p, 720p, 1080p. -fn plan_output_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - match resolution { - None => Ok(None), - Some(CommonResolution::FourEightyP) => Ok(Some(CommonResolutionEnum::FourEightyP)), - Some(CommonResolution::SevenTwentyP) => Ok(Some(CommonResolutionEnum::SevenTwentyP)), - Some(CommonResolution::TenEightyP) => Ok(Some(CommonResolutionEnum::TenEightyP)), - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade - | RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolutionEnum::FourEightyP, - _ => CommonResolutionEnum::TenEightyP, - })) - } - }, - } -} - -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 | 2 | 4 => Ok(count), - _ => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "video_batch_count", - value: format!("{}", count), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(4), - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(if count < 4 { 2 } else { 4 }) - } - }, - } -} - -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)), - }, - } -} - #[cfg(test)] mod tests { use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_p/request.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_p/request.rs index ead5564dc1..69b28146c9 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_p/request.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_p/request.rs @@ -1,12 +1,9 @@ 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 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::generate_video_response::GenerateVideoResponse; +use crate::generate::generate_video_v2::providers::artcraft::request_common::send_artcraft_omni_request; #[derive(Clone, Debug)] pub struct ArtcraftSeedance2p0PlusRequestState { @@ -15,17 +12,6 @@ pub struct ArtcraftSeedance2p0PlusRequestState { impl ArtcraftSeedance2p0PlusRequestState { pub async fn send(&self, client: &RouterArtcraftClient) -> Result { - let response = omni_gen_video_generate( - &client.api_host, - Some(&client.credentials), - self.request.clone(), - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token.clone(), - all_inference_job_tokens: vec![response.inference_job_token], - })) + 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_2p0_p_fast/build.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_p_fast/build.rs index 8bc036e2cd..836681c0eb 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_p_fast/build.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_p_fast/build.rs @@ -1,193 +1,25 @@ -use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; -use enums::common::generation::common_aspect_ratio::CommonAspectRatio as CommonAspectRatioEnum; -use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; use enums::common::generation::common_video_model::CommonVideoModel as CommonVideoModelEnum; -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_v2::providers::artcraft::resolve::{ - resolve_audio_list_ref, resolve_character_list_ref, resolve_image_list_ref, - resolve_image_ref, resolve_video_list_ref, +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_2p0_p_fast::request::ArtcraftSeedance2p0PlusFastRequestState; 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_2p0_p_fast(mut builder: GenerateVideoRequestBuilder) -> Result { - let strategy = builder.request_mismatch_mitigation_strategy; - - let aspect_ratio = plan_aspect_ratio(builder.aspect_ratio.take(), strategy)?; - let resolution = plan_output_resolution(builder.resolution.take(), strategy)?; - let batch_count = plan_batch_count(builder.video_batch_count.take(), strategy)?; - let duration_seconds = plan_duration(builder.duration_seconds.take(), strategy)?; - let prompt = builder.prompt.take(); - - let start_frame = resolve_image_ref(builder.start_frame.take())?; - let end_frame = resolve_image_ref(builder.end_frame.take())?; - let reference_images = resolve_image_list_ref(builder.reference_images.take())?; - let reference_videos = resolve_video_list_ref(builder.reference_videos.take())?; - let reference_audio = resolve_audio_list_ref(builder.reference_audio.take())?; - let reference_characters = resolve_character_list_ref(builder.reference_character_tokens.take()); - let idempotency_token = builder.get_or_generate_idempotency_token(); - - let request = OmniGenVideoCostAndGenerateRequest { - model: Some(CommonVideoModelEnum::Seedance2p0PlusFast), - idempotency_token: Some(idempotency_token), - prompt, - start_frame_image_media_token: start_frame, - end_frame_image_media_token: end_frame, - reference_image_media_tokens: reference_images, - reference_video_media_tokens: reference_videos, - reference_audio_media_tokens: reference_audio, - reference_character_tokens: reference_characters, - resolution, - aspect_ratio, - duration_seconds: duration_seconds.map(|d| d as u16), - video_batch_count: Some(batch_count), - negative_prompt: None, - generate_audio: None, - quality: None, - }; - +pub fn build_artcraft_seedance_2p0_p_fast(builder: GenerateVideoRequestBuilder) -> Result { + let request = build_artcraft_omni_request( + builder, + CommonVideoModelEnum::Seedance2p0PlusFast, + SupportedResolutions::Fast, + UltraWideSupport::Supported, + )?; let state = ArtcraftSeedance2p0PlusFastRequestState { request }; Ok(VideoGenerationDraftOrRequest::Request(VideoGenerationRequest::ArtcraftSeedance2p0PlusFast(state))) } -// -- Plan helpers -- - -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(CommonAspectRatioEnum::WideSixteenByNine)) - } - Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => { - Ok(Some(CommonAspectRatioEnum::TallNineBySixteen)) - } - Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => { - Ok(Some(CommonAspectRatioEnum::Square)) - } - Some(CommonAspectRatio::WideFourByThree) => Ok(Some(CommonAspectRatioEnum::WideFourByThree)), - Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(CommonAspectRatioEnum::TallThreeByFour)), - Some(CommonAspectRatio::WideTwentyOneByNine) => Ok(Some(CommonAspectRatioEnum::WideTwentyOneByNine)), - - 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) -> CommonAspectRatioEnum { - match aspect_ratio { - CommonAspectRatio::WideFiveByFour => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::WideThreeByTwo => CommonAspectRatioEnum::WideFourByThree, - CommonAspectRatio::TallFourByFive => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallTwoByThree => CommonAspectRatioEnum::TallThreeByFour, - CommonAspectRatio::TallNineByTwentyOne => CommonAspectRatioEnum::TallNineBySixteen, - _ => CommonAspectRatioEnum::Square, - } -} - -// Supports output resolutions: 480p and 720p only. -fn plan_output_resolution( - resolution: Option, - strategy: RequestMismatchMitigationStrategy, -) -> Result, ArtcraftRouterError> { - match resolution { - None => Ok(None), - Some(CommonResolution::FourEightyP) => Ok(Some(CommonResolutionEnum::FourEightyP)), - Some(CommonResolution::SevenTwentyP) => Ok(Some(CommonResolutionEnum::SevenTwentyP)), - Some(CommonResolution::TenEightyP) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", CommonResolution::TenEightyP), - })) - } - _ => Ok(Some(CommonResolutionEnum::SevenTwentyP)), - }, - Some(unsupported) => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "resolution", - value: format!("{:?}", unsupported), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade - | RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(Some(match unsupported { - CommonResolution::HalfK => CommonResolutionEnum::FourEightyP, - _ => CommonResolutionEnum::SevenTwentyP, - })) - } - }, - } -} - -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 | 2 | 4 => Ok(count), - _ => match strategy { - RequestMismatchMitigationStrategy::ErrorOut => { - Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption { - field: "video_batch_count", - value: format!("{}", count), - })) - } - RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(4), - RequestMismatchMitigationStrategy::PayLessDowngrade => { - Ok(if count < 4 { 2 } else { 4 }) - } - }, - } -} - -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)), - }, - } -} - #[cfg(test)] mod tests { use enums::common::generation::common_resolution::CommonResolution as CommonResolutionEnum; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_p_fast/request.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_p_fast/request.rs index 54acc15e6a..cac2084660 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_p_fast/request.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video_v2/providers/artcraft/seedance_2p0_p_fast/request.rs @@ -1,12 +1,9 @@ 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 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::generate_video_response::GenerateVideoResponse; +use crate::generate::generate_video_v2::providers::artcraft::request_common::send_artcraft_omni_request; #[derive(Clone, Debug)] pub struct ArtcraftSeedance2p0PlusFastRequestState { @@ -15,17 +12,6 @@ pub struct ArtcraftSeedance2p0PlusFastRequestState { impl ArtcraftSeedance2p0PlusFastRequestState { pub async fn send(&self, client: &RouterArtcraftClient) -> Result { - let response = omni_gen_video_generate( - &client.api_host, - Some(&client.credentials), - self.request.clone(), - ) - .await - .map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?; - - Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload { - inference_job_token: response.inference_job_token.clone(), - all_inference_job_tokens: vec![response.inference_job_token], - })) + send_artcraft_omni_request(&self.request, client).await } }