mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-28 04:22:51 -04:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f93d979691 | ||
|
|
a3d863b16e | ||
|
|
c383237e11 | ||
|
|
27452b3bce | ||
|
|
8b3c3857b1 | ||
|
|
0749f3d530 |
Generated
+2
@@ -758,6 +758,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"artcraft_api_defs",
|
||||
"log",
|
||||
"seedance2pro",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"storyteller_client",
|
||||
@@ -11477,6 +11478,7 @@ dependencies = [
|
||||
"actix_helpers",
|
||||
"anyhow",
|
||||
"artcraft_api_defs",
|
||||
"artcraft_router",
|
||||
"async-stripe 0.26.0",
|
||||
"async-trait",
|
||||
"base64 0.22.1",
|
||||
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use enums::common::generation::common_aspect_ratio::CommonAspectRatio;
|
||||
use enums::common::generation::common_video_model::CommonVideoModel;
|
||||
use enums::common::generation::common_video_resolution::CommonVideoResolution;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
|
||||
pub const ESTIMATE_VIDEO_COST_PATH: &str = "/v1/generate/cost_estimate/video";
|
||||
|
||||
/// Request body for the video cost estimate endpoint.
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
pub struct EstimateVideoCostRequest {
|
||||
/// The video model to estimate costs for.
|
||||
pub model: CommonVideoModel,
|
||||
|
||||
/// The provider to route the generation through.
|
||||
pub provider: GenerationProvider,
|
||||
|
||||
/// The type of generation (determines how many input images are involved).
|
||||
/// This is a tagged enum, so it looks like:
|
||||
/// "generation_mode": {"type": "text_to_video"}
|
||||
/// "generation_mode": {"type": "reference_image_to_video", "count": 1}
|
||||
pub generation_mode: GenerationMode,
|
||||
|
||||
/// Optional aspect ratio.
|
||||
pub aspect_ratio: Option<CommonAspectRatio>,
|
||||
|
||||
/// Optional resolution.
|
||||
pub resolution: Option<CommonVideoResolution>,
|
||||
|
||||
/// Duration in seconds.
|
||||
pub duration_seconds: Option<u16>,
|
||||
|
||||
/// Number of videos to generate in parallel.
|
||||
pub video_batch_count: Option<u16>,
|
||||
}
|
||||
|
||||
/// Describes the type of video generation being requested.
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
pub enum GenerationMode {
|
||||
TextToVideo,
|
||||
StartFrameToVideo,
|
||||
StartAndEndFrameToVideo,
|
||||
ReferenceImageToVideo { count: u32 },
|
||||
}
|
||||
|
||||
/// Response body for the video cost estimate endpoint.
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
pub struct EstimateVideoCostResponse {
|
||||
pub success: bool,
|
||||
|
||||
/// Estimated cost in credits.
|
||||
pub cost_in_credits: Option<u64>,
|
||||
|
||||
/// Estimated cost in USD cents.
|
||||
pub cost_in_usd_cents: Option<u64>,
|
||||
|
||||
/// Whether the generation is free for this user/plan.
|
||||
pub is_free: bool,
|
||||
|
||||
/// Whether the user has unlimited generations.
|
||||
pub is_unlimited: bool,
|
||||
|
||||
/// Whether the user is rate limited.
|
||||
pub is_rate_limited: bool,
|
||||
|
||||
/// Whether the output will have a watermark.
|
||||
pub has_watermark: bool,
|
||||
}
|
||||
|
||||
/// Error response for the video cost estimate endpoint.
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
pub struct EstimateVideoCostError {
|
||||
pub success: bool,
|
||||
pub error_type: EstimateVideoCostErrorType,
|
||||
pub error_message: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum EstimateVideoCostErrorType {
|
||||
InvalidProviderForModel,
|
||||
InvalidInput,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization_tagging1() {
|
||||
let request = EstimateVideoCostRequest {
|
||||
model: CommonVideoModel::GrokVideo,
|
||||
provider: GenerationProvider::Artcraft,
|
||||
generation_mode: GenerationMode::TextToVideo,
|
||||
aspect_ratio: None,
|
||||
resolution: None,
|
||||
duration_seconds: None,
|
||||
video_batch_count: None,
|
||||
};
|
||||
let serialized = serde_json::to_string(&request).unwrap();
|
||||
assert!(serialized.contains("\"generation_mode\":{\"type\":\"text_to_video\"}"));
|
||||
//assert_eq!(serialized, "{}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialization_tagging2() {
|
||||
let request = EstimateVideoCostRequest {
|
||||
model: CommonVideoModel::GrokVideo,
|
||||
provider: GenerationProvider::Artcraft,
|
||||
generation_mode: GenerationMode::ReferenceImageToVideo { count: 1 },
|
||||
aspect_ratio: None,
|
||||
resolution: None,
|
||||
duration_seconds: None,
|
||||
video_batch_count: None,
|
||||
};
|
||||
let serialized = serde_json::to_string(&request).unwrap();
|
||||
assert!(serialized.contains("\"generation_mode\":{\"type\":\"reference_image_to_video\",\"count\":1}"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod estimate_video_cost;
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod cost_estimate;
|
||||
pub mod image;
|
||||
pub mod object;
|
||||
pub mod video;
|
||||
@@ -17,6 +17,7 @@ workspace-build-acceleration.workspace = true
|
||||
|
||||
# Internal
|
||||
artcraft_api_defs.workspace = true
|
||||
seedance2pro.workspace = true
|
||||
storyteller_client.workspace = true
|
||||
tokens.workspace = true
|
||||
|
||||
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
use artcraft_api_defs::generate::video::multi_function::seedance_2p0_multi_function_video_gen::Seedance2p0BatchCount;
|
||||
use seedance2pro::creds::seedance2pro_session::Seedance2ProSession;
|
||||
use seedance2pro::requests::generate_video::generate_video::{BatchCount, GenerateVideoArgs, Resolution};
|
||||
|
||||
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance2p0::PlanArtcraftSeedance2p0;
|
||||
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
|
||||
|
||||
pub (crate) fn estimate_video_cost_artcraft_seedance2p0(
|
||||
plan: &PlanArtcraftSeedance2p0<'_>,
|
||||
) -> VideoGenerationCostEstimate {
|
||||
let duration_seconds = plan.duration_seconds.unwrap_or(5).clamp(4, 15);
|
||||
|
||||
let batch_count = match plan.batch_count {
|
||||
Seedance2p0BatchCount::One => BatchCount::One,
|
||||
Seedance2p0BatchCount::Two => BatchCount::Two,
|
||||
Seedance2p0BatchCount::Four => BatchCount::Four,
|
||||
};
|
||||
|
||||
// TODO: Make a better client that doesn't require this.
|
||||
// A dummy session is sufficient — cost estimation does not make any network calls.
|
||||
let dummy_session = Seedance2ProSession::from_cookies_string(String::new());
|
||||
|
||||
let args = GenerateVideoArgs {
|
||||
session: &dummy_session,
|
||||
prompt: String::new(),
|
||||
resolution: Resolution::Square1x1,
|
||||
duration_seconds,
|
||||
batch_count,
|
||||
|
||||
// NB: These do not contribute to costs in the Seedance2 integration
|
||||
start_frame_url: None,
|
||||
end_frame_url: None,
|
||||
reference_image_urls: None,
|
||||
};
|
||||
|
||||
let cost_in_usd_cents = args.estimate_cost_in_usd_cents();
|
||||
|
||||
VideoGenerationCostEstimate {
|
||||
cost_in_credits: Some(cost_in_usd_cents),
|
||||
cost_in_usd_cents: Some(cost_in_usd_cents),
|
||||
is_free: false,
|
||||
is_unlimited: false,
|
||||
is_rate_limited: false,
|
||||
has_watermark: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::api::common_video_model::CommonVideoModel;
|
||||
use crate::api::provider::Provider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::generate::generate_video::begin_video_generation::begin_video_generation;
|
||||
use crate::generate::generate_video::generate_video_request::GenerateVideoRequest;
|
||||
|
||||
fn estimate_usd_cents(duration_seconds: u16, video_batch_count: u16) -> u64 {
|
||||
let request = GenerateVideoRequest {
|
||||
model: CommonVideoModel::Seedance2p0,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: None,
|
||||
start_frame: None,
|
||||
end_frame: None,
|
||||
reference_images: None,
|
||||
resolution: None,
|
||||
aspect_ratio: None,
|
||||
duration_seconds: Some(duration_seconds),
|
||||
video_batch_count: Some(video_batch_count),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::ErrorOut,
|
||||
idempotency_token: None,
|
||||
};
|
||||
begin_video_generation(&request)
|
||||
.expect("begin_video_generation should succeed")
|
||||
.estimate_costs()
|
||||
.cost_in_usd_cents
|
||||
.expect("cost_in_usd_cents should be present")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_estimate_cost_usd_cents() {
|
||||
// Batch 1:
|
||||
assert_eq!(estimate_usd_cents(4, 1), 64);
|
||||
assert_eq!(estimate_usd_cents(5, 1), 80);
|
||||
assert_eq!(estimate_usd_cents(6, 1), 96);
|
||||
assert_eq!(estimate_usd_cents(7, 1), 112);
|
||||
assert_eq!(estimate_usd_cents(15, 1), 240);
|
||||
|
||||
// Batch 2 = 2×
|
||||
assert_eq!(estimate_usd_cents(4, 2), 128);
|
||||
assert_eq!(estimate_usd_cents(5, 2), 160);
|
||||
assert_eq!(estimate_usd_cents(15, 2), 480);
|
||||
|
||||
// Batch 4 = 3× (not 4×)
|
||||
assert_eq!(estimate_usd_cents(4, 4), 192);
|
||||
assert_eq!(estimate_usd_cents(5, 4), 240);
|
||||
assert_eq!(estimate_usd_cents(15, 4), 720);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod estimate_video_cost_artcraft_seedance2p0;
|
||||
@@ -0,0 +1 @@
|
||||
pub (crate) mod artcraft;
|
||||
@@ -1,5 +1,7 @@
|
||||
pub mod begin_video_generation;
|
||||
pub mod cost;
|
||||
pub mod execute;
|
||||
pub mod generate_video_request;
|
||||
pub mod plan;
|
||||
pub mod begin_video_generation;
|
||||
pub mod video_generation_cost_estimate;
|
||||
pub mod video_generation_plan;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
/// The result of estimating the cost of a video generation plan.
|
||||
pub struct VideoGenerationCostEstimate {
|
||||
pub cost_in_credits: Option<u64>,
|
||||
pub cost_in_usd_cents: Option<u64>,
|
||||
pub is_free: bool,
|
||||
pub is_unlimited: bool,
|
||||
pub is_rate_limited: bool,
|
||||
pub has_watermark: bool,
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
use crate::client::router_client::RouterClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::generate::generate_video::cost::artcraft::estimate_video_cost_artcraft_seedance2p0::estimate_video_cost_artcraft_seedance2p0;
|
||||
use crate::generate::generate_video::execute::artcraft::generate_video_artcraft_seedance2p0::execute_artcraft_seedance2p0;
|
||||
use crate::generate::generate_video::plan::artcraft::plan_generate_video_artcraft_seedance2p0::PlanArtcraftSeedance2p0;
|
||||
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
|
||||
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -27,4 +29,12 @@ impl<'a> VideoGenerationPlan<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn estimate_costs(&self) -> VideoGenerationCostEstimate {
|
||||
match self {
|
||||
VideoGenerationPlan::ArtcraftSeedance2p0(plan) => {
|
||||
estimate_video_cost_artcraft_seedance2p0(plan)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Common aspect ratios for video generation.
|
||||
/// Mirrors artcraft_router::api::common_aspect_ratio::CommonAspectRatio.
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum CommonAspectRatio {
|
||||
Auto,
|
||||
Square,
|
||||
WideThreeByTwo,
|
||||
WideFourByThree,
|
||||
WideFiveByFour,
|
||||
WideSixteenByNine,
|
||||
WideTwentyOneByNine,
|
||||
TallTwoByThree,
|
||||
TallThreeByFour,
|
||||
TallFourByFive,
|
||||
TallNineBySixteen,
|
||||
TallNineByTwentyOne,
|
||||
Wide,
|
||||
Tall,
|
||||
Auto2k,
|
||||
Auto4k,
|
||||
SquareHd,
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Video models available for generation.
|
||||
/// Mirrors artcraft_router::api::common_video_model::CommonVideoModel.
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum CommonVideoModel {
|
||||
#[serde(rename = "grok_video")]
|
||||
GrokVideo,
|
||||
|
||||
#[serde(rename = "kling_1p6_pro")]
|
||||
Kling16Pro,
|
||||
|
||||
#[serde(rename = "kling_2p1_pro")]
|
||||
Kling21Pro,
|
||||
|
||||
#[serde(rename = "kling_2p1_master")]
|
||||
Kling21Master,
|
||||
|
||||
#[serde(rename = "kling_2p5_turbo_pro")]
|
||||
Kling2p5TurboPro,
|
||||
|
||||
#[serde(rename = "kling_2p6_pro")]
|
||||
Kling2p6Pro,
|
||||
|
||||
#[serde(rename = "seedance_1p0_lite")]
|
||||
Seedance10Lite,
|
||||
|
||||
#[serde(rename = "seedance_2p0")]
|
||||
Seedance2p0,
|
||||
|
||||
#[serde(rename = "sora_2")]
|
||||
Sora2,
|
||||
|
||||
#[serde(rename = "sora_2_pro")]
|
||||
Sora2Pro,
|
||||
|
||||
#[serde(rename = "veo_2")]
|
||||
Veo2,
|
||||
|
||||
#[serde(rename = "veo_3")]
|
||||
Veo3,
|
||||
|
||||
#[serde(rename = "veo_3_fast")]
|
||||
Veo3Fast,
|
||||
|
||||
#[serde(rename = "veo_3p1")]
|
||||
Veo3p1,
|
||||
|
||||
#[serde(rename = "veo_3p1_fast")]
|
||||
Veo3p1Fast,
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Common video resolutions.
|
||||
/// Mirrors artcraft_router::api::common_resolution::CommonVideoResolution.
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum CommonVideoResolution {
|
||||
OneK,
|
||||
TwoK,
|
||||
ThreeK,
|
||||
FourK,
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
pub mod common_aspect_ratio;
|
||||
pub mod common_video_model;
|
||||
pub mod common_video_resolution;
|
||||
@@ -1,3 +1,10 @@
|
||||
//! This is an important enum.
|
||||
//!
|
||||
//! It's used in storyteller-web inference generation, the cost estimate handler,
|
||||
//! the ArtCraft Tauri app, and more.
|
||||
//!
|
||||
//! Do not change the values here without cause or care.
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use crate::error::enum_error::EnumError;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
pub mod artcraft_credits_pack_slug;
|
||||
pub mod artcraft_subscription_slug;
|
||||
pub mod generation;
|
||||
pub mod generation_provider;
|
||||
pub mod job_status;
|
||||
pub mod job_status_plus;
|
||||
|
||||
@@ -36,6 +36,7 @@ actix_artcraft.workspace = true
|
||||
actix_cors_configs = { path = "../../../lib/actix_cors_configs" }
|
||||
actix_helpers.workspace = true
|
||||
artcraft_api_defs.workspace = true
|
||||
artcraft_router.workspace = true
|
||||
bootstrap = { path = "../../../lib/bootstrap" }
|
||||
bucket_paths = { path = "../../../lib/bucket_paths" }
|
||||
cloud_storage.workspace = true
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
pub mod video;
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use actix_http::StatusCode;
|
||||
use actix_web::web::Json;
|
||||
use actix_web::{HttpResponse, ResponseError};
|
||||
use artcraft_api_defs::generate::cost_estimate::estimate_video_cost::{
|
||||
EstimateVideoCostError, EstimateVideoCostErrorType, EstimateVideoCostRequest,
|
||||
EstimateVideoCostResponse,
|
||||
};
|
||||
use artcraft_router::api::common_aspect_ratio::CommonAspectRatio as RouterAspectRatio;
|
||||
use artcraft_router::api::common_resolution::CommonVideoResolution as RouterResolution;
|
||||
use artcraft_router::api::common_video_model::CommonVideoModel as RouterVideoModel;
|
||||
use artcraft_router::api::provider::Provider as RouterProvider;
|
||||
use artcraft_router::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use artcraft_router::generate::generate_video::begin_video_generation::begin_video_generation;
|
||||
use artcraft_router::generate::generate_video::generate_video_request::GenerateVideoRequest;
|
||||
use enums::common::generation::common_aspect_ratio::CommonAspectRatio;
|
||||
use enums::common::generation::common_video_model::CommonVideoModel;
|
||||
use enums::common::generation::common_video_resolution::CommonVideoResolution;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
|
||||
|
||||
/// Estimate the credit and USD cost of a video generation request.
|
||||
/// Does not require authentication and does not charge any credits.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
tag = "Cost Estimate",
|
||||
path = "/v1/generate/cost_estimate/video",
|
||||
responses(
|
||||
(status = 200, description = "Cost estimate", body = EstimateVideoCostResponse),
|
||||
(status = 400, description = "Invalid request", body = EstimateVideoCostError),
|
||||
),
|
||||
)]
|
||||
pub async fn estimate_video_cost_handler(
|
||||
request: Json<EstimateVideoCostRequest>,
|
||||
) -> Result<Json<EstimateVideoCostResponse>, HandlerError> {
|
||||
let router_provider = map_provider(request.provider, request.model)?;
|
||||
let router_model = map_video_model(request.model)?;
|
||||
let router_aspect_ratio = request.aspect_ratio.map(map_aspect_ratio);
|
||||
let router_resolution = request.resolution.map(map_resolution);
|
||||
|
||||
let router_request = GenerateVideoRequest {
|
||||
model: router_model,
|
||||
provider: router_provider,
|
||||
prompt: None,
|
||||
start_frame: None,
|
||||
end_frame: None,
|
||||
reference_images: None,
|
||||
resolution: router_resolution,
|
||||
aspect_ratio: router_aspect_ratio,
|
||||
duration_seconds: request.duration_seconds,
|
||||
video_batch_count: request.video_batch_count,
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayLessDowngrade,
|
||||
idempotency_token: None,
|
||||
};
|
||||
|
||||
let plan = begin_video_generation(&router_request)
|
||||
.map_err(|e| HandlerError::InvalidInput(format!("{}", e)))?;
|
||||
|
||||
let estimate = plan.estimate_costs();
|
||||
|
||||
Ok(Json(EstimateVideoCostResponse {
|
||||
success: true,
|
||||
cost_in_credits: estimate.cost_in_credits,
|
||||
cost_in_usd_cents: estimate.cost_in_usd_cents,
|
||||
is_free: estimate.is_free,
|
||||
is_unlimited: estimate.is_unlimited,
|
||||
is_rate_limited: estimate.is_rate_limited,
|
||||
has_watermark: estimate.has_watermark,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Local error type — wraps the serializable API error struct so we can implement
|
||||
/// ResponseError (orphan rules prevent implementing it directly on the foreign type).
|
||||
#[derive(Debug)]
|
||||
pub enum HandlerError {
|
||||
InvalidProviderForModel { provider: String, model: String },
|
||||
InvalidInput(String),
|
||||
}
|
||||
|
||||
impl std::error::Error for HandlerError {}
|
||||
|
||||
impl Display for HandlerError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResponseError for HandlerError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::BAD_REQUEST
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
let (error_type, error_message) = match self {
|
||||
HandlerError::InvalidProviderForModel { provider, model } => (
|
||||
EstimateVideoCostErrorType::InvalidProviderForModel,
|
||||
format!("Provider '{}' is not supported for model '{}'", provider, model),
|
||||
),
|
||||
HandlerError::InvalidInput(msg) => (
|
||||
EstimateVideoCostErrorType::InvalidInput,
|
||||
msg.clone(),
|
||||
),
|
||||
};
|
||||
HttpResponse::BadRequest().json(EstimateVideoCostError {
|
||||
success: false,
|
||||
error_type,
|
||||
error_message,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn map_provider(
|
||||
provider: GenerationProvider,
|
||||
model: CommonVideoModel,
|
||||
) -> Result<RouterProvider, HandlerError> {
|
||||
match provider {
|
||||
GenerationProvider::Artcraft => Ok(RouterProvider::Artcraft),
|
||||
other => Err(HandlerError::InvalidProviderForModel {
|
||||
provider: format!("{:?}", other),
|
||||
model: format!("{:?}", model),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_video_model(model: CommonVideoModel) -> Result<RouterVideoModel, HandlerError> {
|
||||
let router_model = match model {
|
||||
CommonVideoModel::GrokVideo => RouterVideoModel::GrokVideo,
|
||||
CommonVideoModel::Kling16Pro => RouterVideoModel::Kling16Pro,
|
||||
CommonVideoModel::Kling21Pro => RouterVideoModel::Kling21Pro,
|
||||
CommonVideoModel::Kling21Master => RouterVideoModel::Kling21Master,
|
||||
CommonVideoModel::Kling2p5TurboPro => RouterVideoModel::Kling2p5TurboPro,
|
||||
CommonVideoModel::Kling2p6Pro => RouterVideoModel::Kling2p6Pro,
|
||||
CommonVideoModel::Seedance10Lite => RouterVideoModel::Seedance10Lite,
|
||||
CommonVideoModel::Seedance2p0 => RouterVideoModel::Seedance2p0,
|
||||
CommonVideoModel::Sora2 => RouterVideoModel::Sora2,
|
||||
CommonVideoModel::Sora2Pro => RouterVideoModel::Sora2Pro,
|
||||
CommonVideoModel::Veo2 => RouterVideoModel::Veo2,
|
||||
CommonVideoModel::Veo3 => RouterVideoModel::Veo3,
|
||||
CommonVideoModel::Veo3Fast => RouterVideoModel::Veo3Fast,
|
||||
CommonVideoModel::Veo3p1 => RouterVideoModel::Veo3p1,
|
||||
CommonVideoModel::Veo3p1Fast => RouterVideoModel::Veo3p1Fast,
|
||||
};
|
||||
Ok(router_model)
|
||||
}
|
||||
|
||||
fn map_aspect_ratio(ar: CommonAspectRatio) -> RouterAspectRatio {
|
||||
match ar {
|
||||
CommonAspectRatio::Auto => RouterAspectRatio::Auto,
|
||||
CommonAspectRatio::Square => RouterAspectRatio::Square,
|
||||
CommonAspectRatio::WideThreeByTwo => RouterAspectRatio::WideThreeByTwo,
|
||||
CommonAspectRatio::WideFourByThree => RouterAspectRatio::WideFourByThree,
|
||||
CommonAspectRatio::WideFiveByFour => RouterAspectRatio::WideFiveByFour,
|
||||
CommonAspectRatio::WideSixteenByNine => RouterAspectRatio::WideSixteenByNine,
|
||||
CommonAspectRatio::WideTwentyOneByNine => RouterAspectRatio::WideTwentyOneByNine,
|
||||
CommonAspectRatio::TallTwoByThree => RouterAspectRatio::TallTwoByThree,
|
||||
CommonAspectRatio::TallThreeByFour => RouterAspectRatio::TallThreeByFour,
|
||||
CommonAspectRatio::TallFourByFive => RouterAspectRatio::TallFourByFive,
|
||||
CommonAspectRatio::TallNineBySixteen => RouterAspectRatio::TallNineBySixteen,
|
||||
CommonAspectRatio::TallNineByTwentyOne => RouterAspectRatio::TallNineByTwentyOne,
|
||||
CommonAspectRatio::Wide => RouterAspectRatio::Wide,
|
||||
CommonAspectRatio::Tall => RouterAspectRatio::Tall,
|
||||
CommonAspectRatio::Auto2k => RouterAspectRatio::Auto2k,
|
||||
CommonAspectRatio::Auto4k => RouterAspectRatio::Auto4k,
|
||||
CommonAspectRatio::SquareHd => RouterAspectRatio::SquareHd,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_resolution(res: CommonVideoResolution) -> RouterResolution {
|
||||
match res {
|
||||
CommonVideoResolution::OneK => RouterResolution::OneK,
|
||||
CommonVideoResolution::TwoK => RouterResolution::TwoK,
|
||||
CommonVideoResolution::ThreeK => RouterResolution::ThreeK,
|
||||
CommonVideoResolution::FourK => RouterResolution::FourK,
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
pub mod estimate_video_cost_handler;
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod common;
|
||||
pub mod cost_estimate;
|
||||
pub mod image;
|
||||
pub mod object;
|
||||
pub mod video;
|
||||
pub mod common;
|
||||
pub mod video;
|
||||
+7
@@ -1,3 +1,4 @@
|
||||
use crate::http_server::endpoints::generate::cost_estimate::video::estimate_video_cost_handler::estimate_video_cost_handler;
|
||||
use crate::http_server::endpoints::generate::image::edit::flux_pro_kontext_max_edit_image_handler::flux_pro_kontext_max_edit_image_handler;
|
||||
use crate::http_server::endpoints::generate::image::edit::gemini_25_flash_edit_image_handler::gemini_25_flash_edit_image_handler;
|
||||
use crate::http_server::endpoints::generate::image::edit::gpt_image_1_edit_image_handler::gpt_image_1_edit_image_handler;
|
||||
@@ -51,6 +52,12 @@ where
|
||||
>,
|
||||
{
|
||||
app.service(web::scope("/v1/generate")
|
||||
.service(web::scope("/cost_estimate")
|
||||
.service(web::resource("/video")
|
||||
.route(web::post().to(estimate_video_cost_handler))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
)
|
||||
.service(web::scope("/image")
|
||||
.service(web::scope("/multi_function")
|
||||
.service(web::resource("/bytedance_seedream_4")
|
||||
|
||||
Reference in New Issue
Block a user