mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-03 08:57:54 +00:00
surcharge amount
This commit is contained in:
1 parent
923609ea34
commit
5a022d010d
3 files changed
+141
-70
No files matched your search
+61
-26
@@ -3,34 +3,37 @@ use crate::cost::kinovi_generation_cost::KinoviGenerationCost;
|
||||
/// The cost of a Kinovi Seedance generation, with the video-reference
|
||||
/// surcharge broken out from the base price.
|
||||
///
|
||||
/// `total_cost` covers `base_credits_cost + video_reference_surcharge_cost`.
|
||||
/// `total_cost` covers base + surcharge. NB: the total's USD conversions are
|
||||
/// computed from the SUMMED credits (rounded once), so they may differ by a
|
||||
/// cent from adding the parts' rounded USD values together.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct KinoviSeedanceGenerationCost {
|
||||
/// The full cost (base + any surcharge), in credits and USD cents.
|
||||
pub total_cost: KinoviGenerationCost,
|
||||
|
||||
/// The base generation cost in Kinovi credits (resolution rate × output
|
||||
/// duration × batch count), excluding any surcharges.
|
||||
pub base_credits_cost: u64,
|
||||
/// The base generation cost (resolution rate × output duration × batch
|
||||
/// count), excluding any surcharges.
|
||||
pub base_cost: KinoviGenerationCost,
|
||||
|
||||
/// The video-reference surcharge in Kinovi credits, when one or more
|
||||
/// reference videos are attached. `None` when no reference videos are
|
||||
/// attached.
|
||||
pub video_reference_surcharge_cost: Option<u64>,
|
||||
/// The video-reference surcharge, when one or more reference videos are
|
||||
/// attached. `None` when no reference videos are attached.
|
||||
pub video_reference_surcharge_cost: Option<KinoviGenerationCost>,
|
||||
}
|
||||
|
||||
impl KinoviSeedanceGenerationCost {
|
||||
/// Build a cost from base credits plus an optional video-reference
|
||||
/// surcharge. The total (and its USD conversion) is derived.
|
||||
/// surcharge (both in Kinovi credits). The per-part and total USD
|
||||
/// conversions are derived.
|
||||
pub fn from_base_and_surcharge(
|
||||
base_credits_cost: u64,
|
||||
video_reference_surcharge_cost: Option<u64>,
|
||||
base_credits: u64,
|
||||
maybe_video_reference_surcharge_credits: Option<u64>,
|
||||
) -> Self {
|
||||
let total_credits = base_credits_cost + video_reference_surcharge_cost.unwrap_or(0);
|
||||
let total_credits = base_credits + maybe_video_reference_surcharge_credits.unwrap_or(0);
|
||||
Self {
|
||||
total_cost: KinoviGenerationCost::from_kinovi_credits(total_credits),
|
||||
base_credits_cost,
|
||||
video_reference_surcharge_cost,
|
||||
base_cost: KinoviGenerationCost::from_kinovi_credits(base_credits),
|
||||
video_reference_surcharge_cost: maybe_video_reference_surcharge_credits
|
||||
.map(KinoviGenerationCost::from_kinovi_credits),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,32 +47,64 @@ mod tests {
|
||||
#[test]
|
||||
fn without_surcharge() {
|
||||
let cost = KinoviSeedanceGenerationCost::from_base_and_surcharge(200, None);
|
||||
assert_eq!(cost.base_credits_cost, 200);
|
||||
assert_eq!(cost.video_reference_surcharge_cost, None);
|
||||
assert_eq!(cost.total_cost.kinovi_credits, 200);
|
||||
// 20000/193 = 103.63.
|
||||
assert_eq!(cost.total_cost.usd_cents_rounded_up, 104);
|
||||
assert_eq!(cost.total_cost.usd_cents_rounded_down, 103);
|
||||
assert!((cost.total_cost.usd_cents_fractional - (20000.0 / 193.0)).abs() < FLOAT_TOLERANCE);
|
||||
|
||||
assert!(cost.video_reference_surcharge_cost.is_none());
|
||||
|
||||
// Base: 200 credits; 20000/193 = 103.63.
|
||||
assert_eq!(cost.base_cost.kinovi_credits, 200);
|
||||
assert_eq!(cost.base_cost.usd_cents_rounded_up, 104);
|
||||
assert_eq!(cost.base_cost.usd_cents_rounded_down, 103);
|
||||
assert!((cost.base_cost.usd_cents_fractional - (20000.0 / 193.0)).abs() < FLOAT_TOLERANCE);
|
||||
|
||||
// Total equals base when there's no surcharge.
|
||||
assert_eq!(cost.total_cost, cost.base_cost);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_surcharge() {
|
||||
let cost = KinoviSeedanceGenerationCost::from_base_and_surcharge(200, Some(40));
|
||||
assert_eq!(cost.base_credits_cost, 200);
|
||||
assert_eq!(cost.video_reference_surcharge_cost, Some(40));
|
||||
|
||||
// Base: 200 credits; 20000/193 = 103.63.
|
||||
assert_eq!(cost.base_cost.kinovi_credits, 200);
|
||||
assert_eq!(cost.base_cost.usd_cents_rounded_up, 104);
|
||||
assert_eq!(cost.base_cost.usd_cents_rounded_down, 103);
|
||||
assert!((cost.base_cost.usd_cents_fractional - (20000.0 / 193.0)).abs() < FLOAT_TOLERANCE);
|
||||
|
||||
// Surcharge: 40 credits; 4000/193 = 20.73.
|
||||
let surcharge = cost.video_reference_surcharge_cost.expect("should have surcharge");
|
||||
assert_eq!(surcharge.kinovi_credits, 40);
|
||||
assert_eq!(surcharge.usd_cents_rounded_up, 21);
|
||||
assert_eq!(surcharge.usd_cents_rounded_down, 20);
|
||||
assert!((surcharge.usd_cents_fractional - (4000.0 / 193.0)).abs() < FLOAT_TOLERANCE);
|
||||
|
||||
// Total: 240 credits; 24000/193 = 124.35.
|
||||
assert_eq!(cost.total_cost.kinovi_credits, 240);
|
||||
// 24000/193 = 124.35.
|
||||
assert_eq!(cost.total_cost.usd_cents_rounded_up, 125);
|
||||
assert_eq!(cost.total_cost.usd_cents_rounded_down, 124);
|
||||
assert!((cost.total_cost.usd_cents_fractional - (24000.0 / 193.0)).abs() < FLOAT_TOLERANCE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn total_is_base_plus_surcharge() {
|
||||
fn total_credits_are_base_plus_surcharge() {
|
||||
let cost = KinoviSeedanceGenerationCost::from_base_and_surcharge(450, Some(90));
|
||||
assert_eq!(
|
||||
cost.total_cost.kinovi_credits,
|
||||
cost.base_credits_cost + cost.video_reference_surcharge_cost.unwrap());
|
||||
cost.base_cost.kinovi_credits + cost.video_reference_surcharge_cost.unwrap().kinovi_credits);
|
||||
}
|
||||
|
||||
/// The total's USD is rounded ONCE on the summed credits, so it can be a
|
||||
/// cent under the sum of the parts' rounded-up values.
|
||||
#[test]
|
||||
fn total_usd_is_rounded_once_not_per_part() {
|
||||
let cost = KinoviSeedanceGenerationCost::from_base_and_surcharge(200, Some(40));
|
||||
let surcharge = cost.video_reference_surcharge_cost.unwrap();
|
||||
|
||||
// Parts round up to 104 + 21 = 125 — which happens to match here…
|
||||
assert_eq!(cost.base_cost.usd_cents_rounded_up + surcharge.usd_cents_rounded_up, 125);
|
||||
assert_eq!(cost.total_cost.usd_cents_rounded_up, 125);
|
||||
|
||||
// …but the fractional parts always sum exactly to the fractional total.
|
||||
let parts = cost.base_cost.usd_cents_fractional + surcharge.usd_cents_fractional;
|
||||
assert!((parts - cost.total_cost.usd_cents_fractional).abs() < FLOAT_TOLERANCE);
|
||||
}
|
||||
}
|
||||
+41
-23
@@ -115,16 +115,16 @@ impl GenerateSeedance2p0Request {
|
||||
};
|
||||
|
||||
let duration = u64::from(self.duration_seconds);
|
||||
let base_credits_cost = duration * credits_per_second * batch_multiplier;
|
||||
let video_reference_surcharge_cost = if self.has_video_reference() {
|
||||
let base_credits = duration * credits_per_second * batch_multiplier;
|
||||
let maybe_video_reference_surcharge_credits = if self.has_video_reference() {
|
||||
Some(duration * video_reference_surcharge_per_second * batch_multiplier)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
KinoviSeedanceGenerationCost::from_base_and_surcharge(
|
||||
base_credits_cost,
|
||||
video_reference_surcharge_cost,
|
||||
base_credits,
|
||||
maybe_video_reference_surcharge_credits,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -433,8 +433,8 @@ mod tests {
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_up, 39);
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_down, 38);
|
||||
assert!((costs.total_cost.usd_cents_fractional - (7500.0 / 193.0)).abs() < 1e-9);
|
||||
assert_eq!(costs.base_credits_cost, 75);
|
||||
assert_eq!(costs.video_reference_surcharge_cost, None);
|
||||
assert_eq!(costs.base_cost.kinovi_credits, 75);
|
||||
assert!(costs.video_reference_surcharge_cost.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -445,8 +445,8 @@ mod tests {
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_up, 104);
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_down, 103);
|
||||
assert!((costs.total_cost.usd_cents_fractional - (20000.0 / 193.0)).abs() < 1e-9);
|
||||
assert_eq!(costs.base_credits_cost, 200);
|
||||
assert_eq!(costs.video_reference_surcharge_cost, None);
|
||||
assert_eq!(costs.base_cost.kinovi_credits, 200);
|
||||
assert!(costs.video_reference_surcharge_cost.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -457,8 +457,8 @@ mod tests {
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_up, 234);
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_down, 233);
|
||||
assert!((costs.total_cost.usd_cents_fractional - (45000.0 / 193.0)).abs() < 1e-9);
|
||||
assert_eq!(costs.base_credits_cost, 450);
|
||||
assert_eq!(costs.video_reference_surcharge_cost, None);
|
||||
assert_eq!(costs.base_cost.kinovi_credits, 450);
|
||||
assert!(costs.video_reference_surcharge_cost.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -469,8 +469,8 @@ mod tests {
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_up, 311);
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_down, 310);
|
||||
assert!((costs.total_cost.usd_cents_fractional - (60000.0 / 193.0)).abs() < 1e-9);
|
||||
assert_eq!(costs.base_credits_cost, 600);
|
||||
assert_eq!(costs.video_reference_surcharge_cost, None);
|
||||
assert_eq!(costs.base_cost.kinovi_credits, 600);
|
||||
assert!(costs.video_reference_surcharge_cost.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -481,8 +481,8 @@ mod tests {
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_up, 700);
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_down, 699);
|
||||
assert!((costs.total_cost.usd_cents_fractional - (135000.0 / 193.0)).abs() < 1e-9);
|
||||
assert_eq!(costs.base_credits_cost, 1350);
|
||||
assert_eq!(costs.video_reference_surcharge_cost, None);
|
||||
assert_eq!(costs.base_cost.kinovi_credits, 1350);
|
||||
assert!(costs.video_reference_surcharge_cost.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -493,8 +493,8 @@ mod tests {
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_up, 415);
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_down, 414);
|
||||
assert!((costs.total_cost.usd_cents_fractional - (80000.0 / 193.0)).abs() < 1e-9);
|
||||
assert_eq!(costs.base_credits_cost, 800);
|
||||
assert_eq!(costs.video_reference_surcharge_cost, None);
|
||||
assert_eq!(costs.base_cost.kinovi_credits, 800);
|
||||
assert!(costs.video_reference_surcharge_cost.is_none());
|
||||
}
|
||||
|
||||
/// The deprecated shims return the corresponding struct fields.
|
||||
@@ -547,8 +547,8 @@ mod tests {
|
||||
|
||||
for (make, duration, base, surcharge) in cases {
|
||||
let costs = with_video_ref(make(*duration)).calculate_costs();
|
||||
assert_eq!(costs.base_credits_cost, *base, "base for {duration}s");
|
||||
assert_eq!(costs.video_reference_surcharge_cost, Some(*surcharge), "surcharge for {duration}s");
|
||||
assert_eq!(costs.base_cost.kinovi_credits, *base, "base for {duration}s");
|
||||
assert_eq!(costs.video_reference_surcharge_cost.map(|c| c.kinovi_credits), Some(*surcharge), "surcharge for {duration}s");
|
||||
assert_eq!(costs.total_cost.kinovi_credits, base + surcharge, "total for {duration}s");
|
||||
}
|
||||
}
|
||||
@@ -557,21 +557,39 @@ mod tests {
|
||||
fn surcharge_includes_usd_cents() {
|
||||
// 720p 5s + video ref = 200 + 40 = 240 credits; 24000/193 = 124.35 → 125¢
|
||||
let costs = with_video_ref(r720(5)).calculate_costs();
|
||||
assert_eq!(costs.base_credits_cost, 200);
|
||||
assert_eq!(costs.video_reference_surcharge_cost, Some(40));
|
||||
assert_eq!(costs.base_cost.kinovi_credits, 200);
|
||||
assert_eq!(costs.video_reference_surcharge_cost.map(|c| c.kinovi_credits), Some(40));
|
||||
assert_eq!(costs.total_cost.kinovi_credits, 240);
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_up, 125);
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_down, 124);
|
||||
assert!((costs.total_cost.usd_cents_fractional - (24000.0 / 193.0)).abs() < 1e-9);
|
||||
}
|
||||
|
||||
/// The base and surcharge parts each carry their own USD conversions.
|
||||
#[test]
|
||||
fn parts_have_their_own_usd_conversions() {
|
||||
let costs = with_video_ref(r720(5)).calculate_costs();
|
||||
|
||||
// Base: 200 credits; 20000/193 = 103.63.
|
||||
assert_eq!(costs.base_cost.usd_cents_rounded_up, 104);
|
||||
assert_eq!(costs.base_cost.usd_cents_rounded_down, 103);
|
||||
assert!((costs.base_cost.usd_cents_fractional - (20000.0 / 193.0)).abs() < 1e-9);
|
||||
|
||||
// Surcharge: 40 credits; 4000/193 = 20.73.
|
||||
let surcharge = costs.video_reference_surcharge_cost.expect("should have surcharge");
|
||||
assert_eq!(surcharge.kinovi_credits, 40);
|
||||
assert_eq!(surcharge.usd_cents_rounded_up, 21);
|
||||
assert_eq!(surcharge.usd_cents_rounded_down, 20);
|
||||
assert!((surcharge.usd_cents_fractional - (4000.0 / 193.0)).abs() < 1e-9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_video_reference_list_has_no_surcharge() {
|
||||
let mut request = r720(5);
|
||||
request.reference_video_urls = Some(vec![]);
|
||||
let costs = request.calculate_costs();
|
||||
assert_eq!(costs.total_cost.kinovi_credits, 200);
|
||||
assert_eq!(costs.video_reference_surcharge_cost, None);
|
||||
assert!(costs.video_reference_surcharge_cost.is_none());
|
||||
}
|
||||
|
||||
/// Surcharge is flat per generation regardless of how many reference
|
||||
@@ -592,8 +610,8 @@ mod tests {
|
||||
let request = with_video_ref(build_request(5, None, Some(KinoviSeedance2p0BatchCount::Two)));
|
||||
// (200 base + 40 surcharge) × 2 = 480 credits
|
||||
let costs = request.calculate_costs();
|
||||
assert_eq!(costs.base_credits_cost, 400);
|
||||
assert_eq!(costs.video_reference_surcharge_cost, Some(80));
|
||||
assert_eq!(costs.base_cost.kinovi_credits, 400);
|
||||
assert_eq!(costs.video_reference_surcharge_cost.map(|c| c.kinovi_credits), Some(80));
|
||||
assert_eq!(costs.total_cost.kinovi_credits, 480);
|
||||
}
|
||||
}
|
||||
|
||||
+39
-21
@@ -110,16 +110,16 @@ impl GenerateSeedance2p0FastRequest {
|
||||
};
|
||||
|
||||
let duration = u64::from(self.duration_seconds);
|
||||
let base_credits_cost = duration * credits_per_second * batch_multiplier;
|
||||
let video_reference_surcharge_cost = if self.has_video_reference() {
|
||||
let base_credits = duration * credits_per_second * batch_multiplier;
|
||||
let maybe_video_reference_surcharge_credits = if self.has_video_reference() {
|
||||
Some(duration * video_reference_surcharge_per_second * batch_multiplier)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
KinoviSeedanceGenerationCost::from_base_and_surcharge(
|
||||
base_credits_cost,
|
||||
video_reference_surcharge_cost,
|
||||
base_credits,
|
||||
maybe_video_reference_surcharge_credits,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -389,8 +389,8 @@ mod tests {
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_up, 37);
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_down, 36);
|
||||
assert!((costs.total_cost.usd_cents_fractional - (7000.0 / 193.0)).abs() < 1e-9);
|
||||
assert_eq!(costs.base_credits_cost, 70);
|
||||
assert_eq!(costs.video_reference_surcharge_cost, None);
|
||||
assert_eq!(costs.base_cost.kinovi_credits, 70);
|
||||
assert!(costs.video_reference_surcharge_cost.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -401,8 +401,8 @@ mod tests {
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_up, 73);
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_down, 72);
|
||||
assert!((costs.total_cost.usd_cents_fractional - (14000.0 / 193.0)).abs() < 1e-9);
|
||||
assert_eq!(costs.base_credits_cost, 140);
|
||||
assert_eq!(costs.video_reference_surcharge_cost, None);
|
||||
assert_eq!(costs.base_cost.kinovi_credits, 140);
|
||||
assert!(costs.video_reference_surcharge_cost.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -413,8 +413,8 @@ mod tests {
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_up, 218);
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_down, 217);
|
||||
assert!((costs.total_cost.usd_cents_fractional - (42000.0 / 193.0)).abs() < 1e-9);
|
||||
assert_eq!(costs.base_credits_cost, 420);
|
||||
assert_eq!(costs.video_reference_surcharge_cost, None);
|
||||
assert_eq!(costs.base_cost.kinovi_credits, 420);
|
||||
assert!(costs.video_reference_surcharge_cost.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -425,8 +425,8 @@ mod tests {
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_up, 109);
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_down, 108);
|
||||
assert!((costs.total_cost.usd_cents_fractional - (21000.0 / 193.0)).abs() < 1e-9);
|
||||
assert_eq!(costs.base_credits_cost, 210);
|
||||
assert_eq!(costs.video_reference_surcharge_cost, None);
|
||||
assert_eq!(costs.base_cost.kinovi_credits, 210);
|
||||
assert!(costs.video_reference_surcharge_cost.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -437,8 +437,8 @@ mod tests {
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_up, 146);
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_down, 145);
|
||||
assert!((costs.total_cost.usd_cents_fractional - (28000.0 / 193.0)).abs() < 1e-9);
|
||||
assert_eq!(costs.base_credits_cost, 280);
|
||||
assert_eq!(costs.video_reference_surcharge_cost, None);
|
||||
assert_eq!(costs.base_cost.kinovi_credits, 280);
|
||||
assert!(costs.video_reference_surcharge_cost.is_none());
|
||||
}
|
||||
|
||||
/// The deprecated shims return the corresponding struct fields.
|
||||
@@ -487,8 +487,8 @@ mod tests {
|
||||
|
||||
for (make, duration, base, surcharge) in cases {
|
||||
let costs = with_video_ref(make(*duration)).calculate_costs();
|
||||
assert_eq!(costs.base_credits_cost, *base, "base for {duration}s");
|
||||
assert_eq!(costs.video_reference_surcharge_cost, Some(*surcharge), "surcharge for {duration}s");
|
||||
assert_eq!(costs.base_cost.kinovi_credits, *base, "base for {duration}s");
|
||||
assert_eq!(costs.video_reference_surcharge_cost.map(|c| c.kinovi_credits), Some(*surcharge), "surcharge for {duration}s");
|
||||
assert_eq!(costs.total_cost.kinovi_credits, base + surcharge, "total for {duration}s");
|
||||
}
|
||||
}
|
||||
@@ -497,21 +497,39 @@ mod tests {
|
||||
fn surcharge_includes_usd_cents() {
|
||||
// 720p 5s + video ref = 140 + 30 = 170 credits; 17000/193 = 88.08 → 89¢
|
||||
let costs = with_video_ref(r720(5)).calculate_costs();
|
||||
assert_eq!(costs.base_credits_cost, 140);
|
||||
assert_eq!(costs.video_reference_surcharge_cost, Some(30));
|
||||
assert_eq!(costs.base_cost.kinovi_credits, 140);
|
||||
assert_eq!(costs.video_reference_surcharge_cost.map(|c| c.kinovi_credits), Some(30));
|
||||
assert_eq!(costs.total_cost.kinovi_credits, 170);
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_up, 89);
|
||||
assert_eq!(costs.total_cost.usd_cents_rounded_down, 88);
|
||||
assert!((costs.total_cost.usd_cents_fractional - (17000.0 / 193.0)).abs() < 1e-9);
|
||||
}
|
||||
|
||||
/// The base and surcharge parts each carry their own USD conversions.
|
||||
#[test]
|
||||
fn parts_have_their_own_usd_conversions() {
|
||||
let costs = with_video_ref(r720(5)).calculate_costs();
|
||||
|
||||
// Base: 140 credits; 14000/193 = 72.54.
|
||||
assert_eq!(costs.base_cost.usd_cents_rounded_up, 73);
|
||||
assert_eq!(costs.base_cost.usd_cents_rounded_down, 72);
|
||||
assert!((costs.base_cost.usd_cents_fractional - (14000.0 / 193.0)).abs() < 1e-9);
|
||||
|
||||
// Surcharge: 30 credits; 3000/193 = 15.54.
|
||||
let surcharge = costs.video_reference_surcharge_cost.expect("should have surcharge");
|
||||
assert_eq!(surcharge.kinovi_credits, 30);
|
||||
assert_eq!(surcharge.usd_cents_rounded_up, 16);
|
||||
assert_eq!(surcharge.usd_cents_rounded_down, 15);
|
||||
assert!((surcharge.usd_cents_fractional - (3000.0 / 193.0)).abs() < 1e-9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_video_reference_list_has_no_surcharge() {
|
||||
let mut request = r720(5);
|
||||
request.reference_video_urls = Some(vec![]);
|
||||
let costs = request.calculate_costs();
|
||||
assert_eq!(costs.total_cost.kinovi_credits, 140);
|
||||
assert_eq!(costs.video_reference_surcharge_cost, None);
|
||||
assert!(costs.video_reference_surcharge_cost.is_none());
|
||||
}
|
||||
|
||||
/// Surcharge is flat per generation regardless of how many reference
|
||||
@@ -532,8 +550,8 @@ mod tests {
|
||||
let request = with_video_ref(build_request(5, None, Some(KinoviSeedance2p0FastBatchCount::Two)));
|
||||
// (140 base + 30 surcharge) × 2 = 340 credits
|
||||
let costs = request.calculate_costs();
|
||||
assert_eq!(costs.base_credits_cost, 280);
|
||||
assert_eq!(costs.video_reference_surcharge_cost, Some(60));
|
||||
assert_eq!(costs.base_cost.kinovi_credits, 280);
|
||||
assert_eq!(costs.video_reference_surcharge_cost.map(|c| c.kinovi_credits), Some(60));
|
||||
assert_eq!(costs.total_cost.kinovi_credits, 340);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user