seedance pro 1.0 cost

This commit is contained in:
Brandon Thomas committed 2025-12-29 01:17:57 -05:00
1 parent 02cb7558e4
commit efe56050c4
2 files changed
+93 -3

No files matched your search

@@ -86,7 +86,7 @@ impl <U: IntoUrl, T: IntoUrl, V: IntoUrl> FalRequestCostCalculator for Seedance1
}
/// Seedance 1 Lite Image-to-Video
/// Seedance 1.0 Lite Image-to-Video
/// https://fal.ai/models/fal-ai/bytedance/seedance/v1/lite/image-to-video
pub async fn enqueue_seedance_1_lite_image_to_video_webhook<U: IntoUrl, T: IntoUrl, V: IntoUrl>(
args: Seedance1LiteArgs<'_, U, T, V>
@@ -1,6 +1,7 @@
use crate::creds::fal_api_key::FalApiKey;
use crate::error::classify_fal_error::classify_fal_error;
use crate::error::fal_error_plus::FalErrorPlus;
use crate::requests::traits::fal_request_cost_calculator_trait::{FalRequestCostCalculator, UsdCents};
use fal::endpoints::fal_ai::bytedance::seedance::v1::pro::image_to_video::{seedance_v1_pro_image_to_video, SeedanceImageToVideoProRequest};
use fal::webhook::WebhookResponse;
use reqwest::IntoUrl;
@@ -16,7 +17,7 @@ pub struct Seedance1ProArgs<'a, U: IntoUrl, V: IntoUrl> {
pub seed: Option<u32>,
}
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Seedance1ProDuration {
ThreeSeconds,
FourSeconds,
@@ -30,13 +31,63 @@ pub enum Seedance1ProDuration {
TwelveSeconds,
}
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Seedance1ProResolution {
FourEightyP, // 480p
SevenTwentyP, // 720p
TenEightyP, // 1080p
}
impl <U: IntoUrl, V: IntoUrl> FalRequestCostCalculator for Seedance1ProArgs<'_, U, V> {
fn calculate_cost_in_cents(&self) -> UsdCents {
// "Each 1080p 5 second video costs roughly $0.62.
// For other resolutions, 1 million video tokens costs $2.5.
// tokens(video) = (height x width x FPS x duration) / 1024."
if self.resolution == Seedance1ProResolution::TenEightyP
&& self.duration == Seedance1ProDuration::FiveSeconds
{
return 62;
}
// TODO: Only correct for some aspect ratios for now.
let (width, height) = match self.resolution {
Seedance1ProResolution::FourEightyP => (640u32, 480u32), // NB: Only for 4:3 !
Seedance1ProResolution::SevenTwentyP => (1280, 720), // NB: Only for 16:9 !
Seedance1ProResolution::TenEightyP => (1920, 1080),
};
let duration = match self.duration {
Seedance1ProDuration::ThreeSeconds => 3.0,
Seedance1ProDuration::FourSeconds => 4.0,
Seedance1ProDuration::FiveSeconds => 5.0,
Seedance1ProDuration::SixSeconds => 6.0,
Seedance1ProDuration::SevenSeconds => 7.0,
Seedance1ProDuration::EightSeconds => 8.0,
Seedance1ProDuration::NineSeconds => 9.0,
Seedance1ProDuration::TenSeconds => 10.0,
Seedance1ProDuration::ElevenSeconds => 11.0,
Seedance1ProDuration::TwelveSeconds => 12.0,
};
// TODO: Not sure if FPS is right.
// Inferred from https://help.scenario.com/en/articles/seedance-models-the-essentials/
const FPS : f64 = 30.0;
let tokens = (height as f64) * (width as f64) * FPS * duration;
let tokens = tokens / 1024.0;
let cost = tokens * 2.5 / 1_000_000.0;
let cost = cost * 100.0; // Dollars to cents.
let cost = cost.ceil(); // NB: This is probably what Fal does.
cost as UsdCents
}
}
/// Seedance 1.0 Pro Image-to-Video
/// https://fal.ai/models/fal-ai/bytedance/seedance/v1/pro/image-to-video
pub async fn enqueue_seedance_1_pro_image_to_video_webhook<U: IntoUrl, V: IntoUrl>(
args: Seedance1ProArgs<'_, U, V>
) -> Result<WebhookResponse, FalErrorPlus> {
@@ -84,11 +135,50 @@ pub async fn enqueue_seedance_1_pro_image_to_video_webhook<U: IntoUrl, V: IntoUr
#[cfg(test)]
mod tests {
use crate::creds::fal_api_key::FalApiKey;
use crate::requests::traits::fal_request_cost_calculator_trait::FalRequestCostCalculator;
use crate::requests::webhook::video::image::enqueue_seedance_1_pro_image_to_video_webhook::{enqueue_seedance_1_pro_image_to_video_webhook, Seedance1ProArgs, Seedance1ProDuration, Seedance1ProResolution};
use errors::AnyhowResult;
use std::fs::read_to_string;
use test_data::web::image_urls::TALL_MOCHI_WITH_GLASSES_IMAGE_URL;
#[test]
fn test_cost() {
let api_key = FalApiKey::from_str("");
let mut args = Seedance1ProArgs {
image_url: "",
prompt: "",
api_key: &api_key,
camera_fixed: false,
duration: Seedance1ProDuration::FiveSeconds,
resolution: Seedance1ProResolution::TenEightyP,
seed: None,
webhook_url: "https://example.com/webhook",
};
// NB: Constant value specified by FAL
args.duration = Seedance1ProDuration::FiveSeconds;
args.resolution = Seedance1ProResolution::TenEightyP;
let cost = args.calculate_cost_in_cents();
assert_eq!(cost, 62);
// NB: Calculations follow...
args.duration = Seedance1ProDuration::FiveSeconds;
args.resolution = Seedance1ProResolution::SevenTwentyP;
let cost = args.calculate_cost_in_cents();
assert_eq!(cost, 34);
args.duration = Seedance1ProDuration::TenSeconds;
args.resolution = Seedance1ProResolution::SevenTwentyP;
let cost = args.calculate_cost_in_cents();
assert_eq!(cost, 68);
args.duration = Seedance1ProDuration::TenSeconds;
args.resolution = Seedance1ProResolution::TenEightyP;
let cost = args.calculate_cost_in_cents();
assert_eq!(cost, 152);
}
#[tokio::test]
#[ignore]
async fn test() -> AnyhowResult<()> {