plumb through a generate_audio, negative_prompt

This commit is contained in:
Brandon Thomas committed 2026-03-08 20:46:37 -04:00
1 parent d68a92e7cf
commit 1a98d8e9c3
20 files changed
+70 -13

No files matched your search

@@ -38,6 +38,9 @@ pub struct Seedance1p5ProMultiFunctionVideoGenRequest {
/// Optional.
pub aspect_ratio: Option<Seedance1p5ProMultiFunctionVideoGenAspectRatio>,
/// Whether to generate audio.
pub generate_audio: Option<bool>,
}
#[derive(Serialize, Deserialize, ToSchema, Copy, Clone, Debug)]
@@ -32,7 +32,7 @@ pub(crate) fn estimate_video_cost_artcraft_kling3p0_pro(
let api_key = fal_client::creds::fal_api_key::FalApiKey::from_str("");
let args = EnqueueKling3p0ProTextToVideoArgs {
prompt: String::new(),
generate_audio: None,
generate_audio: plan.generate_audio,
negative_prompt: None,
duration,
aspect_ratio: None,
@@ -65,6 +65,7 @@ mod tests {
model: CommonVideoModel::Kling3p0Pro,
provider: Provider::Artcraft,
prompt: None,
negative_prompt: None,
start_frame: None,
end_frame: None,
reference_images: None,
@@ -72,6 +73,7 @@ mod tests {
aspect_ratio: None,
duration_seconds: Some(duration_seconds),
video_batch_count: None,
generate_audio: None,
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
idempotency_token: None,
};
@@ -32,7 +32,7 @@ pub(crate) fn estimate_video_cost_artcraft_kling3p0_standard(
let api_key = fal_client::creds::fal_api_key::FalApiKey::from_str("");
let args = EnqueueKling3p0StandardTextToVideoArgs {
prompt: String::new(),
generate_audio: None,
generate_audio: plan.generate_audio,
negative_prompt: None,
duration,
aspect_ratio: None,
@@ -65,6 +65,7 @@ mod tests {
model: CommonVideoModel::Kling3p0Standard,
provider: Provider::Artcraft,
prompt: None,
negative_prompt: None,
start_frame: None,
end_frame: None,
reference_images: None,
@@ -72,6 +73,7 @@ mod tests {
aspect_ratio: None,
duration_seconds: Some(duration_seconds),
video_batch_count: None,
generate_audio: None,
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
idempotency_token: None,
};
@@ -39,6 +39,7 @@ pub(crate) fn estimate_video_cost_artcraft_seedance1p5_pro(
duration,
resolution,
aspect_ratio: None,
generate_audio: plan.generate_audio,
webhook_url: "https://example.com",
api_key: &api_key,
};
@@ -67,6 +68,7 @@ mod tests {
model: CommonVideoModel::Seedance1p5Pro,
provider: Provider::Artcraft,
prompt: None,
negative_prompt: None,
start_frame: None,
end_frame: None,
reference_images: None,
@@ -74,6 +76,7 @@ mod tests {
aspect_ratio: None,
duration_seconds: Some(duration_seconds),
video_batch_count: None,
generate_audio: None,
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
idempotency_token: None,
};
@@ -57,6 +57,7 @@ mod tests {
model: CommonVideoModel::Seedance2p0,
provider: Provider::Artcraft,
prompt: None,
negative_prompt: None,
start_frame: None,
end_frame: None,
reference_images: None,
@@ -64,6 +65,7 @@ mod tests {
aspect_ratio: None,
duration_seconds: Some(duration_seconds),
video_batch_count: Some(video_batch_count),
generate_audio: None,
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
idempotency_token: None,
};
@@ -15,11 +15,11 @@ pub async fn execute_artcraft_kling3p0_pro(
let request = Kling3p0ProMultiFunctionVideoGenRequest {
uuid_idempotency_token: plan.idempotency_token.clone(),
prompt: plan.prompt.map(|p| p.to_string()),
negative_prompt: None,
negative_prompt: plan.negative_prompt.map(|s| s.to_string()),
image_media_token: plan.start_frame.map(|t| t.to_owned()),
end_image_media_token: plan.end_frame.map(|t| t.to_owned()),
duration: plan.duration,
generate_audio: None,
generate_audio: plan.generate_audio,
aspect_ratio: plan.aspect_ratio,
};
@@ -15,11 +15,11 @@ pub async fn execute_artcraft_kling3p0_standard(
let request = Kling3p0StandardMultiFunctionVideoGenRequest {
uuid_idempotency_token: plan.idempotency_token.clone(),
prompt: plan.prompt.map(|p| p.to_string()),
negative_prompt: None,
negative_prompt: plan.negative_prompt.map(|s| s.to_string()),
image_media_token: plan.start_frame.map(|t| t.to_owned()),
end_image_media_token: plan.end_frame.map(|t| t.to_owned()),
duration: plan.duration,
generate_audio: None,
generate_audio: plan.generate_audio,
aspect_ratio: plan.aspect_ratio,
};
@@ -20,6 +20,7 @@ pub async fn execute_artcraft_seedance1p5_pro(
aspect_ratio: plan.aspect_ratio,
duration: plan.duration,
resolution: plan.resolution,
generate_audio: plan.generate_audio,
};
let response = seedance_1p5_pro_multi_function_video_gen(
@@ -22,8 +22,8 @@ pub struct GenerateVideoRequest<'a> {
/// The prompt for the video generation
pub prompt: Option<&'a str>,
// /// Some models support negative prompts
// pub negative_prompt: Option<String>,
/// Some models support negative prompts
pub negative_prompt: Option<&'a str>,
/// Starting keyframe (optional).
pub start_frame: Option<ImageRef<'a>>,
@@ -46,9 +46,11 @@ pub struct GenerateVideoRequest<'a> {
/// How many videos to generate.
pub video_batch_count: Option<u16>,
// /// Whether to turn on/off audio.
// /// Not all models support audio, not all models have a choice.
// pub generate_audio: Option<bool>,
/// Whether to turn on/off audio.
/// Not all models support audio, not all models have a choice.
/// Some models will default this to true, others will default it to false,
/// so it's best to be explicit.
pub generate_audio: Option<bool>,
/// If the request is a mismatch with the (model/provider), how to mitigate it.
pub request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy,
@@ -13,10 +13,12 @@ use tokens::tokens::media_files::MediaFileToken;
#[derive(Debug, Clone)]
pub struct PlanArtcraftKling3p0Pro<'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<Kling3p0ProMultiFunctionVideoGenAspectRatio>,
pub duration: Option<Kling3p0ProMultiFunctionVideoGenDuration>,
pub generate_audio: Option<bool>,
pub idempotency_token: String,
}
@@ -33,10 +35,12 @@ pub fn plan_generate_video_artcraft_kling3p0_pro<'a>(
Ok(PlanArtcraftKling3p0Pro {
prompt: request.prompt,
negative_prompt: request.negative_prompt,
start_frame,
end_frame,
aspect_ratio,
duration,
generate_audio: request.generate_audio,
idempotency_token: request.get_or_generate_idempotency_token(),
})
}
@@ -169,6 +173,7 @@ mod tests {
model: CommonVideoModel::Kling3p0Pro,
provider: Provider::Artcraft,
prompt: Some("a cat in space"),
negative_prompt: None,
start_frame: None,
end_frame: None,
reference_images: None,
@@ -176,6 +181,7 @@ mod tests {
aspect_ratio: None,
duration_seconds: None,
video_batch_count: None,
generate_audio: None,
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
idempotency_token: None,
}
@@ -13,10 +13,12 @@ use tokens::tokens::media_files::MediaFileToken;
#[derive(Debug, Clone)]
pub struct PlanArtcraftKling3p0Standard<'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<Kling3p0StandardMultiFunctionVideoGenAspectRatio>,
pub duration: Option<Kling3p0StandardMultiFunctionVideoGenDuration>,
pub generate_audio: Option<bool>,
pub idempotency_token: String,
}
@@ -33,10 +35,12 @@ pub fn plan_generate_video_artcraft_kling3p0_standard<'a>(
Ok(PlanArtcraftKling3p0Standard {
prompt: request.prompt,
negative_prompt: request.negative_prompt,
start_frame,
end_frame,
aspect_ratio,
duration,
generate_audio: request.generate_audio,
idempotency_token: request.get_or_generate_idempotency_token(),
})
}
@@ -169,6 +173,7 @@ mod tests {
model: CommonVideoModel::Kling3p0Standard,
provider: Provider::Artcraft,
prompt: Some("a cat in space"),
negative_prompt: None,
start_frame: None,
end_frame: None,
reference_images: None,
@@ -176,6 +181,7 @@ mod tests {
aspect_ratio: None,
duration_seconds: None,
video_batch_count: None,
generate_audio: None,
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
idempotency_token: None,
}
@@ -19,6 +19,7 @@ pub struct PlanArtcraftSeedance1p5Pro<'a> {
pub aspect_ratio: Option<Seedance1p5ProMultiFunctionVideoGenAspectRatio>,
pub duration: Option<Seedance1p5ProMultiFunctionVideoGenDuration>,
pub resolution: Option<Seedance1p5ProMultiFunctionVideoGenResolution>,
pub generate_audio: Option<bool>,
pub idempotency_token: String,
}
@@ -41,6 +42,7 @@ pub fn plan_generate_video_artcraft_seedance1p5_pro<'a>(
aspect_ratio,
duration,
resolution,
generate_audio: request.generate_audio,
idempotency_token: request.get_or_generate_idempotency_token(),
})
}
@@ -184,6 +186,7 @@ mod tests {
model: CommonVideoModel::Seedance1p5Pro,
provider: Provider::Artcraft,
prompt: Some("a cat in space"),
negative_prompt: None,
start_frame: None,
end_frame: None,
reference_images: None,
@@ -191,6 +194,7 @@ mod tests {
aspect_ratio: None,
duration_seconds: None,
video_batch_count: None,
generate_audio: None,
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
idempotency_token: None,
}
@@ -214,6 +214,7 @@ pub fn base_video_request() -> GenerateVideoRequest<'static> {
model: CommonVideoModel::Seedance2p0,
provider: Provider::Artcraft,
prompt: Some("a cat in space"),
negative_prompt: None,
start_frame: None,
end_frame: None,
reference_images: None,
@@ -221,6 +222,7 @@ pub fn base_video_request() -> GenerateVideoRequest<'static> {
aspect_ratio: None,
duration_seconds: None,
video_batch_count: None,
generate_audio: None,
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
idempotency_token: None,
}
@@ -16,6 +16,7 @@ pub struct EnqueueSeedance1p5ProImageToVideoArgs<'a, R: IntoUrl> {
pub resolution: Option<EnqueueSeedance1p5ProImageToVideoResolution>,
pub duration: Option<EnqueueSeedance1p5ProImageToVideoDuration>,
pub aspect_ratio: Option<EnqueueSeedance1p5ProImageToVideoAspectRatio>,
pub generate_audio: Option<bool>,
// Fulfillment
pub webhook_url: R,
@@ -150,7 +151,7 @@ pub async fn enqueue_seedance_1p5_pro_image_to_video_webhook<R: IntoUrl>(
camera_fixed: None,
seed: None,
enable_safety_checker: Some(false),
generate_audio: Some(true),
generate_audio: Some(args.generate_audio.unwrap_or(true)),
};
let result = seedance_1p5_pro_image_to_video(request)
@@ -183,6 +184,7 @@ mod tests {
duration: Some(EnqueueSeedance1p5ProImageToVideoDuration::FiveSeconds),
resolution: Some(EnqueueSeedance1p5ProImageToVideoResolution::SevenTwentyP),
aspect_ratio: None,
generate_audio: None,
webhook_url: "https://example.com/webhook",
};
@@ -220,6 +222,7 @@ mod tests {
aspect_ratio: Some(EnqueueSeedance1p5ProImageToVideoAspectRatio::SixteenByNine),
resolution: Some(EnqueueSeedance1p5ProImageToVideoResolution::SevenTwentyP),
end_image_url: None,
generate_audio: None,
api_key: &api_key,
webhook_url: "https://example.com/webhook",
};
@@ -245,6 +248,7 @@ mod tests {
aspect_ratio: Some(ar),
resolution: None,
end_image_url: None,
generate_audio: None,
api_key: &api_key,
webhook_url: "https://example.com/webhook",
};
@@ -270,6 +274,7 @@ mod tests {
aspect_ratio: Some(EnqueueSeedance1p5ProImageToVideoAspectRatio::SixteenByNine),
resolution: None,
end_image_url: None,
generate_audio: None,
api_key: &api_key,
webhook_url: "https://example.com/webhook",
};
@@ -295,6 +300,7 @@ mod tests {
aspect_ratio: Some(EnqueueSeedance1p5ProImageToVideoAspectRatio::SixteenByNine),
resolution: Some(res),
end_image_url: None,
generate_audio: None,
api_key: &api_key,
webhook_url: "https://example.com/webhook",
};
@@ -14,6 +14,7 @@ pub struct EnqueueSeedance1p5ProTextToVideoArgs<'a, R: IntoUrl> {
pub resolution: Option<EnqueueSeedance1p5ProTextToVideoResolution>,
pub duration: Option<EnqueueSeedance1p5ProTextToVideoDuration>,
pub aspect_ratio: Option<EnqueueSeedance1p5ProTextToVideoAspectRatio>,
pub generate_audio: Option<bool>,
// Fulfillment
pub webhook_url: R,
@@ -53,8 +54,10 @@ pub enum EnqueueSeedance1p5ProTextToVideoAspectRatio {
impl <U: IntoUrl> FalRequestCostCalculator for EnqueueSeedance1p5ProTextToVideoArgs<'_, U> {
fn calculate_cost_in_cents(&self) -> UsdCents {
// Fal:
// "Each 720p 5 second video with audio costs roughly $0.26.
// For other resolutions, 1 million video tokens with audio costs $2.4.
// Without audio, the price is 1.2 per million tokens.
// tokens(video) = (height x width x FPS x duration) / 1024."
let resolution = self.resolution.unwrap_or(EnqueueSeedance1p5ProTextToVideoResolution::SevenTwentyP);
@@ -146,7 +149,7 @@ pub async fn enqueue_seedance_1p5_pro_text_to_video_webhook<R: IntoUrl>(
camera_fixed: None,
seed: None,
enable_safety_checker: Some(false),
generate_audio: Some(true),
generate_audio: Some(args.generate_audio.unwrap_or(true)),
};
let result = seedance_1p5_pro_text_to_video(request)
@@ -176,6 +179,7 @@ mod tests {
duration: Some(EnqueueSeedance1p5ProTextToVideoDuration::FiveSeconds),
resolution: Some(EnqueueSeedance1p5ProTextToVideoResolution::SevenTwentyP),
aspect_ratio: None,
generate_audio: None,
webhook_url: "https://example.com/webhook",
};
@@ -211,6 +215,7 @@ mod tests {
duration: Some(EnqueueSeedance1p5ProTextToVideoDuration::FiveSeconds),
aspect_ratio: Some(EnqueueSeedance1p5ProTextToVideoAspectRatio::SixteenByNine),
resolution: Some(EnqueueSeedance1p5ProTextToVideoResolution::SevenTwentyP),
generate_audio: None,
api_key: &api_key,
webhook_url: "https://example.com/webhook",
};
@@ -234,6 +239,7 @@ mod tests {
duration: Some(EnqueueSeedance1p5ProTextToVideoDuration::FourSeconds),
aspect_ratio: Some(ar),
resolution: None,
generate_audio: None,
api_key: &api_key,
webhook_url: "https://example.com/webhook",
};
@@ -257,6 +263,7 @@ mod tests {
duration: Some(dur),
aspect_ratio: Some(EnqueueSeedance1p5ProTextToVideoAspectRatio::SixteenByNine),
resolution: None,
generate_audio: None,
api_key: &api_key,
webhook_url: "https://example.com/webhook",
};
@@ -280,6 +287,7 @@ mod tests {
duration: Some(EnqueueSeedance1p5ProTextToVideoDuration::FourSeconds),
aspect_ratio: Some(EnqueueSeedance1p5ProTextToVideoAspectRatio::SixteenByNine),
resolution: Some(res),
generate_audio: None,
api_key: &api_key,
webhook_url: "https://example.com/webhook",
};
@@ -32,6 +32,7 @@ pub(super) async fn handle_artcraft_seedance_1p5_pro(
model: CommonVideoModel::Seedance1p5Pro,
provider: Provider::Artcraft,
prompt: request.prompt.as_deref(),
negative_prompt: None,
start_frame,
end_frame,
reference_images: None,
@@ -39,6 +40,7 @@ pub(super) async fn handle_artcraft_seedance_1p5_pro(
aspect_ratio: request.aspect_ratio,
duration_seconds: request.duration_seconds,
video_batch_count: request.video_batch_count,
generate_audio: None,
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade,
idempotency_token: None,
};
@@ -34,6 +34,7 @@ pub(super) async fn handle_artcraft_seedance_2p0(
model: CommonVideoModel::Seedance2p0,
provider: Provider::Artcraft,
prompt: request.prompt.as_deref(),
negative_prompt: None,
start_frame,
end_frame,
reference_images,
@@ -41,6 +42,7 @@ pub(super) async fn handle_artcraft_seedance_2p0(
aspect_ratio: request.aspect_ratio,
duration_seconds: request.duration_seconds,
video_batch_count: request.video_batch_count,
generate_audio: None,
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade,
idempotency_token: None,
};
@@ -34,6 +34,7 @@ pub(super) async fn handle_artcraft_video_via_router(
model,
provider: Provider::Artcraft,
prompt: request.prompt.as_deref(),
negative_prompt: None,
start_frame,
end_frame,
reference_images: None,
@@ -41,6 +42,7 @@ pub(super) async fn handle_artcraft_video_via_router(
aspect_ratio: request.aspect_ratio,
duration_seconds: request.duration_seconds,
video_batch_count: request.video_batch_count,
generate_audio: None,
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade,
idempotency_token: None,
};
@@ -42,6 +42,7 @@ pub async fn estimate_video_cost_handler(
model: router_model,
provider: router_provider,
prompt: None,
negative_prompt: None,
start_frame: None,
end_frame: None,
reference_images: None,
@@ -49,6 +50,7 @@ pub async fn estimate_video_cost_handler(
aspect_ratio: router_aspect_ratio,
duration_seconds: request.duration_seconds,
video_batch_count: request.video_batch_count,
generate_audio: None,
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayLessDowngrade,
idempotency_token: None,
};
@@ -220,6 +220,7 @@ pub async fn seedance_1p5_pro_multi_function_video_gen_handler(
duration: Some(duration),
aspect_ratio: Some(aspect_ratio),
resolution: Some(resolution),
generate_audio: request.generate_audio,
webhook_url: &server_state.fal.webhook_url,
api_key: &server_state.fal.api_key,
};
@@ -254,6 +255,7 @@ pub async fn seedance_1p5_pro_multi_function_video_gen_handler(
duration: Some(duration),
aspect_ratio: Some(aspect_ratio),
resolution: Some(resolution),
generate_audio: request.generate_audio,
webhook_url: &server_state.fal.webhook_url,
api_key: &server_state.fal.api_key,
};