This commit is contained in:
Hanashi
2026-08-08 22:33:14 -04:00
parent 224e5c17f5
commit 426e38be39
10 changed files with 27 additions and 33 deletions
@@ -95,8 +95,6 @@ pub enum RouterVideoModel {
#[serde(rename = "seedance_2p5")]
Seedance2p5,
/// Seedance 2.5 as routed via the BytePlus Ultra kinovi account.
/// Fulfilled by Seedance 2.5; billed at its own (higher) rate.
#[serde(rename = "seedance_2p5_u")]
Seedance2p5Ultra,
@@ -11,8 +11,6 @@ use crate::generate::generate_video::providers::artcraft::seedance_2p5_u::reques
use crate::generate::generate_video::video_generation_draft_or_request::VideoGenerationDraftOrRequest;
use crate::generate::generate_video::video_generation_request::VideoGenerationRequest;
/// Seedance 2.5 Ultra: the same model surface as Seedance 2.5, billed at its
/// own (higher) rate and fulfilled via the BytePlus Ultra kinovi account.
pub fn build_artcraft_seedance_2p5_u(mut builder: GenerateVideoRequestBuilder) -> Result<VideoGenerationDraftOrRequest, ArtcraftRouterError> {
let strategy = builder.request_mismatch_mitigation_strategy;
@@ -5,11 +5,10 @@ use crate::generate::generate_video::video_generation_cost_estimate::VideoGenera
use crate::generate::generate_video::providers::artcraft::seedance_common::seedance_2p5_ultra_usd_cents;
use crate::generate::generate_video::providers::artcraft::seedance_2p5_u::request::ArtcraftSeedance2p5UltraRequestState;
/// Seedance 2.5 Ultra pricing has the same structure as Seedance 2.5 (at
/// higher rates): it depends on the resolution, the output duration, and —
/// when reference videos are attached — the total seconds of reference video
/// input, which are billed on top of the output duration (at a lower
/// per-second rate). Input seconds are clamped to
/// Seedance 2.5 Ultra pricing depends on the resolution, the output
/// duration, and — when reference videos are attached — the total seconds of
/// reference video input, which are billed on top of the output duration (at
/// a lower per-second rate). Input seconds are clamped to
/// [`MAX_BILLED_INPUT_SECONDS`] — the model accepts at most 30 seconds of
/// video. No batching.
pub struct ArtcraftSeedance2p5UltraCostState {
@@ -190,11 +190,9 @@ const SEEDANCE_2P5_ULTRA_VIDEO_REFERENCE_CENTS_PER_SECOND_480P: f64 = 8.55967078
/// Seedance 2.5 Ultra — 720p price with video references, USD cents per second.
const SEEDANCE_2P5_ULTRA_VIDEO_REFERENCE_CENTS_PER_SECOND_720P: f64 = 18.72427984;
/// ArtCraft's price (USD cents) for Seedance 2.5 Ultra (the BytePlus Ultra
/// kinovi account routing of Seedance 2.5).
/// ArtCraft's price (USD cents) for Seedance 2.5 Ultra.
///
/// Same billing structure as [`seedance_2p5_usd_cents`], at higher rates:
/// only 480p and 720p are offered; any other resolution prices at 720p.
/// Only 480p and 720p are offered; any other resolution prices at 720p.
/// Without video references, billed seconds = output duration. With video
/// references, the per-second rate drops but the billed seconds are the
/// output duration PLUS the total seconds of reference video input. The
@@ -222,7 +222,6 @@ pub enum InferenceModelType {
Seedance2p5Preview,
#[serde(rename = "seedance_2p5")]
Seedance2p5,
/// Seedance 2.5 as routed via the BytePlus Ultra kinovi account
#[serde(rename = "seedance_2p5_u")]
Seedance2p5Ultra,
#[serde(rename = "sora_2")]
@@ -193,7 +193,6 @@ pub enum CommonModelType {
Seedance2p5Preview,
#[serde(rename = "seedance_2p5")]
Seedance2p5,
/// Seedance 2.5 as routed via the BytePlus Ultra kinovi account
#[serde(rename = "seedance_2p5_u")]
Seedance2p5Ultra,
#[serde(rename = "sora_2")]
@@ -101,8 +101,6 @@ pub enum CommonVideoModel {
#[serde(rename = "seedance_2p5")]
Seedance2p5,
/// Seedance 2.5 as routed via the BytePlus Ultra kinovi account.
/// Fulfilled by Seedance 2.5; billed at its own (higher) rate.
#[serde(rename = "seedance_2p5_u")]
Seedance2p5Ultra,
@@ -93,13 +93,16 @@ pub async fn run_pipeline_v2(args: RunPipelineV2Args<'_>) -> Result<PipelineResu
let mut exec_builder = router_builder.clone();
exec_builder.provider = provider;
// These variants are FULFILLED by the base model's Kinovi request — the
// variant distinction is billing (each has its own Artcraft cost twin) and
// Kinovi account routing, both handled elsewhere. The collapse is
// EXEC-ONLY: the cost estimate below keeps the original model so the
// wallet bills each variant's own rate. (Collapsing before the cost
// estimate is what silently billed all of these at the base Seedance 2.0
// rate while the cost endpoint quoted their real prices.)
// These variants are FULFILLED by the base model (they build the same
// execution request), but they are PRICED as themselves — each has its own
// cost entry under the Artcraft provider.
//
// IMPORTANT: the model rewrite must apply to the EXECUTION builder only.
// The cost estimate below must see the ORIGINAL model. Rewriting before
// the cost estimate makes every variant price as its base model — a
// pricing bug we actually shipped, where these variants charged the base
// rate while the cost endpoint quoted their real prices. Do not "hoist"
// or "deduplicate" this match to the top of the function.
match exec_builder.model {
RouterVideoModel::PreviewModel |
RouterVideoModel::Seedance2p0BytePlus |
@@ -191,8 +191,7 @@ mod tests {
assert_eq!(low_res_quote.cost_in_credits, Some(92));
}
/// Seedance 2.5 Ultra is fulfilled by Seedance 2.5 but billed at its own
/// higher rate (and routed to a different kinovi account).
/// Seedance 2.5 Ultra has its own (higher) price than Seedance 2.5.
#[tokio::test]
async fn seedance_2p5_ultra_quotes_above_regular_seedance_2p5() {
let regular = post_cost_request(base_request(CommonVideoModel::Seedance2p5))
@@ -94,13 +94,16 @@ pub async fn run_pipeline_v2(args: RunPipelineV2Args<'_>) -> Result<PipelineResu
let mut exec_builder = router_builder.clone();
exec_builder.provider = provider;
// These variants are FULFILLED by the base model's Kinovi request — the
// variant distinction is billing (each has its own Artcraft cost twin) and
// Kinovi account routing, both handled elsewhere. The collapse is
// EXEC-ONLY: the cost estimate below keeps the original model so the
// wallet bills each variant's own rate. (Collapsing before the cost
// estimate is what silently billed all of these at the base Seedance 2.0
// rate while the cost endpoint quoted their real prices.)
// These variants are FULFILLED by the base model (they build the same
// execution request), but they are PRICED as themselves — each has its own
// cost entry under the Artcraft provider.
//
// IMPORTANT: the model rewrite must apply to the EXECUTION builder only.
// The cost estimate below must see the ORIGINAL model. Rewriting before
// the cost estimate makes every variant price as its base model — a
// pricing bug we actually shipped, where these variants charged the base
// rate while the cost endpoint quoted their real prices. Do not "hoist"
// or "deduplicate" this match to the top of the function.
match exec_builder.model {
RouterVideoModel::PreviewModel |
RouterVideoModel::Seedance2p0BytePlus |