diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/first_party_minimax_h3/minimax_h3_ultra_cost.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/providers/first_party/minimax_h3_ultra_cost.rs similarity index 57% rename from crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/first_party_minimax_h3/minimax_h3_ultra_cost.rs rename to crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/providers/first_party/minimax_h3_ultra_cost.rs index cc3b61591d..050d065c41 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/first_party_minimax_h3/minimax_h3_ultra_cost.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/providers/first_party/minimax_h3_ultra_cost.rs @@ -1,9 +1,13 @@ //! Pricing for first-party Minimax H3 Ultra. //! +//! First-party H3 Ultra is fulfilled on our own GPU inference (enqueued +//! directly by storyteller-web's omni_gen pipeline, not routed through a +//! provider), so unlike the other artcraft rate cards there is no provider +//! cost estimate beside it — only this user-facing price. +//! //! TODO(2026-08-06): Placeholder rates copied from the existing Minimax H3 //! pricing. Finalize once first-party GPU inference costs are known. -use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest; use enums::common::generation::common_resolution::CommonResolution; /// Per-second rates in hundredths of a US cent. @@ -15,12 +19,15 @@ const DEFAULT_DURATION_SECONDS: u64 = 5; /// Estimate the user-facing Minimax H3 Ultra cost in USD cents. /// System credits = cents (same convention as the v2 pipeline). -pub fn estimate_minimax_h3_ultra_cost_usd_cents(request: &OmniGenVideoCostAndGenerateRequest) -> u64 { - let duration_seconds = request.duration_seconds +pub fn estimate_minimax_h3_ultra_cost_usd_cents( + maybe_duration_seconds: Option, + maybe_resolution: Option, +) -> u64 { + let duration_seconds = maybe_duration_seconds .map(u64::from) .unwrap_or(DEFAULT_DURATION_SECONDS); - let rate = if is_2k(request.resolution) { + let rate = if is_2k(maybe_resolution) { HIGH_RES_RATE_HUNDREDTH_CENTS_PER_SEC } else { LOW_RES_RATE_HUNDREDTH_CENTS_PER_SEC @@ -52,46 +59,28 @@ mod tests { #[test] fn default_resolution_5s_is_150() { - assert_eq!(cost_cents(None, None), 150); + assert_eq!(estimate_minimax_h3_ultra_cost_usd_cents(None, None), 150); } #[test] fn low_res_5s_is_92() { - assert_eq!(cost_cents(Some(5), Some(CommonResolution::SevenTwentyP)), 92); + assert_eq!( + estimate_minimax_h3_ultra_cost_usd_cents(Some(5), Some(CommonResolution::SevenTwentyP)), + 92, + ); } #[test] fn high_res_10s_is_299() { - assert_eq!(cost_cents(Some(10), Some(CommonResolution::TenEightyP)), 299); + assert_eq!( + estimate_minimax_h3_ultra_cost_usd_cents(Some(10), Some(CommonResolution::TenEightyP)), + 299, + ); } #[test] fn odd_duration_rounds_up_to_whole_cents() { // 7s high res: 2990 × 7 = 20930 hundredth-cents → 210 cents. - assert_eq!(cost_cents(Some(7), None), 210); - } - - fn cost_cents(duration_seconds: Option, resolution: Option) -> u64 { - let request = OmniGenVideoCostAndGenerateRequest { - idempotency_token: None, - model: None, - prompt: None, - negative_prompt: None, - start_frame_image_media_token: None, - end_frame_image_media_token: None, - reference_image_media_tokens: None, - reference_video_media_tokens: None, - reference_audio_media_tokens: None, - reference_character_tokens: None, - resolution, - aspect_ratio: None, - bitrate: None, - quality: None, - duration_seconds, - video_batch_count: None, - generate_audio: None, - estimate_only: None, - }; - estimate_minimax_h3_ultra_cost_usd_cents(&request) + assert_eq!(estimate_minimax_h3_ultra_cost_usd_cents(Some(7), None), 210); } } diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/providers/first_party/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/providers/first_party/mod.rs new file mode 100644 index 0000000000..9845efc50b --- /dev/null +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/providers/first_party/mod.rs @@ -0,0 +1,6 @@ +//! Pricing for models fulfilled on first-party infrastructure (no external +//! provider); these are enqueued directly by storyteller-web rather than +//! routed, but their user-facing rate cards live here with the rest of the +//! artcraft pricing. + +pub mod minimax_h3_ultra_cost; diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/providers/mod.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/providers/mod.rs index b77b7daae5..80bd2abb40 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/providers/mod.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_video/providers/mod.rs @@ -1,4 +1,5 @@ pub mod artcraft; pub mod fal; +pub mod first_party; pub mod grok_api; -pub mod kinovi; \ No newline at end of file +pub mod kinovi; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/first_party_minimax_h3/enqueue_first_party_minimax_h3_job.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/first_party_minimax_h3/enqueue_first_party_minimax_h3_job.rs index 212a5620ad..3596462f06 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/first_party_minimax_h3/enqueue_first_party_minimax_h3_job.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/first_party_minimax_h3/enqueue_first_party_minimax_h3_job.rs @@ -27,7 +27,7 @@ use tokens::tokens::non_unique::debug_logs_event_token::DebugLogEventToken; use tokens::tokens::users::UserToken; use crate::http_server::common_responses::common_web_error::CommonWebError; -use crate::http_server::endpoints::omni_gen::generate::video::first_party_minimax_h3::minimax_h3_ultra_cost::estimate_minimax_h3_ultra_cost_usd_cents; +use artcraft_router::generate::generate_video::providers::first_party::minimax_h3_ultra_cost::estimate_minimax_h3_ultra_cost_usd_cents; use crate::http_server::endpoints::omni_gen::generate::video::helpers::bill_wallet::bill_wallet; use crate::http_server::endpoints::omni_gen::generate::video::helpers::write_prompt_records::{ write_prompt_records, WritePromptRecordsArgs, @@ -86,7 +86,7 @@ pub async fn enqueue_first_party_minimax_h3_job( None } FirstPartyMinimaxH3Model::Ultra => { - Some(estimate_minimax_h3_ultra_cost_usd_cents(request)) + Some(estimate_minimax_h3_ultra_cost_usd_cents(request.duration_seconds, request.resolution)) } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/first_party_minimax_h3/mod.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/first_party_minimax_h3/mod.rs index 04a96f41b2..faa1faffc3 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/first_party_minimax_h3/mod.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/omni_gen/generate/video/first_party_minimax_h3/mod.rs @@ -5,4 +5,3 @@ //! scheduler runs the jobs later. pub mod enqueue_first_party_minimax_h3_job; -pub mod minimax_h3_ultra_cost;