From ca142a252a5836322d7458477da534fe211e6477 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Mon, 29 Dec 2025 01:29:39 -0500 Subject: [PATCH] sora pricing --- .../enqueue_sora_2_image_to_video_webhook.rs | 20 ++++++++++++- ...queue_sora_2_pro_image_to_video_webhook.rs | 28 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/crates/api_clients/fal_client/src/requests/webhook/video/image/enqueue_sora_2_image_to_video_webhook.rs b/crates/api_clients/fal_client/src/requests/webhook/video/image/enqueue_sora_2_image_to_video_webhook.rs index dae173616c..c9101f8720 100644 --- a/crates/api_clients/fal_client/src/requests/webhook/video/image/enqueue_sora_2_image_to_video_webhook.rs +++ b/crates/api_clients/fal_client/src/requests/webhook/video/image/enqueue_sora_2_image_to_video_webhook.rs @@ -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::sora::sora2::sora_2_image_to_video::{sora_2_image_to_video, Sora2ImageToVideoInput}; use fal::webhook::WebhookResponse; use reqwest::IntoUrl; @@ -11,8 +12,11 @@ pub struct EnqueueSora2ImageToVideoArgs<'a, R: IntoUrl> { pub image_url: String, // Optional args - pub resolution: Option, + + // NB: Duration defaults to four seconds pub duration: Option, + + pub resolution: Option, pub aspect_ratio: Option, // Fulfillment @@ -40,6 +44,20 @@ pub enum EnqueueSora2ImageToVideoAspectRatio { SixteenByNine, } +impl FalRequestCostCalculator for EnqueueSora2ImageToVideoArgs<'_, U> { + fn calculate_cost_in_cents(&self) -> UsdCents { + // "The pricing is $0.1/s for Sora 2." + let duration = self.duration.unwrap_or(EnqueueSora2ImageToVideoDurationSeconds::Four); + match duration { + EnqueueSora2ImageToVideoDurationSeconds::Four => 40, // $0.10 * 4 + EnqueueSora2ImageToVideoDurationSeconds::Eight => 80, // $0.10 * 8 + EnqueueSora2ImageToVideoDurationSeconds::Twelve => 120 // $0.10 * 12 + } + } +} + +/// Sora 2 Image-to-Video +/// https://fal.ai/models/fal-ai/sora-2/image-to-video pub async fn enqueue_sora_2_image_to_video_webhook( args: EnqueueSora2ImageToVideoArgs<'_, R> ) -> Result { diff --git a/crates/api_clients/fal_client/src/requests/webhook/video/image/enqueue_sora_2_pro_image_to_video_webhook.rs b/crates/api_clients/fal_client/src/requests/webhook/video/image/enqueue_sora_2_pro_image_to_video_webhook.rs index 955c174ebb..e3e190fa47 100644 --- a/crates/api_clients/fal_client/src/requests/webhook/video/image/enqueue_sora_2_pro_image_to_video_webhook.rs +++ b/crates/api_clients/fal_client/src/requests/webhook/video/image/enqueue_sora_2_pro_image_to_video_webhook.rs @@ -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::sora::sora2::sora_2_pro_image_to_video::{sora_2_pro_image_to_video, Sora2ProImageToVideoInput}; use fal::webhook::WebhookResponse; use reqwest::IntoUrl; @@ -41,6 +42,33 @@ pub enum EnqueueSora2ProImageToVideoAspectRatio { SixteenByNine, } +impl FalRequestCostCalculator for EnqueueSora2ProImageToVideoArgs<'_, U> { + fn calculate_cost_in_cents(&self) -> UsdCents { + // "If an OpenAI API key is provided, it will be directly charged by OpenAI. + // Otherwise, you will be charged fal credits. + // The pricing is $0.30/s for 720p and $0.50/s for 1080p." + // NB(bt): There's no way to provide an API key with this endpoint? + + let duration = self.duration.unwrap_or(EnqueueSora2ProImageToVideoDurationSeconds::Four); + let resolution = self.resolution.unwrap_or(EnqueueSora2ProImageToVideoResolution::Auto); // WHAT IS THIS?! + + match (duration, resolution) { + (EnqueueSora2ProImageToVideoDurationSeconds::Four, EnqueueSora2ProImageToVideoResolution::Auto) => 120, // TODO: Auto = ??? + (EnqueueSora2ProImageToVideoDurationSeconds::Four, EnqueueSora2ProImageToVideoResolution::SevenTwentyP) => 120, + (EnqueueSora2ProImageToVideoDurationSeconds::Four, EnqueueSora2ProImageToVideoResolution::TenEightyP) => 200, + (EnqueueSora2ProImageToVideoDurationSeconds::Eight, EnqueueSora2ProImageToVideoResolution::Auto) => 240, // TODO: Auto = ??? + (EnqueueSora2ProImageToVideoDurationSeconds::Eight, EnqueueSora2ProImageToVideoResolution::SevenTwentyP) => 240, + (EnqueueSora2ProImageToVideoDurationSeconds::Eight, EnqueueSora2ProImageToVideoResolution::TenEightyP) => 400, + (EnqueueSora2ProImageToVideoDurationSeconds::Twelve, EnqueueSora2ProImageToVideoResolution::Auto) => 360, // TODO: Auto = ??? + (EnqueueSora2ProImageToVideoDurationSeconds::Twelve, EnqueueSora2ProImageToVideoResolution::SevenTwentyP) => 360, + (EnqueueSora2ProImageToVideoDurationSeconds::Twelve, EnqueueSora2ProImageToVideoResolution::TenEightyP) => 600, + } + } +} + + +/// Sora 2 Pro Image-to-Video +/// https://fal.ai/models/fal-ai/sora-2/image-to-video/pro pub async fn enqueue_sora_2_pro_image_to_video_webhook( args: EnqueueSora2ProImageToVideoArgs<'_, R> ) -> Result {