diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/image/enqueue_text_to_image_command.rs b/crates/desktop/artcraft/src/core/commands/enqueue/image/enqueue_text_to_image_command.rs index f028dc7de4..3e3b038dcb 100644 --- a/crates/desktop/artcraft/src/core/commands/enqueue/image/enqueue_text_to_image_command.rs +++ b/crates/desktop/artcraft/src/core/commands/enqueue/image/enqueue_text_to_image_command.rs @@ -1,5 +1,5 @@ -use crate::core::commands::enqueue::image::handle_fal::handle_fal; -use crate::core::commands::enqueue::image::handle_sora::handle_sora; +use crate::core::commands::enqueue::image::handle_image_fal::handle_image_fal; +use crate::core::commands::enqueue::image::handle_image_sora::handle_image_sora; use crate::core::commands::enqueue::image::internal_image_error::InternalImageError; use crate::core::commands::response::failure_response_wrapper::{CommandErrorResponseWrapper, CommandErrorStatus}; use crate::core::commands::response::shorthand::Response; @@ -55,6 +55,8 @@ use storyteller_client::media_files::upload_image_media_file_from_file::upload_i use storyteller_client::utils::api_host::ApiHost; use tauri::{AppHandle, Emitter, Manager, State}; use tempfile::NamedTempFile; +use crate::core::commands::enqueue::image::handle_image_artcraft::handle_image_artcraft; +use crate::core::commands::enqueue::object::handle_object_artcraft::handle_object_artcraft; #[derive(Deserialize)] pub struct EnqueueTextToImageRequest { @@ -93,6 +95,8 @@ pub enum EnqueueTextToImageErrorType { NeedsFalApiKey, /// Fal had an API error FalError, + /// Needs to be logged into Artcraft + NeedsStorytellerCredentials, } @@ -172,13 +176,20 @@ pub async fn handle_request( None => { return Err(InternalImageError::NoModelSpecified); } - Some(EnqueueTextToImageModel::FluxProUltra) | Some(EnqueueTextToImageModel::Recraft3) => { - handle_fal(&app, request, fal_creds_manager, fal_task_queue).await?; - }, Some(EnqueueTextToImageModel::GptImage1) => { - handle_sora(&app, request, sora_creds_manager, sora_task_queue).await?; + handle_image_sora(&app, request, sora_creds_manager, sora_task_queue).await?; + return Ok(()); + } + _ => { + // Fall-through } }; + if fal_creds_manager.has_apparent_api_token()? { + handle_image_fal(&app, request, fal_creds_manager, fal_task_queue).await?; + } else { + handle_image_artcraft(request, &app, app_data_root, storyteller_creds_manager).await?; + } + Ok(()) } diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/image/handle_image_artcraft.rs b/crates/desktop/artcraft/src/core/commands/enqueue/image/handle_image_artcraft.rs new file mode 100644 index 0000000000..2cd41a4145 --- /dev/null +++ b/crates/desktop/artcraft/src/core/commands/enqueue/image/handle_image_artcraft.rs @@ -0,0 +1,109 @@ +use crate::core::commands::enqueue::image::enqueue_text_to_image_command::{EnqueueTextToImageModel, EnqueueTextToImageRequest}; +use crate::core::commands::enqueue::image::internal_image_error::InternalImageError; +use crate::core::events::basic_sendable_event_trait::BasicSendableEvent; +use crate::core::events::generation_events::common::{GenerationAction, GenerationModel, GenerationServiceProvider}; +use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent; +use crate::core::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent; +use crate::core::state::data_dir::app_data_root::AppDataRoot; +use crate::core::utils::download_media_file_to_temp_dir::download_media_file_to_temp_dir; +use crate::core::utils::save_base64_image_to_temp_dir::save_base64_image_to_temp_dir; +use crate::services::fal::state::fal_credential_manager::FalCredentialManager; +use crate::services::fal::state::fal_task_queue::FalTaskQueue; +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 anyhow::anyhow; +use artcraft_api_defs::generate::object::generate_hunyuan_2_image_to_3d::GenerateHunyuan2ImageTo3dRequest; +use artcraft_api_defs::generate::video::generate_kling_1_6_image_to_video::GenerateKling16ImageToVideoRequest; +use fal_client::creds::fal_api_key::FalApiKey; +use fal_client::requests::queue::enqueue_hunyuan2_image_to_3d::{enqueue_hunyuan2_image_to_3d, Hunyuan2Args}; +use fal_client::requests::queue::image_gen::enqueue_flux_pro_ultra_text_to_image::{enqueue_flux_pro_ultra_text_to_image, FluxProUltraTextToImageArgs}; +use fal_client::requests::queue::image_gen::enqueue_recraft3_text_to_image::{enqueue_recraft3_text_to_image, Recraft3TextToImageArgs}; +use idempotency::uuid::generate_random_uuid; +use log::{error, info, warn}; +use storyteller_client::generate::object::generate_hunyuan2_image_to_3d::generate_hunyuan2_image_to_3d; +use storyteller_client::generate::video::generate_kling16_image_to_video::generate_kling16_image_to_video; +use storyteller_client::utils::api_host::ApiHost; +use tauri::{AppHandle, State}; + +pub async fn handle_image_artcraft( + request: EnqueueTextToImageRequest, + app: &AppHandle, + app_data_root: &AppDataRoot, + storyteller_creds_manager: &StorytellerCredentialManager, +) -> Result<(), InternalImageError> { + + let creds = match storyteller_creds_manager.get_credentials()? { + Some(creds) => creds, + None => { + error!("No Artcraft credentials are set. Can't perform action."); + let event = + GenerationEnqueueFailureEvent::no_artcraft_credentials(GenerationAction::GenerateImage); + + if let Err(err) = event.send(&app) { + error!("Failed to emit event: {:?}", err); // Fail open. + } + + return Err(InternalImageError::NeedsStorytellerCredentials); + }, + }; + + info!("Calling Artcraft text to image..."); + + let uuid_idempotency_token = generate_random_uuid(); + + //let mut selected_model = None; + + let job_token = match request.model { + None => { + return Err(InternalImageError::NoModelSpecified); + } + _ => { + // TODO: This is not offered serverside yet. + return Err(InternalImageError::NoModelSpecified); + } + //Some(EnqueueImageToVideoModel::Kling16) => { + // //info!("enqueue Kling 1.6"); + // selected_model = Some(GenerationModel::Kling1_6); + // let request = GenerateKling16ImageToVideoRequest { + // uuid_idempotency_token, + // media_file_token: request.image_media_token, + // prompt: None, + // }; + // let result = generate_kling16_image_to_video( + // &ApiHost::Storyteller, + // Some(&creds), + // request, + // ).await; + // match result { + // Ok(enqueued) => { + // info!("Successfully enqueued Artcraft Kling 1.6 video generation"); + // enqueued.inference_job_token + // } + // Err(err) => { + // error!("Failed to use Artcraft Kling 1.6 video generation: {:?}", err); + // return Err(InternalImageError::StorytellerError(err)); + // } + // } + //} + }; + +// info!("Successfully enqueued video generation"); +// +// let event = GenerationEnqueueSuccessEvent { +// action: GenerationAction::GenerateVideo, +// service: GenerationServiceProvider::Artcraft, +// model: selected_model, +// }; +// +// if let Err(err) = event.send(app) { +// error!("Failed to emit event: {:?}", err); // Fail open. +// } +// +// //if let Err(err) = fal_task_queue.insert(&enqueued) { +// // error!("Failed to enqueue task: {:?}", err); +// // return Err(InternalImageError::AnyhowError(anyhow!("Failed to enqueue task: {:?}", err))); +// //} + + Ok(()) +} diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/image/handle_fal.rs b/crates/desktop/artcraft/src/core/commands/enqueue/image/handle_image_fal.rs similarity index 99% rename from crates/desktop/artcraft/src/core/commands/enqueue/image/handle_fal.rs rename to crates/desktop/artcraft/src/core/commands/enqueue/image/handle_image_fal.rs index 1bf21d74f8..94241eb017 100644 --- a/crates/desktop/artcraft/src/core/commands/enqueue/image/handle_fal.rs +++ b/crates/desktop/artcraft/src/core/commands/enqueue/image/handle_image_fal.rs @@ -17,7 +17,7 @@ use fal_client::requests::queue::image_gen::enqueue_recraft3_text_to_image::{enq use log::{error, info, warn}; use tauri::AppHandle; -pub async fn handle_fal( +pub async fn handle_image_fal( app: &AppHandle, request: EnqueueTextToImageRequest, fal_creds_manager: &FalCredentialManager, diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/image/handle_sora.rs b/crates/desktop/artcraft/src/core/commands/enqueue/image/handle_image_sora.rs similarity index 99% rename from crates/desktop/artcraft/src/core/commands/enqueue/image/handle_sora.rs rename to crates/desktop/artcraft/src/core/commands/enqueue/image/handle_image_sora.rs index b8c018beec..1b8e52a7de 100644 --- a/crates/desktop/artcraft/src/core/commands/enqueue/image/handle_sora.rs +++ b/crates/desktop/artcraft/src/core/commands/enqueue/image/handle_image_sora.rs @@ -25,7 +25,7 @@ use tauri::AppHandle; const SORA_SIMPLE_IMAGE_GEN_TIMEOUT : Duration = Duration::from_millis(1000 * 30); // 30 seconds -pub async fn handle_sora( +pub async fn handle_image_sora( app: &AppHandle, request: EnqueueTextToImageRequest, sora_creds_manager: &SoraCredentialManager, diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/image/internal_image_error.rs b/crates/desktop/artcraft/src/core/commands/enqueue/image/internal_image_error.rs index 5f9e69c16c..800a22cc25 100644 --- a/crates/desktop/artcraft/src/core/commands/enqueue/image/internal_image_error.rs +++ b/crates/desktop/artcraft/src/core/commands/enqueue/image/internal_image_error.rs @@ -10,6 +10,7 @@ pub enum InternalImageError { NoModelSpecified, NeedsFalApiKey, NeedsSoraCredentials, + NeedsStorytellerCredentials, FalError(FalErrorPlus), SoraError(SoraError), AnyhowError(AnyhowError), diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/image/mod.rs b/crates/desktop/artcraft/src/core/commands/enqueue/image/mod.rs index e1c54ebd9e..7e71b73802 100644 --- a/crates/desktop/artcraft/src/core/commands/enqueue/image/mod.rs +++ b/crates/desktop/artcraft/src/core/commands/enqueue/image/mod.rs @@ -1,4 +1,5 @@ pub mod enqueue_text_to_image_command; -pub mod handle_fal; -pub mod handle_sora; +pub mod handle_image_artcraft; +pub mod handle_image_fal; +pub mod handle_image_sora; pub mod internal_image_error; \ No newline at end of file