mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-25 10:39:37 +00:00
artcraft_router
This commit is contained in:
Generated
+1
@@ -773,6 +773,7 @@ dependencies = [
|
||||
"artcraft_client",
|
||||
"enums",
|
||||
"fal_client",
|
||||
"gmicloud_client",
|
||||
"log",
|
||||
"muapi_client",
|
||||
"reqwest 0.12.23",
|
||||
|
||||
@@ -20,6 +20,7 @@ artcraft_api_defs.workspace = true
|
||||
enums.workspace = true
|
||||
artcraft_client.workspace = true
|
||||
fal_client.workspace = true
|
||||
gmicloud_client.workspace = true
|
||||
muapi_client.workspace = true
|
||||
seedance2pro_client.workspace = true
|
||||
tokens.workspace = true
|
||||
|
||||
@@ -6,6 +6,7 @@ use serde_derive::{Deserialize, Serialize};
|
||||
pub enum Provider {
|
||||
Artcraft,
|
||||
Fal,
|
||||
GmiCloud,
|
||||
Muapi,
|
||||
Seedance2Pro,
|
||||
}
|
||||
|
||||
@@ -6,5 +6,6 @@ pub mod router_artcraft_client;
|
||||
pub mod router_client;
|
||||
pub mod router_fal_client;
|
||||
pub mod router_fal_webhook_optional_client;
|
||||
pub mod router_gmicloud_client;
|
||||
pub mod router_muapi_client;
|
||||
pub mod router_seedance2pro_client;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::client::router_artcraft_client::RouterArtcraftClient;
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::client::router_fal_webhook_optional_client::RouterFalWebhookOptionalClient;
|
||||
use crate::client::router_gmicloud_client::RouterGmiCloudClient;
|
||||
use crate::client::router_muapi_client::RouterMuapiClient;
|
||||
use crate::client::router_seedance2pro_client::RouterSeedance2ProClient;
|
||||
use crate::errors::client_error::{ClientError, ClientType};
|
||||
@@ -9,6 +10,7 @@ pub struct MultiRouterClient {
|
||||
pub(crate) artcraft_client: Option<RouterArtcraftClient>,
|
||||
pub(crate) fal_client: Option<RouterFalClient>,
|
||||
pub(crate) fal_webhook_optional_client: Option<RouterFalWebhookOptionalClient>,
|
||||
pub(crate) gmicloud_client: Option<RouterGmiCloudClient>,
|
||||
pub(crate) muapi_client: Option<RouterMuapiClient>,
|
||||
pub(crate) seedance2pro_client: Option<RouterSeedance2ProClient>,
|
||||
}
|
||||
@@ -23,11 +25,17 @@ impl MultiRouterClient {
|
||||
self.fal_client.as_ref()
|
||||
.ok_or(ClientError::ClientNotConfigured(ClientType::Fal))
|
||||
}
|
||||
|
||||
pub fn get_fal_webhook_optional_client_ref(&self) -> Result<&RouterFalWebhookOptionalClient, ClientError> {
|
||||
self.fal_webhook_optional_client.as_ref()
|
||||
.ok_or(ClientError::ClientNotConfigured(ClientType::FalWebhookOptional))
|
||||
}
|
||||
|
||||
pub fn get_gmicloud_client_ref(&self) -> Result<&RouterGmiCloudClient, ClientError> {
|
||||
self.gmicloud_client.as_ref()
|
||||
.ok_or(ClientError::ClientNotConfigured(ClientType::GmiCloud))
|
||||
}
|
||||
|
||||
pub fn get_muapi_client_ref(&self) -> Result<&RouterMuapiClient, ClientError> {
|
||||
self.muapi_client.as_ref()
|
||||
.ok_or(ClientError::ClientNotConfigured(ClientType::Muapi))
|
||||
|
||||
+10
-1
@@ -2,6 +2,7 @@ use crate::client::multi_router_client::MultiRouterClient;
|
||||
use crate::client::router_artcraft_client::RouterArtcraftClient;
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::client::router_fal_webhook_optional_client::RouterFalWebhookOptionalClient;
|
||||
use crate::client::router_gmicloud_client::RouterGmiCloudClient;
|
||||
use crate::client::router_muapi_client::RouterMuapiClient;
|
||||
use crate::client::router_seedance2pro_client::RouterSeedance2ProClient;
|
||||
|
||||
@@ -9,6 +10,7 @@ pub struct MultiRouterClientBuilder {
|
||||
artcraft_client: Option<RouterArtcraftClient>,
|
||||
fal_client: Option<RouterFalClient>,
|
||||
fal_webhook_optional_client: Option<RouterFalWebhookOptionalClient>,
|
||||
gmicloud_client: Option<RouterGmiCloudClient>,
|
||||
muapi_client: Option<RouterMuapiClient>,
|
||||
seedance2pro_client: Option<RouterSeedance2ProClient>,
|
||||
}
|
||||
@@ -19,6 +21,7 @@ impl MultiRouterClientBuilder {
|
||||
artcraft_client: None,
|
||||
fal_client: None,
|
||||
fal_webhook_optional_client: None,
|
||||
gmicloud_client: None,
|
||||
muapi_client: None,
|
||||
seedance2pro_client: None,
|
||||
}
|
||||
@@ -33,12 +36,17 @@ impl MultiRouterClientBuilder {
|
||||
self.fal_client = Some(client);
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
pub fn set_fal_webhook_optional_client(mut self, client: RouterFalWebhookOptionalClient) -> Self {
|
||||
self.fal_webhook_optional_client = Some(client);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_gmicloud_client(mut self, client: RouterGmiCloudClient) -> Self {
|
||||
self.gmicloud_client = Some(client);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_muapi_client(mut self, client: RouterMuapiClient) -> Self {
|
||||
self.muapi_client = Some(client);
|
||||
self
|
||||
@@ -54,6 +62,7 @@ impl MultiRouterClientBuilder {
|
||||
artcraft_client: self.artcraft_client,
|
||||
fal_client: self.fal_client,
|
||||
fal_webhook_optional_client: self.fal_webhook_optional_client,
|
||||
gmicloud_client: self.gmicloud_client,
|
||||
muapi_client: self.muapi_client,
|
||||
seedance2pro_client: self.seedance2pro_client,
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::client::multi_router_client::MultiRouterClient;
|
||||
use crate::client::router_artcraft_client::RouterArtcraftClient;
|
||||
use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::client::router_fal_webhook_optional_client::RouterFalWebhookOptionalClient;
|
||||
use crate::client::router_gmicloud_client::RouterGmiCloudClient;
|
||||
use crate::client::router_muapi_client::RouterMuapiClient;
|
||||
use crate::client::router_seedance2pro_client::RouterSeedance2ProClient;
|
||||
use crate::errors::client_error::{ClientError, ClientType};
|
||||
@@ -11,6 +12,7 @@ pub enum RouterClient {
|
||||
Artcraft(RouterArtcraftClient),
|
||||
Fal(RouterFalClient),
|
||||
FalWebhookOptional(RouterFalWebhookOptionalClient),
|
||||
GmiCloud(RouterGmiCloudClient),
|
||||
Muapi(RouterMuapiClient),
|
||||
Seedance2Pro(RouterSeedance2ProClient),
|
||||
}
|
||||
@@ -40,6 +42,14 @@ impl RouterClient {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_gmicloud_client_ref(&self) -> Result<&RouterGmiCloudClient, ClientError> {
|
||||
match self {
|
||||
RouterClient::GmiCloud(client) => Ok(client),
|
||||
RouterClient::Multi(multi) => multi.get_gmicloud_client_ref(),
|
||||
_ => Err(ClientError::ClientNotConfigured(ClientType::GmiCloud)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_muapi_client_ref(&self) -> Result<&RouterMuapiClient, ClientError> {
|
||||
match self {
|
||||
RouterClient::Muapi(client) => Ok(client),
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
use gmicloud_client::creds::gmicloud_api_key::GmiCloudApiKey;
|
||||
|
||||
pub struct RouterGmiCloudClient {
|
||||
pub(crate) api_key: GmiCloudApiKey,
|
||||
}
|
||||
|
||||
impl RouterGmiCloudClient {
|
||||
pub fn new(api_key: GmiCloudApiKey) -> Self {
|
||||
RouterGmiCloudClient { api_key }
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ pub enum ClientType {
|
||||
Artcraft,
|
||||
Fal,
|
||||
FalWebhookOptional,
|
||||
GmiCloud,
|
||||
Muapi,
|
||||
Seedance2Pro,
|
||||
}
|
||||
@@ -18,6 +19,7 @@ impl Display for ClientType {
|
||||
Self::Artcraft => write!(f, "Artcraft"),
|
||||
Self::Fal => write!(f, "Fal"),
|
||||
Self::FalWebhookOptional => write!(f, "FalWebhookOptional"),
|
||||
Self::GmiCloud => write!(f, "GmiCloud"),
|
||||
Self::Muapi => write!(f, "Muapi"),
|
||||
Self::Seedance2Pro => write!(f, "Seedance2Pro"),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::error::Error;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use artcraft_client::error::storyteller_error::StorytellerError;
|
||||
use fal_client::error::fal_error_plus::FalErrorPlus;
|
||||
use gmicloud_client::error::gmicloud_error::GmiCloudError;
|
||||
use muapi_client::error::muapi_error::MuapiError;
|
||||
use seedance2pro_client::error::seedance2pro_error::Seedance2ProError;
|
||||
|
||||
@@ -9,6 +10,7 @@ use seedance2pro_client::error::seedance2pro_error::Seedance2ProError;
|
||||
pub enum ProviderError {
|
||||
Storyteller(StorytellerError),
|
||||
Fal(FalErrorPlus),
|
||||
GmiCloud(GmiCloudError),
|
||||
Muapi(MuapiError),
|
||||
Seedance2Pro(Seedance2ProError),
|
||||
}
|
||||
@@ -20,6 +22,7 @@ impl Display for ProviderError {
|
||||
match self {
|
||||
Self::Storyteller(e) => write!(f, "Storyteller provider error: {}", e),
|
||||
Self::Fal(e) => write!(f, "Fal provider error: {}", e),
|
||||
Self::GmiCloud(e) => write!(f, "GmiCloud provider error: {}", e),
|
||||
Self::Muapi(e) => write!(f, "Muapi provider error: {}", e),
|
||||
Self::Seedance2Pro(e) => write!(f, "Seedance2Pro provider error: {}", e),
|
||||
}
|
||||
@@ -38,6 +41,12 @@ impl From<FalErrorPlus> for ProviderError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GmiCloudError> for ProviderError {
|
||||
fn from(error: GmiCloudError) -> Self {
|
||||
Self::GmiCloud(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MuapiError> for ProviderError {
|
||||
fn from(error: MuapiError) -> Self {
|
||||
Self::Muapi(error)
|
||||
|
||||
+7
-1
@@ -52,6 +52,8 @@ use crate::generate::generate_video_v2::providers::artcraft::seedance_2p0::build
|
||||
use crate::generate::generate_video_v2::providers::artcraft::seedance_2p0_fast::build::build_artcraft_seedance_2p0_fast;
|
||||
use crate::generate::generate_video_v2::providers::kinovi::happy_horse_1p0::build::build_kinovi_happy_horse_1p0;
|
||||
use crate::generate::generate_video_v2::providers::kinovi::seedance_2p0::build::build_kinovi_seedance_2p0;
|
||||
use crate::generate::generate_video_v2::providers::gmicloud::seedance_2p0_g::build::build_gmicloud_seedance_2p0_g;
|
||||
use crate::generate::generate_video_v2::providers::gmicloud::seedance_2p0_fast_g::build::build_gmicloud_seedance_2p0_fast_g;
|
||||
use crate::generate::generate_video_v2::providers::kinovi::seedance_2p0_fast::build::build_kinovi_seedance_2p0_fast;
|
||||
use crate::generate::generate_video_v2::video_generation_draft_or_request::VideoGenerationDraftOrRequest;
|
||||
|
||||
@@ -147,6 +149,8 @@ impl GenerateVideoRequestBuilder {
|
||||
(Provider::Artcraft, CommonVideoModel::HappyHorse1p0) => true,
|
||||
(Provider::Artcraft, CommonVideoModel::Seedance2p0) => true,
|
||||
(Provider::Artcraft, CommonVideoModel::Seedance2p0Fast) => true,
|
||||
(Provider::GmiCloud, CommonVideoModel::Seedance2p0Global) => true,
|
||||
(Provider::GmiCloud, CommonVideoModel::Seedance2p0FastGlobal) => true,
|
||||
(Provider::Seedance2Pro, CommonVideoModel::HappyHorse1p0) => true,
|
||||
(Provider::Seedance2Pro, CommonVideoModel::Seedance2p0) => true,
|
||||
(Provider::Seedance2Pro, CommonVideoModel::Seedance2p0Fast) => true,
|
||||
@@ -160,6 +164,8 @@ impl GenerateVideoRequestBuilder {
|
||||
(Provider::Artcraft, CommonVideoModel::HappyHorse1p0) => build_artcraft_happy_horse_1p0(self),
|
||||
(Provider::Artcraft, CommonVideoModel::Seedance2p0) => build_artcraft_seedance_2p0(self),
|
||||
(Provider::Artcraft, CommonVideoModel::Seedance2p0Fast) => build_artcraft_seedance_2p0_fast(self),
|
||||
(Provider::GmiCloud, CommonVideoModel::Seedance2p0Global) => build_gmicloud_seedance_2p0_g(self),
|
||||
(Provider::GmiCloud, CommonVideoModel::Seedance2p0FastGlobal) => build_gmicloud_seedance_2p0_fast_g(self),
|
||||
(Provider::Seedance2Pro, CommonVideoModel::HappyHorse1p0) => build_kinovi_happy_horse_1p0(self),
|
||||
(Provider::Seedance2Pro, CommonVideoModel::Seedance2p0) => build_kinovi_seedance_2p0(self),
|
||||
(Provider::Seedance2Pro, CommonVideoModel::Seedance2p0Fast) => build_kinovi_seedance_2p0_fast(self),
|
||||
@@ -172,9 +178,9 @@ impl GenerateVideoRequestBuilder {
|
||||
match self.provider {
|
||||
Provider::Artcraft => self.build_artcraft(),
|
||||
Provider::Fal => self.build_fal(),
|
||||
Provider::GmiCloud => self.unsupported_provider(), // GmiCloud uses build2() only
|
||||
Provider::Muapi => self.build_muapi(),
|
||||
Provider::Seedance2Pro => self.build_seedance2pro(),
|
||||
_ => self.unsupported_provider(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
@@ -34,9 +34,15 @@ pub struct FalVideoResponsePayload {
|
||||
pub maybe_outbound_request: Option<Arc<dyn Debug + Send + Sync>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GmiCloudVideoResponsePayload {
|
||||
pub request_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum GenerateVideoResponse {
|
||||
Artcraft(ArtcraftVideoResponsePayload),
|
||||
GmiCloud(GmiCloudVideoResponsePayload),
|
||||
Muapi(MuapiVideoResponsePayload),
|
||||
Seedance2Pro(Seedance2proVideoResponsePayload),
|
||||
Fal(FalVideoResponsePayload),
|
||||
@@ -64,6 +70,13 @@ impl GenerateVideoResponse {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_gmicloud_payload(&self) -> Option<GmiCloudVideoResponsePayload> {
|
||||
match self {
|
||||
Self::GmiCloud(p) => Some(p.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_fal_payload(&self) -> Option<FalVideoResponsePayload> {
|
||||
match self {
|
||||
Self::Fal(p) => Some(p.clone()),
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
pub mod seedance_2p0_g;
|
||||
pub mod seedance_2p0_fast_g;
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
use gmicloud_client::requests::api::video::seedance_2_0_fast_260128::api::{
|
||||
Seedance20FastRatio, Seedance20FastRequest, Seedance20FastResolution,
|
||||
};
|
||||
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::api::common_resolution::CommonResolution;
|
||||
use crate::api::image_ref::ImageRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder;
|
||||
use crate::generate::generate_video_v2::providers::gmicloud::seedance_2p0_fast_g::request::GmiCloudSeedance2p0FastGRequestState;
|
||||
use crate::generate::generate_video_v2::video_generation_draft_or_request::VideoGenerationDraftOrRequest;
|
||||
use crate::generate::generate_video_v2::video_generation_request::VideoGenerationRequest;
|
||||
|
||||
pub fn build_gmicloud_seedance_2p0_fast_g(
|
||||
mut builder: GenerateVideoRequestBuilder,
|
||||
) -> Result<VideoGenerationDraftOrRequest, ArtcraftRouterError> {
|
||||
let strategy = builder.request_mismatch_mitigation_strategy;
|
||||
|
||||
let ratio = plan_ratio(builder.aspect_ratio.take(), strategy)?;
|
||||
let resolution = plan_resolution(builder.resolution.take(), strategy)?;
|
||||
let duration = builder.duration_seconds.take().map(|d| (d as u8).clamp(4, 15));
|
||||
let prompt = builder.prompt.take().unwrap_or_default();
|
||||
|
||||
let first_frame = resolve_url(builder.start_frame.take())?;
|
||||
let last_frame = resolve_url(builder.end_frame.take())?;
|
||||
|
||||
let request = Seedance20FastRequest {
|
||||
prompt,
|
||||
duration,
|
||||
resolution,
|
||||
ratio,
|
||||
seed: None,
|
||||
watermark: None,
|
||||
generate_audio: None,
|
||||
web_search: None,
|
||||
first_frame,
|
||||
last_frame,
|
||||
reference_images: None,
|
||||
reference_videos: None,
|
||||
reference_audios: None,
|
||||
reference_asset_ids: None,
|
||||
};
|
||||
|
||||
let state = GmiCloudSeedance2p0FastGRequestState { request };
|
||||
Ok(VideoGenerationDraftOrRequest::Request(VideoGenerationRequest::GmiCloudSeedance2p0FastG(state)))
|
||||
}
|
||||
|
||||
fn plan_ratio(
|
||||
aspect_ratio: Option<CommonAspectRatio>,
|
||||
_strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<Option<Seedance20FastRatio>, ArtcraftRouterError> {
|
||||
match aspect_ratio {
|
||||
None | Some(CommonAspectRatio::Auto) | Some(CommonAspectRatio::Auto2k)
|
||||
| Some(CommonAspectRatio::Auto3k) | Some(CommonAspectRatio::Auto4k) => Ok(None),
|
||||
Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Seedance20FastRatio::Landscape16x9)),
|
||||
Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Seedance20FastRatio::Portrait9x16)),
|
||||
Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Seedance20FastRatio::Square)),
|
||||
Some(CommonAspectRatio::WideFourByThree) => Ok(Some(Seedance20FastRatio::Standard4x3)),
|
||||
Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(Seedance20FastRatio::Portrait3x4)),
|
||||
Some(CommonAspectRatio::WideTwentyOneByNine) | Some(CommonAspectRatio::TallNineByTwentyOne) => {
|
||||
Ok(Some(Seedance20FastRatio::UltraWide21x9))
|
||||
}
|
||||
Some(CommonAspectRatio::WideThreeByTwo) | Some(CommonAspectRatio::WideFiveByFour)
|
||||
| Some(CommonAspectRatio::TallFourByFive) | Some(CommonAspectRatio::TallTwoByThree) => {
|
||||
Ok(Some(Seedance20FastRatio::Adaptive))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn plan_resolution(
|
||||
resolution: Option<CommonResolution>,
|
||||
_strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<Option<Seedance20FastResolution>, ArtcraftRouterError> {
|
||||
match resolution {
|
||||
None => Ok(None),
|
||||
Some(CommonResolution::FourEightyP) => Ok(Some(Seedance20FastResolution::FourEightyP)),
|
||||
Some(CommonResolution::SevenTwentyP) => Ok(Some(Seedance20FastResolution::SevenTwentyP)),
|
||||
// Fast model doesn't support 1080p — fall back to 720p
|
||||
Some(CommonResolution::TenEightyP) => Ok(Some(Seedance20FastResolution::SevenTwentyP)),
|
||||
Some(CommonResolution::HalfK) | Some(CommonResolution::OneK) => Ok(Some(Seedance20FastResolution::FourEightyP)),
|
||||
Some(CommonResolution::TwoK) | Some(CommonResolution::ThreeK) | Some(CommonResolution::FourK) => {
|
||||
Ok(Some(Seedance20FastResolution::SevenTwentyP))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_url(image_ref: Option<ImageRef>) -> Result<Option<String>, ArtcraftRouterError> {
|
||||
match image_ref {
|
||||
None => Ok(None),
|
||||
Some(ImageRef::Url(url)) => Ok(Some(url)),
|
||||
Some(ImageRef::MediaFileToken(_)) => {
|
||||
Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
|
||||
field: "start_frame/end_frame",
|
||||
value: "GmiCloud only supports image URLs, not media file tokens".to_string(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
use gmicloud_client::traits::gmicloud_request_cost_calculator_trait::GmiCloudRequestCostCalculator;
|
||||
|
||||
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
|
||||
use crate::generate::generate_video_v2::providers::gmicloud::seedance_2p0_fast_g::request::GmiCloudSeedance2p0FastGRequestState;
|
||||
|
||||
pub struct GmiCloudSeedance2p0FastGCostState {
|
||||
request: GmiCloudSeedance2p0FastGRequestState,
|
||||
}
|
||||
|
||||
impl GmiCloudSeedance2p0FastGCostState {
|
||||
pub fn from_request(request: &GmiCloudSeedance2p0FastGRequestState) -> Self {
|
||||
Self { request: request.clone() }
|
||||
}
|
||||
|
||||
pub fn estimate_cost(&self) -> VideoGenerationCostEstimate {
|
||||
let cost_in_usd_cents = self.request.request.calculate_cost_in_cents();
|
||||
|
||||
VideoGenerationCostEstimate {
|
||||
cost_in_credits: None,
|
||||
cost_in_usd_cents: Some(cost_in_usd_cents),
|
||||
is_free: false,
|
||||
is_unlimited: false,
|
||||
is_rate_limited: false,
|
||||
has_watermark: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
pub mod build;
|
||||
pub mod cost;
|
||||
pub mod request;
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
use gmicloud_client::requests::api::video::seedance_2_0_fast_260128::api::Seedance20FastRequest;
|
||||
|
||||
use crate::client::router_gmicloud_client::RouterGmiCloudClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
use crate::generate::generate_video::generate_video_response::{
|
||||
GenerateVideoResponse, GmiCloudVideoResponsePayload,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GmiCloudSeedance2p0FastGRequestState {
|
||||
pub request: Seedance20FastRequest,
|
||||
}
|
||||
|
||||
impl GmiCloudSeedance2p0FastGRequestState {
|
||||
pub async fn send(&self, client: &RouterGmiCloudClient) -> Result<GenerateVideoResponse, ArtcraftRouterError> {
|
||||
let response = self.request.send_request(&client.api_key)
|
||||
.await
|
||||
.map_err(|err| ArtcraftRouterError::Provider(ProviderError::GmiCloud(err)))?;
|
||||
|
||||
Ok(GenerateVideoResponse::GmiCloud(GmiCloudVideoResponsePayload {
|
||||
request_id: response.request_id,
|
||||
}))
|
||||
}
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
use gmicloud_client::requests::api::video::seedance_2_0_260128::api::{
|
||||
Seedance20Ratio, Seedance20Request, Seedance20Resolution,
|
||||
};
|
||||
|
||||
use crate::api::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::api::common_resolution::CommonResolution;
|
||||
use crate::api::image_ref::ImageRef;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
use crate::generate::generate_video::generate_video_request_builder::GenerateVideoRequestBuilder;
|
||||
use crate::generate::generate_video_v2::providers::gmicloud::seedance_2p0_g::request::GmiCloudSeedance2p0GRequestState;
|
||||
use crate::generate::generate_video_v2::video_generation_draft_or_request::VideoGenerationDraftOrRequest;
|
||||
use crate::generate::generate_video_v2::video_generation_request::VideoGenerationRequest;
|
||||
|
||||
pub fn build_gmicloud_seedance_2p0_g(
|
||||
mut builder: GenerateVideoRequestBuilder,
|
||||
) -> Result<VideoGenerationDraftOrRequest, ArtcraftRouterError> {
|
||||
let strategy = builder.request_mismatch_mitigation_strategy;
|
||||
|
||||
let ratio = plan_ratio(builder.aspect_ratio.take(), strategy)?;
|
||||
let resolution = plan_resolution(builder.resolution.take(), strategy)?;
|
||||
let duration = builder.duration_seconds.take().map(|d| (d as u8).clamp(4, 15));
|
||||
let prompt = builder.prompt.take().unwrap_or_default();
|
||||
|
||||
let first_frame = resolve_url(builder.start_frame.take())?;
|
||||
let last_frame = resolve_url(builder.end_frame.take())?;
|
||||
|
||||
let request = Seedance20Request {
|
||||
prompt,
|
||||
duration,
|
||||
resolution,
|
||||
ratio,
|
||||
seed: None,
|
||||
watermark: None,
|
||||
generate_audio: None,
|
||||
web_search: None,
|
||||
first_frame,
|
||||
last_frame,
|
||||
reference_images: None,
|
||||
reference_videos: None,
|
||||
reference_audios: None,
|
||||
reference_asset_ids: None,
|
||||
};
|
||||
|
||||
let state = GmiCloudSeedance2p0GRequestState { request };
|
||||
Ok(VideoGenerationDraftOrRequest::Request(VideoGenerationRequest::GmiCloudSeedance2p0G(state)))
|
||||
}
|
||||
|
||||
fn plan_ratio(
|
||||
aspect_ratio: Option<CommonAspectRatio>,
|
||||
_strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<Option<Seedance20Ratio>, ArtcraftRouterError> {
|
||||
match aspect_ratio {
|
||||
None | Some(CommonAspectRatio::Auto) | Some(CommonAspectRatio::Auto2k)
|
||||
| Some(CommonAspectRatio::Auto3k) | Some(CommonAspectRatio::Auto4k) => Ok(None),
|
||||
Some(CommonAspectRatio::WideSixteenByNine) | Some(CommonAspectRatio::Wide) => Ok(Some(Seedance20Ratio::Landscape16x9)),
|
||||
Some(CommonAspectRatio::TallNineBySixteen) | Some(CommonAspectRatio::Tall) => Ok(Some(Seedance20Ratio::Portrait9x16)),
|
||||
Some(CommonAspectRatio::Square) | Some(CommonAspectRatio::SquareHd) => Ok(Some(Seedance20Ratio::Square)),
|
||||
Some(CommonAspectRatio::WideFourByThree) => Ok(Some(Seedance20Ratio::Standard4x3)),
|
||||
Some(CommonAspectRatio::TallThreeByFour) => Ok(Some(Seedance20Ratio::Portrait3x4)),
|
||||
Some(CommonAspectRatio::WideTwentyOneByNine) | Some(CommonAspectRatio::TallNineByTwentyOne) => {
|
||||
Ok(Some(Seedance20Ratio::UltraWide21x9))
|
||||
}
|
||||
Some(CommonAspectRatio::WideThreeByTwo) | Some(CommonAspectRatio::WideFiveByFour)
|
||||
| Some(CommonAspectRatio::TallFourByFive) | Some(CommonAspectRatio::TallTwoByThree) => {
|
||||
Ok(Some(Seedance20Ratio::Adaptive))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn plan_resolution(
|
||||
resolution: Option<CommonResolution>,
|
||||
_strategy: RequestMismatchMitigationStrategy,
|
||||
) -> Result<Option<Seedance20Resolution>, ArtcraftRouterError> {
|
||||
match resolution {
|
||||
None => Ok(None),
|
||||
Some(CommonResolution::FourEightyP) => Ok(Some(Seedance20Resolution::FourEightyP)),
|
||||
Some(CommonResolution::SevenTwentyP) => Ok(Some(Seedance20Resolution::SevenTwentyP)),
|
||||
Some(CommonResolution::TenEightyP) => Ok(Some(Seedance20Resolution::TenEightyP)),
|
||||
Some(CommonResolution::HalfK) | Some(CommonResolution::OneK) => Ok(Some(Seedance20Resolution::FourEightyP)),
|
||||
Some(CommonResolution::TwoK) | Some(CommonResolution::ThreeK) | Some(CommonResolution::FourK) => {
|
||||
Ok(Some(Seedance20Resolution::TenEightyP))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_url(image_ref: Option<ImageRef>) -> Result<Option<String>, ArtcraftRouterError> {
|
||||
match image_ref {
|
||||
None => Ok(None),
|
||||
Some(ImageRef::Url(url)) => Ok(Some(url)),
|
||||
Some(ImageRef::MediaFileToken(_)) => {
|
||||
Err(ArtcraftRouterError::Client(ClientError::ModelDoesNotSupportOption {
|
||||
field: "start_frame/end_frame",
|
||||
value: "GmiCloud only supports image URLs, not media file tokens".to_string(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
use gmicloud_client::traits::gmicloud_request_cost_calculator_trait::GmiCloudRequestCostCalculator;
|
||||
|
||||
use crate::generate::generate_video::video_generation_cost_estimate::VideoGenerationCostEstimate;
|
||||
use crate::generate::generate_video_v2::providers::gmicloud::seedance_2p0_g::request::GmiCloudSeedance2p0GRequestState;
|
||||
|
||||
pub struct GmiCloudSeedance2p0GCostState {
|
||||
request: GmiCloudSeedance2p0GRequestState,
|
||||
}
|
||||
|
||||
impl GmiCloudSeedance2p0GCostState {
|
||||
pub fn from_request(request: &GmiCloudSeedance2p0GRequestState) -> Self {
|
||||
Self { request: request.clone() }
|
||||
}
|
||||
|
||||
pub fn estimate_cost(&self) -> VideoGenerationCostEstimate {
|
||||
let cost_in_usd_cents = self.request.request.calculate_cost_in_cents();
|
||||
|
||||
VideoGenerationCostEstimate {
|
||||
cost_in_credits: None,
|
||||
cost_in_usd_cents: Some(cost_in_usd_cents),
|
||||
is_free: false,
|
||||
is_unlimited: false,
|
||||
is_rate_limited: false,
|
||||
has_watermark: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
pub mod build;
|
||||
pub mod cost;
|
||||
pub mod request;
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
use gmicloud_client::requests::api::video::seedance_2_0_260128::api::Seedance20Request;
|
||||
|
||||
use crate::client::router_gmicloud_client::RouterGmiCloudClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
use crate::generate::generate_video::generate_video_response::{
|
||||
GenerateVideoResponse, GmiCloudVideoResponsePayload,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GmiCloudSeedance2p0GRequestState {
|
||||
pub request: Seedance20Request,
|
||||
}
|
||||
|
||||
impl GmiCloudSeedance2p0GRequestState {
|
||||
pub async fn send(&self, client: &RouterGmiCloudClient) -> Result<GenerateVideoResponse, ArtcraftRouterError> {
|
||||
let response = self.request.send_request(&client.api_key)
|
||||
.await
|
||||
.map_err(|err| ArtcraftRouterError::Provider(ProviderError::GmiCloud(err)))?;
|
||||
|
||||
Ok(GenerateVideoResponse::GmiCloud(GmiCloudVideoResponsePayload {
|
||||
request_id: response.request_id,
|
||||
}))
|
||||
}
|
||||
}
|
||||
+1
@@ -1,2 +1,3 @@
|
||||
pub mod artcraft;
|
||||
pub mod gmicloud;
|
||||
pub mod kinovi;
|
||||
+18
@@ -9,6 +9,10 @@ use crate::generate::generate_video_v2::providers::artcraft::seedance_2p0::cost:
|
||||
use crate::generate::generate_video_v2::providers::artcraft::seedance_2p0::request::ArtcraftSeedance2p0RequestState;
|
||||
use crate::generate::generate_video_v2::providers::artcraft::seedance_2p0_fast::cost::ArtcraftSeedance2p0FastCostState;
|
||||
use crate::generate::generate_video_v2::providers::artcraft::seedance_2p0_fast::request::ArtcraftSeedance2p0FastRequestState;
|
||||
use crate::generate::generate_video_v2::providers::gmicloud::seedance_2p0_g::cost::GmiCloudSeedance2p0GCostState;
|
||||
use crate::generate::generate_video_v2::providers::gmicloud::seedance_2p0_g::request::GmiCloudSeedance2p0GRequestState;
|
||||
use crate::generate::generate_video_v2::providers::gmicloud::seedance_2p0_fast_g::cost::GmiCloudSeedance2p0FastGCostState;
|
||||
use crate::generate::generate_video_v2::providers::gmicloud::seedance_2p0_fast_g::request::GmiCloudSeedance2p0FastGRequestState;
|
||||
use crate::generate::generate_video_v2::providers::kinovi::happy_horse_1p0::cost::KinoviHappyHorse1p0CostState;
|
||||
use crate::generate::generate_video_v2::providers::kinovi::happy_horse_1p0::request::KinoviHappyHorse1p0RequestState;
|
||||
use crate::generate::generate_video_v2::providers::kinovi::seedance_2p0::cost::KinoviSeedance2p0CostState;
|
||||
@@ -21,6 +25,8 @@ pub enum VideoGenerationRequest {
|
||||
ArtcraftHappyHorse1p0(ArtcraftHappyHorse1p0RequestState),
|
||||
ArtcraftSeedance2p0(ArtcraftSeedance2p0RequestState),
|
||||
ArtcraftSeedance2p0Fast(ArtcraftSeedance2p0FastRequestState),
|
||||
GmiCloudSeedance2p0G(GmiCloudSeedance2p0GRequestState),
|
||||
GmiCloudSeedance2p0FastG(GmiCloudSeedance2p0FastGRequestState),
|
||||
KinoviHappyHorse1p0(KinoviHappyHorse1p0RequestState),
|
||||
KinoviSeedance2p0(KinoviSeedance2p0RequestState),
|
||||
KinoviSeedance2p0Fast(KinoviSeedance2p0FastRequestState),
|
||||
@@ -33,6 +39,8 @@ impl VideoGenerationRequest {
|
||||
Self::ArtcraftHappyHorse1p0(_) => Provider::Artcraft,
|
||||
Self::ArtcraftSeedance2p0(_) => Provider::Artcraft,
|
||||
Self::ArtcraftSeedance2p0Fast(_) => Provider::Artcraft,
|
||||
Self::GmiCloudSeedance2p0G(_) => Provider::GmiCloud,
|
||||
Self::GmiCloudSeedance2p0FastG(_) => Provider::GmiCloud,
|
||||
Self::KinoviHappyHorse1p0(_) => Provider::Seedance2Pro,
|
||||
Self::KinoviSeedance2p0(_) => Provider::Seedance2Pro,
|
||||
Self::KinoviSeedance2p0Fast(_) => Provider::Seedance2Pro,
|
||||
@@ -45,6 +53,8 @@ impl VideoGenerationRequest {
|
||||
VideoGenerationRequest::ArtcraftHappyHorse1p0(request) => Ok(ArtcraftHappyHorse1p0CostState::from_request(request).estimate_cost()),
|
||||
VideoGenerationRequest::ArtcraftSeedance2p0(request) => Ok(ArtcraftSeedance2p0CostState::from_request(request).estimate_cost()),
|
||||
VideoGenerationRequest::ArtcraftSeedance2p0Fast(request) => Ok(ArtcraftSeedance2p0FastCostState::from_request(request).estimate_cost()),
|
||||
VideoGenerationRequest::GmiCloudSeedance2p0G(request) => Ok(GmiCloudSeedance2p0GCostState::from_request(request).estimate_cost()),
|
||||
VideoGenerationRequest::GmiCloudSeedance2p0FastG(request) => Ok(GmiCloudSeedance2p0FastGCostState::from_request(request).estimate_cost()),
|
||||
VideoGenerationRequest::KinoviHappyHorse1p0(request) => Ok(KinoviHappyHorse1p0CostState::from_request(request).estimate_cost()),
|
||||
VideoGenerationRequest::KinoviSeedance2p0(request) => Ok(KinoviSeedance2p0CostState::from_request(request).estimate_cost()),
|
||||
VideoGenerationRequest::KinoviSeedance2p0Fast(request) => Ok(KinoviSeedance2p0FastCostState::from_request(request).estimate_cost()),
|
||||
@@ -67,6 +77,14 @@ impl VideoGenerationRequest {
|
||||
let client_ref = client.get_artcraft_client_ref()?;
|
||||
request.send(client_ref).await
|
||||
},
|
||||
VideoGenerationRequest::GmiCloudSeedance2p0G(request) => {
|
||||
let client_ref = client.get_gmicloud_client_ref()?;
|
||||
request.send(client_ref).await
|
||||
},
|
||||
VideoGenerationRequest::GmiCloudSeedance2p0FastG(request) => {
|
||||
let client_ref = client.get_gmicloud_client_ref()?;
|
||||
request.send(client_ref).await
|
||||
},
|
||||
VideoGenerationRequest::KinoviHappyHorse1p0(request) => {
|
||||
let client_ref = client.get_seedance2pro_client_ref()?;
|
||||
request.send(client_ref).await
|
||||
|
||||
Reference in New Issue
Block a user