mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-10 03:51:25 +00:00
veo endpoints
This commit is contained in:
1 parent
9c79025044
commit
f1b22b564d
28 files changed
+1346
-12
No files matched your search
+20
@@ -0,0 +1,20 @@
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_2::PlanFalVeo2;
|
||||
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
|
||||
|
||||
pub(crate) fn estimate_video_cost_fal_veo_2(
|
||||
plan: &PlanFalVeo2,
|
||||
) -> VideoGenerationCostEstimate {
|
||||
// 5s = $2.50, +$0.50 per additional second.
|
||||
let seconds = plan.duration_seconds_for_cost();
|
||||
let extra = seconds.saturating_sub(5);
|
||||
let cost_in_usd_cents = 250 + extra * 50;
|
||||
|
||||
VideoGenerationCostEstimate {
|
||||
cost_in_credits: Some(cost_in_usd_cents),
|
||||
cost_in_usd_cents: Some(cost_in_usd_cents),
|
||||
is_free: false,
|
||||
is_unlimited: false,
|
||||
is_rate_limited: false,
|
||||
has_watermark: false,
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3::PlanFalVeo3;
|
||||
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
|
||||
|
||||
pub(crate) fn estimate_video_cost_fal_veo_3(
|
||||
plan: &PlanFalVeo3,
|
||||
) -> VideoGenerationCostEstimate {
|
||||
// $0.20/sec audio off, $0.40/sec audio on (720p/1080p).
|
||||
let seconds = plan.duration_seconds_for_cost();
|
||||
let per_second_cents: u64 = if plan.generate_audio { 40 } else { 20 };
|
||||
let cost_in_usd_cents = per_second_cents * seconds;
|
||||
|
||||
VideoGenerationCostEstimate {
|
||||
cost_in_credits: Some(cost_in_usd_cents),
|
||||
cost_in_usd_cents: Some(cost_in_usd_cents),
|
||||
is_free: false,
|
||||
is_unlimited: false,
|
||||
is_rate_limited: false,
|
||||
has_watermark: false,
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3_fast::PlanFalVeo3Fast;
|
||||
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
|
||||
|
||||
pub(crate) fn estimate_video_cost_fal_veo_3_fast(
|
||||
plan: &PlanFalVeo3Fast,
|
||||
) -> VideoGenerationCostEstimate {
|
||||
// $0.10/sec audio off, $0.15/sec audio on (720p/1080p).
|
||||
let seconds = plan.duration_seconds_for_cost();
|
||||
let per_second_cents: u64 = if plan.generate_audio { 15 } else { 10 };
|
||||
let cost_in_usd_cents = per_second_cents * seconds;
|
||||
|
||||
VideoGenerationCostEstimate {
|
||||
cost_in_credits: Some(cost_in_usd_cents),
|
||||
cost_in_usd_cents: Some(cost_in_usd_cents),
|
||||
is_free: false,
|
||||
is_unlimited: false,
|
||||
is_rate_limited: false,
|
||||
has_watermark: false,
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1::PlanFalVeo3p1;
|
||||
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
|
||||
|
||||
pub(crate) fn estimate_video_cost_fal_veo_3p1(
|
||||
plan: &PlanFalVeo3p1,
|
||||
) -> VideoGenerationCostEstimate {
|
||||
// $0.20/sec audio off, $0.40/sec audio on (720p/1080p).
|
||||
let seconds = plan.duration_seconds_for_cost();
|
||||
let per_second_cents: u64 = if plan.generate_audio_for_cost() { 40 } else { 20 };
|
||||
let cost_in_usd_cents = per_second_cents * seconds;
|
||||
|
||||
VideoGenerationCostEstimate {
|
||||
cost_in_credits: Some(cost_in_usd_cents),
|
||||
cost_in_usd_cents: Some(cost_in_usd_cents),
|
||||
is_free: false,
|
||||
is_unlimited: false,
|
||||
is_rate_limited: false,
|
||||
has_watermark: false,
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1_fast::PlanFalVeo3p1Fast;
|
||||
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
|
||||
|
||||
pub(crate) fn estimate_video_cost_fal_veo_3p1_fast(
|
||||
plan: &PlanFalVeo3p1Fast,
|
||||
) -> VideoGenerationCostEstimate {
|
||||
// $0.10/sec audio off, $0.15/sec audio on (720p/1080p).
|
||||
let seconds = plan.inner.duration_seconds_for_cost();
|
||||
let per_second_cents: u64 = if plan.inner.generate_audio_for_cost() { 15 } else { 10 };
|
||||
let cost_in_usd_cents = per_second_cents * seconds;
|
||||
|
||||
VideoGenerationCostEstimate {
|
||||
cost_in_credits: Some(cost_in_usd_cents),
|
||||
cost_in_usd_cents: Some(cost_in_usd_cents),
|
||||
is_free: false,
|
||||
is_unlimited: false,
|
||||
is_rate_limited: false,
|
||||
has_watermark: false,
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
pub(crate) mod estimate_video_cost_fal_veo_2;
|
||||
pub(crate) mod estimate_video_cost_fal_veo_3;
|
||||
pub(crate) mod estimate_video_cost_fal_veo_3_fast;
|
||||
pub(crate) mod estimate_video_cost_fal_veo_3p1;
|
||||
pub(crate) mod estimate_video_cost_fal_veo_3p1_fast;
|
||||
@@ -1,3 +1,4 @@
|
||||
pub (crate) mod artcraft;
|
||||
pub (crate) mod fal;
|
||||
pub (crate) mod muapi;
|
||||
pub (crate) mod seedance2pro;
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
use crate::generate::generate_video::generate_video_response::{
|
||||
FalVideoResponsePayload, GenerateVideoResponse,
|
||||
};
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_2::PlanFalVeo2;
|
||||
use fal_client::requests::webhook::video::image::enqueue_veo_2_image_to_video_webhook::{
|
||||
enqueue_veo_2_image_to_video_webhook, Veo2Args,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_veo_2(
|
||||
plan: &PlanFalVeo2,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateVideoResponse, ArtcraftRouterError> {
|
||||
let args = Veo2Args {
|
||||
image_url: plan.start_frame_url.as_str(),
|
||||
prompt: plan.prompt.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
duration: plan.duration,
|
||||
aspect_ratio: plan.aspect_ratio,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
};
|
||||
|
||||
let webhook_response = enqueue_veo_2_image_to_video_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
|
||||
Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
}))
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
use crate::generate::generate_video::generate_video_response::{
|
||||
FalVideoResponsePayload, GenerateVideoResponse,
|
||||
};
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3::PlanFalVeo3;
|
||||
use fal_client::requests::webhook::video::image::enqueue_veo_3_image_to_video_webhook::{
|
||||
enqueue_veo_3_image_to_video_webhook, Veo3Args,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_veo_3(
|
||||
plan: &PlanFalVeo3,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateVideoResponse, ArtcraftRouterError> {
|
||||
let args = Veo3Args {
|
||||
image_url: plan.start_frame_url.as_str(),
|
||||
prompt: plan.prompt.as_str(),
|
||||
duration: plan.duration,
|
||||
aspect_ratio: plan.aspect_ratio,
|
||||
resolution: plan.resolution,
|
||||
generate_audio: plan.generate_audio,
|
||||
api_key: &fal_client.api_key,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
};
|
||||
|
||||
let webhook_response = enqueue_veo_3_image_to_video_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
|
||||
Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
}))
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
use crate::generate::generate_video::generate_video_response::{
|
||||
FalVideoResponsePayload, GenerateVideoResponse,
|
||||
};
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3_fast::PlanFalVeo3Fast;
|
||||
use fal_client::requests::webhook::video::image::enqueue_veo_3_fast_image_to_video_webhook::{
|
||||
enqueue_veo_3_fast_image_to_video_webhook, Veo3FastArgs,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_veo_3_fast(
|
||||
plan: &PlanFalVeo3Fast,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateVideoResponse, ArtcraftRouterError> {
|
||||
let args = Veo3FastArgs {
|
||||
prompt: plan.prompt.as_str(),
|
||||
image_url: plan.start_frame_url.as_str(),
|
||||
duration: plan.duration,
|
||||
api_key: &fal_client.api_key,
|
||||
resolution: plan.resolution,
|
||||
generate_audio: plan.generate_audio,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
};
|
||||
|
||||
let webhook_response = enqueue_veo_3_fast_image_to_video_webhook(args)
|
||||
.await
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
|
||||
Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
}))
|
||||
}
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
use crate::generate::generate_video::generate_video_response::{
|
||||
FalVideoResponsePayload, GenerateVideoResponse,
|
||||
};
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1::{
|
||||
FalVeo3p1AspectRatio, FalVeo3p1Duration, FalVeo3p1Mode, FalVeo3p1Resolution, PlanFalVeo3p1,
|
||||
};
|
||||
use fal_client::requests::webhook::video::image::enqueue_veo_3p1_first_last_frame_image_to_video_webhook::{
|
||||
enqueue_veo_3p1_first_last_frame_image_to_video_webhook,
|
||||
EnqueueVeo3p1FirstLastFrameImageToVideoArgs,
|
||||
EnqueueVeo3p1FirstLastFrameImageToVideoAspectRatio,
|
||||
EnqueueVeo3p1FirstLastFrameImageToVideoDurationSeconds,
|
||||
EnqueueVeo3p1FirstLastFrameImageToVideoResolution,
|
||||
};
|
||||
use fal_client::requests::webhook::video::image::enqueue_veo_3p1_image_to_video_webhook::{
|
||||
enqueue_veo_3p1_image_to_video_webhook, EnqueueVeo3p1ImageToVideoArgs,
|
||||
EnqueueVeo3p1ImageToVideoAspectRatio, EnqueueVeo3p1ImageToVideoDurationSeconds,
|
||||
EnqueueVeo3p1ImageToVideoResolution,
|
||||
};
|
||||
use fal_client::requests::webhook::video::text::enqueue_veo_3p1_text_to_video_webhook::{
|
||||
enqueue_veo_3p1_text_to_video_webhook, EnqueueVeo3p1TextToVideoArgs,
|
||||
EnqueueVeo3p1TextToVideoAspectRatio, EnqueueVeo3p1TextToVideoDurationSeconds,
|
||||
EnqueueVeo3p1TextToVideoResolution,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_veo_3p1(
|
||||
plan: &PlanFalVeo3p1,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateVideoResponse, ArtcraftRouterError> {
|
||||
let webhook_response = match &plan.mode {
|
||||
FalVeo3p1Mode::TextToVideo => {
|
||||
let args = EnqueueVeo3p1TextToVideoArgs {
|
||||
prompt: plan.prompt.clone(),
|
||||
duration: plan.duration.map(to_t2v_duration),
|
||||
aspect_ratio: plan.aspect_ratio.map(to_t2v_aspect_ratio),
|
||||
resolution: plan.resolution.map(to_t2v_resolution),
|
||||
generate_audio: plan.generate_audio,
|
||||
enhance_prompt: None,
|
||||
negative_prompt: plan.negative_prompt.clone(),
|
||||
seed: None,
|
||||
auto_fix: None,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_veo_3p1_text_to_video_webhook(args).await
|
||||
}
|
||||
FalVeo3p1Mode::ImageToVideo { start_frame_url } => {
|
||||
let args = EnqueueVeo3p1ImageToVideoArgs {
|
||||
prompt: plan.prompt.clone(),
|
||||
image_url: start_frame_url.clone(),
|
||||
duration: plan.duration.map(to_i2v_duration),
|
||||
aspect_ratio: plan.aspect_ratio.map(to_i2v_aspect_ratio),
|
||||
resolution: plan.resolution.map(to_i2v_resolution),
|
||||
generate_audio: plan.generate_audio,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_veo_3p1_image_to_video_webhook(args).await
|
||||
}
|
||||
FalVeo3p1Mode::FirstLastFrame { first_frame_url, last_frame_url } => {
|
||||
let args = EnqueueVeo3p1FirstLastFrameImageToVideoArgs {
|
||||
prompt: plan.prompt.clone(),
|
||||
first_frame_url: first_frame_url.clone(),
|
||||
last_frame_url: last_frame_url.clone(),
|
||||
duration: plan.duration.map(to_flf_duration),
|
||||
aspect_ratio: plan.aspect_ratio.map(to_flf_aspect_ratio),
|
||||
resolution: plan.resolution.map(to_flf_resolution),
|
||||
generate_audio: plan.generate_audio,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_veo_3p1_first_last_frame_image_to_video_webhook(args).await
|
||||
}
|
||||
};
|
||||
|
||||
let webhook_response = webhook_response
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
|
||||
Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
}))
|
||||
}
|
||||
|
||||
fn to_t2v_duration(d: FalVeo3p1Duration) -> EnqueueVeo3p1TextToVideoDurationSeconds {
|
||||
match d {
|
||||
FalVeo3p1Duration::Four => EnqueueVeo3p1TextToVideoDurationSeconds::Four,
|
||||
FalVeo3p1Duration::Six => EnqueueVeo3p1TextToVideoDurationSeconds::Six,
|
||||
FalVeo3p1Duration::Eight => EnqueueVeo3p1TextToVideoDurationSeconds::Eight,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_t2v_aspect_ratio(a: FalVeo3p1AspectRatio) -> EnqueueVeo3p1TextToVideoAspectRatio {
|
||||
match a {
|
||||
FalVeo3p1AspectRatio::Auto => EnqueueVeo3p1TextToVideoAspectRatio::Auto,
|
||||
FalVeo3p1AspectRatio::SixteenByNine => EnqueueVeo3p1TextToVideoAspectRatio::SixteenByNine,
|
||||
FalVeo3p1AspectRatio::NineBySixteen => EnqueueVeo3p1TextToVideoAspectRatio::NineBySixteen,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_t2v_resolution(r: FalVeo3p1Resolution) -> EnqueueVeo3p1TextToVideoResolution {
|
||||
match r {
|
||||
FalVeo3p1Resolution::SevenTwentyP => EnqueueVeo3p1TextToVideoResolution::SevenTwentyP,
|
||||
FalVeo3p1Resolution::TenEightyP => EnqueueVeo3p1TextToVideoResolution::TenEightyP,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_i2v_duration(d: FalVeo3p1Duration) -> EnqueueVeo3p1ImageToVideoDurationSeconds {
|
||||
match d {
|
||||
FalVeo3p1Duration::Four => EnqueueVeo3p1ImageToVideoDurationSeconds::Four,
|
||||
FalVeo3p1Duration::Six => EnqueueVeo3p1ImageToVideoDurationSeconds::Six,
|
||||
FalVeo3p1Duration::Eight => EnqueueVeo3p1ImageToVideoDurationSeconds::Eight,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_i2v_aspect_ratio(a: FalVeo3p1AspectRatio) -> EnqueueVeo3p1ImageToVideoAspectRatio {
|
||||
match a {
|
||||
FalVeo3p1AspectRatio::Auto => EnqueueVeo3p1ImageToVideoAspectRatio::Auto,
|
||||
FalVeo3p1AspectRatio::SixteenByNine => EnqueueVeo3p1ImageToVideoAspectRatio::SixteenByNine,
|
||||
FalVeo3p1AspectRatio::NineBySixteen => EnqueueVeo3p1ImageToVideoAspectRatio::NineBySixteen,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_i2v_resolution(r: FalVeo3p1Resolution) -> EnqueueVeo3p1ImageToVideoResolution {
|
||||
match r {
|
||||
FalVeo3p1Resolution::SevenTwentyP => EnqueueVeo3p1ImageToVideoResolution::SevenTwentyP,
|
||||
FalVeo3p1Resolution::TenEightyP => EnqueueVeo3p1ImageToVideoResolution::TenEightyP,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_flf_duration(d: FalVeo3p1Duration) -> EnqueueVeo3p1FirstLastFrameImageToVideoDurationSeconds {
|
||||
match d {
|
||||
FalVeo3p1Duration::Four => EnqueueVeo3p1FirstLastFrameImageToVideoDurationSeconds::Four,
|
||||
FalVeo3p1Duration::Six => EnqueueVeo3p1FirstLastFrameImageToVideoDurationSeconds::Six,
|
||||
FalVeo3p1Duration::Eight => EnqueueVeo3p1FirstLastFrameImageToVideoDurationSeconds::Eight,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_flf_aspect_ratio(a: FalVeo3p1AspectRatio) -> EnqueueVeo3p1FirstLastFrameImageToVideoAspectRatio {
|
||||
match a {
|
||||
FalVeo3p1AspectRatio::Auto => EnqueueVeo3p1FirstLastFrameImageToVideoAspectRatio::Auto,
|
||||
FalVeo3p1AspectRatio::SixteenByNine => EnqueueVeo3p1FirstLastFrameImageToVideoAspectRatio::SixteenByNine,
|
||||
FalVeo3p1AspectRatio::NineBySixteen => EnqueueVeo3p1FirstLastFrameImageToVideoAspectRatio::NineBySixteen,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_flf_resolution(r: FalVeo3p1Resolution) -> EnqueueVeo3p1FirstLastFrameImageToVideoResolution {
|
||||
match r {
|
||||
FalVeo3p1Resolution::SevenTwentyP => EnqueueVeo3p1FirstLastFrameImageToVideoResolution::SevenTwentyP,
|
||||
FalVeo3p1Resolution::TenEightyP => EnqueueVeo3p1FirstLastFrameImageToVideoResolution::TenEightyP,
|
||||
}
|
||||
}
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
use crate::generate::generate_video::generate_video_response::{
|
||||
FalVideoResponsePayload, GenerateVideoResponse,
|
||||
};
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1::{
|
||||
FalVeo3p1AspectRatio, FalVeo3p1Duration, FalVeo3p1Mode, FalVeo3p1Resolution,
|
||||
};
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1_fast::PlanFalVeo3p1Fast;
|
||||
use fal_client::requests::webhook::video::image::enqueue_veo_3p1_fast_first_last_frame_image_to_video_webhook::{
|
||||
enqueue_veo_3p1_fast_first_last_frame_image_to_video_webhook,
|
||||
EnqueueVeo3p1FastFirstLastFrameImageToVideoArgs,
|
||||
EnqueueVeo3p1FastFirstLastFrameImageToVideoAspectRatio,
|
||||
EnqueueVeo3p1FastFirstLastFrameImageToVideoDurationSeconds,
|
||||
EnqueueVeo3p1FastFirstLastFrameImageToVideoResolution,
|
||||
};
|
||||
use fal_client::requests::webhook::video::image::enqueue_veo_3p1_fast_image_to_video_webhook::{
|
||||
enqueue_veo_3p1_fast_image_to_video_webhook, EnqueueVeo3p1FastImageToVideoArgs,
|
||||
EnqueueVeo3p1FastImageToVideoAspectRatio, EnqueueVeo3p1FastImageToVideoDurationSeconds,
|
||||
EnqueueVeo3p1FastImageToVideoResolution,
|
||||
};
|
||||
use fal_client::requests::webhook::video::text::enqueue_veo_3p1_fast_text_to_video_webhook::{
|
||||
enqueue_veo_3p1_fast_text_to_video_webhook, EnqueueVeo3p1FastTextToVideoArgs,
|
||||
EnqueueVeo3p1FastTextToVideoAspectRatio, EnqueueVeo3p1FastTextToVideoDurationSeconds,
|
||||
EnqueueVeo3p1FastTextToVideoResolution,
|
||||
};
|
||||
|
||||
pub async fn execute_fal_veo_3p1_fast(
|
||||
plan: &PlanFalVeo3p1Fast,
|
||||
fal_client: &RouterFalClient,
|
||||
) -> Result<GenerateVideoResponse, ArtcraftRouterError> {
|
||||
let inner = &plan.inner;
|
||||
|
||||
let webhook_response = match &inner.mode {
|
||||
FalVeo3p1Mode::TextToVideo => {
|
||||
let args = EnqueueVeo3p1FastTextToVideoArgs {
|
||||
prompt: inner.prompt.clone(),
|
||||
duration: inner.duration.map(to_t2v_duration),
|
||||
aspect_ratio: inner.aspect_ratio.map(to_t2v_aspect_ratio),
|
||||
resolution: inner.resolution.map(to_t2v_resolution),
|
||||
generate_audio: inner.generate_audio,
|
||||
enhance_prompt: None,
|
||||
negative_prompt: inner.negative_prompt.clone(),
|
||||
seed: None,
|
||||
auto_fix: None,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_veo_3p1_fast_text_to_video_webhook(args).await
|
||||
}
|
||||
FalVeo3p1Mode::ImageToVideo { start_frame_url } => {
|
||||
let args = EnqueueVeo3p1FastImageToVideoArgs {
|
||||
prompt: inner.prompt.clone(),
|
||||
image_url: start_frame_url.clone(),
|
||||
duration: inner.duration.map(to_i2v_duration),
|
||||
aspect_ratio: inner.aspect_ratio.map(to_i2v_aspect_ratio),
|
||||
resolution: inner.resolution.map(to_i2v_resolution),
|
||||
generate_audio: inner.generate_audio,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_veo_3p1_fast_image_to_video_webhook(args).await
|
||||
}
|
||||
FalVeo3p1Mode::FirstLastFrame { first_frame_url, last_frame_url } => {
|
||||
let args = EnqueueVeo3p1FastFirstLastFrameImageToVideoArgs {
|
||||
prompt: inner.prompt.clone(),
|
||||
first_frame_url: first_frame_url.clone(),
|
||||
last_frame_url: last_frame_url.clone(),
|
||||
duration: inner.duration.map(to_flf_duration),
|
||||
aspect_ratio: inner.aspect_ratio.map(to_flf_aspect_ratio),
|
||||
resolution: inner.resolution.map(to_flf_resolution),
|
||||
generate_audio: inner.generate_audio,
|
||||
webhook_url: fal_client.webhook_url.as_str(),
|
||||
api_key: &fal_client.api_key,
|
||||
};
|
||||
enqueue_veo_3p1_fast_first_last_frame_image_to_video_webhook(args).await
|
||||
}
|
||||
};
|
||||
|
||||
let webhook_response = webhook_response
|
||||
.map_err(|e| ArtcraftRouterError::Provider(ProviderError::Fal(e)))?;
|
||||
|
||||
Ok(GenerateVideoResponse::Fal(FalVideoResponsePayload {
|
||||
request_id: webhook_response.request_id,
|
||||
gateway_request_id: webhook_response.gateway_request_id,
|
||||
}))
|
||||
}
|
||||
|
||||
fn to_t2v_duration(d: FalVeo3p1Duration) -> EnqueueVeo3p1FastTextToVideoDurationSeconds {
|
||||
match d {
|
||||
FalVeo3p1Duration::Four => EnqueueVeo3p1FastTextToVideoDurationSeconds::Four,
|
||||
FalVeo3p1Duration::Six => EnqueueVeo3p1FastTextToVideoDurationSeconds::Six,
|
||||
FalVeo3p1Duration::Eight => EnqueueVeo3p1FastTextToVideoDurationSeconds::Eight,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_t2v_aspect_ratio(a: FalVeo3p1AspectRatio) -> EnqueueVeo3p1FastTextToVideoAspectRatio {
|
||||
match a {
|
||||
FalVeo3p1AspectRatio::Auto => EnqueueVeo3p1FastTextToVideoAspectRatio::Auto,
|
||||
FalVeo3p1AspectRatio::SixteenByNine => EnqueueVeo3p1FastTextToVideoAspectRatio::SixteenByNine,
|
||||
FalVeo3p1AspectRatio::NineBySixteen => EnqueueVeo3p1FastTextToVideoAspectRatio::NineBySixteen,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_t2v_resolution(r: FalVeo3p1Resolution) -> EnqueueVeo3p1FastTextToVideoResolution {
|
||||
match r {
|
||||
FalVeo3p1Resolution::SevenTwentyP => EnqueueVeo3p1FastTextToVideoResolution::SevenTwentyP,
|
||||
FalVeo3p1Resolution::TenEightyP => EnqueueVeo3p1FastTextToVideoResolution::TenEightyP,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_i2v_duration(d: FalVeo3p1Duration) -> EnqueueVeo3p1FastImageToVideoDurationSeconds {
|
||||
match d {
|
||||
FalVeo3p1Duration::Four => EnqueueVeo3p1FastImageToVideoDurationSeconds::Four,
|
||||
FalVeo3p1Duration::Six => EnqueueVeo3p1FastImageToVideoDurationSeconds::Six,
|
||||
FalVeo3p1Duration::Eight => EnqueueVeo3p1FastImageToVideoDurationSeconds::Eight,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_i2v_aspect_ratio(a: FalVeo3p1AspectRatio) -> EnqueueVeo3p1FastImageToVideoAspectRatio {
|
||||
match a {
|
||||
FalVeo3p1AspectRatio::Auto => EnqueueVeo3p1FastImageToVideoAspectRatio::Auto,
|
||||
FalVeo3p1AspectRatio::SixteenByNine => EnqueueVeo3p1FastImageToVideoAspectRatio::SixteenByNine,
|
||||
FalVeo3p1AspectRatio::NineBySixteen => EnqueueVeo3p1FastImageToVideoAspectRatio::NineBySixteen,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_i2v_resolution(r: FalVeo3p1Resolution) -> EnqueueVeo3p1FastImageToVideoResolution {
|
||||
match r {
|
||||
FalVeo3p1Resolution::SevenTwentyP => EnqueueVeo3p1FastImageToVideoResolution::SevenTwentyP,
|
||||
FalVeo3p1Resolution::TenEightyP => EnqueueVeo3p1FastImageToVideoResolution::TenEightyP,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_flf_duration(d: FalVeo3p1Duration) -> EnqueueVeo3p1FastFirstLastFrameImageToVideoDurationSeconds {
|
||||
match d {
|
||||
FalVeo3p1Duration::Four => EnqueueVeo3p1FastFirstLastFrameImageToVideoDurationSeconds::Four,
|
||||
FalVeo3p1Duration::Six => EnqueueVeo3p1FastFirstLastFrameImageToVideoDurationSeconds::Six,
|
||||
FalVeo3p1Duration::Eight => EnqueueVeo3p1FastFirstLastFrameImageToVideoDurationSeconds::Eight,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_flf_aspect_ratio(a: FalVeo3p1AspectRatio) -> EnqueueVeo3p1FastFirstLastFrameImageToVideoAspectRatio {
|
||||
match a {
|
||||
FalVeo3p1AspectRatio::Auto => EnqueueVeo3p1FastFirstLastFrameImageToVideoAspectRatio::Auto,
|
||||
FalVeo3p1AspectRatio::SixteenByNine => EnqueueVeo3p1FastFirstLastFrameImageToVideoAspectRatio::SixteenByNine,
|
||||
FalVeo3p1AspectRatio::NineBySixteen => EnqueueVeo3p1FastFirstLastFrameImageToVideoAspectRatio::NineBySixteen,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_flf_resolution(r: FalVeo3p1Resolution) -> EnqueueVeo3p1FastFirstLastFrameImageToVideoResolution {
|
||||
match r {
|
||||
FalVeo3p1Resolution::SevenTwentyP => EnqueueVeo3p1FastFirstLastFrameImageToVideoResolution::SevenTwentyP,
|
||||
FalVeo3p1Resolution::TenEightyP => EnqueueVeo3p1FastFirstLastFrameImageToVideoResolution::TenEightyP,
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
pub mod generate_video_fal_veo_2;
|
||||
pub mod generate_video_fal_veo_3;
|
||||
pub mod generate_video_fal_veo_3_fast;
|
||||
pub mod generate_video_fal_veo_3p1;
|
||||
pub mod generate_video_fal_veo_3p1_fast;
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod artcraft;
|
||||
pub mod fal;
|
||||
pub mod muapi;
|
||||
pub mod seedance2pro;
|
||||
+17
@@ -13,6 +13,11 @@ use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraf
|
||||
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;
|
||||
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance2p0::plan_generate_video_artcraft_seedance2p0;
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_2::plan_generate_video_fal_veo_2;
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3::plan_generate_video_fal_veo_3;
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3_fast::plan_generate_video_fal_veo_3_fast;
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1::plan_generate_video_fal_veo_3p1;
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1_fast::plan_generate_video_fal_veo_3p1_fast;
|
||||
use crate::generate::generate_video::plan::muapi::plan_generate_video_muapi_seedance2p0::plan_generate_video_muapi_seedance2p0;
|
||||
use crate::generate::generate_video::plan::seedance2pro::plan_generate_video_seedance2pro_seedance2p0::plan_generate_video_seedance2pro_seedance2p0;
|
||||
use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan;
|
||||
@@ -83,6 +88,7 @@ impl<'a> GenerateVideoRequest<'a> {
|
||||
pub fn build(&self) -> Result<VideoGenerationPlan<'_>, ArtcraftRouterError> {
|
||||
match self.provider {
|
||||
Provider::Artcraft => self.build_artcraft(),
|
||||
Provider::Fal => self.build_fal(),
|
||||
Provider::Muapi => self.build_muapi(),
|
||||
Provider::Seedance2Pro => self.build_seedance2pro(),
|
||||
_ => self.unsupported_provider(),
|
||||
@@ -99,6 +105,17 @@ impl<'a> GenerateVideoRequest<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_fal(&self) -> Result<VideoGenerationPlan<'_>, ArtcraftRouterError> {
|
||||
match self.model {
|
||||
CommonVideoModel::Veo2 => plan_generate_video_fal_veo_2(self),
|
||||
CommonVideoModel::Veo3 => plan_generate_video_fal_veo_3(self),
|
||||
CommonVideoModel::Veo3Fast => plan_generate_video_fal_veo_3_fast(self),
|
||||
CommonVideoModel::Veo3p1 => plan_generate_video_fal_veo_3p1(self),
|
||||
CommonVideoModel::Veo3p1Fast => plan_generate_video_fal_veo_3p1_fast(self),
|
||||
_ => Err(ArtcraftRouterError::UnsupportedModel(format!("{:?}", self.model))),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_muapi(&self) -> Result<VideoGenerationPlan<'_>, ArtcraftRouterError> {
|
||||
match self.model {
|
||||
CommonVideoModel::Seedance2p0 => plan_generate_video_muapi_seedance2p0(self),
|
||||
|
||||
+14
@@ -18,11 +18,18 @@ pub struct Seedance2proVideoResponsePayload {
|
||||
pub task_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FalVideoResponsePayload {
|
||||
pub request_id: Option<String>,
|
||||
pub gateway_request_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum GenerateVideoResponse {
|
||||
Artcraft(ArtcraftVideoResponsePayload),
|
||||
Muapi(MuapiVideoResponsePayload),
|
||||
Seedance2Pro(Seedance2proVideoResponsePayload),
|
||||
Fal(FalVideoResponsePayload),
|
||||
}
|
||||
|
||||
impl GenerateVideoResponse {
|
||||
@@ -46,4 +53,11 @@ impl GenerateVideoResponse {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_fal_payload(&self) -> Option<FalVideoResponsePayload> {
|
||||
match self {
|
||||
Self::Fal(p) => Some(p.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
pub mod plan_generate_video_fal_veo_2;
|
||||
pub mod plan_generate_video_fal_veo_3;
|
||||
pub mod plan_generate_video_fal_veo_3_fast;
|
||||
pub mod plan_generate_video_fal_veo_3p1;
|
||||
pub mod plan_generate_video_fal_veo_3p1_fast;
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
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 fal_client::requests::webhook::video::image::enqueue_veo_2_image_to_video_webhook::{
|
||||
Veo2AspectRatio, Veo2Duration,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PlanFalVeo2 {
|
||||
pub prompt: String,
|
||||
pub start_frame_url: String,
|
||||
pub aspect_ratio: Veo2AspectRatio,
|
||||
pub duration: Veo2Duration,
|
||||
}
|
||||
|
||||
pub fn plan_generate_video_fal_veo_2<'a>(
|
||||
request: &'a GenerateVideoRequest<'a>,
|
||||
) -> Result<VideoGenerationPlan<'a>, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
|
||||
let start_frame_url = resolve_required_image_url(request.start_frame, "start_frame")?;
|
||||
if request.end_frame.is_some() {
|
||||
return Err(unsupported("end_frame", "Veo 2 does not support an ending frame"));
|
||||
}
|
||||
|
||||
let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?;
|
||||
let duration = plan_duration(request.duration_seconds, strategy)?;
|
||||
|
||||
Ok(VideoGenerationPlan::FalVeo2(PlanFalVeo2 {
|
||||
prompt: request.prompt.unwrap_or("").to_string(),
|
||||
start_frame_url,
|
||||
aspect_ratio,
|
||||
duration,
|
||||
}))
|
||||
}
|
||||
|
||||
fn resolve_required_image_url(
|
||||
image_ref: Option<ImageRef<'_>>,
|
||||
field: &'static str,
|
||||
) -> Result<String, ArtcraftRouterError> {
|
||||
match image_ref {
|
||||
Some(ImageRef::Url(url)) => Ok(url.to_string()),
|
||||
Some(ImageRef::MediaFileToken(_)) => {
|
||||
Err(ArtcraftRouterError::Client(ClientError::FalOnlySupportsUrls))
|
||||
}
|
||||
None => Err(unsupported(field, "Veo 2 requires a starting frame")),
|
||||
}
|
||||
}
|
||||
|
||||
fn plan_aspect_ratio(
|
||||
aspect_ratio: Option<CommonAspectRatio>,
|
||||
strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<Veo2AspectRatio, ArtcraftRouterError> {
|
||||
use Veo2AspectRatio as Ar;
|
||||
match aspect_ratio {
|
||||
None
|
||||
| Some(CommonAspectRatio::Auto)
|
||||
| Some(CommonAspectRatio::Auto2k)
|
||||
| Some(CommonAspectRatio::Auto4k) => Ok(Ar::Auto),
|
||||
|
||||
Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Ar::WideSixteenNine),
|
||||
Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Ar::TallNineSixteen),
|
||||
|
||||
Some(unsupported_ar) => match strategy {
|
||||
RequestMismatchMitigationStrategy::ErrorOut => {
|
||||
Err(unsupported("aspect_ratio", &format!("{:?}", unsupported_ar)))
|
||||
}
|
||||
_ => Ok(Ar::Auto),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn plan_duration(
|
||||
duration_seconds: Option<u16>,
|
||||
strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<Veo2Duration, ArtcraftRouterError> {
|
||||
match duration_seconds {
|
||||
None => Ok(Veo2Duration::Default),
|
||||
Some(5) => Ok(Veo2Duration::FiveSeconds),
|
||||
Some(6) => Ok(Veo2Duration::SixSeconds),
|
||||
Some(7) => Ok(Veo2Duration::SevenSeconds),
|
||||
Some(8) => Ok(Veo2Duration::EightSeconds),
|
||||
Some(other) => match strategy {
|
||||
RequestMismatchMitigationStrategy::ErrorOut => {
|
||||
Err(unsupported("duration_seconds", &format!("{}", other)))
|
||||
}
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Veo2Duration::EightSeconds),
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Veo2Duration::FiveSeconds),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn unsupported(field: &'static str, value: &str) -> ArtcraftRouterError {
|
||||
ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
|
||||
field,
|
||||
value: value.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
impl PlanFalVeo2 {
|
||||
pub fn duration_seconds_for_cost(&self) -> u64 {
|
||||
match self.duration {
|
||||
Veo2Duration::Default | Veo2Duration::FiveSeconds => 5,
|
||||
Veo2Duration::SixSeconds => 6,
|
||||
Veo2Duration::SevenSeconds => 7,
|
||||
Veo2Duration::EightSeconds => 8,
|
||||
}
|
||||
}
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::api::common_resolution::CommonResolution;
|
||||
use crate::api::image_ref::ImageRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_video::generate_video_request::GenerateVideoRequest;
|
||||
use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan;
|
||||
use fal_client::requests::webhook::video::image::enqueue_veo_3_image_to_video_webhook::{
|
||||
Veo3AspectRatio, Veo3Duration, Veo3Resolution,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PlanFalVeo3 {
|
||||
pub prompt: String,
|
||||
pub start_frame_url: String,
|
||||
pub aspect_ratio: Veo3AspectRatio,
|
||||
pub resolution: Veo3Resolution,
|
||||
pub duration: Veo3Duration,
|
||||
pub generate_audio: bool,
|
||||
}
|
||||
|
||||
pub fn plan_generate_video_fal_veo_3<'a>(
|
||||
request: &'a GenerateVideoRequest<'a>,
|
||||
) -> Result<VideoGenerationPlan<'a>, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
|
||||
let start_frame_url = resolve_required_image_url(request.start_frame)?;
|
||||
if request.end_frame.is_some() {
|
||||
return Err(unsupported("end_frame", "Veo 3 does not support an ending frame"));
|
||||
}
|
||||
|
||||
let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?;
|
||||
let resolution = plan_resolution(request.resolution, strategy)?;
|
||||
let duration = plan_duration(request.duration_seconds, strategy)?;
|
||||
let generate_audio = request.generate_audio.unwrap_or(true);
|
||||
|
||||
Ok(VideoGenerationPlan::FalVeo3(PlanFalVeo3 {
|
||||
prompt: request.prompt.unwrap_or("").to_string(),
|
||||
start_frame_url,
|
||||
aspect_ratio,
|
||||
resolution,
|
||||
duration,
|
||||
generate_audio,
|
||||
}))
|
||||
}
|
||||
|
||||
fn resolve_required_image_url(
|
||||
image_ref: Option<ImageRef<'_>>,
|
||||
) -> Result<String, ArtcraftRouterError> {
|
||||
match image_ref {
|
||||
Some(ImageRef::Url(url)) => Ok(url.to_string()),
|
||||
Some(ImageRef::MediaFileToken(_)) => {
|
||||
Err(ArtcraftRouterError::Client(ClientError::FalOnlySupportsUrls))
|
||||
}
|
||||
None => Err(unsupported("start_frame", "Veo 3 requires a starting frame")),
|
||||
}
|
||||
}
|
||||
|
||||
fn plan_aspect_ratio(
|
||||
aspect_ratio: Option<CommonAspectRatio>,
|
||||
strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<Veo3AspectRatio, ArtcraftRouterError> {
|
||||
use Veo3AspectRatio as Ar;
|
||||
match aspect_ratio {
|
||||
None
|
||||
| Some(CommonAspectRatio::Auto)
|
||||
| Some(CommonAspectRatio::Auto2k)
|
||||
| Some(CommonAspectRatio::Auto4k) => Ok(Ar::Default),
|
||||
|
||||
Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Ar::Square),
|
||||
Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Ar::WideSixteenNine),
|
||||
Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Ar::TallNineSixteen),
|
||||
|
||||
Some(unsupported_ar) => match strategy {
|
||||
RequestMismatchMitigationStrategy::ErrorOut => {
|
||||
Err(unsupported("aspect_ratio", &format!("{:?}", unsupported_ar)))
|
||||
}
|
||||
_ => Ok(Ar::Default),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn plan_resolution(
|
||||
resolution: Option<CommonResolution>,
|
||||
strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<Veo3Resolution, ArtcraftRouterError> {
|
||||
use Veo3Resolution as R;
|
||||
match resolution {
|
||||
None => Ok(R::Default),
|
||||
Some(CommonResolution::SevenTwentyP) => Ok(R::SevenTwentyP),
|
||||
Some(CommonResolution::TenEightyP) => Ok(R::TenEightyP),
|
||||
Some(other) => match strategy {
|
||||
RequestMismatchMitigationStrategy::ErrorOut => {
|
||||
Err(unsupported("resolution", &format!("{:?}", other)))
|
||||
}
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(R::TenEightyP),
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(R::SevenTwentyP),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn plan_duration(
|
||||
duration_seconds: Option<u16>,
|
||||
strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<Veo3Duration, ArtcraftRouterError> {
|
||||
match duration_seconds {
|
||||
None => Ok(Veo3Duration::Default),
|
||||
Some(4) => Ok(Veo3Duration::FourSeconds),
|
||||
Some(6) => Ok(Veo3Duration::SixSeconds),
|
||||
Some(8) => Ok(Veo3Duration::EightSeconds),
|
||||
Some(other) => match strategy {
|
||||
RequestMismatchMitigationStrategy::ErrorOut => {
|
||||
Err(unsupported("duration_seconds", &format!("{}", other)))
|
||||
}
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Veo3Duration::EightSeconds),
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Veo3Duration::FourSeconds),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn unsupported(field: &'static str, value: &str) -> ArtcraftRouterError {
|
||||
ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
|
||||
field,
|
||||
value: value.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
impl PlanFalVeo3 {
|
||||
pub fn duration_seconds_for_cost(&self) -> u64 {
|
||||
match self.duration {
|
||||
Veo3Duration::Default | Veo3Duration::EightSeconds => 8,
|
||||
Veo3Duration::SixSeconds => 6,
|
||||
Veo3Duration::FourSeconds => 4,
|
||||
}
|
||||
}
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
use crate::api::common_resolution::CommonResolution;
|
||||
use crate::api::image_ref::ImageRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_video::generate_video_request::GenerateVideoRequest;
|
||||
use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan;
|
||||
use fal_client::requests::webhook::video::image::enqueue_veo_3_fast_image_to_video_webhook::{
|
||||
Veo3FastDuration, Veo3FastResolution,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PlanFalVeo3Fast {
|
||||
pub prompt: String,
|
||||
pub start_frame_url: String,
|
||||
pub resolution: Veo3FastResolution,
|
||||
pub duration: Veo3FastDuration,
|
||||
pub generate_audio: bool,
|
||||
}
|
||||
|
||||
pub fn plan_generate_video_fal_veo_3_fast<'a>(
|
||||
request: &'a GenerateVideoRequest<'a>,
|
||||
) -> Result<VideoGenerationPlan<'a>, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
|
||||
let start_frame_url = resolve_required_image_url(request.start_frame)?;
|
||||
if request.end_frame.is_some() {
|
||||
return Err(unsupported("end_frame", "Veo 3 Fast does not support an ending frame"));
|
||||
}
|
||||
|
||||
let resolution = plan_resolution(request.resolution, strategy)?;
|
||||
let duration = plan_duration(request.duration_seconds, strategy)?;
|
||||
let generate_audio = request.generate_audio.unwrap_or(true);
|
||||
|
||||
Ok(VideoGenerationPlan::FalVeo3Fast(PlanFalVeo3Fast {
|
||||
prompt: request.prompt.unwrap_or("").to_string(),
|
||||
start_frame_url,
|
||||
resolution,
|
||||
duration,
|
||||
generate_audio,
|
||||
}))
|
||||
}
|
||||
|
||||
fn resolve_required_image_url(
|
||||
image_ref: Option<ImageRef<'_>>,
|
||||
) -> Result<String, ArtcraftRouterError> {
|
||||
match image_ref {
|
||||
Some(ImageRef::Url(url)) => Ok(url.to_string()),
|
||||
Some(ImageRef::MediaFileToken(_)) => {
|
||||
Err(ArtcraftRouterError::Client(ClientError::FalOnlySupportsUrls))
|
||||
}
|
||||
None => Err(unsupported("start_frame", "Veo 3 Fast requires a starting frame")),
|
||||
}
|
||||
}
|
||||
|
||||
fn plan_resolution(
|
||||
resolution: Option<CommonResolution>,
|
||||
strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<Veo3FastResolution, ArtcraftRouterError> {
|
||||
use Veo3FastResolution as R;
|
||||
match resolution {
|
||||
None => Ok(R::Default),
|
||||
Some(CommonResolution::SevenTwentyP) => Ok(R::SevenTwentyP),
|
||||
Some(CommonResolution::TenEightyP) => Ok(R::TenEightyP),
|
||||
Some(other) => match strategy {
|
||||
RequestMismatchMitigationStrategy::ErrorOut => {
|
||||
Err(unsupported("resolution", &format!("{:?}", other)))
|
||||
}
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(R::TenEightyP),
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(R::SevenTwentyP),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn plan_duration(
|
||||
duration_seconds: Option<u16>,
|
||||
strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<Veo3FastDuration, ArtcraftRouterError> {
|
||||
match duration_seconds {
|
||||
None => Ok(Veo3FastDuration::Default),
|
||||
Some(4) => Ok(Veo3FastDuration::FourSeconds),
|
||||
Some(6) => Ok(Veo3FastDuration::SixSeconds),
|
||||
Some(8) => Ok(Veo3FastDuration::EightSeconds),
|
||||
Some(other) => match strategy {
|
||||
RequestMismatchMitigationStrategy::ErrorOut => {
|
||||
Err(unsupported("duration_seconds", &format!("{}", other)))
|
||||
}
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Veo3FastDuration::EightSeconds),
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Veo3FastDuration::FourSeconds),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn unsupported(field: &'static str, value: &str) -> ArtcraftRouterError {
|
||||
ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
|
||||
field,
|
||||
value: value.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
impl PlanFalVeo3Fast {
|
||||
pub fn duration_seconds_for_cost(&self) -> u64 {
|
||||
match self.duration {
|
||||
Veo3FastDuration::Default | Veo3FastDuration::EightSeconds => 8,
|
||||
Veo3FastDuration::SixSeconds => 6,
|
||||
Veo3FastDuration::FourSeconds => 4,
|
||||
}
|
||||
}
|
||||
}
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::api::common_resolution::CommonResolution;
|
||||
use crate::api::image_ref::ImageRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_video::generate_video_request::GenerateVideoRequest;
|
||||
use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan;
|
||||
|
||||
/// Three-way internal selection of which Fal Veo 3.1 endpoint to call.
|
||||
/// Veo 3.1 / 3.1 Fast each expose distinct (but parallel) types per endpoint —
|
||||
/// we resolve those at execute time.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum FalVeo3p1Mode {
|
||||
TextToVideo,
|
||||
ImageToVideo { start_frame_url: String },
|
||||
FirstLastFrame { first_frame_url: String, last_frame_url: String },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum FalVeo3p1AspectRatio {
|
||||
Auto,
|
||||
SixteenByNine,
|
||||
NineBySixteen,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum FalVeo3p1Resolution {
|
||||
SevenTwentyP,
|
||||
TenEightyP,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum FalVeo3p1Duration {
|
||||
Four,
|
||||
Six,
|
||||
Eight,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PlanFalVeo3p1 {
|
||||
pub prompt: String,
|
||||
pub negative_prompt: Option<String>,
|
||||
pub mode: FalVeo3p1Mode,
|
||||
pub aspect_ratio: Option<FalVeo3p1AspectRatio>,
|
||||
pub resolution: Option<FalVeo3p1Resolution>,
|
||||
pub duration: Option<FalVeo3p1Duration>,
|
||||
pub generate_audio: Option<bool>,
|
||||
}
|
||||
|
||||
pub fn plan_generate_video_fal_veo_3p1<'a>(
|
||||
request: &'a GenerateVideoRequest<'a>,
|
||||
) -> Result<VideoGenerationPlan<'a>, ArtcraftRouterError> {
|
||||
let plan = build_plan_fal_veo_3p1(request, "Veo 3.1")?;
|
||||
Ok(VideoGenerationPlan::FalVeo3p1(plan))
|
||||
}
|
||||
|
||||
pub(crate) fn build_plan_fal_veo_3p1<'a>(
|
||||
request: &'a GenerateVideoRequest<'a>,
|
||||
model_label: &'static str,
|
||||
) -> Result<PlanFalVeo3p1, ArtcraftRouterError> {
|
||||
let strategy = request.request_mismatch_mitigation_strategy;
|
||||
|
||||
let mode = resolve_mode(request.start_frame, request.end_frame, model_label)?;
|
||||
let aspect_ratio = plan_aspect_ratio(request.aspect_ratio, strategy)?;
|
||||
let resolution = plan_resolution(request.resolution, strategy)?;
|
||||
let duration = plan_duration(request.duration_seconds, strategy)?;
|
||||
|
||||
Ok(PlanFalVeo3p1 {
|
||||
prompt: request.prompt.unwrap_or("").to_string(),
|
||||
negative_prompt: request.negative_prompt.map(|s| s.to_string()),
|
||||
mode,
|
||||
aspect_ratio,
|
||||
resolution,
|
||||
duration,
|
||||
generate_audio: request.generate_audio,
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_mode(
|
||||
start_frame: Option<ImageRef<'_>>,
|
||||
end_frame: Option<ImageRef<'_>>,
|
||||
model_label: &'static str,
|
||||
) -> Result<FalVeo3p1Mode, ArtcraftRouterError> {
|
||||
let start = resolve_optional_image_url(start_frame)?;
|
||||
let end = resolve_optional_image_url(end_frame)?;
|
||||
match (start, end) {
|
||||
(None, None) => Ok(FalVeo3p1Mode::TextToVideo),
|
||||
(Some(s), None) => Ok(FalVeo3p1Mode::ImageToVideo { start_frame_url: s }),
|
||||
(Some(s), Some(e)) => Ok(FalVeo3p1Mode::FirstLastFrame {
|
||||
first_frame_url: s,
|
||||
last_frame_url: e,
|
||||
}),
|
||||
(None, Some(_)) => Err(unsupported(
|
||||
"end_frame",
|
||||
&format!("{} requires a start_frame when end_frame is provided", model_label),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_optional_image_url(
|
||||
image_ref: Option<ImageRef<'_>>,
|
||||
) -> Result<Option<String>, ArtcraftRouterError> {
|
||||
match image_ref {
|
||||
None => Ok(None),
|
||||
Some(ImageRef::Url(url)) => Ok(Some(url.to_string())),
|
||||
Some(ImageRef::MediaFileToken(_)) => {
|
||||
Err(ArtcraftRouterError::Client(ClientError::FalOnlySupportsUrls))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn plan_aspect_ratio(
|
||||
aspect_ratio: Option<CommonAspectRatio>,
|
||||
strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<Option<FalVeo3p1AspectRatio>, ArtcraftRouterError> {
|
||||
use FalVeo3p1AspectRatio as Ar;
|
||||
match aspect_ratio {
|
||||
None => Ok(None),
|
||||
|
||||
Some(CommonAspectRatio::Auto)
|
||||
| Some(CommonAspectRatio::Auto2k)
|
||||
| Some(CommonAspectRatio::Auto4k) => Ok(Some(Ar::Auto)),
|
||||
|
||||
Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Ar::SixteenByNine)),
|
||||
Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Ar::NineBySixteen)),
|
||||
|
||||
Some(other) => match strategy {
|
||||
RequestMismatchMitigationStrategy::ErrorOut => {
|
||||
Err(unsupported("aspect_ratio", &format!("{:?}", other)))
|
||||
}
|
||||
_ => Ok(Some(Ar::Auto)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn plan_resolution(
|
||||
resolution: Option<CommonResolution>,
|
||||
strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<Option<FalVeo3p1Resolution>, ArtcraftRouterError> {
|
||||
use FalVeo3p1Resolution as R;
|
||||
match resolution {
|
||||
None => Ok(None),
|
||||
Some(CommonResolution::SevenTwentyP) => Ok(Some(R::SevenTwentyP)),
|
||||
Some(CommonResolution::TenEightyP) => Ok(Some(R::TenEightyP)),
|
||||
Some(other) => match strategy {
|
||||
RequestMismatchMitigationStrategy::ErrorOut => {
|
||||
Err(unsupported("resolution", &format!("{:?}", other)))
|
||||
}
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(R::TenEightyP)),
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(R::SevenTwentyP)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn plan_duration(
|
||||
duration_seconds: Option<u16>,
|
||||
strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<Option<FalVeo3p1Duration>, ArtcraftRouterError> {
|
||||
match duration_seconds {
|
||||
None => Ok(None),
|
||||
Some(4) => Ok(Some(FalVeo3p1Duration::Four)),
|
||||
Some(6) => Ok(Some(FalVeo3p1Duration::Six)),
|
||||
Some(8) => Ok(Some(FalVeo3p1Duration::Eight)),
|
||||
Some(other) => match strategy {
|
||||
RequestMismatchMitigationStrategy::ErrorOut => {
|
||||
Err(unsupported("duration_seconds", &format!("{}", other)))
|
||||
}
|
||||
RequestMismatchMitigationStrategy::PayMoreUpgrade => Ok(Some(FalVeo3p1Duration::Eight)),
|
||||
RequestMismatchMitigationStrategy::PayLessDowngrade => Ok(Some(FalVeo3p1Duration::Four)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn unsupported(field: &'static str, value: &str) -> ArtcraftRouterError {
|
||||
ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
|
||||
field,
|
||||
value: value.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
impl PlanFalVeo3p1 {
|
||||
pub fn duration_seconds_for_cost(&self) -> u64 {
|
||||
match self.duration {
|
||||
Some(FalVeo3p1Duration::Four) => 4,
|
||||
Some(FalVeo3p1Duration::Six) => 6,
|
||||
Some(FalVeo3p1Duration::Eight) | None => 8,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_audio_for_cost(&self) -> bool {
|
||||
self.generate_audio.unwrap_or(true)
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::generate::generate_video::generate_video_request::GenerateVideoRequest;
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1::{
|
||||
build_plan_fal_veo_3p1, PlanFalVeo3p1,
|
||||
};
|
||||
use crate::generate::generate_video::video_generation_plan::VideoGenerationPlan;
|
||||
|
||||
/// Veo 3.1 Fast shares the exact same input shape as Veo 3.1 — only the
|
||||
/// downstream Fal endpoint and pricing differ. We reuse the planner and tag the
|
||||
/// resulting plan as the Fast variant for execute/cost dispatch.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PlanFalVeo3p1Fast {
|
||||
pub inner: PlanFalVeo3p1,
|
||||
}
|
||||
|
||||
pub fn plan_generate_video_fal_veo_3p1_fast<'a>(
|
||||
request: &'a GenerateVideoRequest<'a>,
|
||||
) -> Result<VideoGenerationPlan<'a>, ArtcraftRouterError> {
|
||||
let inner = build_plan_fal_veo_3p1(request, "Veo 3.1 Fast")?;
|
||||
Ok(VideoGenerationPlan::FalVeo3p1Fast(PlanFalVeo3p1Fast { inner }))
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod artcraft;
|
||||
pub mod fal;
|
||||
pub mod muapi;
|
||||
pub mod seedance2pro;
|
||||
+45
@@ -4,12 +4,22 @@ use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraf
|
||||
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;
|
||||
use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_seedance2p0::estimate_video_cost_artcraft_seedance2p0;
|
||||
use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_veo_2::estimate_video_cost_fal_veo_2;
|
||||
use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_veo_3::estimate_video_cost_fal_veo_3;
|
||||
use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_veo_3_fast::estimate_video_cost_fal_veo_3_fast;
|
||||
use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_veo_3p1::estimate_video_cost_fal_veo_3p1;
|
||||
use crate::generate::generate_video::cost::fal::estimate_video_cost_fal_veo_3p1_fast::estimate_video_cost_fal_veo_3p1_fast;
|
||||
use crate::generate::generate_video::cost::muapi::estimate_video_cost_muapi_seedance2p0::estimate_video_cost_muapi_seedance2p0;
|
||||
use crate::generate::generate_video::cost::seedance2pro::estimate_video_cost_seedance2pro_seedance2p0::estimate_video_cost_seedance2pro_seedance2p0;
|
||||
use crate::generate::generate_video::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;
|
||||
use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_seedance2p0::execute_artcraft_seedance2p0;
|
||||
use crate::generate::generate_video::execute::fal::generate_video_fal_veo_2::execute_fal_veo_2;
|
||||
use crate::generate::generate_video::execute::fal::generate_video_fal_veo_3::execute_fal_veo_3;
|
||||
use crate::generate::generate_video::execute::fal::generate_video_fal_veo_3_fast::execute_fal_veo_3_fast;
|
||||
use crate::generate::generate_video::execute::fal::generate_video_fal_veo_3p1::execute_fal_veo_3p1;
|
||||
use crate::generate::generate_video::execute::fal::generate_video_fal_veo_3p1_fast::execute_fal_veo_3p1_fast;
|
||||
use crate::generate::generate_video::execute::muapi::execute_muapi_seedance2p0::execute_muapi_seedance2p0;
|
||||
use crate::generate::generate_video::execute::seedance2pro::execute_seedance2pro_seedance2p0::execute_seedance2pro_seedance2p0;
|
||||
use crate::generate::generate_video::generate_video_response::GenerateVideoResponse;
|
||||
@@ -17,6 +27,11 @@ use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraf
|
||||
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;
|
||||
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance2p0::PlanArtcraftSeedance2p0;
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_2::PlanFalVeo2;
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3::PlanFalVeo3;
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3_fast::PlanFalVeo3Fast;
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1::PlanFalVeo3p1;
|
||||
use crate::generate::generate_video::plan::fal::plan_generate_video_fal_veo_3p1_fast::PlanFalVeo3p1Fast;
|
||||
use crate::generate::generate_video::plan::muapi::plan_generate_video_muapi_seedance2p0::PlanMuapiSeedance2p0;
|
||||
use crate::generate::generate_video::plan::seedance2pro::plan_generate_video_seedance2pro_seedance2p0::PlanSeedance2proSeedance2p0;
|
||||
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
|
||||
@@ -29,6 +44,11 @@ pub enum VideoGenerationPlan<'a> {
|
||||
ArtcraftSeedance2p0(PlanArtcraftSeedance2p0<'a>),
|
||||
MuapiSeedance2p0(PlanMuapiSeedance2p0),
|
||||
Seedance2proSeedance2p0(PlanSeedance2proSeedance2p0),
|
||||
FalVeo2(PlanFalVeo2),
|
||||
FalVeo3(PlanFalVeo3),
|
||||
FalVeo3Fast(PlanFalVeo3Fast),
|
||||
FalVeo3p1(PlanFalVeo3p1),
|
||||
FalVeo3p1Fast(PlanFalVeo3p1Fast),
|
||||
}
|
||||
|
||||
impl<'a> VideoGenerationPlan<'a> {
|
||||
@@ -61,6 +81,26 @@ impl<'a> VideoGenerationPlan<'a> {
|
||||
let seedance2pro_client = client.get_seedance2pro_client_ref()?;
|
||||
execute_seedance2pro_seedance2p0(plan, seedance2pro_client).await
|
||||
}
|
||||
VideoGenerationPlan::FalVeo2(plan) => {
|
||||
let fal_client = client.get_fal_client_ref()?;
|
||||
execute_fal_veo_2(plan, fal_client).await
|
||||
}
|
||||
VideoGenerationPlan::FalVeo3(plan) => {
|
||||
let fal_client = client.get_fal_client_ref()?;
|
||||
execute_fal_veo_3(plan, fal_client).await
|
||||
}
|
||||
VideoGenerationPlan::FalVeo3Fast(plan) => {
|
||||
let fal_client = client.get_fal_client_ref()?;
|
||||
execute_fal_veo_3_fast(plan, fal_client).await
|
||||
}
|
||||
VideoGenerationPlan::FalVeo3p1(plan) => {
|
||||
let fal_client = client.get_fal_client_ref()?;
|
||||
execute_fal_veo_3p1(plan, fal_client).await
|
||||
}
|
||||
VideoGenerationPlan::FalVeo3p1Fast(plan) => {
|
||||
let fal_client = client.get_fal_client_ref()?;
|
||||
execute_fal_veo_3p1_fast(plan, fal_client).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +124,11 @@ impl<'a> VideoGenerationPlan<'a> {
|
||||
VideoGenerationPlan::Seedance2proSeedance2p0(plan) => {
|
||||
estimate_video_cost_seedance2pro_seedance2p0(plan)
|
||||
}
|
||||
VideoGenerationPlan::FalVeo2(plan) => estimate_video_cost_fal_veo_2(plan),
|
||||
VideoGenerationPlan::FalVeo3(plan) => estimate_video_cost_fal_veo_3(plan),
|
||||
VideoGenerationPlan::FalVeo3Fast(plan) => estimate_video_cost_fal_veo_3_fast(plan),
|
||||
VideoGenerationPlan::FalVeo3p1(plan) => estimate_video_cost_fal_veo_3p1(plan),
|
||||
VideoGenerationPlan::FalVeo3p1Fast(plan) => estimate_video_cost_fal_veo_3p1_fast(plan),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,6 +80,111 @@ fn build_omni_gen_video_models() -> Vec<OmniGenVideoModelDetails> {
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
models.push(OmniGenVideoModelDetails {
|
||||
model: CommonVideoModel::Veo2,
|
||||
full_name: Some("Google Veo 2".to_string()),
|
||||
text_prompt_supported: Some(true),
|
||||
starting_keyframe_supported: Some(true),
|
||||
aspect_ratio_options: Some(vec![
|
||||
CommonAspectRatio::Auto,
|
||||
CommonAspectRatio::WideSixteenByNine,
|
||||
CommonAspectRatio::TallNineBySixteen,
|
||||
]),
|
||||
aspect_ratio_default: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
duration_seconds_min: Some(5),
|
||||
duration_seconds_max: Some(8),
|
||||
duration_seconds_default: Some(5),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
models.push(OmniGenVideoModelDetails {
|
||||
model: CommonVideoModel::Veo3,
|
||||
full_name: Some("Google Veo 3".to_string()),
|
||||
text_prompt_supported: Some(true),
|
||||
starting_keyframe_supported: Some(true),
|
||||
show_generate_with_sound_toggle: Some(true),
|
||||
aspect_ratio_options: Some(vec![
|
||||
CommonAspectRatio::WideSixteenByNine,
|
||||
CommonAspectRatio::TallNineBySixteen,
|
||||
CommonAspectRatio::Square,
|
||||
]),
|
||||
aspect_ratio_default: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
resolution_options: Some(vec![
|
||||
CommonResolution::SevenTwentyP,
|
||||
CommonResolution::TenEightyP,
|
||||
]),
|
||||
resolution_default: Some(CommonResolution::TenEightyP),
|
||||
duration_seconds_min: Some(4),
|
||||
duration_seconds_max: Some(8),
|
||||
duration_seconds_default: Some(8),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
models.push(OmniGenVideoModelDetails {
|
||||
model: CommonVideoModel::Veo3Fast,
|
||||
full_name: Some("Google Veo 3 Fast".to_string()),
|
||||
text_prompt_supported: Some(true),
|
||||
starting_keyframe_supported: Some(true),
|
||||
show_generate_with_sound_toggle: Some(true),
|
||||
resolution_options: Some(vec![
|
||||
CommonResolution::SevenTwentyP,
|
||||
CommonResolution::TenEightyP,
|
||||
]),
|
||||
resolution_default: Some(CommonResolution::TenEightyP),
|
||||
duration_seconds_min: Some(4),
|
||||
duration_seconds_max: Some(8),
|
||||
duration_seconds_default: Some(8),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
models.push(OmniGenVideoModelDetails {
|
||||
model: CommonVideoModel::Veo3p1,
|
||||
full_name: Some("Google Veo 3.1".to_string()),
|
||||
text_prompt_supported: Some(true),
|
||||
starting_keyframe_supported: Some(true),
|
||||
ending_keyframe_supported: Some(true),
|
||||
show_generate_with_sound_toggle: Some(true),
|
||||
aspect_ratio_options: Some(vec![
|
||||
CommonAspectRatio::Auto,
|
||||
CommonAspectRatio::WideSixteenByNine,
|
||||
CommonAspectRatio::TallNineBySixteen,
|
||||
]),
|
||||
aspect_ratio_default: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
resolution_options: Some(vec![
|
||||
CommonResolution::SevenTwentyP,
|
||||
CommonResolution::TenEightyP,
|
||||
]),
|
||||
resolution_default: Some(CommonResolution::TenEightyP),
|
||||
duration_seconds_min: Some(4),
|
||||
duration_seconds_max: Some(8),
|
||||
duration_seconds_default: Some(8),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
models.push(OmniGenVideoModelDetails {
|
||||
model: CommonVideoModel::Veo3p1Fast,
|
||||
full_name: Some("Google Veo 3.1 Fast".to_string()),
|
||||
text_prompt_supported: Some(true),
|
||||
starting_keyframe_supported: Some(true),
|
||||
ending_keyframe_supported: Some(true),
|
||||
show_generate_with_sound_toggle: Some(true),
|
||||
aspect_ratio_options: Some(vec![
|
||||
CommonAspectRatio::Auto,
|
||||
CommonAspectRatio::WideSixteenByNine,
|
||||
CommonAspectRatio::TallNineBySixteen,
|
||||
]),
|
||||
aspect_ratio_default: Some(CommonAspectRatio::WideSixteenByNine),
|
||||
resolution_options: Some(vec![
|
||||
CommonResolution::SevenTwentyP,
|
||||
CommonResolution::TenEightyP,
|
||||
]),
|
||||
resolution_default: Some(CommonResolution::TenEightyP),
|
||||
duration_seconds_min: Some(4),
|
||||
duration_seconds_max: Some(8),
|
||||
duration_seconds_default: Some(8),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
models
|
||||
}
|
||||
|
||||
@@ -97,6 +202,26 @@ fn build_omni_gen_video_model_providers() -> Vec<OmniGenVideoModelProviderDetail
|
||||
model: CommonVideoModel::Seedance2p0,
|
||||
overrides: None,
|
||||
},
|
||||
OmniGenVideoProviderModelDetails {
|
||||
model: CommonVideoModel::Veo2,
|
||||
overrides: None,
|
||||
},
|
||||
OmniGenVideoProviderModelDetails {
|
||||
model: CommonVideoModel::Veo3,
|
||||
overrides: None,
|
||||
},
|
||||
OmniGenVideoProviderModelDetails {
|
||||
model: CommonVideoModel::Veo3Fast,
|
||||
overrides: None,
|
||||
},
|
||||
OmniGenVideoProviderModelDetails {
|
||||
model: CommonVideoModel::Veo3p1,
|
||||
overrides: None,
|
||||
},
|
||||
OmniGenVideoProviderModelDetails {
|
||||
model: CommonVideoModel::Veo3p1Fast,
|
||||
overrides: None,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
|
||||
+15
-4
@@ -5,6 +5,7 @@ use actix_web::{web, HttpRequest};
|
||||
use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest;
|
||||
use artcraft_api_defs::omni_gen::cost_response::omni_gen_video_cost_response::OmniGenVideoCostResponse;
|
||||
use artcraft_router::api::provider::Provider;
|
||||
use artcraft_router::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use log::warn;
|
||||
|
||||
use crate::http_server::common_responses::advanced_common_web_error::AdvancedCommonWebError;
|
||||
@@ -31,11 +32,21 @@ pub async fn omni_gen_video_cost_handler(
|
||||
let mut generate_request = transform_request(&request)?;
|
||||
generate_request.provider = Provider::Artcraft;
|
||||
|
||||
let plan = generate_request.build()
|
||||
.map_err(|e| {
|
||||
let plan = match generate_request.build() {
|
||||
Ok(plan) => plan,
|
||||
Err(ArtcraftRouterError::UnsupportedModel(_)) => {
|
||||
generate_request.provider = Provider::Fal;
|
||||
generate_request.build()
|
||||
.map_err(|e| {
|
||||
warn!("Failed to build Fal cost plan: {}", e);
|
||||
AdvancedCommonWebError::from_error(e)
|
||||
})?
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Failed to build cost plan: {}", e);
|
||||
AdvancedCommonWebError::from_error(e)
|
||||
})?;
|
||||
return Err(AdvancedCommonWebError::from_error(e));
|
||||
}
|
||||
};
|
||||
|
||||
let estimate = plan.estimate_costs();
|
||||
|
||||
|
||||
+3
@@ -167,6 +167,9 @@ pub async fn omni_gen_video_generate_handler(
|
||||
artcraft_router::generate::generate_video::generate_video_response::GenerateVideoResponse::Seedance2Pro(p) => {
|
||||
p.order_id.clone()
|
||||
}
|
||||
artcraft_router::generate::generate_video::generate_video_response::GenerateVideoResponse::Fal(p) => {
|
||||
p.request_id.clone().unwrap_or_default()
|
||||
}
|
||||
};
|
||||
|
||||
// ==================== DB TRANSACTION ==================== //
|
||||
|
||||
+22
-8
@@ -1,4 +1,5 @@
|
||||
use artcraft_router::api::provider::Provider;
|
||||
use artcraft_router::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use artcraft_router::generate::generate_video::generate_video_request::GenerateVideoRequest;
|
||||
use artcraft_router::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
|
||||
use log::warn;
|
||||
@@ -6,20 +7,33 @@ use log::warn;
|
||||
use crate::http_server::common_responses::advanced_common_web_error::AdvancedCommonWebError;
|
||||
|
||||
/// Estimate costs for a video generation request.
|
||||
/// Always uses the Artcraft provider for costing regardless of the execution provider.
|
||||
/// Prefers the Artcraft provider for costing, but falls back to Fal for models
|
||||
/// that are only available via Fal (e.g. Veo).
|
||||
pub fn request_to_costs(
|
||||
request: &GenerateVideoRequest<'_>,
|
||||
) -> Result<VideoGenerationCostEstimate, AdvancedCommonWebError> {
|
||||
let mut cost_request = GenerateVideoRequest {
|
||||
let artcraft_request = GenerateVideoRequest {
|
||||
provider: Provider::Artcraft,
|
||||
..*request
|
||||
};
|
||||
|
||||
let plan = cost_request.build()
|
||||
.map_err(|e| {
|
||||
match artcraft_request.build() {
|
||||
Ok(plan) => Ok(plan.estimate_costs()),
|
||||
Err(ArtcraftRouterError::UnsupportedModel(_)) => {
|
||||
let fal_request = GenerateVideoRequest {
|
||||
provider: Provider::Fal,
|
||||
..*request
|
||||
};
|
||||
let plan = fal_request.build()
|
||||
.map_err(|e| {
|
||||
warn!("Failed to build Fal cost plan: {}", e);
|
||||
AdvancedCommonWebError::from_error(e)
|
||||
})?;
|
||||
Ok(plan.estimate_costs())
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Failed to build cost plan: {}", e);
|
||||
AdvancedCommonWebError::from_error(e)
|
||||
})?;
|
||||
|
||||
Ok(plan.estimate_costs())
|
||||
Err(AdvancedCommonWebError::from_error(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user