kling cost estimates + artcraft

This commit is contained in:
Brandon Thomas committed 2026-04-07 15:09:26 -04:00
1 parent f1c7878d9d
commit 9274294de2
25 files changed
+1024 -10

No files matched your search

@@ -28,7 +28,7 @@ pub struct GenerateKling16ProImageToVideoRequest {
pub duration: Option<GenerateKling16ProDuration>,
}
#[derive(Serialize, Deserialize, ToSchema)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateKling16ProAspectRatio {
/// 16:9 aspect ratio
@@ -39,7 +39,7 @@ pub enum GenerateKling16ProAspectRatio {
Square,
}
#[derive(Serialize, Deserialize, ToSchema)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateKling16ProDuration {
FiveSeconds,
@@ -24,7 +24,7 @@ pub struct GenerateKling21MasterImageToVideoRequest {
pub duration: Option<GenerateKling21MasterDuration>,
}
#[derive(Serialize, Deserialize, ToSchema)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateKling21MasterAspectRatio {
/// 16:9 aspect ratio
@@ -35,7 +35,7 @@ pub enum GenerateKling21MasterAspectRatio {
Square,
}
#[derive(Serialize, Deserialize, ToSchema)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateKling21MasterDuration {
FiveSeconds,
@@ -28,7 +28,7 @@ pub struct GenerateKling21ProImageToVideoRequest {
pub duration: Option<GenerateKling21ProDuration>,
}
#[derive(Serialize, Deserialize, ToSchema)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateKling21ProAspectRatio {
/// 16:9 aspect ratio
@@ -39,7 +39,7 @@ pub enum GenerateKling21ProAspectRatio {
Square,
}
#[derive(Serialize, Deserialize, ToSchema)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum GenerateKling21ProDuration {
FiveSeconds,
@@ -41,14 +41,14 @@ pub struct Kling2p5TurboProMultiFunctionVideoGenRequest {
pub aspect_ratio: Option<Kling2p5TurboProMultiFunctionVideoGenAspectRatio>,
}
#[derive(Serialize, Deserialize, ToSchema)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Kling2p5TurboProMultiFunctionVideoGenDuration {
FiveSeconds,
TenSeconds,
}
#[derive(Serialize, Deserialize, ToSchema)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Kling2p5TurboProMultiFunctionVideoGenAspectRatio {
Square,
@@ -45,14 +45,14 @@ pub struct Kling2p6ProMultiFunctionVideoGenRequest {
pub aspect_ratio: Option<Kling2p6ProMultiFunctionVideoGenAspectRatio>,
}
#[derive(Serialize, Deserialize, ToSchema)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Kling2p6ProMultiFunctionVideoGenDuration {
FiveSeconds,
TenSeconds,
}
#[derive(Serialize, Deserialize, ToSchema)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum Kling2p6ProMultiFunctionVideoGenAspectRatio {
Square,
@@ -0,0 +1,18 @@
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_1_6_pro::PlanArtcraftKling16Pro;
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
pub(crate) fn estimate_video_cost_artcraft_kling_1_6_pro(
plan: &PlanArtcraftKling16Pro<'_>,
) -> VideoGenerationCostEstimate {
// Mirrors fal_client kling_v1p6_pro: 5s = $0.475 (rounded up to 48¢), 10s = $0.95 (95¢).
let cost_in_usd_cents: u64 = if plan.is_ten_seconds() { 95 } else { 48 };
VideoGenerationCostEstimate {
cost_in_credits: Some(cost_in_usd_cents),
cost_in_usd_cents: Some(cost_in_usd_cents),
is_free: false,
is_unlimited: false,
is_rate_limited: false,
has_watermark: false,
}
}
@@ -0,0 +1,18 @@
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_1_master::PlanArtcraftKling21Master;
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
pub(crate) fn estimate_video_cost_artcraft_kling_2_1_master(
plan: &PlanArtcraftKling21Master<'_>,
) -> VideoGenerationCostEstimate {
// Mirrors fal_client kling_v2p1_master: 5s = $1.40, 10s = $2.80.
let cost_in_usd_cents: u64 = if plan.is_ten_seconds() { 280 } else { 140 };
VideoGenerationCostEstimate {
cost_in_credits: Some(cost_in_usd_cents),
cost_in_usd_cents: Some(cost_in_usd_cents),
is_free: false,
is_unlimited: false,
is_rate_limited: false,
has_watermark: false,
}
}
@@ -0,0 +1,18 @@
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_1_pro::PlanArtcraftKling21Pro;
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
pub(crate) fn estimate_video_cost_artcraft_kling_2_1_pro(
plan: &PlanArtcraftKling21Pro<'_>,
) -> VideoGenerationCostEstimate {
// Mirrors fal_client kling_v2p1_pro: 5s = $0.45, 10s = $0.90.
let cost_in_usd_cents: u64 = if plan.is_ten_seconds() { 90 } else { 45 };
VideoGenerationCostEstimate {
cost_in_credits: Some(cost_in_usd_cents),
cost_in_usd_cents: Some(cost_in_usd_cents),
is_free: false,
is_unlimited: false,
is_rate_limited: false,
has_watermark: false,
}
}
@@ -0,0 +1,18 @@
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_5_turbo_pro::PlanArtcraftKling2p5TurboPro;
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
pub(crate) fn estimate_video_cost_artcraft_kling_2_5_turbo_pro(
plan: &PlanArtcraftKling2p5TurboPro<'_>,
) -> VideoGenerationCostEstimate {
// Mirrors fal_client kling_v2p5_turbo_pro: 5s = $0.35, 10s = $0.70.
let cost_in_usd_cents: u64 = if plan.is_ten_seconds() { 70 } else { 35 };
VideoGenerationCostEstimate {
cost_in_credits: Some(cost_in_usd_cents),
cost_in_usd_cents: Some(cost_in_usd_cents),
is_free: false,
is_unlimited: false,
is_rate_limited: false,
has_watermark: false,
}
}
@@ -0,0 +1,26 @@
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_6_pro::PlanArtcraftKling2p6Pro;
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
pub(crate) fn estimate_video_cost_artcraft_kling_2_6_pro(
plan: &PlanArtcraftKling2p6Pro<'_>,
) -> VideoGenerationCostEstimate {
// Mirrors fal_client kling_v2p6_pro:
// audio off: $0.07/sec → 5s=35¢, 10s=70¢
// audio on: $0.14/sec → 5s=70¢, 10s=140¢
// Default duration is 5s; default generate_audio is true.
let cost_in_usd_cents: u64 = match (plan.generate_audio_for_cost(), plan.is_ten_seconds()) {
(false, false) => 35,
(false, true) => 70,
(true, false) => 70,
(true, true) => 140,
};
VideoGenerationCostEstimate {
cost_in_credits: Some(cost_in_usd_cents),
cost_in_usd_cents: Some(cost_in_usd_cents),
is_free: false,
is_unlimited: false,
is_rate_limited: false,
has_watermark: false,
}
}
@@ -1,3 +1,8 @@
pub mod estimate_video_cost_artcraft_kling_1_6_pro;
pub mod estimate_video_cost_artcraft_kling_2_1_master;
pub mod estimate_video_cost_artcraft_kling_2_1_pro;
pub mod estimate_video_cost_artcraft_kling_2_5_turbo_pro;
pub mod estimate_video_cost_artcraft_kling_2_6_pro;
pub mod estimate_video_cost_artcraft_kling3p0_pro;
pub mod estimate_video_cost_artcraft_kling3p0_standard;
pub mod estimate_video_cost_artcraft_seedance1p5_pro;
@@ -0,0 +1,37 @@
use crate::client::router_artcraft_client::RouterArtcraftClient;
use crate::errors::artcraft_router_error::ArtcraftRouterError;
use crate::errors::provider_error::ProviderError;
use crate::generate::generate_video::generate_video_response::{
ArtcraftVideoResponsePayload, GenerateVideoResponse,
};
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_1_6_pro::PlanArtcraftKling16Pro;
use artcraft_api_defs::generate::video::generate_kling_1_6_pro_image_to_video::GenerateKling16ProImageToVideoRequest;
use artcraft_client::endpoints::generate::video::generate_kling_16_pro_image_to_video::generate_kling_16_pro_image_to_video;
pub async fn execute_artcraft_kling_1_6_pro(
plan: &PlanArtcraftKling16Pro<'_>,
artcraft_client: &RouterArtcraftClient,
) -> Result<GenerateVideoResponse, ArtcraftRouterError> {
let request = GenerateKling16ProImageToVideoRequest {
uuid_idempotency_token: plan.idempotency_token.clone(),
media_file_token: Some(plan.start_frame.to_owned()),
end_frame_image_media_token: plan.end_frame.map(|t| t.to_owned()),
prompt: plan.prompt.map(|p| p.to_string()),
aspect_ratio: plan.aspect_ratio,
duration: plan.duration,
};
let response = generate_kling_16_pro_image_to_video(
&artcraft_client.api_host,
Some(&artcraft_client.credentials),
request,
)
.await
.map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?;
let all_tokens = vec![response.inference_job_token.clone()];
Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload {
inference_job_token: response.inference_job_token,
all_inference_job_tokens: all_tokens,
}))
}
@@ -0,0 +1,36 @@
use crate::client::router_artcraft_client::RouterArtcraftClient;
use crate::errors::artcraft_router_error::ArtcraftRouterError;
use crate::errors::provider_error::ProviderError;
use crate::generate::generate_video::generate_video_response::{
ArtcraftVideoResponsePayload, GenerateVideoResponse,
};
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_1_master::PlanArtcraftKling21Master;
use artcraft_api_defs::generate::video::generate_kling_2_1_master_image_to_video::GenerateKling21MasterImageToVideoRequest;
use artcraft_client::endpoints::generate::video::generate_kling_21_master_image_to_video::generate_kling_21_master_image_to_video;
pub async fn execute_artcraft_kling_2_1_master(
plan: &PlanArtcraftKling21Master<'_>,
artcraft_client: &RouterArtcraftClient,
) -> Result<GenerateVideoResponse, ArtcraftRouterError> {
let request = GenerateKling21MasterImageToVideoRequest {
uuid_idempotency_token: plan.idempotency_token.clone(),
media_file_token: Some(plan.start_frame.to_owned()),
prompt: plan.prompt.map(|p| p.to_string()),
aspect_ratio: plan.aspect_ratio,
duration: plan.duration,
};
let response = generate_kling_21_master_image_to_video(
&artcraft_client.api_host,
Some(&artcraft_client.credentials),
request,
)
.await
.map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?;
let all_tokens = vec![response.inference_job_token.clone()];
Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload {
inference_job_token: response.inference_job_token,
all_inference_job_tokens: all_tokens,
}))
}
@@ -0,0 +1,37 @@
use crate::client::router_artcraft_client::RouterArtcraftClient;
use crate::errors::artcraft_router_error::ArtcraftRouterError;
use crate::errors::provider_error::ProviderError;
use crate::generate::generate_video::generate_video_response::{
ArtcraftVideoResponsePayload, GenerateVideoResponse,
};
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_1_pro::PlanArtcraftKling21Pro;
use artcraft_api_defs::generate::video::generate_kling_2_1_pro_image_to_video::GenerateKling21ProImageToVideoRequest;
use artcraft_client::endpoints::generate::video::generate_kling_21_pro_image_to_video::generate_kling_21_pro_image_to_video;
pub async fn execute_artcraft_kling_2_1_pro(
plan: &PlanArtcraftKling21Pro<'_>,
artcraft_client: &RouterArtcraftClient,
) -> Result<GenerateVideoResponse, ArtcraftRouterError> {
let request = GenerateKling21ProImageToVideoRequest {
uuid_idempotency_token: plan.idempotency_token.clone(),
media_file_token: Some(plan.start_frame.to_owned()),
end_frame_image_media_token: plan.end_frame.map(|t| t.to_owned()),
prompt: plan.prompt.map(|p| p.to_string()),
aspect_ratio: plan.aspect_ratio,
duration: plan.duration,
};
let response = generate_kling_21_pro_image_to_video(
&artcraft_client.api_host,
Some(&artcraft_client.credentials),
request,
)
.await
.map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?;
let all_tokens = vec![response.inference_job_token.clone()];
Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload {
inference_job_token: response.inference_job_token,
all_inference_job_tokens: all_tokens,
}))
}
@@ -0,0 +1,38 @@
use crate::client::router_artcraft_client::RouterArtcraftClient;
use crate::errors::artcraft_router_error::ArtcraftRouterError;
use crate::errors::provider_error::ProviderError;
use crate::generate::generate_video::generate_video_response::{
ArtcraftVideoResponsePayload, GenerateVideoResponse,
};
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_5_turbo_pro::PlanArtcraftKling2p5TurboPro;
use artcraft_api_defs::generate::video::multi_function::kling_2_5_turbo_multi_function_video_gen::Kling2p5TurboProMultiFunctionVideoGenRequest;
use artcraft_client::endpoints::generate::video::multi_function::kling_2p5_turbo_pro_multi_function_video_gen::kling_2p5_turbo_pro_multi_function_video_gen;
pub async fn execute_artcraft_kling_2_5_turbo_pro(
plan: &PlanArtcraftKling2p5TurboPro<'_>,
artcraft_client: &RouterArtcraftClient,
) -> Result<GenerateVideoResponse, ArtcraftRouterError> {
let request = Kling2p5TurboProMultiFunctionVideoGenRequest {
uuid_idempotency_token: plan.idempotency_token.clone(),
prompt: plan.prompt.map(|p| p.to_string()),
negative_prompt: plan.negative_prompt.map(|p| p.to_string()),
start_frame_image_media_token: plan.start_frame.map(|t| t.to_owned()),
end_frame_image_media_token: plan.end_frame.map(|t| t.to_owned()),
duration: plan.duration,
aspect_ratio: plan.aspect_ratio,
};
let response = kling_2p5_turbo_pro_multi_function_video_gen(
&artcraft_client.api_host,
Some(&artcraft_client.credentials),
request,
)
.await
.map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?;
let all_tokens = vec![response.inference_job_token.clone()];
Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload {
inference_job_token: response.inference_job_token,
all_inference_job_tokens: all_tokens,
}))
}
@@ -0,0 +1,38 @@
use crate::client::router_artcraft_client::RouterArtcraftClient;
use crate::errors::artcraft_router_error::ArtcraftRouterError;
use crate::errors::provider_error::ProviderError;
use crate::generate::generate_video::generate_video_response::{
ArtcraftVideoResponsePayload, GenerateVideoResponse,
};
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_6_pro::PlanArtcraftKling2p6Pro;
use artcraft_api_defs::generate::video::multi_function::kling_2_6_multi_function_video_gen::Kling2p6ProMultiFunctionVideoGenRequest;
use artcraft_client::endpoints::generate::video::multi_function::kling_2p6_pro_multi_function_video_gen::kling_2p6_pro_multi_function_video_gen;
pub async fn execute_artcraft_kling_2_6_pro(
plan: &PlanArtcraftKling2p6Pro<'_>,
artcraft_client: &RouterArtcraftClient,
) -> Result<GenerateVideoResponse, ArtcraftRouterError> {
let request = Kling2p6ProMultiFunctionVideoGenRequest {
uuid_idempotency_token: plan.idempotency_token.clone(),
prompt: plan.prompt.map(|p| p.to_string()),
negative_prompt: plan.negative_prompt.map(|p| p.to_string()),
start_frame_image_media_token: plan.start_frame.map(|t| t.to_owned()),
duration: plan.duration,
generate_audio: plan.generate_audio,
aspect_ratio: plan.aspect_ratio,
};
let response = kling_2p6_pro_multi_function_video_gen(
&artcraft_client.api_host,
Some(&artcraft_client.credentials),
request,
)
.await
.map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?;
let all_tokens = vec![response.inference_job_token.clone()];
Ok(GenerateVideoResponse::Artcraft(ArtcraftVideoResponsePayload {
inference_job_token: response.inference_job_token,
all_inference_job_tokens: all_tokens,
}))
}
@@ -1,3 +1,8 @@
pub mod generate_video_artcraft_kling_1_6_pro;
pub mod generate_video_artcraft_kling_2_1_master;
pub mod generate_video_artcraft_kling_2_1_pro;
pub mod generate_video_artcraft_kling_2_5_turbo_pro;
pub mod generate_video_artcraft_kling_2_6_pro;
pub mod generate_video_artcraft_kling3p0_pro;
pub mod generate_video_artcraft_kling3p0_standard;
pub mod generate_video_artcraft_seedance1p5_pro;
@@ -9,6 +9,11 @@ use crate::api::provider::Provider;
use crate::api::video_list_ref::VideoListRef;
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
use crate::errors::artcraft_router_error::ArtcraftRouterError;
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_1_6_pro::plan_generate_video_artcraft_kling_1_6_pro;
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_1_master::plan_generate_video_artcraft_kling_2_1_master;
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_1_pro::plan_generate_video_artcraft_kling_2_1_pro;
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_5_turbo_pro::plan_generate_video_artcraft_kling_2_5_turbo_pro;
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_6_pro::plan_generate_video_artcraft_kling_2_6_pro;
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling3p0_pro::plan_generate_video_artcraft_kling3p0_pro;
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling3p0_standard::plan_generate_video_artcraft_kling3p0_standard;
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance1p5_pro::plan_generate_video_artcraft_seedance1p5_pro;
@@ -102,6 +107,11 @@ impl<'a> GenerateVideoRequest<'a> {
fn build_artcraft(&self) -> Result<VideoGenerationPlan<'_>, ArtcraftRouterError> {
match self.model {
CommonVideoModel::Kling16Pro => plan_generate_video_artcraft_kling_1_6_pro(self),
CommonVideoModel::Kling21Master => plan_generate_video_artcraft_kling_2_1_master(self),
CommonVideoModel::Kling21Pro => plan_generate_video_artcraft_kling_2_1_pro(self),
CommonVideoModel::Kling2p5TurboPro => plan_generate_video_artcraft_kling_2_5_turbo_pro(self),
CommonVideoModel::Kling2p6Pro => plan_generate_video_artcraft_kling_2_6_pro(self),
CommonVideoModel::Kling3p0Pro => plan_generate_video_artcraft_kling3p0_pro(self),
CommonVideoModel::Kling3p0Standard => plan_generate_video_artcraft_kling3p0_standard(self),
CommonVideoModel::Seedance1p5Pro => plan_generate_video_artcraft_seedance1p5_pro(self),
@@ -1,3 +1,8 @@
pub mod plan_generate_video_artcraft_kling_1_6_pro;
pub mod plan_generate_video_artcraft_kling_2_1_master;
pub mod plan_generate_video_artcraft_kling_2_1_pro;
pub mod plan_generate_video_artcraft_kling_2_5_turbo_pro;
pub mod plan_generate_video_artcraft_kling_2_6_pro;
pub mod plan_generate_video_artcraft_kling3p0_pro;
pub mod plan_generate_video_artcraft_kling3p0_standard;
pub mod plan_generate_video_artcraft_seedance1p5_pro;
@@ -0,0 +1,136 @@
use crate::api::common_aspect_ratio::CommonAspectRatio;
use crate::api::image_ref::ImageRef;
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
use crate::errors::artcraft_router_error::ArtcraftRouterError;
use crate::errors::client_error::ClientError;
use crate::generate::generate_video::generate_video_request::GenerateVideoRequest;
use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan;
use artcraft_api_defs::generate::video::generate_kling_1_6_pro_image_to_video::{
GenerateKling16ProAspectRatio, GenerateKling16ProDuration,
};
use tokens::tokens::media_files::MediaFileToken;
#[derive(Debug, Clone)]
pub struct PlanArtcraftKling16Pro<'a> {
pub prompt: Option<&'a str>,
pub start_frame: &'a MediaFileToken,
pub end_frame: Option<&'a MediaFileToken>,
pub aspect_ratio: Option<GenerateKling16ProAspectRatio>,
pub duration: Option<GenerateKling16ProDuration>,
pub idempotency_token: String,
}
pub fn plan_generate_video_artcraft_kling_1_6_pro<'a>(
request: &'a GenerateVideoRequest<'a>,
) -> Result<VideoGenerationPlan<'a>, ArtcraftRouterError> {
let strategy = request.request_mismatch_mitigation_strategy;
let start_frame = match request.start_frame {
Some(ImageRef::MediaFileToken(t)) => t,
Some(ImageRef::Url(_)) => {
return Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens))
}
None => {
return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
field: "start_frame",
value: "Kling 1.6 Pro requires a starting frame".to_string(),
}))
}
};
let end_frame = resolve_end_frame(request.end_frame)?;
let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?;
let duration = plan_duration(request.duration_seconds, strategy)?;
Ok(VideoGenerationPlan::ArtcraftKling16Pro(PlanArtcraftKling16Pro {
prompt: request.prompt,
start_frame,
end_frame,
aspect_ratio,
duration,
idempotency_token: request.get_or_generate_idempotency_token(),
}))
}
fn resolve_end_frame<'a>(
image_ref: Option<ImageRef<'a>>,
) -> Result<Option<&'a MediaFileToken>, ArtcraftRouterError> {
match image_ref {
None => Ok(None),
Some(ImageRef::MediaFileToken(t)) => Ok(Some(t)),
Some(ImageRef::Url(_)) => {
Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens))
}
}
}
fn plan_aspect_ratio(
aspect_ratio: Option<CommonAspectRatio>,
strategy: RequestMismatchMitigationStrategy,
) -> Result<Option<GenerateKling16ProAspectRatio>, ArtcraftRouterError> {
use GenerateKling16ProAspectRatio as Ar;
match aspect_ratio {
None => Ok(None),
Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Ar::Square)),
Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::WideSixteenNine)),
Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::TallNineSixteen)),
Some(CommonAspectRatio::Auto)
| Some(CommonAspectRatio::Auto2k)
| Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::WideSixteenNine)),
Some(unsupported) => match strategy {
RequestMismatchMitigationStrategy::ErrorOut => {
Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
field: "aspect_ratio",
value: format!("{:?}", unsupported),
}))
}
_ => Ok(Some(nearest_aspect_ratio(unsupported))),
},
}
}
fn nearest_aspect_ratio(ar: CommonAspectRatio) -> GenerateKling16ProAspectRatio {
use GenerateKling16ProAspectRatio as Ar;
match ar {
CommonAspectRatio::WideFourByThree
| CommonAspectRatio::WideFiveByFour
| CommonAspectRatio::WideThreeByTwo
| CommonAspectRatio::WideTwentyOneByNine => Ar::WideSixteenNine,
CommonAspectRatio::TallThreeByFour
| CommonAspectRatio::TallFourByFive
| CommonAspectRatio::TallTwoByThree
| CommonAspectRatio::TallNineByTwentyOne => Ar::TallNineSixteen,
_ => Ar::Square,
}
}
fn plan_duration(
duration_seconds: Option<u16>,
strategy: RequestMismatchMitigationStrategy,
) -> Result<Option<GenerateKling16ProDuration>, ArtcraftRouterError> {
use GenerateKling16ProDuration as D;
match duration_seconds {
None => Ok(None),
Some(5) => Ok(Some(D::FiveSeconds)),
Some(10) => Ok(Some(D::TenSeconds)),
Some(other) => match strategy {
RequestMismatchMitigationStrategy::ErrorOut => {
Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
field: "duration_seconds",
value: format!("{}", other),
}))
}
RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::TenSeconds)),
RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::FiveSeconds)),
},
}
}
impl PlanArtcraftKling16Pro<'_> {
pub fn is_ten_seconds(&self) -> bool {
matches!(self.duration, Some(GenerateKling16ProDuration::TenSeconds))
}
}
@@ -0,0 +1,128 @@
use crate::api::common_aspect_ratio::CommonAspectRatio;
use crate::api::image_ref::ImageRef;
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
use crate::errors::artcraft_router_error::ArtcraftRouterError;
use crate::errors::client_error::ClientError;
use crate::generate::generate_video::generate_video_request::GenerateVideoRequest;
use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan;
use artcraft_api_defs::generate::video::generate_kling_2_1_master_image_to_video::{
GenerateKling21MasterAspectRatio, GenerateKling21MasterDuration,
};
use tokens::tokens::media_files::MediaFileToken;
#[derive(Debug, Clone)]
pub struct PlanArtcraftKling21Master<'a> {
pub prompt: Option<&'a str>,
pub start_frame: &'a MediaFileToken,
pub aspect_ratio: Option<GenerateKling21MasterAspectRatio>,
pub duration: Option<GenerateKling21MasterDuration>,
pub idempotency_token: String,
}
pub fn plan_generate_video_artcraft_kling_2_1_master<'a>(
request: &'a GenerateVideoRequest<'a>,
) -> Result<VideoGenerationPlan<'a>, ArtcraftRouterError> {
let strategy = request.request_mismatch_mitigation_strategy;
let start_frame = match request.start_frame {
Some(ImageRef::MediaFileToken(t)) => t,
Some(ImageRef::Url(_)) => {
return Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens))
}
None => {
return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
field: "start_frame",
value: "Kling 2.1 Master requires a starting frame".to_string(),
}))
}
};
if request.end_frame.is_some() {
return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
field: "end_frame",
value: "Kling 2.1 Master does not support an ending frame".to_string(),
}));
}
let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?;
let duration = plan_duration(request.duration_seconds, strategy)?;
Ok(VideoGenerationPlan::ArtcraftKling21Master(PlanArtcraftKling21Master {
prompt: request.prompt,
start_frame,
aspect_ratio,
duration,
idempotency_token: request.get_or_generate_idempotency_token(),
}))
}
fn plan_aspect_ratio(
aspect_ratio: Option<CommonAspectRatio>,
strategy: RequestMismatchMitigationStrategy,
) -> Result<Option<GenerateKling21MasterAspectRatio>, ArtcraftRouterError> {
use GenerateKling21MasterAspectRatio as Ar;
match aspect_ratio {
None => Ok(None),
Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Ar::Square)),
Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::WideSixteenNine)),
Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::TallNineSixteen)),
Some(CommonAspectRatio::Auto)
| Some(CommonAspectRatio::Auto2k)
| Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::WideSixteenNine)),
Some(unsupported) => match strategy {
RequestMismatchMitigationStrategy::ErrorOut => {
Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
field: "aspect_ratio",
value: format!("{:?}", unsupported),
}))
}
_ => Ok(Some(nearest_aspect_ratio(unsupported))),
},
}
}
fn nearest_aspect_ratio(ar: CommonAspectRatio) -> GenerateKling21MasterAspectRatio {
use GenerateKling21MasterAspectRatio as Ar;
match ar {
CommonAspectRatio::WideFourByThree
| CommonAspectRatio::WideFiveByFour
| CommonAspectRatio::WideThreeByTwo
| CommonAspectRatio::WideTwentyOneByNine => Ar::WideSixteenNine,
CommonAspectRatio::TallThreeByFour
| CommonAspectRatio::TallFourByFive
| CommonAspectRatio::TallTwoByThree
| CommonAspectRatio::TallNineByTwentyOne => Ar::TallNineSixteen,
_ => Ar::Square,
}
}
fn plan_duration(
duration_seconds: Option<u16>,
strategy: RequestMismatchMitigationStrategy,
) -> Result<Option<GenerateKling21MasterDuration>, ArtcraftRouterError> {
use GenerateKling21MasterDuration as D;
match duration_seconds {
None => Ok(None),
Some(5) => Ok(Some(D::FiveSeconds)),
Some(10) => Ok(Some(D::TenSeconds)),
Some(other) => match strategy {
RequestMismatchMitigationStrategy::ErrorOut => {
Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
field: "duration_seconds",
value: format!("{}", other),
}))
}
RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::TenSeconds)),
RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::FiveSeconds)),
},
}
}
impl PlanArtcraftKling21Master<'_> {
pub fn is_ten_seconds(&self) -> bool {
matches!(self.duration, Some(GenerateKling21MasterDuration::TenSeconds))
}
}
@@ -0,0 +1,136 @@
use crate::api::common_aspect_ratio::CommonAspectRatio;
use crate::api::image_ref::ImageRef;
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
use crate::errors::artcraft_router_error::ArtcraftRouterError;
use crate::errors::client_error::ClientError;
use crate::generate::generate_video::generate_video_request::GenerateVideoRequest;
use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan;
use artcraft_api_defs::generate::video::generate_kling_2_1_pro_image_to_video::{
GenerateKling21ProAspectRatio, GenerateKling21ProDuration,
};
use tokens::tokens::media_files::MediaFileToken;
#[derive(Debug, Clone)]
pub struct PlanArtcraftKling21Pro<'a> {
pub prompt: Option<&'a str>,
pub start_frame: &'a MediaFileToken,
pub end_frame: Option<&'a MediaFileToken>,
pub aspect_ratio: Option<GenerateKling21ProAspectRatio>,
pub duration: Option<GenerateKling21ProDuration>,
pub idempotency_token: String,
}
pub fn plan_generate_video_artcraft_kling_2_1_pro<'a>(
request: &'a GenerateVideoRequest<'a>,
) -> Result<VideoGenerationPlan<'a>, ArtcraftRouterError> {
let strategy = request.request_mismatch_mitigation_strategy;
let start_frame = match request.start_frame {
Some(ImageRef::MediaFileToken(t)) => t,
Some(ImageRef::Url(_)) => {
return Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens))
}
None => {
return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
field: "start_frame",
value: "Kling 2.1 Pro requires a starting frame".to_string(),
}))
}
};
let end_frame = resolve_end_frame(request.end_frame)?;
let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?;
let duration = plan_duration(request.duration_seconds, strategy)?;
Ok(VideoGenerationPlan::ArtcraftKling21Pro(PlanArtcraftKling21Pro {
prompt: request.prompt,
start_frame,
end_frame,
aspect_ratio,
duration,
idempotency_token: request.get_or_generate_idempotency_token(),
}))
}
fn resolve_end_frame<'a>(
image_ref: Option<ImageRef<'a>>,
) -> Result<Option<&'a MediaFileToken>, ArtcraftRouterError> {
match image_ref {
None => Ok(None),
Some(ImageRef::MediaFileToken(t)) => Ok(Some(t)),
Some(ImageRef::Url(_)) => {
Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens))
}
}
}
fn plan_aspect_ratio(
aspect_ratio: Option<CommonAspectRatio>,
strategy: RequestMismatchMitigationStrategy,
) -> Result<Option<GenerateKling21ProAspectRatio>, ArtcraftRouterError> {
use GenerateKling21ProAspectRatio as Ar;
match aspect_ratio {
None => Ok(None),
Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Ar::Square)),
Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::WideSixteenNine)),
Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::TallNineSixteen)),
Some(CommonAspectRatio::Auto)
| Some(CommonAspectRatio::Auto2k)
| Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::WideSixteenNine)),
Some(unsupported) => match strategy {
RequestMismatchMitigationStrategy::ErrorOut => {
Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
field: "aspect_ratio",
value: format!("{:?}", unsupported),
}))
}
_ => Ok(Some(nearest_aspect_ratio(unsupported))),
},
}
}
fn nearest_aspect_ratio(ar: CommonAspectRatio) -> GenerateKling21ProAspectRatio {
use GenerateKling21ProAspectRatio as Ar;
match ar {
CommonAspectRatio::WideFourByThree
| CommonAspectRatio::WideFiveByFour
| CommonAspectRatio::WideThreeByTwo
| CommonAspectRatio::WideTwentyOneByNine => Ar::WideSixteenNine,
CommonAspectRatio::TallThreeByFour
| CommonAspectRatio::TallFourByFive
| CommonAspectRatio::TallTwoByThree
| CommonAspectRatio::TallNineByTwentyOne => Ar::TallNineSixteen,
_ => Ar::Square,
}
}
fn plan_duration(
duration_seconds: Option<u16>,
strategy: RequestMismatchMitigationStrategy,
) -> Result<Option<GenerateKling21ProDuration>, ArtcraftRouterError> {
use GenerateKling21ProDuration as D;
match duration_seconds {
None => Ok(None),
Some(5) => Ok(Some(D::FiveSeconds)),
Some(10) => Ok(Some(D::TenSeconds)),
Some(other) => match strategy {
RequestMismatchMitigationStrategy::ErrorOut => {
Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
field: "duration_seconds",
value: format!("{}", other),
}))
}
RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::TenSeconds)),
RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::FiveSeconds)),
},
}
}
impl PlanArtcraftKling21Pro<'_> {
pub fn is_ten_seconds(&self) -> bool {
matches!(self.duration, Some(GenerateKling21ProDuration::TenSeconds))
}
}
@@ -0,0 +1,127 @@
use crate::api::common_aspect_ratio::CommonAspectRatio;
use crate::api::image_ref::ImageRef;
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
use crate::errors::artcraft_router_error::ArtcraftRouterError;
use crate::errors::client_error::ClientError;
use crate::generate::generate_video::generate_video_request::GenerateVideoRequest;
use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan;
use artcraft_api_defs::generate::video::multi_function::kling_2_5_turbo_multi_function_video_gen::{
Kling2p5TurboProMultiFunctionVideoGenAspectRatio, Kling2p5TurboProMultiFunctionVideoGenDuration,
};
use tokens::tokens::media_files::MediaFileToken;
#[derive(Debug, Clone)]
pub struct PlanArtcraftKling2p5TurboPro<'a> {
pub prompt: Option<&'a str>,
pub negative_prompt: Option<&'a str>,
pub start_frame: Option<&'a MediaFileToken>,
pub end_frame: Option<&'a MediaFileToken>,
pub aspect_ratio: Option<Kling2p5TurboProMultiFunctionVideoGenAspectRatio>,
pub duration: Option<Kling2p5TurboProMultiFunctionVideoGenDuration>,
pub idempotency_token: String,
}
pub fn plan_generate_video_artcraft_kling_2_5_turbo_pro<'a>(
request: &'a GenerateVideoRequest<'a>,
) -> Result<VideoGenerationPlan<'a>, ArtcraftRouterError> {
let strategy = request.request_mismatch_mitigation_strategy;
let start_frame = resolve_image_ref(request.start_frame)?;
let end_frame = resolve_image_ref(request.end_frame)?;
let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?;
let duration = plan_duration(request.duration_seconds, strategy)?;
Ok(VideoGenerationPlan::ArtcraftKling2p5TurboPro(PlanArtcraftKling2p5TurboPro {
prompt: request.prompt,
negative_prompt: request.negative_prompt,
start_frame,
end_frame,
aspect_ratio,
duration,
idempotency_token: request.get_or_generate_idempotency_token(),
}))
}
fn resolve_image_ref<'a>(
image_ref: Option<ImageRef<'a>>,
) -> Result<Option<&'a MediaFileToken>, ArtcraftRouterError> {
match image_ref {
None => Ok(None),
Some(ImageRef::MediaFileToken(t)) => Ok(Some(t)),
Some(ImageRef::Url(_)) => {
Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens))
}
}
}
fn plan_aspect_ratio(
aspect_ratio: Option<CommonAspectRatio>,
strategy: RequestMismatchMitigationStrategy,
) -> Result<Option<Kling2p5TurboProMultiFunctionVideoGenAspectRatio>, ArtcraftRouterError> {
use Kling2p5TurboProMultiFunctionVideoGenAspectRatio as Ar;
match aspect_ratio {
None => Ok(None),
Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Ar::Square)),
Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)),
Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)),
Some(CommonAspectRatio::Auto)
| Some(CommonAspectRatio::Auto2k)
| Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::SixteenByNine)),
Some(unsupported) => match strategy {
RequestMismatchMitigationStrategy::ErrorOut => {
Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
field: "aspect_ratio",
value: format!("{:?}", unsupported),
}))
}
_ => Ok(Some(nearest_aspect_ratio(unsupported))),
},
}
}
fn nearest_aspect_ratio(ar: CommonAspectRatio) -> Kling2p5TurboProMultiFunctionVideoGenAspectRatio {
use Kling2p5TurboProMultiFunctionVideoGenAspectRatio as Ar;
match ar {
CommonAspectRatio::WideFourByThree
| CommonAspectRatio::WideFiveByFour
| CommonAspectRatio::WideThreeByTwo
| CommonAspectRatio::WideTwentyOneByNine => Ar::SixteenByNine,
CommonAspectRatio::TallThreeByFour
| CommonAspectRatio::TallFourByFive
| CommonAspectRatio::TallTwoByThree
| CommonAspectRatio::TallNineByTwentyOne => Ar::NineBySixteen,
_ => Ar::Square,
}
}
fn plan_duration(
duration_seconds: Option<u16>,
strategy: RequestMismatchMitigationStrategy,
) -> Result<Option<Kling2p5TurboProMultiFunctionVideoGenDuration>, ArtcraftRouterError> {
use Kling2p5TurboProMultiFunctionVideoGenDuration as D;
match duration_seconds {
None => Ok(None),
Some(5) => Ok(Some(D::FiveSeconds)),
Some(10) => Ok(Some(D::TenSeconds)),
Some(other) => match strategy {
RequestMismatchMitigationStrategy::ErrorOut => {
Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
field: "duration_seconds",
value: format!("{}", other),
}))
}
RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::TenSeconds)),
RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::FiveSeconds)),
},
}
}
impl PlanArtcraftKling2p5TurboPro<'_> {
pub fn is_ten_seconds(&self) -> bool {
matches!(self.duration, Some(Kling2p5TurboProMultiFunctionVideoGenDuration::TenSeconds))
}
}
@@ -0,0 +1,133 @@
use crate::api::common_aspect_ratio::CommonAspectRatio;
use crate::api::image_ref::ImageRef;
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
use crate::errors::artcraft_router_error::ArtcraftRouterError;
use crate::errors::client_error::ClientError;
use crate::generate::generate_video::generate_video_request::GenerateVideoRequest;
use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan;
use artcraft_api_defs::generate::video::multi_function::kling_2_6_multi_function_video_gen::{
Kling2p6ProMultiFunctionVideoGenAspectRatio, Kling2p6ProMultiFunctionVideoGenDuration,
};
use tokens::tokens::media_files::MediaFileToken;
#[derive(Debug, Clone)]
pub struct PlanArtcraftKling2p6Pro<'a> {
pub prompt: Option<&'a str>,
pub negative_prompt: Option<&'a str>,
pub start_frame: Option<&'a MediaFileToken>,
pub aspect_ratio: Option<Kling2p6ProMultiFunctionVideoGenAspectRatio>,
pub duration: Option<Kling2p6ProMultiFunctionVideoGenDuration>,
pub generate_audio: Option<bool>,
pub idempotency_token: String,
}
pub fn plan_generate_video_artcraft_kling_2_6_pro<'a>(
request: &'a GenerateVideoRequest<'a>,
) -> Result<VideoGenerationPlan<'a>, ArtcraftRouterError> {
let strategy = request.request_mismatch_mitigation_strategy;
let start_frame = match request.start_frame {
None => None,
Some(ImageRef::MediaFileToken(t)) => Some(t),
Some(ImageRef::Url(_)) => {
return Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens))
}
};
if request.end_frame.is_some() {
return Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
field: "end_frame",
value: "Kling 2.6 Pro does not support an ending frame".to_string(),
}));
}
let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?;
let duration = plan_duration(request.duration_seconds, strategy)?;
Ok(VideoGenerationPlan::ArtcraftKling2p6Pro(PlanArtcraftKling2p6Pro {
prompt: request.prompt,
negative_prompt: request.negative_prompt,
start_frame,
aspect_ratio,
duration,
generate_audio: request.generate_audio,
idempotency_token: request.get_or_generate_idempotency_token(),
}))
}
fn plan_aspect_ratio(
aspect_ratio: Option<CommonAspectRatio>,
strategy: RequestMismatchMitigationStrategy,
) -> Result<Option<Kling2p6ProMultiFunctionVideoGenAspectRatio>, ArtcraftRouterError> {
use Kling2p6ProMultiFunctionVideoGenAspectRatio as Ar;
match aspect_ratio {
None => Ok(None),
Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Ar::Square)),
Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)),
Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)),
Some(CommonAspectRatio::Auto)
| Some(CommonAspectRatio::Auto2k)
| Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::SixteenByNine)),
Some(unsupported) => match strategy {
RequestMismatchMitigationStrategy::ErrorOut => {
Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
field: "aspect_ratio",
value: format!("{:?}", unsupported),
}))
}
_ => Ok(Some(nearest_aspect_ratio(unsupported))),
},
}
}
fn nearest_aspect_ratio(ar: CommonAspectRatio) -> Kling2p6ProMultiFunctionVideoGenAspectRatio {
use Kling2p6ProMultiFunctionVideoGenAspectRatio as Ar;
match ar {
CommonAspectRatio::WideFourByThree
| CommonAspectRatio::WideFiveByFour
| CommonAspectRatio::WideThreeByTwo
| CommonAspectRatio::WideTwentyOneByNine => Ar::SixteenByNine,
CommonAspectRatio::TallThreeByFour
| CommonAspectRatio::TallFourByFive
| CommonAspectRatio::TallTwoByThree
| CommonAspectRatio::TallNineByTwentyOne => Ar::NineBySixteen,
_ => Ar::Square,
}
}
fn plan_duration(
duration_seconds: Option<u16>,
strategy: RequestMismatchMitigationStrategy,
) -> Result<Option<Kling2p6ProMultiFunctionVideoGenDuration>, ArtcraftRouterError> {
use Kling2p6ProMultiFunctionVideoGenDuration as D;
match duration_seconds {
None => Ok(None),
Some(5) => Ok(Some(D::FiveSeconds)),
Some(10) => Ok(Some(D::TenSeconds)),
Some(other) => match strategy {
RequestMismatchMitigationStrategy::ErrorOut => {
Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
field: "duration_seconds",
value: format!("{}", other),
}))
}
RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(D::TenSeconds)),
RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(D::FiveSeconds)),
},
}
}
impl PlanArtcraftKling2p6Pro<'_> {
pub fn is_ten_seconds(&self) -> bool {
matches!(self.duration, Some(Kling2p6ProMultiFunctionVideoGenDuration::TenSeconds))
}
/// Legacy Kling 2.6 Pro generate handler forwards `request.generate_audio` as-is
/// to the Fal client, which defaults to `true`.
pub fn generate_audio_for_cost(&self) -> bool {
self.generate_audio.unwrap_or(true)
}
}
@@ -1,5 +1,10 @@
use crate::client::router_client::RouterClient;
use crate::errors::artcraft_router_error::ArtcraftRouterError;
use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_kling_1_6_pro::estimate_video_cost_artcraft_kling_1_6_pro;
use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_kling_2_1_master::estimate_video_cost_artcraft_kling_2_1_master;
use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_kling_2_1_pro::estimate_video_cost_artcraft_kling_2_1_pro;
use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_kling_2_5_turbo_pro::estimate_video_cost_artcraft_kling_2_5_turbo_pro;
use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_kling_2_6_pro::estimate_video_cost_artcraft_kling_2_6_pro;
use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_kling3p0_pro::estimate_video_cost_artcraft_kling3p0_pro;
use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_kling3p0_standard::estimate_video_cost_artcraft_kling3p0_standard;
use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_seedance1p5_pro::estimate_video_cost_artcraft_seedance1p5_pro;
@@ -16,6 +21,11 @@ use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_veo_3p1:
use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_veo_3p1_fast::estimate_video_cost_fal_veo_3p1_fast;
use crate::generate::generate_video::cost::muapi::estimate_video_cost_muapi_seedance2p0::estimate_video_cost_muapi_seedance2p0;
use crate::generate::generate_video::cost::seedance2pro::estimate_video_cost_seedance2pro_seedance2p0::estimate_video_cost_seedance2pro_seedance2p0;
use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_kling_1_6_pro::execute_artcraft_kling_1_6_pro;
use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_kling_2_1_master::execute_artcraft_kling_2_1_master;
use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_kling_2_1_pro::execute_artcraft_kling_2_1_pro;
use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_kling_2_5_turbo_pro::execute_artcraft_kling_2_5_turbo_pro;
use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_kling_2_6_pro::execute_artcraft_kling_2_6_pro;
use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_kling3p0_pro::execute_artcraft_kling3p0_pro;
use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_kling3p0_standard::execute_artcraft_kling3p0_standard;
use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_seedance1p5_pro::execute_artcraft_seedance1p5_pro;
@@ -33,6 +43,11 @@ use crate::generate::generate_video::execute::fal::generate_video_fal_veo_3p1_fa
use crate::generate::generate_video::execute::muapi::execute_muapi_seedance2p0::execute_muapi_seedance2p0;
use crate::generate::generate_video::execute::seedance2pro::execute_seedance2pro_seedance2p0::execute_seedance2pro_seedance2p0;
use crate::generate::generate_video::generate_video_response::GenerateVideoResponse;
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_1_6_pro::PlanArtcraftKling16Pro;
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_1_master::PlanArtcraftKling21Master;
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_1_pro::PlanArtcraftKling21Pro;
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_5_turbo_pro::PlanArtcraftKling2p5TurboPro;
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling_2_6_pro::PlanArtcraftKling2p6Pro;
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling3p0_pro::PlanArtcraftKling3p0Pro;
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_kling3p0_standard::PlanArtcraftKling3p0Standard;
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance1p5_pro::PlanArtcraftSeedance1p5Pro;
@@ -53,6 +68,11 @@ use crate::generate::generate_video::video_generation_cost_estimate::VideoGenera
#[derive(Debug)]
pub enum VideoGenerationPlan<'a> {
ArtcraftKling16Pro(PlanArtcraftKling16Pro<'a>),
ArtcraftKling21Master(PlanArtcraftKling21Master<'a>),
ArtcraftKling21Pro(PlanArtcraftKling21Pro<'a>),
ArtcraftKling2p5TurboPro(PlanArtcraftKling2p5TurboPro<'a>),
ArtcraftKling2p6Pro(PlanArtcraftKling2p6Pro<'a>),
ArtcraftKling3p0Pro(PlanArtcraftKling3p0Pro<'a>),
ArtcraftKling3p0Standard(PlanArtcraftKling3p0Standard<'a>),
ArtcraftSeedance1p5Pro(PlanArtcraftSeedance1p5Pro<'a>),
@@ -77,6 +97,26 @@ impl<'a> VideoGenerationPlan<'a> {
client: &RouterClient,
) -> Result<GenerateVideoResponse, ArtcraftRouterError> {
match self {
VideoGenerationPlan::ArtcraftKling16Pro(plan) => {
let artcraft_client = client.get_artcraft_client_ref()?;
execute_artcraft_kling_1_6_pro(plan, artcraft_client).await
}
VideoGenerationPlan::ArtcraftKling21Master(plan) => {
let artcraft_client = client.get_artcraft_client_ref()?;
execute_artcraft_kling_2_1_master(plan, artcraft_client).await
}
VideoGenerationPlan::ArtcraftKling21Pro(plan) => {
let artcraft_client = client.get_artcraft_client_ref()?;
execute_artcraft_kling_2_1_pro(plan, artcraft_client).await
}
VideoGenerationPlan::ArtcraftKling2p5TurboPro(plan) => {
let artcraft_client = client.get_artcraft_client_ref()?;
execute_artcraft_kling_2_5_turbo_pro(plan, artcraft_client).await
}
VideoGenerationPlan::ArtcraftKling2p6Pro(plan) => {
let artcraft_client = client.get_artcraft_client_ref()?;
execute_artcraft_kling_2_6_pro(plan, artcraft_client).await
}
VideoGenerationPlan::ArtcraftKling3p0Pro(plan) => {
let artcraft_client = client.get_artcraft_client_ref()?;
execute_artcraft_kling3p0_pro(plan, artcraft_client).await
@@ -146,6 +186,11 @@ impl<'a> VideoGenerationPlan<'a> {
pub fn estimate_costs(&self) -> VideoGenerationCostEstimate {
match self {
VideoGenerationPlan::ArtcraftKling16Pro(plan) => estimate_video_cost_artcraft_kling_1_6_pro(plan),
VideoGenerationPlan::ArtcraftKling21Master(plan) => estimate_video_cost_artcraft_kling_2_1_master(plan),
VideoGenerationPlan::ArtcraftKling21Pro(plan) => estimate_video_cost_artcraft_kling_2_1_pro(plan),
VideoGenerationPlan::ArtcraftKling2p5TurboPro(plan) => estimate_video_cost_artcraft_kling_2_5_turbo_pro(plan),
VideoGenerationPlan::ArtcraftKling2p6Pro(plan) => estimate_video_cost_artcraft_kling_2_6_pro(plan),
VideoGenerationPlan::ArtcraftKling3p0Pro(plan) => {
estimate_video_cost_artcraft_kling3p0_pro(plan)
}