This commit is contained in:
Brandon Thomas committed 2026-06-24 17:17:20 -04:00
1 parent 43086c9071
commit dfe71177ce
7 files changed
+84 -75

No files matched your search

@@ -289,70 +289,6 @@ pub fn plan_duration(
}
}
// ── Seedance 2.0 4K pricing (5% margin over Kinovi) ──
//
// 4K is priced uniformly across the non-Fast Seedance 2.0 ArtCraft providers,
// off the Kinovi Seedance 2.0 4K cost (the `seedance2pro_client` source of
// truth) plus a 5% margin. Kinovi's 4K cost already includes the per-second
// video-reference surcharge, so both with- and without-reference are handled.
/// Margin applied to Kinovi's Seedance 2.0 4K cost to set ArtCraft's user price.
const SEEDANCE_2P0_FOUR_K_MARGIN_MULTIPLIER: f64 = 1.05;
/// Kinovi's cost (USD cents) for Seedance 2.0 at 4K — the source of truth.
/// `has_video_reference` toggles Kinovi's per-second video-reference surcharge.
pub fn kinovi_seedance_2p0_four_k_usd_cents(
duration_seconds: u16,
batch_count: u16,
has_video_reference: bool,
) -> u64 {
use seedance2pro_client::generate::video::generate_seedance_2p0::{
GenerateSeedance2p0Request, KinoviSeedance2p0BatchCount, KinoviSeedance2p0OutputResolution,
};
let batch_count = match batch_count {
2 => Some(KinoviSeedance2p0BatchCount::Two),
4 => Some(KinoviSeedance2p0BatchCount::Four),
_ => Some(KinoviSeedance2p0BatchCount::One),
};
let reference_video_urls = if has_video_reference {
// Presence drives the surcharge; the URL contents don't matter for pricing.
Some(vec!["pricing-placeholder".to_string()])
} else {
None
};
GenerateSeedance2p0Request {
output_resolution: Some(KinoviSeedance2p0OutputResolution::FourK),
duration_seconds: duration_seconds as u8,
batch_count,
reference_video_urls,
prompt: String::new(),
aspect_ratio: None,
start_frame_url: None,
end_frame_url: None,
reference_image_urls: None,
reference_audio_urls: None,
character_ids: None,
use_face_blur_hack: None,
bitrate: None,
}
.calculate_costs()
.total_cost
.usd_cents_rounded_up
}
/// ArtCraft's user-facing price (USD cents) for Seedance 2.0 at 4K: a 5% margin
/// over Kinovi's cost, rounded up so the margin never drops below 5%.
pub fn seedance_2p0_four_k_usd_cents(
duration_seconds: u16,
batch_count: u16,
has_video_reference: bool,
) -> u64 {
let kinovi_cents = kinovi_seedance_2p0_four_k_usd_cents(duration_seconds, batch_count, has_video_reference);
(kinovi_cents as f64 * SEEDANCE_2P0_FOUR_K_MARGIN_MULTIPLIER).ceil() as u64
}
#[cfg(test)]
mod tests {
use super::*;
@@ -1,4 +1,5 @@
pub(crate) mod build_common;
pub(crate) mod seedance_common;
#[cfg(test)]
mod parity_tests;
pub mod grok_imagine_video;
@@ -1,6 +1,6 @@
use enums::common::generation::common_resolution::CommonResolution;
use crate::generate::generate_video::providers::artcraft::build_common::seedance_2p0_four_k_usd_cents;
use crate::generate::generate_video::providers::artcraft::seedance_common::seedance_2p0_four_k_usd_cents;
use crate::generate::generate_video::providers::artcraft::seedance_2p0::request::ArtcraftSeedance2p0RequestState;
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
@@ -197,7 +197,7 @@ mod tests {
assert_eq!(artcraft_4k_cents(4, 1, false), 347);
assert_eq!(artcraft_4k_cents(5, 1, false), 433);
assert_eq!(artcraft_4k_cents(10, 1, false), 866);
assert_eq!(artcraft_4k_cents(15, 1, false), 1297);
assert_eq!(artcraft_4k_cents(15, 1, false), 1299);
}
#[test]
@@ -1,6 +1,6 @@
use enums::common::generation::common_resolution::CommonResolution;
use crate::generate::generate_video::providers::artcraft::build_common::seedance_2p0_four_k_usd_cents;
use crate::generate::generate_video::providers::artcraft::seedance_common::seedance_2p0_four_k_usd_cents;
use crate::generate::generate_video::providers::artcraft::seedance_2p0_bp::request::ArtcraftSeedance2p0BytePlusRequestState;
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
@@ -167,7 +167,7 @@ mod tests {
assert_eq!(artcraft_4k_cents(4, 1, false), 347);
assert_eq!(artcraft_4k_cents(5, 1, false), 433);
assert_eq!(artcraft_4k_cents(10, 1, false), 866);
assert_eq!(artcraft_4k_cents(15, 1, false), 1297);
assert_eq!(artcraft_4k_cents(15, 1, false), 1299);
}
#[test]
@@ -1,6 +1,6 @@
use enums::common::generation::common_resolution::CommonResolution;
use crate::generate::generate_video::providers::artcraft::build_common::seedance_2p0_four_k_usd_cents;
use crate::generate::generate_video::providers::artcraft::seedance_common::seedance_2p0_four_k_usd_cents;
use crate::generate::generate_video::providers::artcraft::seedance_2p0_bpu::request::ArtcraftSeedance2p0BytePlusUltraRequestState;
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
@@ -167,7 +167,7 @@ mod tests {
assert_eq!(artcraft_4k_cents(4, 1, false), 347);
assert_eq!(artcraft_4k_cents(5, 1, false), 433);
assert_eq!(artcraft_4k_cents(10, 1, false), 866);
assert_eq!(artcraft_4k_cents(15, 1, false), 1297);
assert_eq!(artcraft_4k_cents(15, 1, false), 1299);
}
#[test]
@@ -1,6 +1,6 @@
use enums::common::generation::common_resolution::CommonResolution;
use crate::generate::generate_video::providers::artcraft::build_common::seedance_2p0_four_k_usd_cents;
use crate::generate::generate_video::providers::artcraft::seedance_common::seedance_2p0_four_k_usd_cents;
use crate::generate::generate_video::providers::artcraft::seedance_2p0_u::request::ArtcraftSeedance2p0UltraRequestState;
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
@@ -31,9 +31,6 @@ impl ArtcraftSeedance2p0UltraCostState {
}
pub fn estimate_cost(&self) -> VideoGenerationCostEstimate {
// 4K is priced at a 5% margin over Kinovi's Seedance 2.0 4K cost (which
// already includes the per-second video-reference surcharge). Other
// resolutions use this model's own per-second rates.
if self.resolution == CommonResolution::FourK {
let usd_cents = seedance_2p0_four_k_usd_cents(
self.duration_seconds,
@@ -167,7 +164,7 @@ mod tests {
assert_eq!(artcraft_4k_cents(4, 1, false), 347);
assert_eq!(artcraft_4k_cents(5, 1, false), 433);
assert_eq!(artcraft_4k_cents(10, 1, false), 866);
assert_eq!(artcraft_4k_cents(15, 1, false), 1297);
assert_eq!(artcraft_4k_cents(15, 1, false), 1299);
}
#[test]
@@ -0,0 +1,75 @@
//! Shared pricing for the Seedance 2.0 family of ArtCraft providers.
//!
//! ArtCraft credits equal USD cents (100 credits = $1.00).
// 4K is priced uniformly across the non-Fast Seedance 2.0 models. Rates are held
// in hundredths of a USD cent per second so the math is exact integer arithmetic
// (no floating point), then rounded up to whole cents.
/// 4K output price, in hundredths of a USD cent per second (86.60 ¢/s).
const FOUR_K_CENTI_CENTS_PER_SECOND: u64 = 8660;
/// Extra hundredths of a USD cent per second when a reference video is attached
/// at 4K (17.20 ¢/s surcharge).
const FOUR_K_VIDEO_REFERENCE_SURCHARGE_CENTI_CENTS_PER_SECOND: u64 = 1720;
/// ArtCraft's user-facing price (USD cents) for Seedance 2.0 at 4K.
///
/// A reference video adds a per-second surcharge (4K with and without a video
/// reference are priced differently). The cost scales with duration and batch
/// count, rounded up to whole cents.
pub fn seedance_2p0_four_k_usd_cents(
duration_seconds: u16,
batch_count: u16,
has_video_reference: bool,
) -> u64 {
let mut centi_cents_per_second = FOUR_K_CENTI_CENTS_PER_SECOND;
if has_video_reference {
centi_cents_per_second += FOUR_K_VIDEO_REFERENCE_SURCHARGE_CENTI_CENTS_PER_SECOND;
}
let total_centi_cents =
centi_cents_per_second * duration_seconds as u64 * batch_count as u64;
// Round up to whole cents.
total_centi_cents.div_ceil(100)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn four_k_without_video_reference() {
assert_eq!(seedance_2p0_four_k_usd_cents(4, 1, false), 347);
assert_eq!(seedance_2p0_four_k_usd_cents(5, 1, false), 433);
assert_eq!(seedance_2p0_four_k_usd_cents(10, 1, false), 866);
assert_eq!(seedance_2p0_four_k_usd_cents(15, 1, false), 1299);
}
#[test]
fn four_k_with_video_reference() {
assert_eq!(seedance_2p0_four_k_usd_cents(4, 1, true), 416);
assert_eq!(seedance_2p0_four_k_usd_cents(5, 1, true), 519);
assert_eq!(seedance_2p0_four_k_usd_cents(10, 1, true), 1038);
assert_eq!(seedance_2p0_four_k_usd_cents(15, 1, true), 1557);
}
#[test]
fn video_reference_always_costs_more() {
for &duration in &[4u16, 5, 10, 15] {
assert!(
seedance_2p0_four_k_usd_cents(duration, 1, true)
> seedance_2p0_four_k_usd_cents(duration, 1, false),
"video reference should cost more at {duration}s",
);
}
}
#[test]
fn batch_count_multiplies() {
assert_eq!(seedance_2p0_four_k_usd_cents(5, 2, false), 866);
assert_eq!(seedance_2p0_four_k_usd_cents(5, 4, false), 1732);
assert_eq!(seedance_2p0_four_k_usd_cents(5, 2, true), 1038);
}
}