rename generate video command

This commit is contained in:
Brandon Thomas committed 2026-05-03 00:28:58 -04:00
1 parent 9d38b45bc2
commit a75052ac44
32 files changed
+451 -516

No files matched your search

@@ -1,66 +0,0 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::enqueue::image_to_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::enqueue::image_to_video::artcraft::handle_artcraft_kling_1p6_pro::handle_artcraft_kling_1p6_pro;
use crate::core::commands::enqueue::image_to_video::artcraft::handle_artcraft_kling_2p1_master::handle_artcraft_kling_2p1_master;
use crate::core::commands::enqueue::image_to_video::artcraft::handle_artcraft_kling_2p1_pro::handle_artcraft_kling_2p1_pro;
use crate::core::commands::enqueue::image_to_video::artcraft::handle_artcraft_kling_2p5_turbo_pro::handle_artcraft_kling_2p5_turbo_pro;
use crate::core::commands::enqueue::image_to_video::artcraft::handle_artcraft_kling_2p6_pro::handle_artcraft_kling_2p6_pro;
use crate::core::commands::enqueue::image_to_video::artcraft::handle_artcraft_video_via_router::handle_artcraft_video_via_router;
use crate::core::commands::enqueue::image_to_video::artcraft::handle_artcraft_seedance_1_lite::handle_artcraft_seedance_1_lite;
use crate::core::events::generation_events::common::GenerationModel;
use artcraft_router::api::common_video_model::CommonVideoModel;
use crate::core::commands::enqueue::image_to_video::artcraft::handle_artcraft_seedance_2p0::handle_artcraft_seedance_2p0;
use crate::core::commands::enqueue::image_to_video::artcraft::handle_artcraft_sora2::handle_artcraft_sora2;
use crate::core::commands::enqueue::image_to_video::artcraft::handle_artcraft_sora2_pro::handle_artcraft_sora2_pro;
use crate::core::commands::enqueue::image_to_video::artcraft::handle_artcraft_veo2::handle_artcraft_veo2;
use crate::core::commands::enqueue::image_to_video::artcraft::handle_artcraft_veo3::handle_artcraft_veo3;
use crate::core::commands::enqueue::image_to_video::artcraft::handle_artcraft_veo3_fast::handle_artcraft_veo3_fast;
use crate::core::commands::enqueue::image_to_video::artcraft::handle_artcraft_veo3p1::handle_artcraft_veo3p1;
use crate::core::commands::enqueue::image_to_video::artcraft::handle_artcraft_veo3p1_fast::handle_artcraft_veo3p1_fast;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, VideoModel};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs;
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
use anyhow::anyhow;
use tauri::AppHandle;
pub async fn handle_video_artcraft(
request: &EnqueueImageToVideoRequest,
app: &AppHandle,
app_env_configs: &AppEnvConfigs,
storyteller_creds_manager: &StorytellerCredentialManager,
) -> Result<TaskEnqueueSuccess, GenerateError> {
let creds = get_storyteller_creds_or_error(app, storyteller_creds_manager)?;
match request.model {
None => {
Err(GenerateError::no_model_specified())
},
// Handled via router
Some(VideoModel::Kling3p0Pro) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonVideoModel::Kling3p0Pro, GenerationModel::Kling3p0Pro).await,
Some(VideoModel::Kling3p0Standard) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonVideoModel::Kling3p0Standard, GenerationModel::Kling3p0Standard).await,
Some(VideoModel::Seedance1p5Pro) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonVideoModel::Seedance1p5Pro, GenerationModel::Seedance1p5Pro).await,
Some(VideoModel::Seedance2p0) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonVideoModel::Seedance2p0, GenerationModel::Seedance2p0).await,
Some(VideoModel::Seedance2p0Fast) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonVideoModel::Seedance2p0Fast, GenerationModel::Seedance2p0Fast).await,
Some(VideoModel::HappyHorse1p0) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonVideoModel::HappyHorse1p0, GenerationModel::HappyHorse1p0).await,
// Legacy endpoints
Some(VideoModel::Kling16Pro) => handle_artcraft_kling_1p6_pro(request, app_env_configs, &creds).await,
Some(VideoModel::Kling21Pro) => handle_artcraft_kling_2p1_pro(request, app_env_configs, &creds).await,
Some(VideoModel::Kling21Master) => handle_artcraft_kling_2p1_master(request, app_env_configs, &creds).await,
Some(VideoModel::Kling2p5TurboPro) => handle_artcraft_kling_2p5_turbo_pro(request, app_env_configs, &creds).await,
Some(VideoModel::Kling2p6Pro) => handle_artcraft_kling_2p6_pro(request, app_env_configs, &creds).await,
Some(VideoModel::Seedance10Lite) => handle_artcraft_seedance_1_lite(request, app_env_configs, &creds).await,
Some(VideoModel::Sora2) => handle_artcraft_sora2(request, app_env_configs, &creds).await,
Some(VideoModel::Sora2Pro) => handle_artcraft_sora2_pro(request, app_env_configs, &creds).await,
Some(VideoModel::Veo2) => handle_artcraft_veo2(request, app_env_configs, &creds).await,
Some(VideoModel::Veo3) => handle_artcraft_veo3(request, app_env_configs, &creds).await,
Some(VideoModel::Veo3Fast) => handle_artcraft_veo3_fast(request, app_env_configs, &creds).await,
Some(VideoModel::Veo3p1) => handle_artcraft_veo3p1(request, app_env_configs, &creds).await,
Some(VideoModel::Veo3p1Fast) => handle_artcraft_veo3p1_fast(request, app_env_configs, &creds).await,
Some(_) => {
Err(GenerateError::AnyhowError(
anyhow!("wrong logic: another branch should handle this: {:?}", request.model)))
},
}
}
@@ -1,395 +0,0 @@
use crate::core::commands::enqueue::common::notify_frontend_of_errors::notify_frontend_of_errors;
use crate::core::commands::enqueue::generate_error::{BadInputReason, GenerateError, MissingCredentialsReason};
use crate::core::commands::enqueue::image_to_video::artcraft::handle_artcraft_video::handle_video_artcraft;
use crate::core::commands::enqueue::image_to_video::grok::handle_grok_video::handle_grok_video;
use crate::core::commands::enqueue::image_to_video::sora2::handle_sora_sora2::handle_sora_sora2;
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::commands::response::failure_response_wrapper::{CommandErrorResponseWrapper, CommandErrorStatus};
use crate::core::commands::response::shorthand::Response;
use crate::core::commands::response::success_response_wrapper::SerializeMarker;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::functional_events::credits_balance_changed_event::CreditsBalanceChangedEvent;
use crate::core::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent;
use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs;
use crate::core::state::artcraft_usage_tracker::artcraft_usage_tracker::ArtcraftUsageTracker;
use crate::core::state::artcraft_usage_tracker::artcraft_usage_type::{ArtcraftUsagePage, ArtcraftUsageType};
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::core::state::provider_priority::{Provider, ProviderPriorityStore};
use crate::core::state::task_database::TaskDatabase;
use crate::services::grok::state::grok_credential_manager::GrokCredentialManager;
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
use crate::services::sora::state::sora_task_queue::SoraTaskQueue;
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
use artcraft_router::api::common_aspect_ratio::CommonAspectRatio;
use artcraft_router::api::common_resolution::CommonResolution;
use enums::common::generation_provider::GenerationProvider;
use enums::tauri::ux::tauri_command_caller::TauriCommandCaller;
use log::{error, info, warn};
use serde_derive::{Deserialize, Serialize};
use tauri::{AppHandle, State};
use tokens::tokens::characters::CharacterToken;
use tokens::tokens::media_files::MediaFileToken;
/// This is used in the Tauri command bridge.
/// Don't change the serializations without coordinating with the frontend.
#[derive(Deserialize, Debug, Copy, Clone)]
#[serde(rename_all = "snake_case")]
pub enum VideoModel {
#[serde(rename = "grok_video")]
GrokVideo,
#[serde(rename = "kling_1.6_pro")]
Kling16Pro,
#[serde(rename = "kling_2.1_pro")]
Kling21Pro,
#[serde(rename = "kling_2.1_master")]
Kling21Master,
#[serde(rename = "kling_2p5_turbo_pro")]
Kling2p5TurboPro,
#[serde(rename = "kling_2p6_pro")]
Kling2p6Pro,
#[serde(rename = "kling_3p0_standard")]
Kling3p0Standard,
#[serde(rename = "kling_3p0_pro")]
Kling3p0Pro,
#[serde(rename = "happy_horse_1p0")]
HappyHorse1p0,
#[serde(rename = "seedance_1.0_lite")]
Seedance10Lite,
#[serde(rename = "seedance_1p5_pro")]
Seedance1p5Pro,
#[serde(rename = "seedance_2p0")]
Seedance2p0,
#[serde(rename = "seedance_2p0_fast")]
Seedance2p0Fast,
#[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,
}
#[derive(Deserialize, Debug)]
pub struct EnqueueImageToVideoRequest {
/// The provider to use (defaults to Artcraft/Storyteller).
/// Not all (provider, model) combinations are valid.
pub provider: Option<GenerationProvider>,
/// REQUIRED.
/// The model to use.
pub model: Option<VideoModel>,
/// Currently REQUIRED by some downstream models.
/// Image media file; the starting frame of the video.
/// TODO: In the future we may support base64 images, URLs, or file paths here.
pub image_media_token: Option<MediaFileToken>,
/// Optional.
/// Image media file; the image to remove the background from.
/// TODO: In the future we may support base64 images, URLs, or file paths here.
pub end_frame_image_media_token: Option<MediaFileToken>,
/// OPTIONAL.
/// Reference images for the video generation (e.g. character consistency, props, etc.)
pub reference_image_media_tokens: Option<Vec<MediaFileToken>>,
/// OPTIONAL.
/// Reference videos for the video generation (e.g. video edits, etc.)
pub reference_video_media_tokens: Option<Vec<MediaFileToken>>,
/// OPTIONAL.
/// Reference audio for the video generation (e.g. voices, lip sync, music, etc.)
pub reference_audio_media_tokens: Option<Vec<MediaFileToken>>,
/// Optional character tokens to reference in the prompt.
/// Characters are referenced in prompts as @CharacterName.
pub reference_character_tokens: Option<Vec<CharacterToken>>,
/// Optional.
/// Text prompt used to direct the video.
pub prompt: Option<String>,
/// Optional.
/// Generate the video with audio, if there is an option.
/// Typically, this costs money when presented as an option, so we default to off.
pub generate_audio: Option<bool>,
/// OPTIONAL.
/// Aspect ratio for the generated video.
pub aspect_ratio: Option<CommonAspectRatio>,
/// OPTIONAL.
/// Resolution for the generated video.
pub resolution: Option<CommonResolution>,
/// OPTIONAL.
/// Duration of the generated video in seconds.
pub duration_seconds: Option<u16>,
/// OPTIONAL.
/// Number of videos to generate in one batch.
pub video_batch_count: Option<u16>,
/// OPTIONAL.
/// Only for Sora2 model currently.
pub sora_orientation: Option<SoraOrientation>,
/// OPTIONAL.
/// Only for Grok model currently
pub grok_aspect_ratio: Option<GrokAspectRatio>,
/// OPTIONAL.
/// Name of the frontend caller.
/// We'll use this to selectively trigger events.
pub frontend_caller: Option<TauriCommandCaller>,
/// OPTIONAL.
/// A frontend-defined identifier that we'll send back to the frontend
/// as a Tauri event on task completion.
pub frontend_subscriber_id: Option<String>,
/// OPTIONAL.
/// A frontend-defined payload that we'll send back to the frontend
/// as a Tauri event on task completion.
pub frontend_subscriber_payload: Option<String>,
}
// TODO: Not sure how to handle so many different types of video (model) x (services).
#[derive(Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum SoraOrientation {
Portrait,
Landscape,
}
// TODO: Not sure how to handle so many different types of video (model) x (services).
#[derive(Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum GrokAspectRatio {
Portrait,
Landscape,
Square
}
#[derive(Serialize)]
pub struct EnqueueImageToVideoSuccessResponse {
}
impl SerializeMarker for EnqueueImageToVideoSuccessResponse {}
#[derive(Serialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum EnqueueImageToVideoErrorType {
/// Caller didn't specify a model
ModelNotSpecified,
/// No model available for video generation
NoProviderAvailable,
/// Generic server error
ServerError,
/// No Fal API key available
NeedsFalApiKey,
/// Fal had an API error
FalError,
/// Needs to be logged into Artcraft
NeedsStorytellerCredentials,
}
#[tauri::command]
pub async fn enqueue_image_to_video_command(
request: EnqueueImageToVideoRequest,
app: AppHandle,
app_env_configs: State<'_, AppEnvConfigs>,
app_data_root: State<'_, AppDataRoot>,
artcraft_usage_tracker: State<'_, ArtcraftUsageTracker>,
provider_priority_store: State<'_, ProviderPriorityStore>,
task_database: State<'_, TaskDatabase>,
grok_creds_manager: State<'_, GrokCredentialManager>,
storyteller_creds_manager: State<'_, StorytellerCredentialManager>,
sora_task_queue: State<'_, SoraTaskQueue>,
sora_creds_manager: State<'_, SoraCredentialManager>,
) -> Response<EnqueueImageToVideoSuccessResponse, EnqueueImageToVideoErrorType, ()> {
info!("enqueue_image_to_video_command called, request: {:?}", request);
let result = handle_request(
request,
&app,
&app_env_configs,
&app_data_root,
&artcraft_usage_tracker,
&provider_priority_store,
&task_database,
&grok_creds_manager,
&sora_creds_manager,
&storyteller_creds_manager,
).await;
match result {
Err(err) => {
error!("error: {:?}", err);
notify_frontend_of_errors(&app, &err).await;
let mut status = CommandErrorStatus::ServerError;
let mut error_type = EnqueueImageToVideoErrorType::ServerError;
let mut error_message = "A server error occurred. Please try again. If it continues, please tell our staff about the problem.";
match err {
GenerateError::BadInput(BadInputReason::NoModelSpecified) => {
status = CommandErrorStatus::BadRequest;
error_type = EnqueueImageToVideoErrorType::ModelNotSpecified;
error_message = "No model specified for video generation";
}
GenerateError::NoProviderAvailable => {
status = CommandErrorStatus::ServerError;
error_type = EnqueueImageToVideoErrorType::NoProviderAvailable;
error_message = "No configured provider available for video generation";
}
GenerateError::MissingCredentials(MissingCredentialsReason::NeedsFalApiKey) => {
status = CommandErrorStatus::Unauthorized;
error_type = EnqueueImageToVideoErrorType::NeedsFalApiKey;
error_message = "You need to set a FAL api key";
},
GenerateError::MissingCredentials(MissingCredentialsReason::NeedsStorytellerCredentials) => {
status = CommandErrorStatus::Unauthorized;
error_type = EnqueueImageToVideoErrorType::NeedsStorytellerCredentials;
error_message = "You need to be logged into Artcraft.";
}
_ => {}, // Fall-through
}
Err(CommandErrorResponseWrapper {
status,
error_message: Some(error_message.to_string()),
error_type: Some(error_type),
error_details: None,
})
}
Ok(event) => {
let event = GenerationEnqueueSuccessEvent {
action: event.to_frontend_event_action(),
service: event.to_frontend_event_service(),
model: event.model,
};
if let Err(err) = event.send(&app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
CreditsBalanceChangedEvent{}.send_infallible(&app);
Ok(EnqueueImageToVideoSuccessResponse {}.into())
}
}
}
pub async fn handle_request(
request: EnqueueImageToVideoRequest,
app: &AppHandle,
app_env_configs: &AppEnvConfigs,
app_data_root: &AppDataRoot,
artcraft_usage_tracker: &ArtcraftUsageTracker,
provider_priority_store: &ProviderPriorityStore,
task_database: &TaskDatabase,
grok_creds_manager: &GrokCredentialManager,
sora_creds_manager: &SoraCredentialManager,
storyteller_creds_manager: &StorytellerCredentialManager,
) -> Result<TaskEnqueueSuccess, GenerateError> {
let model = match request.model {
Some(model) => model,
None => {
return Err(GenerateError::no_model_specified())
}
};
let provider = match (model, request.provider) {
(VideoModel::GrokVideo, _) => GenerationProvider::Grok,
_ => request.provider.unwrap_or(GenerationProvider::Artcraft),
};
info!("generate video with {:?} via provider {:?}", &model, &provider);
let result = match provider {
GenerationProvider::Grok => {
handle_grok_video(
&request,
app,
app_data_root,
app_env_configs,
grok_creds_manager,
).await
}
GenerationProvider::Sora => {
handle_sora_sora2(
&request,
app,
app_data_root,
app_env_configs,
sora_creds_manager,
).await
}
_ => {
handle_video_artcraft(
&request,
app,
app_env_configs,
storyteller_creds_manager,
).await
}
};
let success_event = match result {
Err(err) => return Err(err),
Ok(event) => event,
};
let result = success_event
.insert_into_task_database_with_frontend_payload(
task_database,
request.frontend_caller,
request.frontend_subscriber_id.as_deref(),
request.frontend_subscriber_payload.as_deref()
)
.await;
if let Err(err) = result {
error!("Failed to create task in database: {:?}", err);
// NB: Fail open, but find a way to flag this.
}
if let Err(err) = artcraft_usage_tracker.record_video_generation(1, ArtcraftUsageType::ImageToResult, ArtcraftUsagePage::VideoPage) {
// NB: Fail open.
warn!("Failed to report usage: {:?}", err);
}
Ok(success_event)
}
@@ -1,4 +0,0 @@
pub mod enqueue_image_to_video_command;
pub mod sora2;
mod grok;
mod artcraft;
@@ -4,7 +4,6 @@ pub mod image_bg_removal;
pub mod image_edit;
pub mod image_inpaint;
pub mod image_to_object;
pub mod image_to_video;
pub mod task_enqueue_success;
pub mod text_to_image;
pub mod image_to_gaussian;
@@ -1,6 +1,6 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::enqueue::image_to_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, SoraOrientation};
use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
@@ -26,7 +26,7 @@ use tauri::AppHandle;
use tokens::tokens::media_files::MediaFileToken;
pub (super) async fn handle_artcraft_kling_1p6_pro(
request: &EnqueueImageToVideoRequest,
request: &TauriGenerateVideoRequest,
app_env_configs: &AppEnvConfigs,
creds: &StorytellerCredentialSet,
) -> Result<TaskEnqueueSuccess, GenerateError> {
@@ -1,6 +1,6 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::enqueue::image_to_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, SoraOrientation};
use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
@@ -26,7 +26,7 @@ use tauri::AppHandle;
use tokens::tokens::media_files::MediaFileToken;
pub (super) async fn handle_artcraft_kling_2p1_master(
request: &EnqueueImageToVideoRequest,
request: &TauriGenerateVideoRequest,
app_env_configs: &AppEnvConfigs,
creds: &StorytellerCredentialSet,
) -> Result<TaskEnqueueSuccess, GenerateError> {
@@ -1,6 +1,6 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::enqueue::image_to_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, SoraOrientation};
use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
@@ -25,7 +25,7 @@ use tauri::AppHandle;
use tokens::tokens::media_files::MediaFileToken;
pub (super) async fn handle_artcraft_kling_2p1_pro(
request: &EnqueueImageToVideoRequest,
request: &TauriGenerateVideoRequest,
app_env_configs: &AppEnvConfigs,
creds: &StorytellerCredentialSet,
) -> Result<TaskEnqueueSuccess, GenerateError> {
@@ -1,6 +1,6 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::enqueue::image_to_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, SoraOrientation};
use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
@@ -24,7 +24,7 @@ use tauri::AppHandle;
use tokens::tokens::media_files::MediaFileToken;
pub (super) async fn handle_artcraft_kling_2p5_turbo_pro(
request: &EnqueueImageToVideoRequest,
request: &TauriGenerateVideoRequest,
app_env_configs: &AppEnvConfigs,
creds: &StorytellerCredentialSet,
) -> Result<TaskEnqueueSuccess, GenerateError> {
@@ -1,6 +1,6 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::enqueue::image_to_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, SoraOrientation};
use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
@@ -26,7 +26,7 @@ use tauri::AppHandle;
use tokens::tokens::media_files::MediaFileToken;
pub (super) async fn handle_artcraft_kling_2p6_pro(
request: &EnqueueImageToVideoRequest,
request: &TauriGenerateVideoRequest,
app_env_configs: &AppEnvConfigs,
creds: &StorytellerCredentialSet,
) -> Result<TaskEnqueueSuccess, GenerateError> {
@@ -1,6 +1,6 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::enqueue::image_to_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, SoraOrientation};
use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
@@ -27,7 +27,7 @@ use tauri::AppHandle;
use tokens::tokens::media_files::MediaFileToken;
pub (super) async fn handle_artcraft_seedance_1_lite(
request: &EnqueueImageToVideoRequest,
request: &TauriGenerateVideoRequest,
app_env_configs: &AppEnvConfigs,
creds: &StorytellerCredentialSet,
) -> Result<TaskEnqueueSuccess, GenerateError> {
@@ -1,5 +1,5 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::EnqueueImageToVideoRequest;
use crate::core::commands::generate::generate_video::request::TauriGenerateVideoRequest;
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::generation_events::common::GenerationModel;
use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs;
@@ -20,7 +20,7 @@ use enums::tauri::tasks::task_type::TaskType;
use log::{error, info};
pub(super) async fn handle_artcraft_seedance_2p0(
request: &EnqueueImageToVideoRequest,
request: &TauriGenerateVideoRequest,
app_env_configs: &AppEnvConfigs,
creds: &StorytellerCredentialSet,
) -> Result<TaskEnqueueSuccess, GenerateError> {
@@ -34,7 +34,7 @@ pub(super) async fn handle_artcraft_seedance_2p0(
let reference_images = request.reference_image_media_tokens.clone().map(ImageListRef::MediaFileTokens);
let router_request = GenerateVideoRequestBuilder {
model: CommonVideoModel::Seedance2p0,
model: CommonTauriVideoModel::Seedance2p0,
provider: Provider::Artcraft,
prompt: request.prompt.clone(),
negative_prompt: None,
@@ -1,6 +1,6 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::enqueue::image_to_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, SoraOrientation};
use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
@@ -28,7 +28,7 @@ use tauri::AppHandle;
use tokens::tokens::media_files::MediaFileToken;
pub (super) async fn handle_artcraft_sora2(
request: &EnqueueImageToVideoRequest,
request: &TauriGenerateVideoRequest,
app_env_configs: &AppEnvConfigs,
creds: &StorytellerCredentialSet,
) -> Result<TaskEnqueueSuccess, GenerateError> {
@@ -1,6 +1,6 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::enqueue::image_to_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, SoraOrientation};
use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
@@ -27,7 +27,7 @@ use artcraft_client::credentials::storyteller_credential_set::StorytellerCredent
use tokens::tokens::media_files::MediaFileToken;
pub (super) async fn handle_artcraft_sora2_pro(
request: &EnqueueImageToVideoRequest,
request: &TauriGenerateVideoRequest,
app_env_configs: &AppEnvConfigs,
creds: &StorytellerCredentialSet,
) -> Result<TaskEnqueueSuccess, GenerateError> {
@@ -1,6 +1,6 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::enqueue::image_to_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, SoraOrientation};
use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
@@ -25,7 +25,7 @@ use tauri::AppHandle;
use tokens::tokens::media_files::MediaFileToken;
pub (super) async fn handle_artcraft_veo2(
request: &EnqueueImageToVideoRequest,
request: &TauriGenerateVideoRequest,
app_env_configs: &AppEnvConfigs,
creds: &StorytellerCredentialSet,
) -> Result<TaskEnqueueSuccess, GenerateError> {
@@ -1,6 +1,6 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::enqueue::image_to_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, SoraOrientation};
use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
@@ -25,7 +25,7 @@ use tauri::AppHandle;
use tokens::tokens::media_files::MediaFileToken;
pub (super) async fn handle_artcraft_veo3(
request: &EnqueueImageToVideoRequest,
request: &TauriGenerateVideoRequest,
app_env_configs: &AppEnvConfigs,
creds: &StorytellerCredentialSet,
) -> Result<TaskEnqueueSuccess, GenerateError> {
@@ -1,6 +1,6 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::enqueue::image_to_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, SoraOrientation};
use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
@@ -26,7 +26,7 @@ use tauri::AppHandle;
use tokens::tokens::media_files::MediaFileToken;
pub (super) async fn handle_artcraft_veo3_fast(
request: &EnqueueImageToVideoRequest,
request: &TauriGenerateVideoRequest,
app_env_configs: &AppEnvConfigs,
creds: &StorytellerCredentialSet,
) -> Result<TaskEnqueueSuccess, GenerateError> {
@@ -1,6 +1,6 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::enqueue::image_to_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, SoraOrientation};
use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
@@ -24,7 +24,7 @@ use tauri::AppHandle;
use tokens::tokens::media_files::MediaFileToken;
pub (super) async fn handle_artcraft_veo3p1(
request: &EnqueueImageToVideoRequest,
request: &TauriGenerateVideoRequest,
app_env_configs: &AppEnvConfigs,
creds: &StorytellerCredentialSet,
) -> Result<TaskEnqueueSuccess, GenerateError> {
@@ -1,6 +1,6 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::enqueue::image_to_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, SoraOrientation};
use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
@@ -24,7 +24,7 @@ use tauri::AppHandle;
use tokens::tokens::media_files::MediaFileToken;
pub (super) async fn handle_artcraft_veo3p1_fast(
request: &EnqueueImageToVideoRequest,
request: &TauriGenerateVideoRequest,
app_env_configs: &AppEnvConfigs,
creds: &StorytellerCredentialSet,
) -> Result<TaskEnqueueSuccess, GenerateError> {
@@ -0,0 +1,66 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::generate::generate_video::artcraft::get_storyteller_creds_or_error::get_storyteller_creds_or_error;
use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_kling_1p6_pro::handle_artcraft_kling_1p6_pro;
use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_kling_2p1_master::handle_artcraft_kling_2p1_master;
use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_kling_2p1_pro::handle_artcraft_kling_2p1_pro;
use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_kling_2p5_turbo_pro::handle_artcraft_kling_2p5_turbo_pro;
use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_kling_2p6_pro::handle_artcraft_kling_2p6_pro;
use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_video_via_router::handle_artcraft_video_via_router;
use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_seedance_1_lite::handle_artcraft_seedance_1_lite;
use crate::core::events::generation_events::common::GenerationModel;
use artcraft_router::api::common_video_model::CommonVideoModel;
use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_seedance_2p0::handle_artcraft_seedance_2p0;
use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_sora2::handle_artcraft_sora2;
use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_sora2_pro::handle_artcraft_sora2_pro;
use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_veo2::handle_artcraft_veo2;
use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_veo3::handle_artcraft_veo3;
use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_veo3_fast::handle_artcraft_veo3_fast;
use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_veo3p1::handle_artcraft_veo3p1;
use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_veo3p1_fast::handle_artcraft_veo3p1_fast;
use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, TauriVideoModel};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs;
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
use anyhow::anyhow;
use tauri::AppHandle;
pub async fn handle_video_artcraft(
request: &TauriGenerateVideoRequest,
app: &AppHandle,
app_env_configs: &AppEnvConfigs,
storyteller_creds_manager: &StorytellerCredentialManager,
) -> Result<TaskEnqueueSuccess, GenerateError> {
let creds = get_storyteller_creds_or_error(app, storyteller_creds_manager)?;
match request.model {
None => {
Err(GenerateError::no_model_specified())
},
// Handled via router
Some(TauriVideoModel::Kling3p0Pro) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonTauriVideoModel::Kling3p0Pro, GenerationModel::Kling3p0Pro).await,
Some(TauriVideoModel::Kling3p0Standard) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonTauriVideoModel::Kling3p0Standard, GenerationModel::Kling3p0Standard).await,
Some(TauriVideoModel::Seedance1p5Pro) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonTauriVideoModel::Seedance1p5Pro, GenerationModel::Seedance1p5Pro).await,
Some(TauriVideoModel::Seedance2p0) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonTauriVideoModel::Seedance2p0, GenerationModel::Seedance2p0).await,
Some(TauriVideoModel::Seedance2p0Fast) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonTauriVideoModel::Seedance2p0Fast, GenerationModel::Seedance2p0Fast).await,
Some(TauriVideoModel::HappyHorse1p0) => handle_artcraft_video_via_router(request, app_env_configs, &creds, CommonTauriVideoModel::HappyHorse1p0, GenerationModel::HappyHorse1p0).await,
// Legacy endpoints
Some(TauriVideoModel::Kling16Pro) => handle_artcraft_kling_1p6_pro(request, app_env_configs, &creds).await,
Some(TauriVideoModel::Kling21Pro) => handle_artcraft_kling_2p1_pro(request, app_env_configs, &creds).await,
Some(TauriVideoModel::Kling21Master) => handle_artcraft_kling_2p1_master(request, app_env_configs, &creds).await,
Some(TauriVideoModel::Kling2p5TurboPro) => handle_artcraft_kling_2p5_turbo_pro(request, app_env_configs, &creds).await,
Some(TauriVideoModel::Kling2p6Pro) => handle_artcraft_kling_2p6_pro(request, app_env_configs, &creds).await,
Some(TauriVideoModel::Seedance10Lite) => handle_artcraft_seedance_1_lite(request, app_env_configs, &creds).await,
Some(TauriVideoModel::Sora2) => handle_artcraft_sora2(request, app_env_configs, &creds).await,
Some(TauriVideoModel::Sora2Pro) => handle_artcraft_sora2_pro(request, app_env_configs, &creds).await,
Some(TauriVideoModel::Veo2) => handle_artcraft_veo2(request, app_env_configs, &creds).await,
Some(TauriVideoModel::Veo3) => handle_artcraft_veo3(request, app_env_configs, &creds).await,
Some(TauriVideoModel::Veo3Fast) => handle_artcraft_veo3_fast(request, app_env_configs, &creds).await,
Some(TauriVideoModel::Veo3p1) => handle_artcraft_veo3p1(request, app_env_configs, &creds).await,
Some(TauriVideoModel::Veo3p1Fast) => handle_artcraft_veo3p1_fast(request, app_env_configs, &creds).await,
Some(_) => {
Err(GenerateError::AnyhowError(
anyhow!("wrong logic: another branch should handle this: {:?}", request.model)))
},
}
}
@@ -1,5 +1,5 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::EnqueueImageToVideoRequest;
use crate::core::commands::generate::generate_video::request::TauriGenerateVideoRequest;
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::generation_events::common::GenerationModel;
use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs;
@@ -22,7 +22,7 @@ use enums::tauri::tasks::task_type::TaskType;
use log::{error, info};
pub(super) async fn handle_artcraft_video_via_router(
request: &EnqueueImageToVideoRequest,
request: &TauriGenerateVideoRequest,
app_env_configs: &AppEnvConfigs,
creds: &StorytellerCredentialSet,
model: CommonVideoModel,
@@ -0,0 +1,198 @@
use crate::core::commands::enqueue::common::notify_frontend_of_errors::notify_frontend_of_errors;
use crate::core::commands::enqueue::generate_error::{BadInputReason, GenerateError, MissingCredentialsReason};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::commands::generate::generate_video::artcraft::handle_artcraft_video::handle_video_artcraft;
use crate::core::commands::generate::generate_video::grok::handle_grok_video::handle_grok_video;
use crate::core::commands::generate::generate_video::request::{
TauriGenerateVideoErrorType, TauriGenerateVideoRequest, TauriGenerateVideoResponse,
TauriVideoModel,
};
use crate::core::commands::generate::generate_video::sora2::handle_sora_sora2::handle_sora_sora2;
use crate::core::commands::response::failure_response_wrapper::{CommandErrorResponseWrapper, CommandErrorStatus};
use crate::core::commands::response::shorthand::Response;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::functional_events::credits_balance_changed_event::CreditsBalanceChangedEvent;
use crate::core::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent;
use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs;
use crate::core::state::artcraft_usage_tracker::artcraft_usage_tracker::ArtcraftUsageTracker;
use crate::core::state::artcraft_usage_tracker::artcraft_usage_type::{ArtcraftUsagePage, ArtcraftUsageType};
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::core::state::provider_priority::{Provider, ProviderPriorityStore};
use crate::core::state::task_database::TaskDatabase;
use crate::services::grok::state::grok_credential_manager::GrokCredentialManager;
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
use crate::services::sora::state::sora_task_queue::SoraTaskQueue;
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
use enums::common::generation_provider::GenerationProvider;
use log::{error, info, warn};
use tauri::{AppHandle, State};
#[tauri::command]
pub async fn generate_video_command(
request: TauriGenerateVideoRequest,
app: AppHandle,
app_env_configs: State<'_, AppEnvConfigs>,
app_data_root: State<'_, AppDataRoot>,
artcraft_usage_tracker: State<'_, ArtcraftUsageTracker>,
provider_priority_store: State<'_, ProviderPriorityStore>,
task_database: State<'_, TaskDatabase>,
grok_creds_manager: State<'_, GrokCredentialManager>,
storyteller_creds_manager: State<'_, StorytellerCredentialManager>,
sora_task_queue: State<'_, SoraTaskQueue>,
sora_creds_manager: State<'_, SoraCredentialManager>,
) -> Response<TauriGenerateVideoResponse, TauriGenerateVideoErrorType, ()> {
info!("generate_video_command called, request: {:?}", request);
let result = handle_request(
request,
&app,
&app_env_configs,
&app_data_root,
&artcraft_usage_tracker,
&provider_priority_store,
&task_database,
&grok_creds_manager,
&sora_creds_manager,
&storyteller_creds_manager,
).await;
match result {
Err(err) => {
error!("error: {:?}", err);
notify_frontend_of_errors(&app, &err).await;
let mut status = CommandErrorStatus::ServerError;
let mut error_type = TauriGenerateVideoErrorType::ServerError;
let mut error_message = "A server error occurred. Please try again. If it continues, please tell our staff about the problem.";
match err {
GenerateError::BadInput(BadInputReason::NoModelSpecified) => {
status = CommandErrorStatus::BadRequest;
error_type = TauriGenerateVideoErrorType::ModelNotSpecified;
error_message = "No model specified for video generation";
}
GenerateError::NoProviderAvailable => {
status = CommandErrorStatus::ServerError;
error_type = TauriGenerateVideoErrorType::NoProviderAvailable;
error_message = "No configured provider available for video generation";
}
GenerateError::MissingCredentials(MissingCredentialsReason::NeedsFalApiKey) => {
status = CommandErrorStatus::Unauthorized;
error_type = TauriGenerateVideoErrorType::NeedsFalApiKey;
error_message = "You need to set a FAL api key";
},
GenerateError::MissingCredentials(MissingCredentialsReason::NeedsStorytellerCredentials) => {
status = CommandErrorStatus::Unauthorized;
error_type = TauriGenerateVideoErrorType::NeedsStorytellerCredentials;
error_message = "You need to be logged into Artcraft.";
}
_ => {}, // Fall-through
}
Err(CommandErrorResponseWrapper {
status,
error_message: Some(error_message.to_string()),
error_type: Some(error_type),
error_details: None,
})
}
Ok(event) => {
let event = GenerationEnqueueSuccessEvent {
action: event.to_frontend_event_action(),
service: event.to_frontend_event_service(),
model: event.model,
};
if let Err(err) = event.send(&app) {
error!("Failed to emit event: {:?}", err);
}
CreditsBalanceChangedEvent{}.send_infallible(&app);
Ok(TauriGenerateVideoResponse {}.into())
}
}
}
async fn handle_request(
request: TauriGenerateVideoRequest,
app: &AppHandle,
app_env_configs: &AppEnvConfigs,
app_data_root: &AppDataRoot,
artcraft_usage_tracker: &ArtcraftUsageTracker,
provider_priority_store: &ProviderPriorityStore,
task_database: &TaskDatabase,
grok_creds_manager: &GrokCredentialManager,
sora_creds_manager: &SoraCredentialManager,
storyteller_creds_manager: &StorytellerCredentialManager,
) -> Result<TaskEnqueueSuccess, GenerateError> {
let model = match request.model {
Some(model) => model,
None => {
return Err(GenerateError::no_model_specified())
}
};
let provider = match (model, request.provider) {
(TauriVideoModel::GrokVideo, _) => GenerationProvider::Grok,
_ => request.provider.unwrap_or(GenerationProvider::Artcraft),
};
info!("generate video with {:?} via provider {:?}", &model, &provider);
let result = match provider {
GenerationProvider::Grok => {
handle_grok_video(
&request,
app,
app_data_root,
app_env_configs,
grok_creds_manager,
).await
}
GenerationProvider::Sora => {
handle_sora_sora2(
&request,
app,
app_data_root,
app_env_configs,
sora_creds_manager,
).await
}
_ => {
handle_video_artcraft(
&request,
app,
app_env_configs,
storyteller_creds_manager,
).await
}
};
let success_event = match result {
Err(err) => return Err(err),
Ok(event) => event,
};
let result = success_event
.insert_into_task_database_with_frontend_payload(
task_database,
request.frontend_caller,
request.frontend_subscriber_id.as_deref(),
request.frontend_subscriber_payload.as_deref()
)
.await;
if let Err(err) = result {
error!("Failed to create task in database: {:?}", err);
}
if let Err(err) = artcraft_usage_tracker.record_video_generation(1, ArtcraftUsageType::ImageToResult, ArtcraftUsagePage::VideoPage) {
warn!("Failed to report usage: {:?}", err);
}
Ok(success_event)
}
@@ -1,7 +1,7 @@
use crate::core::commands::enqueue::generate_error::{BadInputReason, GenerateError};
use crate::core::commands::enqueue::image_edit::enqueue_edit_image_command::EnqueueEditImageCommand;
use crate::core::commands::enqueue::image_inpaint::enqueue_image_inpaint_command::EnqueueInpaintImageCommand;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, GrokAspectRatio, SoraOrientation};
use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, GrokAspectRatio, SoraOrientation};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
use crate::core::events::generation_events::common::GenerationModel;
@@ -33,7 +33,7 @@ use tauri::AppHandle;
const GROK_IMAGE_UPLOAD_TIMEOUT: Duration = Duration::from_millis(1000 * 30); // 30 seconds
pub async fn handle_grok_video(
request: &EnqueueImageToVideoRequest,
request: &TauriGenerateVideoRequest,
app: &AppHandle,
app_data_root: &AppDataRoot,
app_env_configs: &AppEnvConfigs,
@@ -0,0 +1,5 @@
pub mod generate_video_command;
pub mod request;
mod artcraft;
mod grok;
pub mod sora2;
@@ -0,0 +1,130 @@
use artcraft_router::api::common_aspect_ratio::CommonAspectRatio;
use artcraft_router::api::common_resolution::CommonResolution;
use enums::common::generation_provider::GenerationProvider;
use enums::tauri::ux::tauri_command_caller::TauriCommandCaller;
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::characters::CharacterToken;
use tokens::tokens::media_files::MediaFileToken;
use crate::core::commands::response::success_response_wrapper::SerializeMarker;
/// This is used in the Tauri command bridge.
/// Don't change the serializations without coordinating with the frontend.
#[derive(Deserialize, Debug, Copy, Clone)]
#[serde(rename_all = "snake_case")]
pub enum TauriVideoModel {
#[serde(rename = "grok_video")]
GrokVideo,
#[serde(rename = "kling_1.6_pro")]
Kling16Pro,
#[serde(rename = "kling_2.1_pro")]
Kling21Pro,
#[serde(rename = "kling_2.1_master")]
Kling21Master,
#[serde(rename = "kling_2p5_turbo_pro")]
Kling2p5TurboPro,
#[serde(rename = "kling_2p6_pro")]
Kling2p6Pro,
#[serde(rename = "kling_3p0_standard")]
Kling3p0Standard,
#[serde(rename = "kling_3p0_pro")]
Kling3p0Pro,
#[serde(rename = "happy_horse_1p0")]
HappyHorse1p0,
#[serde(rename = "seedance_1.0_lite")]
Seedance10Lite,
#[serde(rename = "seedance_1p5_pro")]
Seedance1p5Pro,
#[serde(rename = "seedance_2p0")]
Seedance2p0,
#[serde(rename = "seedance_2p0_fast")]
Seedance2p0Fast,
#[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,
}
#[derive(Deserialize, Debug)]
pub struct TauriGenerateVideoRequest {
pub provider: Option<GenerationProvider>,
pub model: Option<TauriVideoModel>,
pub image_media_token: Option<MediaFileToken>,
pub end_frame_image_media_token: Option<MediaFileToken>,
pub reference_image_media_tokens: Option<Vec<MediaFileToken>>,
pub reference_video_media_tokens: Option<Vec<MediaFileToken>>,
pub reference_audio_media_tokens: Option<Vec<MediaFileToken>>,
pub reference_character_tokens: Option<Vec<CharacterToken>>,
pub prompt: Option<String>,
pub generate_audio: Option<bool>,
pub aspect_ratio: Option<CommonAspectRatio>,
pub resolution: Option<CommonResolution>,
pub duration_seconds: Option<u16>,
pub video_batch_count: Option<u16>,
pub sora_orientation: Option<SoraOrientation>,
pub grok_aspect_ratio: Option<GrokAspectRatio>,
pub frontend_caller: Option<TauriCommandCaller>,
pub frontend_subscriber_id: Option<String>,
pub frontend_subscriber_payload: Option<String>,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum SoraOrientation {
Portrait,
Landscape,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum GrokAspectRatio {
Portrait,
Landscape,
Square,
}
#[derive(Serialize)]
pub struct TauriGenerateVideoResponse {
}
impl SerializeMarker for TauriGenerateVideoResponse {}
#[derive(Serialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum TauriGenerateVideoErrorType {
ModelNotSpecified,
NoProviderAvailable,
ServerError,
NeedsFalApiKey,
FalError,
NeedsStorytellerCredentials,
}
@@ -1,5 +1,5 @@
use crate::core::commands::enqueue::generate_error::GenerateError;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::{EnqueueImageToVideoRequest, SoraOrientation};
use crate::core::commands::generate::generate_video::request::{TauriGenerateVideoRequest, SoraOrientation};
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
use crate::core::events::generation_events::common::GenerationModel;
@@ -19,7 +19,7 @@ use tauri::AppHandle;
use tokens::tokens::media_files::MediaFileToken;
pub async fn handle_sora_sora2(
request: &EnqueueImageToVideoRequest,
request: &TauriGenerateVideoRequest,
app: &AppHandle,
app_data_root: &AppDataRoot,
app_env_configs: &AppEnvConfigs,
@@ -0,0 +1 @@
pub mod generate_video;
@@ -4,6 +4,7 @@ pub mod cost_estimate;
pub mod download;
pub mod enqueue;
pub mod flip_image;
pub mod generate;
pub mod get_app_info_command;
pub mod load_without_cors_command;
pub mod media_files;
+2 -2
View File
@@ -17,8 +17,8 @@ use crate::core::commands::enqueue::image_edit::enqueue_edit_image_command::enqu
use crate::core::commands::enqueue::image_inpaint::enqueue_image_inpaint_command::enqueue_image_inpaint_command;
use crate::core::commands::enqueue::image_to_gaussian::enqueue_image_to_gaussian_command::enqueue_image_to_gaussian_command;
use crate::core::commands::enqueue::image_to_object::enqueue_image_to_3d_object_command::enqueue_image_to_3d_object_command;
use crate::core::commands::enqueue::image_to_video::enqueue_image_to_video_command::enqueue_image_to_video_command;
use crate::core::commands::enqueue::text_to_image::enqueue_text_to_image_command::enqueue_text_to_image_command;
use crate::core::commands::generate::generate_video::generate_video_command::generate_video_command;
use crate::core::commands::flip_image::flip_image;
use crate::core::commands::get_app_info_command::get_app_info_command;
use crate::core::commands::load_without_cors_command::load_without_cors_command;
@@ -212,12 +212,12 @@ pub fn run() {
enqueue_image_inpaint_command,
enqueue_image_to_3d_object_command,
enqueue_image_to_gaussian_command,
enqueue_image_to_video_command,
enqueue_text_to_image_command,
estimate_image_cost_command,
estimate_splat_cost_command,
estimate_video_cost_command,
flip_image,
generate_video_command,
get_app_info_command,
get_app_preferences_command,
get_provider_order_command,