diff --git a/crates/api_clients/storyteller_client/src/endpoints/generate/video/generate_veo_3_fast_image_to_video.rs b/crates/api_clients/storyteller_client/src/endpoints/generate/video/generate_veo_3_fast_image_to_video.rs new file mode 100644 index 0000000000..1f5b29dbef --- /dev/null +++ b/crates/api_clients/storyteller_client/src/endpoints/generate/video/generate_veo_3_fast_image_to_video.rs @@ -0,0 +1,18 @@ +use crate::credentials::storyteller_credential_set::StorytellerCredentialSet; +use crate::error::storyteller_error::StorytellerError; +use crate::utils::api_host::ApiHost; +use crate::utils::basic_json_post_request::basic_json_post_request; +use artcraft_api_defs::generate::video::generate_veo_3_fast_image_to_video::{GenerateVeo3FastImageToVideoRequest, GenerateVeo3FastImageToVideoResponse, GENERATE_VEO_3_FAST_IMAGE_TO_VIDEO_URL_PATH}; + +pub async fn generate_veo_3_fast_image_to_video( + api_host: &ApiHost, + maybe_creds: Option<&StorytellerCredentialSet>, + request: GenerateVeo3FastImageToVideoRequest, +) -> Result { + Ok(basic_json_post_request( + api_host, + GENERATE_VEO_3_FAST_IMAGE_TO_VIDEO_URL_PATH, + maybe_creds, + request, + ).await?) +} diff --git a/crates/api_clients/storyteller_client/src/endpoints/generate/video/generate_veo_3_image_to_video.rs b/crates/api_clients/storyteller_client/src/endpoints/generate/video/generate_veo_3_image_to_video.rs new file mode 100644 index 0000000000..acb5bf073d --- /dev/null +++ b/crates/api_clients/storyteller_client/src/endpoints/generate/video/generate_veo_3_image_to_video.rs @@ -0,0 +1,18 @@ +use crate::credentials::storyteller_credential_set::StorytellerCredentialSet; +use crate::error::storyteller_error::StorytellerError; +use crate::utils::api_host::ApiHost; +use crate::utils::basic_json_post_request::basic_json_post_request; +use artcraft_api_defs::generate::video::generate_veo_3_image_to_video::{GenerateVeo3ImageToVideoRequest, GenerateVeo3ImageToVideoResponse, GENERATE_VEO_3_IMAGE_TO_VIDEO_URL_PATH}; + +pub async fn generate_veo_3_image_to_video( + api_host: &ApiHost, + maybe_creds: Option<&StorytellerCredentialSet>, + request: GenerateVeo3ImageToVideoRequest, +) -> Result { + Ok(basic_json_post_request( + api_host, + GENERATE_VEO_3_IMAGE_TO_VIDEO_URL_PATH, + maybe_creds, + request, + ).await?) +} diff --git a/crates/api_clients/storyteller_client/src/endpoints/generate/video/mod.rs b/crates/api_clients/storyteller_client/src/endpoints/generate/video/mod.rs index 6feaa265f0..ab29e4f1ee 100644 --- a/crates/api_clients/storyteller_client/src/endpoints/generate/video/mod.rs +++ b/crates/api_clients/storyteller_client/src/endpoints/generate/video/mod.rs @@ -2,4 +2,6 @@ pub mod generate_kling_16_pro_image_to_video; pub mod generate_kling_21_master_image_to_video; pub mod generate_kling_21_pro_image_to_video; pub mod generate_seedance_1_0_lite_image_to_video; -pub mod generate_veo_2_image_to_video; \ No newline at end of file +pub mod generate_veo_2_image_to_video; +pub mod generate_veo_3_fast_image_to_video; +pub mod generate_veo_3_image_to_video; diff --git a/crates/api_clients/storyteller_client/src/utils/basic_query_string_post_request.rs b/crates/api_clients/storyteller_client/src/utils/basic_query_string_post_request.rs index 1c99351ff3..3567d67d10 100644 --- a/crates/api_clients/storyteller_client/src/utils/basic_query_string_post_request.rs +++ b/crates/api_clients/storyteller_client/src/utils/basic_query_string_post_request.rs @@ -25,7 +25,7 @@ pub async fn basic_query_string_post_request( // TODO: Please stop using this URL Builder library. It's not very safe or intuitive. let url = get_route(api_host, route_path, query_params); - info!("Requesting {:?}", &url); + debug!("Requesting {:?}", &url); let client = Client::builder() .gzip(true) diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/image_to_video/enqueue_image_to_video_command.rs b/crates/desktop/artcraft/src/core/commands/enqueue/image_to_video/enqueue_image_to_video_command.rs index 65f18a210d..f747dfdc71 100644 --- a/crates/desktop/artcraft/src/core/commands/enqueue/image_to_video/enqueue_image_to_video_command.rs +++ b/crates/desktop/artcraft/src/core/commands/enqueue/image_to_video/enqueue_image_to_video_command.rs @@ -41,6 +41,12 @@ pub enum VideoModel { #[serde(rename = "veo_2")] Veo2, + + #[serde(rename = "veo_3")] + Veo3, + + #[serde(rename = "veo_3_fast")] + Veo3Fast, } #[derive(Deserialize)] diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/image_to_video/generic/handle_video_artcraft.rs b/crates/desktop/artcraft/src/core/commands/enqueue/image_to_video/generic/handle_video_artcraft.rs index 4cca5891c5..4664bcdb98 100644 --- a/crates/desktop/artcraft/src/core/commands/enqueue/image_to_video/generic/handle_video_artcraft.rs +++ b/crates/desktop/artcraft/src/core/commands/enqueue/image_to_video/generic/handle_video_artcraft.rs @@ -13,6 +13,8 @@ use artcraft_api_defs::generate::video::generate_kling_2_1_master_image_to_video use artcraft_api_defs::generate::video::generate_kling_2_1_pro_image_to_video::{GenerateKling21ProAspectRatio, GenerateKling21ProImageToVideoRequest}; use artcraft_api_defs::generate::video::generate_seedance_1_0_lite_image_to_video::GenerateSeedance10LiteImageToVideoRequest; use artcraft_api_defs::generate::video::generate_veo_2_image_to_video::{GenerateVeo2AspectRatio, GenerateVeo2ImageToVideoRequest}; +use artcraft_api_defs::generate::video::generate_veo_3_fast_image_to_video::GenerateVeo3FastImageToVideoRequest; +use artcraft_api_defs::generate::video::generate_veo_3_image_to_video::{GenerateVeo3AspectRatio, GenerateVeo3ImageToVideoRequest}; use enums::common::generation_provider::GenerationProvider; use enums::tauri::tasks::task_type::TaskType; use fal_client::requests::queue::image_gen::enqueue_flux_pro_11_ultra_text_to_image::{enqueue_flux_pro_11_ultra_text_to_image, FluxPro11UltraTextToImageArgs}; @@ -25,6 +27,8 @@ use storyteller_client::endpoints::generate::video::generate_kling_21_master_ima use storyteller_client::endpoints::generate::video::generate_kling_21_pro_image_to_video::generate_kling_21_pro_image_to_video; use storyteller_client::endpoints::generate::video::generate_seedance_1_0_lite_image_to_video::generate_seedance_1_0_lite_image_to_video; use storyteller_client::endpoints::generate::video::generate_veo_2_image_to_video::generate_veo_2_image_to_video; +use storyteller_client::endpoints::generate::video::generate_veo_3_fast_image_to_video::generate_veo_3_fast_image_to_video; +use storyteller_client::endpoints::generate::video::generate_veo_3_image_to_video::generate_veo_3_image_to_video; use storyteller_client::utils::api_host::ApiHost; use tauri::AppHandle; @@ -202,6 +206,61 @@ pub async fn handle_video_artcraft( } } } + Some(VideoModel::Veo3) => { + info!("enqueue Veo 3 with Artcraft API"); + selected_model = Some(GenerationModel::Veo3); + let request = GenerateVeo3ImageToVideoRequest { + uuid_idempotency_token, + media_file_token: request.image_media_token, + aspect_ratio: Some(GenerateVeo3AspectRatio::WideSixteenNine), + prompt: request.prompt, + duration: None, + resolution: None, + generate_audio: None, + }; + let result = generate_veo_3_image_to_video( + &app_env_configs.storyteller_host, + Some(&creds), + request, + ).await; + match result { + Ok(enqueued) => { + info!("Successfully enqueued Artcraft Veo 3 video generation"); + enqueued.inference_job_token + } + Err(err) => { + error!("Failed to use Artcraft Veo 3 video generation: {:?}", err); + return Err(GenerateError::from(err)); + } + } + } + Some(VideoModel::Veo3Fast) => { + info!("enqueue Veo 3 Fast with Artcraft API"); + selected_model = Some(GenerationModel::Veo3Fast); + let request = GenerateVeo3FastImageToVideoRequest { + uuid_idempotency_token, + media_file_token: request.image_media_token, + prompt: request.prompt, + duration: None, + resolution: None, + generate_audio: None, + }; + let result = generate_veo_3_fast_image_to_video( + &app_env_configs.storyteller_host, + Some(&creds), + request, + ).await; + match result { + Ok(enqueued) => { + info!("Successfully enqueued Artcraft Veo 3 video generation"); + enqueued.inference_job_token + } + Err(err) => { + error!("Failed to use Artcraft Veo 3 video generation: {:?}", err); + return Err(GenerateError::from(err)); + } + } + } }; info!("Successfully enqueued video generation"); diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/task_enqueue_success.rs b/crates/desktop/artcraft/src/core/commands/enqueue/task_enqueue_success.rs index b6a6435cd1..efc126f7fd 100644 --- a/crates/desktop/artcraft/src/core/commands/enqueue/task_enqueue_success.rs +++ b/crates/desktop/artcraft/src/core/commands/enqueue/task_enqueue_success.rs @@ -71,6 +71,8 @@ impl TaskEnqueueSuccess{ Some(GenerationModel::Kling21Master) => Some(TaskModelType::Kling21Master), Some(GenerationModel::Seedance10Lite) => Some(TaskModelType::Seedance10Lite), Some(GenerationModel::Veo2) => Some(TaskModelType::Veo2), + Some(GenerationModel::Veo3) => Some(TaskModelType::Veo3), + Some(GenerationModel::Veo3Fast) => Some(TaskModelType::Veo3Fast), Some(GenerationModel::Hunyuan3d2_0) => Some(TaskModelType::Hunyuan3d2_0), Some(GenerationModel::Hunyuan3d2_1) => Some(TaskModelType::Hunyuan3d2_1), Some(GenerationModel::Midjourney) => Some(TaskModelType::Midjourney), // NB: This is a generic Midjourney model, version unknown. diff --git a/crates/desktop/artcraft/src/core/events/generation_events/common.rs b/crates/desktop/artcraft/src/core/events/generation_events/common.rs index 9afa70d177..80f84c2e53 100644 --- a/crates/desktop/artcraft/src/core/events/generation_events/common.rs +++ b/crates/desktop/artcraft/src/core/events/generation_events/common.rs @@ -59,6 +59,10 @@ pub enum GenerationModel { Seedance10Lite, #[serde(rename = "veo_2")] Veo2, + #[serde(rename = "veo_3")] + Veo3, + #[serde(rename = "veo_3_fast")] + Veo3Fast, } #[derive(Debug, Copy, Clone, Serialize)] diff --git a/crates/schema/public/enums/src/tauri/tasks/task_model_type.rs b/crates/schema/public/enums/src/tauri/tasks/task_model_type.rs index 79ce2ce293..6e0f8abdcb 100644 --- a/crates/schema/public/enums/src/tauri/tasks/task_model_type.rs +++ b/crates/schema/public/enums/src/tauri/tasks/task_model_type.rs @@ -48,6 +48,10 @@ pub enum TaskModelType { Seedance10Lite, #[serde(rename = "veo_2")] Veo2, + #[serde(rename = "veo_3")] + Veo3, + #[serde(rename = "veo_3_fast")] + Veo3Fast, // 3D Object generation models #[serde(rename = "hunyuan_3d_2.0")] @@ -83,6 +87,8 @@ impl TaskModelType { Self::Kling21Master => "kling_2.1_master", Self::Seedance10Lite => "seedance_1.0_lite", Self::Veo2 => "veo_2", + Self::Veo3 => "veo_3", + Self::Veo3Fast => "veo_3_fast", // 3D Object generation models Self::Hunyuan3d2_0 => "hunyuan_3d_2.0", Self::Hunyuan3d2_1 => "hunyuan_3d_2.1", @@ -109,6 +115,8 @@ impl TaskModelType { "kling_2.1_master" => Ok(Self::Kling21Master), "seedance_1.0_lite" => Ok(Self::Seedance10Lite), "veo_2" => Ok(Self::Veo2), + "veo_3" => Ok(Self::Veo3), + "veo_3_fast" => Ok(Self::Veo3Fast), // 3D Object generation models "hunyuan_3d_2.0" => Ok(Self::Hunyuan3d2_0), "hunyuan_3d_2.1" => Ok(Self::Hunyuan3d2_1), @@ -138,6 +146,8 @@ impl TaskModelType { Self::Kling21Master, Self::Seedance10Lite, Self::Veo2, + Self::Veo3, + Self::Veo3Fast, // 3D Object generation models Self::Hunyuan3d2_0, Self::Hunyuan3d2_1, @@ -173,6 +183,8 @@ mod tests { assert_serialization(TaskModelType::Kling21Master, "kling_2.1_master"); assert_serialization(TaskModelType::Seedance10Lite, "seedance_1.0_lite"); assert_serialization(TaskModelType::Veo2, "veo_2"); + assert_serialization(TaskModelType::Veo3, "veo_3"); + assert_serialization(TaskModelType::Veo3Fast, "veo_3_fast"); // 3D Object generation models assert_serialization(TaskModelType::Hunyuan3d2_0, "hunyuan_3d_2.0"); assert_serialization(TaskModelType::Hunyuan3d2_1, "hunyuan_3d_2.1"); @@ -198,6 +210,8 @@ mod tests { assert_eq!(TaskModelType::Kling21Master.to_str(), "kling_2.1_master"); assert_eq!(TaskModelType::Seedance10Lite.to_str(), "seedance_1.0_lite"); assert_eq!(TaskModelType::Veo2.to_str(), "veo_2"); + assert_eq!(TaskModelType::Veo3.to_str(), "veo_3"); + assert_eq!(TaskModelType::Veo3Fast.to_str(), "veo_3_fast"); // 3D Object generation models assert_eq!(TaskModelType::Hunyuan3d2_0.to_str(), "hunyuan_3d_2.0"); assert_eq!(TaskModelType::Hunyuan3d2_1.to_str(), "hunyuan_3d_2.1"); @@ -223,6 +237,8 @@ mod tests { assert_eq!(TaskModelType::from_str("kling_2.1_master").unwrap(), TaskModelType::Kling21Master); assert_eq!(TaskModelType::from_str("seedance_1.0_lite").unwrap(), TaskModelType::Seedance10Lite); assert_eq!(TaskModelType::from_str("veo_2").unwrap(), TaskModelType::Veo2); + assert_eq!(TaskModelType::from_str("veo_3").unwrap(), TaskModelType::Veo3); + assert_eq!(TaskModelType::from_str("veo_3_fast").unwrap(), TaskModelType::Veo3Fast); // 3D Object generation models assert_eq!(TaskModelType::from_str("hunyuan_3d_2.0").unwrap(), TaskModelType::Hunyuan3d2_0); assert_eq!(TaskModelType::from_str("hunyuan_3d_2.1").unwrap(), TaskModelType::Hunyuan3d2_1); @@ -231,7 +247,7 @@ mod tests { #[test] fn all_variants() { let mut variants = TaskModelType::all_variants(); - assert_eq!(variants.len(), 18); + assert_eq!(variants.len(), 20); // Image models assert_eq!(variants.pop_first(), Some(TaskModelType::Flux1Dev)); assert_eq!(variants.pop_first(), Some(TaskModelType::Flux1Schnell)); @@ -250,6 +266,8 @@ mod tests { assert_eq!(variants.pop_first(), Some(TaskModelType::Kling21Master)); assert_eq!(variants.pop_first(), Some(TaskModelType::Seedance10Lite)); assert_eq!(variants.pop_first(), Some(TaskModelType::Veo2)); + assert_eq!(variants.pop_first(), Some(TaskModelType::Veo3)); + assert_eq!(variants.pop_first(), Some(TaskModelType::Veo3Fast)); // 3D Object generation models assert_eq!(variants.pop_first(), Some(TaskModelType::Hunyuan3d2_0)); assert_eq!(variants.pop_first(), Some(TaskModelType::Hunyuan3d2_1)); diff --git a/frontend/libs/model-list/src/lib/lists/VideoModels.ts b/frontend/libs/model-list/src/lib/lists/VideoModels.ts index 28636b2c71..f1c47e6e51 100644 --- a/frontend/libs/model-list/src/lib/lists/VideoModels.ts +++ b/frontend/libs/model-list/src/lib/lists/VideoModels.ts @@ -62,4 +62,28 @@ export const VIDEO_MODELS: VideoModel[] = [ startFrame: true, endFrame: false, }), + new VideoModel({ + id: "veo_3", + tauriId: "veo_3", + fullName: "Google Veo 3", + category: "video", + creator: ModelCreator.Google, + selectorName: "Google Veo 3", + selectorDescription: "Slow, high-quality model", + selectorBadges: ["2 min."], + startFrame: true, + endFrame: false, + }), + new VideoModel({ + id: "veo_3_fast", + tauriId: "veo_3_fast", + fullName: "Google Veo 3 Fast", + category: "video", + creator: ModelCreator.Google, + selectorName: "Google Veo 3 Fast", + selectorDescription: "High-quality model (faster)", + selectorBadges: ["2 min."], + startFrame: true, + endFrame: false, + }), ];