From 775841e6c7a2b6886d8cead59346edbf64161f01 Mon Sep 17 00:00:00 2001 From: Hanashi Date: Tue, 4 Aug 2026 02:05:25 -0400 Subject: [PATCH] cleanup --- .../handle_generic_bg_removal_artcraft.rs | 125 --- .../background_removal/artcraft/mod.rs | 1 - .../enqueue_image_bg_removal_command.rs | 230 ------ .../src/commands/background_removal/mod.rs | 2 - crates/artcraftx/src/commands/flip_image.rs | 36 - .../media_files/media_file_delete_command.rs | 80 -- .../artcraftx/src/commands/media_files/mod.rs | 1 - crates/artcraftx/src/commands/mod.rs | 10 +- .../deprecated/get_provider_order_command.rs | 30 - .../src/commands/providers/deprecated/mod.rs | 2 - .../deprecated/set_provider_order_command.rs | 34 - .../artcraftx/src/commands/providers/mod.rs | 4 - .../providers/provider_clear_command.rs | 33 - .../providers/provider_list_command.rs | 106 --- .../providers/provider_set_api_key_command.rs | 39 - .../get_app_preferences_command.rs | 0 .../{ => service}/app_preferences/mod.rs | 0 .../update_app_preference_command.rs | 0 .../commands/{ => service}/app_state/mod.rs | 0 .../app_state/reset_artcraft_command.rs | 0 .../{ => service}/get_app_info_command.rs | 0 .../load_without_cors_command.rs | 0 crates/artcraftx/src/commands/service/mod.rs | 5 + .../{ => service}/platform_info_command.rs | 0 crates/artcraftx/src/lib.rs | 26 +- .../src/Helpers/galleryModalTauriBindings.ts | 23 - .../apps/artcraft/app/src/config/appMenu.tsx | 2 - .../apps/artcraft/app/src/pages/MainApp.tsx | 7 - .../PageRemoveBackground/RemoveBackground.tsx | 769 ------------------ .../RemoveBackgroundStore.ts | 93 --- .../src/pages/PageRemoveBackground/index.ts | 3 - .../artcraft/app/src/pages/Stores/TabState.ts | 1 - .../lightbox-modal/src/lib/lightbox-modal.tsx | 45 - .../components/lightbox-modal/tsconfig.json | 9 +- .../lightbox-modal/tsconfig.lib.json | 9 +- .../panes/ProviderPrioritySettingsPane.tsx | 233 ------ .../settings-modal/src/lib/settings-modal.tsx | 4 - .../components/settings-modal/tsconfig.json | 3 - .../settings-modal/tsconfig.lib.json | 3 - frontend/libs/tauri-api/src/index.ts | 4 - .../enqueue/EnqueueImageBgRemovalCommand.ts | 71 -- .../lib/media_files/MediaFileDeleteCommand.ts | 26 - .../src/lib/providers/GetProviderOrder.ts | 22 - .../src/lib/providers/SetProviderOrder.ts | 17 - 44 files changed, 17 insertions(+), 2091 deletions(-) delete mode 100644 crates/artcraftx/src/commands/background_removal/artcraft/handle_generic_bg_removal_artcraft.rs delete mode 100644 crates/artcraftx/src/commands/background_removal/artcraft/mod.rs delete mode 100644 crates/artcraftx/src/commands/background_removal/enqueue_image_bg_removal_command.rs delete mode 100644 crates/artcraftx/src/commands/background_removal/mod.rs delete mode 100644 crates/artcraftx/src/commands/flip_image.rs delete mode 100644 crates/artcraftx/src/commands/media_files/media_file_delete_command.rs delete mode 100644 crates/artcraftx/src/commands/media_files/mod.rs delete mode 100644 crates/artcraftx/src/commands/providers/deprecated/get_provider_order_command.rs delete mode 100644 crates/artcraftx/src/commands/providers/deprecated/mod.rs delete mode 100644 crates/artcraftx/src/commands/providers/deprecated/set_provider_order_command.rs delete mode 100644 crates/artcraftx/src/commands/providers/mod.rs delete mode 100644 crates/artcraftx/src/commands/providers/provider_clear_command.rs delete mode 100644 crates/artcraftx/src/commands/providers/provider_list_command.rs delete mode 100644 crates/artcraftx/src/commands/providers/provider_set_api_key_command.rs rename crates/artcraftx/src/commands/{ => service}/app_preferences/get_app_preferences_command.rs (100%) rename crates/artcraftx/src/commands/{ => service}/app_preferences/mod.rs (100%) rename crates/artcraftx/src/commands/{ => service}/app_preferences/update_app_preference_command.rs (100%) rename crates/artcraftx/src/commands/{ => service}/app_state/mod.rs (100%) rename crates/artcraftx/src/commands/{ => service}/app_state/reset_artcraft_command.rs (100%) rename crates/artcraftx/src/commands/{ => service}/get_app_info_command.rs (100%) rename crates/artcraftx/src/commands/{ => service}/load_without_cors_command.rs (100%) create mode 100644 crates/artcraftx/src/commands/service/mod.rs rename crates/artcraftx/src/commands/{ => service}/platform_info_command.rs (100%) delete mode 100644 frontend/apps/artcraft/app/src/Helpers/galleryModalTauriBindings.ts delete mode 100644 frontend/apps/artcraft/app/src/pages/PageRemoveBackground/RemoveBackground.tsx delete mode 100644 frontend/apps/artcraft/app/src/pages/PageRemoveBackground/RemoveBackgroundStore.ts delete mode 100644 frontend/apps/artcraft/app/src/pages/PageRemoveBackground/index.ts delete mode 100644 frontend/libs/components/settings-modal/src/lib/panes/ProviderPrioritySettingsPane.tsx delete mode 100644 frontend/libs/tauri-api/src/lib/enqueue/EnqueueImageBgRemovalCommand.ts delete mode 100644 frontend/libs/tauri-api/src/lib/media_files/MediaFileDeleteCommand.ts delete mode 100644 frontend/libs/tauri-api/src/lib/providers/GetProviderOrder.ts delete mode 100644 frontend/libs/tauri-api/src/lib/providers/SetProviderOrder.ts diff --git a/crates/artcraftx/src/commands/background_removal/artcraft/handle_generic_bg_removal_artcraft.rs b/crates/artcraftx/src/commands/background_removal/artcraft/handle_generic_bg_removal_artcraft.rs deleted file mode 100644 index a9ab0c46..00000000 --- a/crates/artcraftx/src/commands/background_removal/artcraft/handle_generic_bg_removal_artcraft.rs +++ /dev/null @@ -1,125 +0,0 @@ -use crate::commands::generate::generate_error::{BadInputReason, GenerateError, MissingCredentialsReason, ProviderFailureReason}; -use crate::commands::background_removal::enqueue_image_bg_removal_command::EnqueueImageBgRemovalCommand; -use crate::commands::generate::task_enqueue_success::TaskEnqueueSuccess; -use crate::events::basic_sendable_event_trait::BasicSendableEvent; -use crate::events::generation_events::common::{GenerationAction, GenerationServiceProvider}; -use crate::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent; -use crate::state::app_env_configs::app_env_configs::AppEnvConfigs; -use crate::state::data_dir::app_data_root::AppDataRoot; -use crate::state::provider_priority::ProviderPriorityStore; -use crate::utils::save_base64_image_to_temp_dir::save_base64_image_to_temp_dir; -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_client::api_defs::generate::image::bg_removal::remove_image_background::RemoveImageBackgroundRequest; -use enums::common::generation_provider::GenerationProvider; -use enums::tauri::tasks::task_type::TaskType; -use uuid_utils::uuid::generate_random_uuid; -use log::{error, info}; -use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet; -use artcraft_client::endpoints::generate::image::bg_removal::remove_image_background::remove_image_background; -use artcraft_client::endpoints::media_files::upload_image_media_file_from_file::{upload_image_media_file_from_file, UploadImageFromFileArgs}; -use tauri::AppHandle; -use tokens::tokens::media_files::MediaFileToken; - -pub async fn handle_generic_bg_removal_artcraft( - request: &EnqueueImageBgRemovalCommand, - app: &AppHandle, - app_data_root: &AppDataRoot, - app_env_configs: &AppEnvConfigs, - storyteller_creds_manager: &StorytellerCredentialManager, -) -> Result { - - let creds = match storyteller_creds_manager.get_credentials()? { - Some(creds) => creds, - None => { - return Err(GenerateError::MissingCredentials(MissingCredentialsReason::NeedsStorytellerCredentials)); - }, - }; - - info!("Calling Artcraft bg removal ..."); - - let uuid_idempotency_token = generate_random_uuid(); - - let image_media_token = match &request.image_media_token { - Some(image_media_token) => image_media_token.clone(), - None => { - upload_image_from_base64_bytes(&request, &app_data_root, &app_env_configs, &creds).await? - } - }; - - let request = RemoveImageBackgroundRequest { - uuid_idempotency_token, - media_file_token: Some(image_media_token), - }; - - let result = remove_image_background( - &app_env_configs.storyteller_host, - Some(&creds), - request, - ).await; - - let success_result = match result { - Ok(enqueued) => { - // TODO(bt,2025-07-05): Enqueue job token? - info!("Successfully enqueued Artcraft background removal. Job token: {}", - enqueued.inference_job_token); - enqueued - } - Err(err) => { - error!("Failed to use Artcraft background removal: {:?}", err); - return Err(GenerateError::ProviderFailure(ProviderFailureReason::StorytellerError(err))); - } - }; - - Ok(TaskEnqueueSuccess { - provider: GenerationProvider::Artcraft, - task_type: TaskType::BackgroundRemoval, - provider_job_id: Some(success_result.inference_job_token.to_string()), - model: None, - maybe_queue_status_url: None, - maybe_prompt_token: None, - maybe_queue_response_url: None, - }) -} - -async fn upload_image_from_base64_bytes( - request: &EnqueueImageBgRemovalCommand, - app_data_root: &AppDataRoot, - app_env_configs: &AppEnvConfigs, - creds: &StorytellerCredentialSet -) -> Result { - let temp_file; - - if let Some(base64_bytes) = &request.base64_image { - info!("Saving base64 image to temp dir ..."); - temp_file = save_base64_image_to_temp_dir(&app_data_root, base64_bytes) - .await - .map_err(|err| { - error!("Failed to save base64 image to temp dir: {:?}", err); - GenerateError::BadInput(BadInputReason::Base64DecodeError) - })?; - } else { - return Err(GenerateError::BadInput(BadInputReason::RequiredSourceImageNotProvided)); - }; - - info!("Uploading image media file from temp file: {:?}", temp_file.path()); - - let result = - upload_image_media_file_from_file(UploadImageFromFileArgs { - api_host: &app_env_configs.storyteller_host, - maybe_creds: Some(&creds), - path: temp_file, - is_intermediate_system_file: true, // NB: Probably not essential to keep this. - maybe_prompt_token: None, // NB: Not used for bg removal. - maybe_batch_token: None, // NB: Not used for bg removal. - maybe_generation_provider: None, - }).await - .map_err(|err| { - error!("Failed to upload image media file: {:?}", err); - GenerateError::ProviderFailure(ProviderFailureReason::StorytellerError(err)) - })?; - - Ok(result.media_file_token) -} diff --git a/crates/artcraftx/src/commands/background_removal/artcraft/mod.rs b/crates/artcraftx/src/commands/background_removal/artcraft/mod.rs deleted file mode 100644 index a02c2e24..00000000 --- a/crates/artcraftx/src/commands/background_removal/artcraft/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod handle_generic_bg_removal_artcraft; \ No newline at end of file diff --git a/crates/artcraftx/src/commands/background_removal/enqueue_image_bg_removal_command.rs b/crates/artcraftx/src/commands/background_removal/enqueue_image_bg_removal_command.rs deleted file mode 100644 index f9c39775..00000000 --- a/crates/artcraftx/src/commands/background_removal/enqueue_image_bg_removal_command.rs +++ /dev/null @@ -1,230 +0,0 @@ -use crate::commands::generate::common::notify_frontend_of_errors::notify_frontend_of_errors; -use crate::commands::generate::generate_error::{BadInputReason, GenerateError}; -use crate::commands::background_removal::artcraft::handle_generic_bg_removal_artcraft::handle_generic_bg_removal_artcraft; -use crate::commands::generate::task_enqueue_success::TaskEnqueueSuccess; -use crate::commands::response::failure_response_wrapper::{CommandErrorResponseWrapper, CommandErrorStatus}; -use crate::commands::response::shorthand::{Response, ResponseOrErrorType}; -use crate::commands::response::success_response_wrapper::SerializeMarker; -use crate::events::basic_sendable_event_trait::BasicSendableEvent; -use crate::events::functional_events::credits_balance_changed_event::CreditsBalanceChangedEvent; -use crate::events::generation_events::common::{GenerationAction, GenerationServiceProvider}; -use crate::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent; -use crate::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent; -use crate::events::sendable_event_trait::SendableEvent; -use crate::state::app_env_configs::app_env_configs::AppEnvConfigs; -use crate::state::artcraft_usage_tracker::artcraft_usage_tracker::ArtcraftUsageTracker; -use crate::state::artcraft_usage_tracker::artcraft_usage_type::{ArtcraftUsagePage, ArtcraftUsageType}; -use crate::state::data_dir::app_data_root::AppDataRoot; -use crate::state::data_dir::subdirectory::trait_data_subdir::DataSubdir; -use crate::state::provider_priority::{Provider, ProviderPriorityStore}; -use crate::state::task_database::TaskDatabase; -use crate::utils::get_url_file_extension::get_url_file_extension; -use crate::utils::simple_http_download::simple_http_download; -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::tauri::ux::tauri_command_caller::TauriCommandCaller; -use errors::AnyhowError; -use log::{error, info, warn}; -use openai_sora_client::recipes::image_remix_with_session_auto_renew::{image_remix_with_session_auto_renew, ImageRemixAutoRenewRequest}; -use openai_sora_client::recipes::image_upload_from_file_with_session_auto_renew::{image_upload_from_file_with_session_auto_renew, ImageUploadFromFileAutoRenewRequest}; -use openai_sora_client::recipes::maybe_upgrade_or_renew_session::maybe_upgrade_or_renew_session; -use openai_sora_client::requests::image_gen::common::{ImageSize, NumImages}; -use serde_derive::{Deserialize, Serialize}; -use sqlite_database::queries::create_task::{create_task, CreateTaskArgs}; -use std::time::Duration; -use artcraft_client::endpoints::media_files::get_media_file::get_media_file; -use artcraft_client::error::storyteller_error::StorytellerError; -use artcraft_client::utils::api_host::ApiHost; -use tauri::{AppHandle, Manager, State}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Deserialize, Debug)] -pub struct EnqueueImageBgRemovalCommand { - // /// The bg removal model to use (optional). - // pub model: Option, - - /// Image media file; the image to remove the background from. - pub image_media_token: Option, - - /// Base64-encoded image - pub base64_image: Option, - - /// OPTIONAL. - /// Name of the frontend caller. - /// We'll use this to selectively trigger events. - pub frontend_caller: Option, - - /// 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, - - /// 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, -} - -#[derive(Serialize, Debug)] -#[serde(rename_all = "snake_case")] -pub enum EnqueueImageBgRemovalErrorType { - /// No model available for image generation - NoProviderAvailable, - - /// No image was provided for background removal - MissingImage, - - /// Bad base64 image data - Base64DecodeError, - - /// Generic bad request error - BadRequest, - - /// Generic server error - ServerError, -} - -#[derive(Serialize)] -pub struct EnqueueImageBgRemovalSuccessResponse { -} - -impl SerializeMarker for EnqueueImageBgRemovalSuccessResponse {} - -#[tauri::command] -pub async fn enqueue_image_bg_removal_command( - app: AppHandle, - request: EnqueueImageBgRemovalCommand, - app_data_root: State<'_, AppDataRoot>, - app_env_configs: State<'_, AppEnvConfigs>, - artcraft_usage_tracker: State<'_, ArtcraftUsageTracker>, - provider_priority_store: State<'_, ProviderPriorityStore>, - task_database: State<'_, TaskDatabase>, - storyteller_creds_manager: State<'_, StorytellerCredentialManager>, -) -> ResponseOrErrorType { - - info!("enqueue_image_bg_removal_command called"); - - let result = handle_request( - &request, - &app, - &app_data_root, - &app_env_configs, - &artcraft_usage_tracker, - &provider_priority_store, - &task_database, - &storyteller_creds_manager, - ).await; - - match result { - Err(err) => { - error!("Error removing background: {:?}", err); - - notify_frontend_of_errors(&app, &err).await; - - // TODO: Derive from err. Make service provider optional. - let event = GenerationEnqueueFailureEvent { - action: GenerationAction::RemoveBackground, - service: GenerationServiceProvider::Artcraft, // FIXME: This is wrong. - model: None, - reason: None, - }; - - if let Err(err) = event.send(&app) { - error!("Failed to emit event: {:?}", err); // Fail open. - } - - Err(error_to_tauri_response(err)) - } - Ok(event) => { - let event = GenerationEnqueueSuccessEvent { - action: event.to_frontend_event_action(), - service: event.to_frontend_event_service(), - model: None, // FIXME: This isn't right, though we probably don't care for simple bg removal. - }; - - if let Err(err) = event.send(&app) { - error!("Failed to emit event: {:?}", err); // Fail open. - } - - CreditsBalanceChangedEvent{}.send_infallible(&app); - - Ok(EnqueueImageBgRemovalSuccessResponse {}.into()) - } - } -} - -pub async fn handle_request( - request: &EnqueueImageBgRemovalCommand, - app: &AppHandle, - app_data_root: &AppDataRoot, - app_env_configs: &AppEnvConfigs, - artcraft_usage_tracker: &ArtcraftUsageTracker, - provider_priority_store: &ProviderPriorityStore, - task_database: &TaskDatabase, - storyteller_creds_manager: &StorytellerCredentialManager, -) -> Result { - - // TODO(bt,2025-07-07): Other model/provider routing... - - let success_event = handle_generic_bg_removal_artcraft( - request, - app, - app_data_root, - app_env_configs, - storyteller_creds_manager, - ).await?; - - 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_image_generation(1, ArtcraftUsageType::ImageToResult, ArtcraftUsagePage::EditPage) { - // NB: Fail open. - warn!("Failed to report usage: {:?}", err); - } - - Ok(success_event) -} - -fn error_to_tauri_response(error: GenerateError) -> CommandErrorResponseWrapper { - let mut status = CommandErrorStatus::ServerError; - let mut error_type = EnqueueImageBgRemovalErrorType::ServerError; - let mut error_message = "A server error occurred. Please try again. If it continues, please tell our staff about the problem.".to_string(); - - match error { - GenerateError::NoProviderAvailable => { - status = CommandErrorStatus::ServerError; - error_type = EnqueueImageBgRemovalErrorType::NoProviderAvailable; - error_message = "No configured provider available for background removal".to_string(); - } - GenerateError::BadInput(BadInputReason::RequiredSourceImageNotProvided) => { - status = CommandErrorStatus::BadRequest; - error_type = EnqueueImageBgRemovalErrorType::MissingImage; - error_message = "No image provided for background removal".to_string(); - } - GenerateError::BadInput(BadInputReason::Base64DecodeError) => { - status = CommandErrorStatus::BadRequest; - error_type = EnqueueImageBgRemovalErrorType::Base64DecodeError; - error_message = "Failed to decode base64 image data".to_string(); - } - _ => {}, // Other cases fall through. - } - - CommandErrorResponseWrapper { - status, - error_message: Some(error_message.to_string()), - error_type: Some(error_type), - error_details: None, - } -} diff --git a/crates/artcraftx/src/commands/background_removal/mod.rs b/crates/artcraftx/src/commands/background_removal/mod.rs deleted file mode 100644 index 31900208..00000000 --- a/crates/artcraftx/src/commands/background_removal/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod enqueue_image_bg_removal_command; -pub (super) mod artcraft; \ No newline at end of file diff --git a/crates/artcraftx/src/commands/flip_image.rs b/crates/artcraftx/src/commands/flip_image.rs deleted file mode 100644 index cc6b2a7f..00000000 --- a/crates/artcraftx/src/commands/flip_image.rs +++ /dev/null @@ -1,36 +0,0 @@ -use base64::prelude::BASE64_STANDARD; -use base64::Engine; -use image::codecs::png::{CompressionType, FilterType, PngEncoder}; -use image::ImageReader; -use std::io::Cursor; - -#[tauri::command] -pub fn flip_image(image: &str) -> Result { - println!("infer_image called; processing image..."); - - let bytes = BASE64_STANDARD.decode(image) - .map_err(|err| format!("Base64 decode error: {}", err))?; - - let image = ImageReader::new(Cursor::new(bytes)) - .with_guessed_format() - .map_err(|err| format!("Image format error: {}", err))? - .decode() - .map_err(|err| format!("Image decode error: {}", err))?; - - let rotated_image = image.rotate180(); - - let mut buffer = Vec::new(); // TODO: Preallocate, better data structure - let mut writer = Cursor::new(&mut buffer); - - let encoder = PngEncoder::new_with_quality - (&mut writer, CompressionType::Fast, FilterType::Adaptive); - - rotated_image.write_with_encoder(encoder) - .map_err(|err| format!("Image encoding error: {}", err))?; - - let encoded = BASE64_STANDARD.encode(&buffer); - - println!("Encoded: {:?}", encoded.split_at(10).0); - - Ok(encoded) -} diff --git a/crates/artcraftx/src/commands/media_files/media_file_delete_command.rs b/crates/artcraftx/src/commands/media_files/media_file_delete_command.rs deleted file mode 100644 index 8f5a9084..00000000 --- a/crates/artcraftx/src/commands/media_files/media_file_delete_command.rs +++ /dev/null @@ -1,80 +0,0 @@ -use crate::commands::response::shorthand::ResponseOrErrorMessage; -use crate::commands::response::success_response_wrapper::SerializeMarker; -use crate::events::basic_sendable_event_trait::BasicSendableEvent; -use crate::events::functional_events::media_file_deleted_event::MediaFileDeletedEvent; -use crate::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent; -use crate::state::app_env_configs::app_env_configs::AppEnvConfigs; -use crate::state::data_dir::app_data_root::AppDataRoot; -use crate::state::provider_priority::{Provider, ProviderPriorityStore}; -use crate::state::task_database::TaskDatabase; -use crate::services::sora::state::sora_task_queue::SoraTaskQueue; -use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager; -use errors::AnyhowResult; -use log::{error, info, warn}; -use serde_derive::{Deserialize, Serialize}; -use artcraft_client::endpoints::media_files::delete_media_file::delete_media_file; -use tauri::{AppHandle, State}; -use tokens::tokens::media_files::MediaFileToken; - -#[derive(Deserialize)] -pub struct MediaFileDeleteRequest { - /// REQUIRED. - /// Media file to delete. The user must own the file. - pub media_file_token: MediaFileToken, -} - -#[derive(Serialize)] -pub struct MediaFileDeleteSuccessResponse { - pub success: bool, -} - -impl SerializeMarker for MediaFileDeleteSuccessResponse {} - -#[tauri::command] -pub async fn media_file_delete_command( - app: AppHandle, - request: MediaFileDeleteRequest, - app_env_configs: State<'_, AppEnvConfigs>, - storyteller_creds_manager: State<'_, StorytellerCredentialManager>, -) -> ResponseOrErrorMessage { - - info!("media_file_delete_command called"); - - let result = handle_request( - request, - &app, - &app_env_configs, - &storyteller_creds_manager, - ).await; - - if let Err(err) = result { - error!("media_file_delete_command failed: {:?}", err); - return Err("delete failed".into()) - } - - Ok(MediaFileDeleteSuccessResponse { - success: true, - }.into()) -} - -pub async fn handle_request( - request: MediaFileDeleteRequest, - app: &AppHandle, - app_env_configs: &AppEnvConfigs, - storyteller_creds_manager: &StorytellerCredentialManager, -) -> AnyhowResult<()> { - - let creds = storyteller_creds_manager.get_credentials()?; - - let _result = delete_media_file( - &app_env_configs.storyteller_host, - creds.as_ref(), - &request.media_file_token - ).await?; - - MediaFileDeletedEvent { - media_file_token: request.media_file_token, - }.send_infallible(app); - - Ok(()) -} diff --git a/crates/artcraftx/src/commands/media_files/mod.rs b/crates/artcraftx/src/commands/media_files/mod.rs deleted file mode 100644 index c3bf63aa..00000000 --- a/crates/artcraftx/src/commands/media_files/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod media_file_delete_command; \ No newline at end of file diff --git a/crates/artcraftx/src/commands/mod.rs b/crates/artcraftx/src/commands/mod.rs index f4ec1d29..2db3a0bb 100644 --- a/crates/artcraftx/src/commands/mod.rs +++ b/crates/artcraftx/src/commands/mod.rs @@ -1,15 +1,7 @@ -pub mod app_preferences; -pub mod app_state; -pub mod background_removal; pub mod cost_estimate; pub mod credentials; pub mod download; -pub mod flip_image; pub mod generate; -pub mod get_app_info_command; -pub mod load_without_cors_command; -pub mod media_files; -pub mod platform_info_command; -pub mod providers; pub mod response; +pub mod service; pub mod task_queue; diff --git a/crates/artcraftx/src/commands/providers/deprecated/get_provider_order_command.rs b/crates/artcraftx/src/commands/providers/deprecated/get_provider_order_command.rs deleted file mode 100644 index 6543f158..00000000 --- a/crates/artcraftx/src/commands/providers/deprecated/get_provider_order_command.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::commands::response::shorthand::ResponseOrErrorMessage; -use crate::commands::response::success_response_wrapper::SerializeMarker; -use crate::state::provider_priority::{Provider, ProviderPriorityStore}; -use log::{error, info}; -use serde_derive::Serialize; -use tauri::State; - -#[derive(Serialize)] -pub struct GetProviderOrderResponse { - pub providers: Vec, -} - -impl SerializeMarker for GetProviderOrderResponse{} - -#[tauri::command] -pub async fn get_provider_order_command( - provider_priority_store: State<'_, ProviderPriorityStore>, -) -> ResponseOrErrorMessage { - info!("get_provider_order_command called"); - - let providers = provider_priority_store.get_priority() - .map_err(|err| { - error!("Failed to get provider order: {:?}", err); - "Failed to retrieve provider order" - })?; - - Ok(GetProviderOrderResponse { - providers, - }.into()) -} diff --git a/crates/artcraftx/src/commands/providers/deprecated/mod.rs b/crates/artcraftx/src/commands/providers/deprecated/mod.rs deleted file mode 100644 index 83c74a64..00000000 --- a/crates/artcraftx/src/commands/providers/deprecated/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod get_provider_order_command; -pub mod set_provider_order_command; diff --git a/crates/artcraftx/src/commands/providers/deprecated/set_provider_order_command.rs b/crates/artcraftx/src/commands/providers/deprecated/set_provider_order_command.rs deleted file mode 100644 index 08f72968..00000000 --- a/crates/artcraftx/src/commands/providers/deprecated/set_provider_order_command.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::commands::response::shorthand::SuccessOrErrorMessage; -use crate::state::data_dir::app_data_root::AppDataRoot; -use crate::state::provider_priority::{Provider, ProviderPriorityStore}; -use log::{error, info}; -use serde_derive::Deserialize; -use tauri::State; - -#[derive(Deserialize)] -pub struct SetProviderOrderRequest { - pub providers: Vec, -} - -#[tauri::command] -pub async fn set_provider_order_command( - request: SetProviderOrderRequest, - provider_priority_store: State<'_, ProviderPriorityStore>, - app_data_root: State<'_, AppDataRoot>, -) -> SuccessOrErrorMessage { - info!("set_provider_order_command called"); - - provider_priority_store.set_priority(&request.providers) - .map_err(|err| { - error!("Failed to set provider order: {:?}", err); - "Failed to set provider order" - })?; - - provider_priority_store.persist_to_filesystem(&app_data_root) - .map_err(|err| { - error!("Failed to persist provider order to filesystem: {:?}", err); - "Failed to persist provider order" - })?; - - Ok(().into()) -} diff --git a/crates/artcraftx/src/commands/providers/mod.rs b/crates/artcraftx/src/commands/providers/mod.rs deleted file mode 100644 index 74b32e16..00000000 --- a/crates/artcraftx/src/commands/providers/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod deprecated; -pub mod provider_list_command; -pub mod provider_set_api_key_command; -pub mod provider_clear_command; \ No newline at end of file diff --git a/crates/artcraftx/src/commands/providers/provider_clear_command.rs b/crates/artcraftx/src/commands/providers/provider_clear_command.rs deleted file mode 100644 index 1ceedf14..00000000 --- a/crates/artcraftx/src/commands/providers/provider_clear_command.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::commands::response::shorthand::ResponseOrErrorMessage; -use crate::commands::response::success_response_wrapper::SerializeMarker; -use crate::providers::credentials::provider_credential_key::ProviderCredentialKey; -use crate::providers::credentials::provider_credential_loading_cache::ProviderCredentialLoadingCache; -use log::{error, info}; -use serde_derive::{Deserialize, Serialize}; -use tauri::State; - -#[derive(Deserialize)] -pub struct ProviderClearRequest { - pub provider_credential: ProviderCredentialKey, -} - -#[derive(Serialize)] -pub struct ProviderClearResponse {} - -impl SerializeMarker for ProviderClearResponse {} - -#[tauri::command] -pub async fn provider_clear_command( - request: ProviderClearRequest, - credential_cache: State<'_, ProviderCredentialLoadingCache>, -) -> ResponseOrErrorMessage { - info!("provider_clear_command called for key: {:?}", request.provider_credential); - - credential_cache.delete_credentials(request.provider_credential) - .map_err(|err| { - error!("Failed to clear provider credential: {:?}", err); - "Failed to clear provider credential" - })?; - - Ok(ProviderClearResponse {}.into()) -} diff --git a/crates/artcraftx/src/commands/providers/provider_list_command.rs b/crates/artcraftx/src/commands/providers/provider_list_command.rs deleted file mode 100644 index 1994403a..00000000 --- a/crates/artcraftx/src/commands/providers/provider_list_command.rs +++ /dev/null @@ -1,106 +0,0 @@ -use crate::commands::response::shorthand::ResponseOrErrorMessage; -use crate::commands::response::success_response_wrapper::SerializeMarker; -use crate::providers::credentials::payload::provider_credential_payload::ProviderCredentialPayload; -use crate::providers::credentials::provider_credential_key::ProviderCredentialKey; -use crate::providers::credentials::provider_credential_loading_cache::ProviderCredentialLoadingCache; -use crate::providers::credentials::provider_credential_type::ProviderCredentialType; -use log::{info, warn}; -use serde_derive::Serialize; -use tauri::State; - -/// All known credential keys. Add new ones here as providers are added. -const ALL_KEYS: &[ProviderCredentialKey] = &[ - ProviderCredentialKey::FalApiKey, - ProviderCredentialKey::ReplicateApiKey, - ProviderCredentialKey::GrokWebLogin, - ProviderCredentialKey::HiggsfieldWebLogin, - ProviderCredentialKey::MidjourneyLogin, - ProviderCredentialKey::RunwayWebLogin, -]; - -const REDACTED_KEY_VISIBLE_CHARS: usize = 6; - -#[derive(Serialize)] -pub struct ProviderListResponse { - pub providers: Vec, -} - -impl SerializeMarker for ProviderListResponse {} - -#[derive(Serialize)] -pub struct ProviderListEntry { - pub provider_credential: ProviderCredentialKey, - pub credential_type: ProviderCredentialType, - pub has_credentials: bool, - pub maybe_details: Option, -} - -#[derive(Serialize)] -pub struct ProviderCredentialDetails { - /// For API keys: the first few characters followed by asterisks. - pub maybe_key_start: Option, - /// For API keys: the full key value. - pub maybe_full_key: Option, - /// For web logins: the email address if available. - pub maybe_email_address: Option, - /// For web logins: the username if available. - pub maybe_username: Option, -} - -#[tauri::command] -pub async fn provider_list_command( - credential_cache: State<'_, ProviderCredentialLoadingCache>, -) -> ResponseOrErrorMessage { - info!("provider_list_command called"); - - let mut providers = Vec::with_capacity(ALL_KEYS.len()); - - for &key in ALL_KEYS { - let maybe_payload = match credential_cache.get_credentials(key) { - Ok(payload) => payload, - Err(err) => { - warn!("Error checking credential for {:?}: {:?}", key, err); - None - } - }; - - let has_credentials = maybe_payload.is_some(); - - let maybe_details = maybe_payload.map(|payload| match payload { - ProviderCredentialPayload::ApiKey(data) => { - ProviderCredentialDetails { - maybe_key_start: Some(redact_key(data.as_str())), - maybe_full_key: Some(data.as_str().to_string()), - maybe_email_address: None, - maybe_username: None, - } - } - ProviderCredentialPayload::WebLogin(data) => { - ProviderCredentialDetails { - maybe_key_start: None, - maybe_full_key: None, - maybe_email_address: data.email_address, - maybe_username: data.username, - } - } - }); - - providers.push(ProviderListEntry { - provider_credential: key, - credential_type: key.get_type(), - has_credentials, - maybe_details, - }); - } - - Ok(ProviderListResponse { providers }.into()) -} - -fn redact_key(key: &str) -> String { - if key.len() <= REDACTED_KEY_VISIBLE_CHARS { - "********".to_string() - } else { - let visible = &key[..REDACTED_KEY_VISIBLE_CHARS]; - format!("{}********", visible) - } -} diff --git a/crates/artcraftx/src/commands/providers/provider_set_api_key_command.rs b/crates/artcraftx/src/commands/providers/provider_set_api_key_command.rs deleted file mode 100644 index 119a5350..00000000 --- a/crates/artcraftx/src/commands/providers/provider_set_api_key_command.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::commands::response::shorthand::ResponseOrErrorMessage; -use crate::commands::response::success_response_wrapper::SerializeMarker; -use crate::providers::credentials::payload::api_key::ApiKeyData; -use crate::providers::credentials::payload::provider_credential_payload::ProviderCredentialPayload; -use crate::providers::credentials::provider_credential_key::ProviderCredentialKey; -use crate::providers::credentials::provider_credential_loading_cache::ProviderCredentialLoadingCache; -use log::{error, info}; -use serde_derive::{Deserialize, Serialize}; -use tauri::State; - -#[derive(Deserialize)] -pub struct ProviderSetApiKeyRequest { - pub provider_credential: ProviderCredentialKey, - pub api_key: String, -} - -#[derive(Serialize)] -pub struct ProviderSetApiKeyResponse {} - -impl SerializeMarker for ProviderSetApiKeyResponse {} - -#[tauri::command] -pub async fn provider_set_api_key_command( - request: ProviderSetApiKeyRequest, - credential_cache: State<'_, ProviderCredentialLoadingCache>, -) -> ResponseOrErrorMessage { - info!("provider_set_api_key_command called for provider: {:?}", request.provider_credential); - - let api_key_data = ApiKeyData::from_str(&request.api_key); - let payload = ProviderCredentialPayload::ApiKey(api_key_data); - - credential_cache.save_credentials(request.provider_credential, payload) - .map_err(|err| { - error!("Failed to save API key: {:?}", err); - "Failed to save API key" - })?; - - Ok(ProviderSetApiKeyResponse {}.into()) -} diff --git a/crates/artcraftx/src/commands/app_preferences/get_app_preferences_command.rs b/crates/artcraftx/src/commands/service/app_preferences/get_app_preferences_command.rs similarity index 100% rename from crates/artcraftx/src/commands/app_preferences/get_app_preferences_command.rs rename to crates/artcraftx/src/commands/service/app_preferences/get_app_preferences_command.rs diff --git a/crates/artcraftx/src/commands/app_preferences/mod.rs b/crates/artcraftx/src/commands/service/app_preferences/mod.rs similarity index 100% rename from crates/artcraftx/src/commands/app_preferences/mod.rs rename to crates/artcraftx/src/commands/service/app_preferences/mod.rs diff --git a/crates/artcraftx/src/commands/app_preferences/update_app_preference_command.rs b/crates/artcraftx/src/commands/service/app_preferences/update_app_preference_command.rs similarity index 100% rename from crates/artcraftx/src/commands/app_preferences/update_app_preference_command.rs rename to crates/artcraftx/src/commands/service/app_preferences/update_app_preference_command.rs diff --git a/crates/artcraftx/src/commands/app_state/mod.rs b/crates/artcraftx/src/commands/service/app_state/mod.rs similarity index 100% rename from crates/artcraftx/src/commands/app_state/mod.rs rename to crates/artcraftx/src/commands/service/app_state/mod.rs diff --git a/crates/artcraftx/src/commands/app_state/reset_artcraft_command.rs b/crates/artcraftx/src/commands/service/app_state/reset_artcraft_command.rs similarity index 100% rename from crates/artcraftx/src/commands/app_state/reset_artcraft_command.rs rename to crates/artcraftx/src/commands/service/app_state/reset_artcraft_command.rs diff --git a/crates/artcraftx/src/commands/get_app_info_command.rs b/crates/artcraftx/src/commands/service/get_app_info_command.rs similarity index 100% rename from crates/artcraftx/src/commands/get_app_info_command.rs rename to crates/artcraftx/src/commands/service/get_app_info_command.rs diff --git a/crates/artcraftx/src/commands/load_without_cors_command.rs b/crates/artcraftx/src/commands/service/load_without_cors_command.rs similarity index 100% rename from crates/artcraftx/src/commands/load_without_cors_command.rs rename to crates/artcraftx/src/commands/service/load_without_cors_command.rs diff --git a/crates/artcraftx/src/commands/service/mod.rs b/crates/artcraftx/src/commands/service/mod.rs new file mode 100644 index 00000000..8d189d1f --- /dev/null +++ b/crates/artcraftx/src/commands/service/mod.rs @@ -0,0 +1,5 @@ +pub mod app_preferences; +pub mod app_state; +pub mod get_app_info_command; +pub mod load_without_cors_command; +pub mod platform_info_command; diff --git a/crates/artcraftx/src/commands/platform_info_command.rs b/crates/artcraftx/src/commands/service/platform_info_command.rs similarity index 100% rename from crates/artcraftx/src/commands/platform_info_command.rs rename to crates/artcraftx/src/commands/service/platform_info_command.rs diff --git a/crates/artcraftx/src/lib.rs b/crates/artcraftx/src/lib.rs index ddba6da5..75aa023f 100644 --- a/crates/artcraftx/src/lib.rs +++ b/crates/artcraftx/src/lib.rs @@ -23,8 +23,8 @@ use crate::commands::credentials::edit_api_credential_command::edit_api_credenti use crate::commands::credentials::edit_web_credential_command::edit_web_credential_command; use crate::commands::credentials::list_credentials_command::list_credentials_command; use crate::commands::credentials::open_web_login_command::open_web_login_command; -use crate::commands::app_preferences::get_app_preferences_command::get_app_preferences_command; -use crate::commands::app_preferences::update_app_preference_command::update_app_preferences_command; +use crate::commands::service::app_preferences::get_app_preferences_command::get_app_preferences_command; +use crate::commands::service::app_preferences::update_app_preference_command::update_app_preferences_command; use crate::commands::cost_estimate::estimate_audio_cost_command::estimate_audio_cost_command; use crate::commands::cost_estimate::estimate_image_cost_command::estimate_image_cost_command; use crate::commands::cost_estimate::estimate_mesh_cost_command::estimate_mesh_cost_command; @@ -35,22 +35,14 @@ use crate::commands::generate::models::video::list_video_models_command::list_vi use crate::commands::download::download_directory_reveal_command::download_directory_reveal_command; use crate::commands::download::download_media_file_command::download_media_file_command; use crate::commands::download::download_url_command::download_url_command; -use crate::commands::background_removal::enqueue_image_bg_removal_command::enqueue_image_bg_removal_command; use crate::commands::generate::generate_audio::generate_audio_command::generate_audio_command; use crate::commands::generate::generate_image::generate_image_command::generate_image_command; use crate::commands::generate::generate_mesh::generate_mesh_command::generate_mesh_command; use crate::commands::generate::generate_splat::generate_splat_command::generate_splat_command; use crate::commands::generate::generate_video::generate_video_command::generate_video_command; -use crate::commands::flip_image::flip_image; -use crate::commands::get_app_info_command::get_app_info_command; -use crate::commands::load_without_cors_command::load_without_cors_command; -use crate::commands::media_files::media_file_delete_command::media_file_delete_command; -use crate::commands::platform_info_command::platform_info_command; -use crate::commands::providers::deprecated::get_provider_order_command::get_provider_order_command; -use crate::commands::providers::deprecated::set_provider_order_command::set_provider_order_command; -use crate::commands::providers::provider_clear_command::provider_clear_command; -use crate::commands::providers::provider_list_command::provider_list_command; -use crate::commands::providers::provider_set_api_key_command::provider_set_api_key_command; +use crate::commands::service::get_app_info_command::get_app_info_command; +use crate::commands::service::load_without_cors_command::load_without_cors_command; +use crate::commands::service::platform_info_command::platform_info_command; use crate::commands::task_queue::get_task_queue_command::get_task_queue_command; use crate::commands::task_queue::mark_task_as_dismissed_command::mark_task_as_dismissed_command; use crate::commands::task_queue::tasks_nuke_all_command::tasks_nuke_all_command; @@ -221,7 +213,6 @@ pub fn run() { download_directory_reveal_command, download_media_file_command, download_url_command, - enqueue_image_bg_removal_command, estimate_audio_cost_command, estimate_image_cost_command, estimate_mesh_cost_command, @@ -229,7 +220,6 @@ pub fn run() { estimate_video_cost_command, list_image_models_command, list_video_models_command, - flip_image, generate_audio_command, generate_image_command, generate_mesh_command, @@ -237,16 +227,10 @@ pub fn run() { generate_video_command, get_app_info_command, get_app_preferences_command, - get_provider_order_command, get_task_queue_command, - provider_clear_command, - provider_list_command, - provider_set_api_key_command, load_without_cors_command, mark_task_as_dismissed_command, - media_file_delete_command, platform_info_command, - set_provider_order_command, tasks_nuke_all_command, update_app_preferences_command, ]); diff --git a/frontend/apps/artcraft/app/src/Helpers/galleryModalTauriBindings.ts b/frontend/apps/artcraft/app/src/Helpers/galleryModalTauriBindings.ts deleted file mode 100644 index 5cc7a9a0..00000000 --- a/frontend/apps/artcraft/app/src/Helpers/galleryModalTauriBindings.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MediaFileDelete } from "@storyteller/tauri-api"; -import { listen } from "@tauri-apps/api/event"; - -export const galleryModalDeleteMedia = (id: string) => MediaFileDelete(id); - -export const galleryModalSubscribeToMediaEvents = (handlers: { - onGenerationComplete: () => void; - onMediaDeleted: (mediaId: string) => void; -}) => { - const unlistenGen = listen("generation-complete-event", () => { - handlers.onGenerationComplete(); - }); - const unlistenDel = listen("media_file_deleted_event", (event) => { - const token: string | undefined = - event?.payload?.data?.media_file_token ?? - event?.payload?.media_file_token; - if (token) handlers.onMediaDeleted(token); - }); - return () => { - unlistenGen.then((fn) => fn()); - unlistenDel.then((fn) => fn()); - }; -}; diff --git a/frontend/apps/artcraft/app/src/config/appMenu.tsx b/frontend/apps/artcraft/app/src/config/appMenu.tsx index 40f5f2f7..99dc5045 100644 --- a/frontend/apps/artcraft/app/src/config/appMenu.tsx +++ b/frontend/apps/artcraft/app/src/config/appMenu.tsx @@ -19,7 +19,6 @@ export type AppId = | "IMAGE_WATERMARK_REMOVAL" | "IMAGE_TO_3D_OBJECT" | "IMAGE_TO_3D_WORLD" - | "REMOVE_BACKGROUND" | "ANGLES" | "STORYBOARD" | "BACKGROUND_CHANGE" @@ -78,7 +77,6 @@ export const goToApp = (action?: string) => { "IMAGE_WATERMARK_REMOVAL", "IMAGE_TO_3D_OBJECT", "IMAGE_TO_3D_WORLD", - "REMOVE_BACKGROUND", "ANGLES", "STORYBOARD", "BACKGROUND_CHANGE", diff --git a/frontend/apps/artcraft/app/src/pages/MainApp.tsx b/frontend/apps/artcraft/app/src/pages/MainApp.tsx index 8085630b..fd400c1e 100644 --- a/frontend/apps/artcraft/app/src/pages/MainApp.tsx +++ b/frontend/apps/artcraft/app/src/pages/MainApp.tsx @@ -47,7 +47,6 @@ import { VideoWatermarkRemover } from "./PageVideoWatermarkRemover"; import { ImageWatermarkRemover } from "./PageImageWatermarkRemover"; import { ImageTo3DObject } from "./PageImageTo3DObject"; import { ImageTo3DWorld } from "./PageImageTo3DWorld"; -import { RemoveBackground } from "./PageRemoveBackground"; import { Angles } from "./PageAngles"; import { Storyboard } from "./PageStoryboard"; import { PageBackgroundChange } from "./PageBackgroundChange"; @@ -211,12 +210,6 @@ const TabBody = () => { ); - case "REMOVE_BACKGROUND": - return ( -
- -
- ); case "ANGLES": return (
diff --git a/frontend/apps/artcraft/app/src/pages/PageRemoveBackground/RemoveBackground.tsx b/frontend/apps/artcraft/app/src/pages/PageRemoveBackground/RemoveBackground.tsx deleted file mode 100644 index e61c4da1..00000000 --- a/frontend/apps/artcraft/app/src/pages/PageRemoveBackground/RemoveBackground.tsx +++ /dev/null @@ -1,769 +0,0 @@ -import { useState, useRef, useEffect, useCallback, useMemo } from "react"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { - faWandMagicSparkles, - faImages, - faPlus, - faEye, - faDownload, - faUpload, -} from "@fortawesome/pro-solid-svg-icons"; -import { Button } from "@storyteller/ui-button"; -import { GalleryItem, GalleryModal } from "@storyteller/ui-gallery-modal"; -import { downloadFileFromUrl } from "@storyteller/api"; -import toast from "react-hot-toast"; -import { v4 as uuidv4 } from "uuid"; -import { UploadEntryCard } from "../../components/media/UploadEntryCard"; -import { - useRemoveBackgroundStore, - ProcessedImage, -} from "./RemoveBackgroundStore"; -import { - EnqueueImageBgRemoval, - useCanvasBgRemovedEvent, -} from "@storyteller/tauri-api"; -import { PopoverMenu, PopoverItem } from "@storyteller/ui-popover"; -import { twMerge } from "tailwind-merge"; -import { LoadingSpinner } from "@storyteller/ui-loading-spinner"; - -const convertFileToBase64 = (file: File): Promise => { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onloadend = () => { - if (reader.result) { - resolve(reader.result as string); - } else { - reject(new Error("Failed to convert file to base64.")); - } - }; - reader.onerror = () => reject(new Error("Error reading file.")); - reader.readAsDataURL(file); - }); -}; - -export const RemoveBackground = () => { - const [isGalleryModalOpen, setIsGalleryModalOpen] = useState(false); - const [selectedGalleryImages, setSelectedGalleryImages] = useState( - [], - ); - const [windowSize, setWindowSize] = useState({ - width: window.innerWidth, - height: window.innerHeight, - }); - const [isHoldingCompare, setIsHoldingCompare] = useState(false); - const [animationComplete, setAnimationComplete] = useState(true); - const [isLoadingImage, setIsLoadingImage] = useState(false); - - const fileInputRef = useRef(null); - const clipLayerRef = useRef(null); - const progressBarRef = useRef(null); - const revealProgressRef = useRef(100); - const animationFrameRef = useRef(null); - const processingExternalUrlRef = useRef(null); - - const store = useRemoveBackgroundStore(); - const { - images, - activeImageId, - isProcessing, - currentOriginalUrl, - pendingJobId, - imageDimensions, - pendingExternalUrl, - setIsProcessing, - setCurrentOriginalUrl, - setPendingJobId, - setImageDimensions, - setPendingExternalUrl, - addImage, - setActiveImage, - getActiveImage, - } = store; - - const activeImage = getActiveImage(); - - const pendingJobIdRef = useRef(pendingJobId); - const currentOriginalUrlRef = useRef(currentOriginalUrl); - - useEffect(() => { - pendingJobIdRef.current = pendingJobId; - }, [pendingJobId]); - - useEffect(() => { - currentOriginalUrlRef.current = currentOriginalUrl; - }, [currentOriginalUrl]); - - useEffect(() => { - const handleResize = () => { - setWindowSize({ width: window.innerWidth, height: window.innerHeight }); - }; - window.addEventListener("resize", handleResize); - return () => window.removeEventListener("resize", handleResize); - }, []); - - useEffect(() => { - const processExternalUrl = async () => { - if (!pendingExternalUrl) return; - if (processingExternalUrlRef.current === pendingExternalUrl) return; - - processingExternalUrlRef.current = pendingExternalUrl; - const imageUrl = pendingExternalUrl; - setPendingExternalUrl(null); - setIsLoadingImage(true); - - try { - const response = await fetch(imageUrl); - const blob = await response.blob(); - const file = new File([blob], "external-image.png", { - type: blob.type, - }); - const base64Image = await convertFileToBase64(file); - - await new Promise((resolve, reject) => { - const img = new Image(); - img.onload = () => { - setImageDimensions({ - width: img.naturalWidth, - height: img.naturalHeight, - }); - resolve(); - }; - img.onerror = () => reject(new Error("Failed to load image")); - img.src = imageUrl; - }); - - setActiveImage(null); - setCurrentOriginalUrl(imageUrl); - setIsLoadingImage(false); - setIsProcessing(true); - - const jobId = uuidv4(); - setPendingJobId(jobId); - - await EnqueueImageBgRemoval({ - base64_image: base64Image, - frontend_caller: "mini_app", - frontend_subscriber_id: jobId, - }); - } catch (error) { - console.error("Error processing external image:", error); - toast.error("Failed to process image"); - setIsLoadingImage(false); - setIsProcessing(false); - setPendingJobId(null); - } finally { - processingExternalUrlRef.current = null; - } - }; - - processExternalUrl(); - }, [ - pendingExternalUrl, - setPendingExternalUrl, - setActiveImage, - setCurrentOriginalUrl, - setIsProcessing, - setPendingJobId, - setImageDimensions, - ]); - - const addMenuItems: PopoverItem[] = useMemo( - () => [ - { - label: "Upload Image", - selected: false, - icon: , - action: "upload", - }, - { - label: "Choose from Library", - selected: false, - icon: , - action: "library", - }, - ], - [], - ); - - const handleAddMenuSelect = useCallback((item: PopoverItem) => { - if (item.action === "upload") { - fileInputRef.current?.click(); - } else if (item.action === "library") { - setIsGalleryModalOpen(true); - } - }, []); - - const startRevealAnimation = useCallback(() => { - if (animationFrameRef.current) { - cancelAnimationFrame(animationFrameRef.current); - } - - revealProgressRef.current = 0; - setAnimationComplete(false); - - const duration = 800; - const startTime = performance.now(); - - const animate = (currentTime: number) => { - const elapsed = currentTime - startTime; - const progress = Math.min(elapsed / duration, 1); - const eased = 1 - Math.pow(1 - progress, 3); - const progressPercent = eased * 100; - - revealProgressRef.current = progressPercent; - - if (clipLayerRef.current) { - clipLayerRef.current.style.clipPath = `inset(0 0 0 ${progressPercent}%)`; - } - if (progressBarRef.current) { - progressBarRef.current.style.left = `${progressPercent}%`; - progressBarRef.current.style.display = - progressPercent < 100 ? "block" : "none"; - } - - if (progress < 1) { - animationFrameRef.current = requestAnimationFrame(animate); - } else { - setAnimationComplete(true); - animationFrameRef.current = null; - } - }; - - requestAnimationFrame(() => { - requestAnimationFrame(() => { - setTimeout(() => { - animationFrameRef.current = requestAnimationFrame(animate); - }, 50); - }); - }); - }, []); - - useEffect(() => { - return () => { - if (animationFrameRef.current) { - cancelAnimationFrame(animationFrameRef.current); - } - }; - }, []); - - useCanvasBgRemovedEvent(async (event) => { - if (event.maybe_frontend_subscriber_id !== pendingJobIdRef.current) return; - - const newImage: ProcessedImage = { - id: uuidv4(), - originalUrl: currentOriginalUrlRef.current, - processedUrl: event.image_cdn_url, - timestamp: Date.now(), - }; - - const loadImage = (src: string): Promise => { - return new Promise((resolve, reject) => { - const img = new Image(); - img.onload = () => resolve(img); - img.onerror = () => reject(new Error(`Failed to load: ${src}`)); - img.src = src; - }); - }; - - try { - const [originalImg] = await Promise.all([ - loadImage(currentOriginalUrlRef.current), - loadImage(event.image_cdn_url), - ]); - - addImage(newImage); - setIsProcessing(false); - setPendingJobId(null); - toast.success("Saved to Library"); - - setImageDimensions({ - width: originalImg.naturalWidth, - height: originalImg.naturalHeight, - }); - - startRevealAnimation(); - } catch (error) { - console.error("Error loading images:", error); - addImage(newImage); - setIsProcessing(false); - setPendingJobId(null); - toast.success("Saved to Library"); - } - }); - - const resetAnimationState = useCallback(() => { - if (animationFrameRef.current) { - cancelAnimationFrame(animationFrameRef.current); - animationFrameRef.current = null; - } - revealProgressRef.current = 0; - setAnimationComplete(true); - setIsHoldingCompare(false); - }, []); - - const handleLocalImageSelect = useCallback( - async (files: FileList) => { - const file = files[0]; - if (!file || !file.type.startsWith("image/")) return; - - setIsLoadingImage(true); - - try { - const base64Image = await convertFileToBase64(file); - const objectUrl = URL.createObjectURL(file); - - await new Promise((resolve, reject) => { - const img = new Image(); - img.onload = () => { - setImageDimensions({ - width: img.naturalWidth, - height: img.naturalHeight, - }); - resolve(); - }; - img.onerror = () => reject(new Error("Failed to load image")); - img.src = objectUrl; - }); - - setActiveImage(null); - resetAnimationState(); - setCurrentOriginalUrl(objectUrl); - setIsLoadingImage(false); - setIsProcessing(true); - - const jobId = uuidv4(); - setPendingJobId(jobId); - - await EnqueueImageBgRemoval({ - base64_image: base64Image, - frontend_caller: "mini_app", - frontend_subscriber_id: jobId, - }); - } catch (error) { - console.error("Error processing image:", error); - toast.error("Failed to process image"); - setIsLoadingImage(false); - setIsProcessing(false); - setPendingJobId(null); - } - }, - [ - setActiveImage, - resetAnimationState, - setCurrentOriginalUrl, - setIsProcessing, - setPendingJobId, - setImageDimensions, - ], - ); - - const handleImageSelect = useCallback((id: string) => { - setSelectedGalleryImages((prev) => { - if (prev.includes(id)) return prev.filter((x) => x !== id); - return [id]; - }); - }, []); - - const handleGallerySelect = useCallback( - async (selectedItems: GalleryItem[]) => { - const item = selectedItems[0]; - if (!item || !item.fullImage) { - toast.error("No image selected"); - return; - } - - const imageUrl = item.fullImage; - setIsGalleryModalOpen(false); - setSelectedGalleryImages([]); - setIsLoadingImage(true); - - try { - const response = await fetch(imageUrl); - const blob = await response.blob(); - const file = new File([blob], "library-image.png", { type: blob.type }); - - const base64Image = await convertFileToBase64(file); - - await new Promise((resolve, reject) => { - const img = new Image(); - img.onload = () => { - setImageDimensions({ - width: img.naturalWidth, - height: img.naturalHeight, - }); - resolve(); - }; - img.onerror = () => reject(new Error("Failed to load image")); - img.src = imageUrl; - }); - - setActiveImage(null); - resetAnimationState(); - setCurrentOriginalUrl(imageUrl); - setIsLoadingImage(false); - setIsProcessing(true); - - const jobId = uuidv4(); - setPendingJobId(jobId); - - await EnqueueImageBgRemoval({ - base64_image: base64Image, - frontend_caller: "mini_app", - frontend_subscriber_id: jobId, - }); - } catch (error) { - console.error("Error processing gallery image:", error); - toast.error("Failed to process image"); - setIsLoadingImage(false); - setIsProcessing(false); - setPendingJobId(null); - } - }, - [ - setActiveImage, - resetAnimationState, - setCurrentOriginalUrl, - setIsProcessing, - setPendingJobId, - setImageDimensions, - ], - ); - - const handleDownload = useCallback(async () => { - const currentActiveImage = getActiveImage(); - if (!currentActiveImage) { - toast.error("No image to download"); - return; - } - try { - await downloadFileFromUrl(currentActiveImage.processedUrl); - toast.success("Image saved to Downloads folder"); - } catch (error) { - console.error("Download failed:", error); - toast.error("Failed to download image"); - } - }, [getActiveImage]); - - const handleCompareMouseDown = useCallback(() => { - setIsHoldingCompare(true); - if (clipLayerRef.current) { - clipLayerRef.current.style.clipPath = "inset(0 0 0 0)"; - } - if (progressBarRef.current) { - progressBarRef.current.style.display = "none"; - } - }, []); - - const handleCompareMouseUp = useCallback(() => { - setIsHoldingCompare(false); - if (clipLayerRef.current) { - clipLayerRef.current.style.clipPath = `inset(0 0 0 ${revealProgressRef.current}%)`; - } - if (progressBarRef.current && revealProgressRef.current < 100) { - progressBarRef.current.style.display = "block"; - } - }, []); - - useEffect(() => { - if (isHoldingCompare) { - document.addEventListener("mouseup", handleCompareMouseUp); - document.addEventListener("mouseleave", handleCompareMouseUp); - } - return () => { - document.removeEventListener("mouseup", handleCompareMouseUp); - document.removeEventListener("mouseleave", handleCompareMouseUp); - }; - }, [isHoldingCompare, handleCompareMouseUp]); - - const handleThumbnailClick = useCallback( - (img: ProcessedImage) => { - setActiveImage(img.id); - revealProgressRef.current = 100; - setAnimationComplete(true); - if (clipLayerRef.current) { - clipLayerRef.current.style.clipPath = "inset(0 0 0 100%)"; - } - if (progressBarRef.current) { - progressBarRef.current.style.display = "none"; - } - const loadImg = new Image(); - loadImg.onload = () => { - setImageDimensions({ - width: loadImg.naturalWidth, - height: loadImg.naturalHeight, - }); - }; - loadImg.src = img.originalUrl; - }, - [setActiveImage, setImageDimensions], - ); - - const hasImages = images.length > 0; - const showUploadScreen = !hasImages && !isProcessing; - - const imageContainerStyle = useMemo(() => { - if (!imageDimensions) { - return { width: "600px", height: "450px" }; - } - - const horizontalPadding = 128 + 32; - const verticalPadding = 128 + 150; - - const availableWidth = windowSize.width - horizontalPadding; - const availableHeight = windowSize.height - 56 - verticalPadding; - - const maxWidth = Math.min(availableWidth, 1400); - const maxHeight = Math.max(availableHeight, 200); - const imageAspect = imageDimensions.width / imageDimensions.height; - - let width = maxWidth; - let height = width / imageAspect; - - if (height > maxHeight) { - height = maxHeight; - width = height * imageAspect; - } - - width = Math.max(width, 200); - height = Math.max(height, 150); - - return { width: `${width}px`, height: `${height}px` }; - }, [imageDimensions, windowSize.width, windowSize.height]); - - const handleFileInputChange = useCallback( - (e: React.ChangeEvent) => { - if (e.target.files) { - handleLocalImageSelect(e.target.files); - e.target.value = ""; - } - }, - [handleLocalImageSelect], - ); - - const handleOpenGallery = useCallback(() => { - setIsGalleryModalOpen(true); - }, []); - - const handleCloseGallery = useCallback(() => { - setIsGalleryModalOpen(false); - setSelectedGalleryImages([]); - }, []); - - return ( - <> -
-
-
- {showUploadScreen ? ( -
-
- - {isLoadingImage && ( -
- -
- )} -
-
- ) : ( -
- {(activeImage || isProcessing) && ( -
- - -
- )} - -
-
- {isProcessing && ( -
- {currentOriginalUrl && ( - Processing - )} -
-
-
- -
- - Removing Background... - -
-
- )} - {activeImage && ( - <> -
- - Background Removed - -
- Original -
- -
= 100 - ? "none" - : "block", - }} - /> - - )} -
-
- -
- - - - } - /> - - {images.map((img) => ( - - ))} -
-
- )} -
-
-
- - - - ); -}; diff --git a/frontend/apps/artcraft/app/src/pages/PageRemoveBackground/RemoveBackgroundStore.ts b/frontend/apps/artcraft/app/src/pages/PageRemoveBackground/RemoveBackgroundStore.ts deleted file mode 100644 index 144f942f..00000000 --- a/frontend/apps/artcraft/app/src/pages/PageRemoveBackground/RemoveBackgroundStore.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { create } from "zustand"; - -export interface ProcessedImage { - id: string; - originalUrl: string; - processedUrl: string; - timestamp: number; -} - -export interface ImageDimensions { - width: number; - height: number; -} - -interface RemoveBackgroundState { - images: ProcessedImage[]; - activeImageId: string | null; - isProcessing: boolean; - currentOriginalUrl: string; - pendingJobId: string | null; - imageDimensions: ImageDimensions | null; - pendingExternalUrl: string | null; - - addImage: (image: ProcessedImage) => void; - setActiveImage: (id: string | null) => void; - getActiveImage: () => ProcessedImage | null; - setIsProcessing: (value: boolean) => void; - setCurrentOriginalUrl: (url: string) => void; - setPendingJobId: (id: string | null) => void; - setImageDimensions: (dimensions: ImageDimensions | null) => void; - setPendingExternalUrl: (url: string | null) => void; - clearAll: () => void; -} - -export const useRemoveBackgroundStore = create( - (set, get) => ({ - images: [], - activeImageId: null, - isProcessing: false, - currentOriginalUrl: "", - pendingJobId: null, - imageDimensions: null, - pendingExternalUrl: null, - - addImage: (image) => { - set((state) => ({ - images: [...state.images, image], - activeImageId: image.id, - })); - }, - - setActiveImage: (id) => { - set({ activeImageId: id }); - }, - - getActiveImage: () => { - const state = get(); - return state.images.find((img) => img.id === state.activeImageId) ?? null; - }, - - setIsProcessing: (value) => { - set({ isProcessing: value }); - }, - - setCurrentOriginalUrl: (url) => { - set({ currentOriginalUrl: url }); - }, - - setPendingJobId: (id) => { - set({ pendingJobId: id }); - }, - - setImageDimensions: (dimensions) => { - set({ imageDimensions: dimensions }); - }, - - setPendingExternalUrl: (url) => { - set({ pendingExternalUrl: url }); - }, - - clearAll: () => { - set({ - images: [], - activeImageId: null, - isProcessing: false, - currentOriginalUrl: "", - pendingJobId: null, - imageDimensions: null, - pendingExternalUrl: null, - }); - }, - }), -); diff --git a/frontend/apps/artcraft/app/src/pages/PageRemoveBackground/index.ts b/frontend/apps/artcraft/app/src/pages/PageRemoveBackground/index.ts deleted file mode 100644 index b6881719..00000000 --- a/frontend/apps/artcraft/app/src/pages/PageRemoveBackground/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { RemoveBackground } from "./RemoveBackground"; -export { useRemoveBackgroundStore } from "./RemoveBackgroundStore"; - diff --git a/frontend/apps/artcraft/app/src/pages/Stores/TabState.ts b/frontend/apps/artcraft/app/src/pages/Stores/TabState.ts index b36edefe..601ae082 100644 --- a/frontend/apps/artcraft/app/src/pages/Stores/TabState.ts +++ b/frontend/apps/artcraft/app/src/pages/Stores/TabState.ts @@ -10,7 +10,6 @@ export type TabId = | "IMAGE_WATERMARK_REMOVAL" | "IMAGE_TO_3D_OBJECT" | "IMAGE_TO_3D_WORLD" - | "REMOVE_BACKGROUND" | "ANGLES" | "STORYBOARD" | "BACKGROUND_CHANGE" diff --git a/frontend/libs/components/lightbox-modal/src/lib/lightbox-modal.tsx b/frontend/libs/components/lightbox-modal/src/lib/lightbox-modal.tsx index fb1aa9c4..784c3734 100644 --- a/frontend/libs/components/lightbox-modal/src/lib/lightbox-modal.tsx +++ b/frontend/libs/components/lightbox-modal/src/lib/lightbox-modal.tsx @@ -14,12 +14,10 @@ import { faPause, faPencil, faPlay, - faTrashCan, faVideo, faWandMagicSparkles, faArrowRotateRight, } from "@fortawesome/pro-solid-svg-icons"; -import { MediaFileDelete } from "@storyteller/tauri-api"; import { LoadingSpinner } from "@storyteller/ui-loading-spinner"; import { Viewer3D } from "@storyteller/ui-viewer-3d"; import { WaveformAudioPlayer } from "@storyteller/ui-audio-player"; @@ -41,8 +39,6 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faCopy, faLink, faCheck } from "@fortawesome/pro-solid-svg-icons"; import { twMerge } from "tailwind-merge"; import { - showActionReminder, - isActionReminderOpen, } from "@storyteller/ui-action-reminder-modal"; import { getCreatorIconPathForModelId, @@ -408,33 +404,6 @@ export function LightboxModal({ [emblaMainApi, emblaThumbsApi], ); - const onDeleteClicked = useCallback( - (mediaToken: string) => { - showActionReminder({ - reminderType: "default", - title: "Delete this media?", - message: ( -

- This will permanently remove the media from your library. This - action cannot be undone. -

- ), - primaryActionText: "Delete", - secondaryActionText: "Cancel", - primaryActionBtnClassName: "bg-red text-white hover:bg-red/90", - onPrimaryAction: async () => { - try { - await MediaFileDelete(mediaToken); - } finally { - isActionReminderOpen.value = false; - onClose(); - } - }, - }); - }, - [onClose], - ); - const onSelect = useCallback(() => { if (!emblaMainApi || !emblaThumbsApi) return; const index = emblaMainApi.selectedScrollSnap(); @@ -1256,20 +1225,6 @@ export function LightboxModal({ )} - {selectedMediaToken && onDeleteClicked && ( - - )}
)} diff --git a/frontend/libs/components/lightbox-modal/tsconfig.json b/frontend/libs/components/lightbox-modal/tsconfig.json index 4d4bd12f..1efaefb8 100644 --- a/frontend/libs/components/lightbox-modal/tsconfig.json +++ b/frontend/libs/components/lightbox-modal/tsconfig.json @@ -23,18 +23,15 @@ { "path": "../../analytics/google-analytics" }, + { + "path": "../audio-player" + }, { "path": "../viewer-3d" }, { "path": "../loading-spinner" }, - { - "path": "../audio-player" - }, - { - "path": "../../tauri-api" - }, { "path": "../button" }, diff --git a/frontend/libs/components/lightbox-modal/tsconfig.lib.json b/frontend/libs/components/lightbox-modal/tsconfig.lib.json index 7dea2bba..7d9e5f59 100644 --- a/frontend/libs/components/lightbox-modal/tsconfig.lib.json +++ b/frontend/libs/components/lightbox-modal/tsconfig.lib.json @@ -64,18 +64,15 @@ { "path": "../../analytics/google-analytics/tsconfig.lib.json" }, + { + "path": "../audio-player/tsconfig.lib.json" + }, { "path": "../viewer-3d/tsconfig.lib.json" }, { "path": "../loading-spinner/tsconfig.lib.json" }, - { - "path": "../audio-player/tsconfig.lib.json" - }, - { - "path": "../../tauri-api/tsconfig.lib.json" - }, { "path": "../button/tsconfig.lib.json" }, diff --git a/frontend/libs/components/settings-modal/src/lib/panes/ProviderPrioritySettingsPane.tsx b/frontend/libs/components/settings-modal/src/lib/panes/ProviderPrioritySettingsPane.tsx deleted file mode 100644 index 8cd3ccdf..00000000 --- a/frontend/libs/components/settings-modal/src/lib/panes/ProviderPrioritySettingsPane.tsx +++ /dev/null @@ -1,233 +0,0 @@ -import { useEffect, useState, ReactNode } from "react"; -import { - DndContext, - closestCenter, - KeyboardSensor, - PointerSensor, - useSensor, - useSensors, - DragEndEvent, -} from "@dnd-kit/core"; -import { - arrayMove, - SortableContext, - sortableKeyboardCoordinates, - verticalListSortingStrategy, - useSortable, -} from "@dnd-kit/sortable"; -import { CSS } from "@dnd-kit/utilities"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { - faGripVertical, - faSpinnerThird, -} from "@fortawesome/pro-solid-svg-icons"; -import { - SetProviderOrder, - Provider, - GetProviderOrder, -} from "@storyteller/tauri-api"; -import { getCreatorIcon, ModelCreator } from "@storyteller/model-list"; -import { IsDesktopApp } from "@storyteller/tauri-utils"; - -interface ProviderItem { - id: Provider; - name: string; -} - -interface SortableItemProps { - id: string; - name: string; - icon: ReactNode; - isUpdating?: boolean; -} - -const SortableItem = ({ - id, - name, - icon, - isUpdating = false, -}: SortableItemProps) => { - const { - attributes, - listeners, - setNodeRef, - transform, - transition, - isDragging, - } = useSortable({ id }); - - const style = { - transform: CSS.Transform.toString(transform), - transition, - }; - - return ( -
-
- - {icon} - - {name} -
-
- -
-
- ); -}; - -const ProviderItemMap = { - [Provider.ArtCraft]: { id: Provider.ArtCraft, name: "ArtCraft" }, - [Provider.Fal]: { id: Provider.Fal, name: "Fal" }, - [Provider.Sora]: { id: Provider.Sora, name: "Sora / ChatGPT" }, -}; - -const PROVIDER_TO_CREATOR: Partial> = { - [Provider.ArtCraft]: ModelCreator.ArtCraft, - [Provider.Fal]: ModelCreator.Fal, - [Provider.Sora]: ModelCreator.OpenAi, -}; - -const getProviderIcon = (provider: Provider): ReactNode => { - const creator = PROVIDER_TO_CREATOR[provider]; - if (creator) return getCreatorIcon(creator, "h-4 w-4 icon-auto-contrast"); - return ( - generic logo - ); -}; - -export const ProviderPrioritySettingsPane = () => { - const [items, setItems] = useState([]); - - const [isUpdating, setIsUpdating] = useState(false); - - useEffect(() => { - const fetchData = async () => { - const providers = await GetProviderOrder(); - - let items: ProviderItem[] = []; - - // Add providers from backend (in order) - for (let provider of providers.payload.providers) { - items.push(ProviderItemMap[provider]); - } - - // Add providers not in backend (in order) - for (const [key, value] of Object.entries(ProviderItemMap)) { - if (!providers.payload.providers.includes(key as Provider)) { - items.push(value); - } - } - - setItems(items); - }; - fetchData(); - }, []); - - const sensors = useSensors( - useSensor(PointerSensor), - useSensor(KeyboardSensor, { - coordinateGetter: sortableKeyboardCoordinates, - }) - ); - - const updateProviderPriorityOnBackend = async (newOrder: ProviderItem[]) => { - try { - setIsUpdating(true); - console.log("Updating provider priority on backend:", newOrder); - - let ordering = newOrder.map((item) => item.id); - console.log("Provider order:", ordering); - - await SetProviderOrder({ providers: ordering }); - - console.log("Provider priority updated successfully"); - } catch (error) { - console.error("Failed to update provider priority:", error); - } finally { - setIsUpdating(false); - } - }; - - const handleDragEnd = (event: DragEndEvent) => { - const { active, over } = event; - - if (active.id !== over?.id) { - setItems((prevItems) => { - const oldIndex = prevItems.findIndex((item) => item.id === active.id); - const newIndex = prevItems.findIndex((item) => item.id === over?.id); - - const newOrder = arrayMove(prevItems, oldIndex, newIndex); - - // Send update to backend - updateProviderPriorityOnBackend(newOrder); - - return newOrder; - }); - } - }; - - return ( -
-
-

- Drag and drop to reorder model provider priority. Higher items will be - tried first. You can use this to control favorite services and - spending. -

-
- - - -
- {items.map((item) => ( - - ))} -
-
-
- - {isUpdating && ( -
- - Updating... -
- )} -
- ); -}; diff --git a/frontend/libs/components/settings-modal/src/lib/settings-modal.tsx b/frontend/libs/components/settings-modal/src/lib/settings-modal.tsx index 31136380..faf500fb 100644 --- a/frontend/libs/components/settings-modal/src/lib/settings-modal.tsx +++ b/frontend/libs/components/settings-modal/src/lib/settings-modal.tsx @@ -5,7 +5,6 @@ import { MiscSettingsPane } from "./panes/MiscSettingsPane"; import { AudioSettingsPane } from "./panes/AudioSettingsPane"; import { AccountSettingsPane } from "./panes/AccountSettings/AccountSettingsPane"; import { AboutSettingsPane } from "./panes/AboutSettingsPane"; -import { ProviderPrioritySettingsPane } from "./panes/ProviderPrioritySettingsPane"; import { ExperimentalSettingsPane } from "./panes/ExperimentalSettingsPane"; import { gtagEvent } from "@storyteller/google-analytics"; import { BillingSettingsPane } from "./panes/BillingSettingsPane"; @@ -20,7 +19,6 @@ export type SettingsSection = | "accounts" | "alerts" | "about" - | "provider_priority" | "billing" | "experimental"; @@ -85,8 +83,6 @@ export const SettingsContent = ({ ); case "about": return ; - case "provider_priority": - return ; case "billing": return ; case "experimental": diff --git a/frontend/libs/components/settings-modal/tsconfig.json b/frontend/libs/components/settings-modal/tsconfig.json index fdf2b73d..b6e1c361 100644 --- a/frontend/libs/components/settings-modal/tsconfig.json +++ b/frontend/libs/components/settings-modal/tsconfig.json @@ -2,9 +2,6 @@ "files": [], "include": [], "references": [ - { - "path": "../../tauri-utils" - }, { "path": "../../api" }, diff --git a/frontend/libs/components/settings-modal/tsconfig.lib.json b/frontend/libs/components/settings-modal/tsconfig.lib.json index e6895d63..98c59eb0 100644 --- a/frontend/libs/components/settings-modal/tsconfig.lib.json +++ b/frontend/libs/components/settings-modal/tsconfig.lib.json @@ -43,9 +43,6 @@ "src/**/*.tsx" ], "references": [ - { - "path": "../../tauri-utils/tsconfig.lib.json" - }, { "path": "../../api/tsconfig.lib.json" }, diff --git a/frontend/libs/tauri-api/src/index.ts b/frontend/libs/tauri-api/src/index.ts index 1f5b12a7..ae468ef3 100644 --- a/frontend/libs/tauri-api/src/index.ts +++ b/frontend/libs/tauri-api/src/index.ts @@ -7,7 +7,6 @@ export * from "./lib/common/CommandStatus.js"; export * from "./lib/download/DownloadDirectoryReveal.js"; export * from "./lib/download/DownloadUrl.js"; export * from "./lib/enqueue/EnqueueEditImage.js"; -export * from "./lib/enqueue/EnqueueImageBgRemovalCommand.js"; export * from "./lib/enqueue/EnqueueImageInpaint.js"; export * from "./lib/enqueue/EnqueueImageToVideo.js"; export * from "./lib/enqueue/EnqueueTextToImage.js"; @@ -26,14 +25,11 @@ export * from "./lib/fal/FalKlingImageToVideo.js"; export * from "./lib/fal/GetFalApiKey.js"; export * from "./lib/fal/SetFalApiKey.js"; export * from "./lib/grok/GrokGetCredentialInfo.js"; -export * from "./lib/media_files/MediaFileDeleteCommand.js"; export * from "./lib/midjourney/MidjourneyGetCredentialInfo.js"; export * from "./lib/openai/GetOpenAIApiKey.js"; export * from "./lib/openai/SetOpenAIApiKey.js"; export * from "./lib/opener/OpenUrl.js"; -export * from "./lib/providers/GetProviderOrder.js"; export * from "./lib/providers/Provider.js"; -export * from "./lib/providers/SetProviderOrder.js"; export * from "./lib/settings/GetAppPreferences.js"; export * from "./lib/settings/UpdateAppPreference.js"; export * from "./lib/sora/CheckSoraSession.js"; diff --git a/frontend/libs/tauri-api/src/lib/enqueue/EnqueueImageBgRemovalCommand.ts b/frontend/libs/tauri-api/src/lib/enqueue/EnqueueImageBgRemovalCommand.ts deleted file mode 100644 index 9e9ab3b4..00000000 --- a/frontend/libs/tauri-api/src/lib/enqueue/EnqueueImageBgRemovalCommand.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { invoke } from "@tauri-apps/api/core"; -import { CommandResult } from "../common/CommandStatus"; - -export interface EnqueueImageBgRemovalRequest { - image_media_token?: string; - base64_image?: string; - - // TODO: Actual enum. - frontend_caller?: string; - - // We'll use the node id here. - frontend_subscriber_id?: string; -} - -interface RawEnqueueImageBgRemovalRequest { - image_media_token?: string; - base64_image?: string; - frontend_caller?: string; - frontend_subscriber_id?: string; -} - -export enum EnqueueImageBgRemovalErrorType { - /// Caller didn't specify a model - ModelNotSpecified = "model_not_specified", - /// Generic server error - ServerError = "server_error", - /// No Fal API key available - NeedsFalApiKey = "needs_fal_api_key", - /// Fal had an API error - FalError = "fal_error", -} - -export interface EnqueueImageBgRemovalError extends CommandResult { - error_type: EnqueueImageBgRemovalErrorType; - error_message?: string; -} - -export interface EnqueueImageBgRemovalPayload { -} - -export interface EnqueueImageBgRemovalSuccess extends CommandResult { - payload: EnqueueImageBgRemovalPayload; -} - -export type EnqueueImageBgRemovalResult = EnqueueImageBgRemovalSuccess | EnqueueImageBgRemovalError; - -export const EnqueueImageBgRemoval = async (request: EnqueueImageBgRemovalRequest) : Promise => { - let mutableRequest : RawEnqueueImageBgRemovalRequest = {}; - - if (!!request.image_media_token) { - mutableRequest.image_media_token = request.image_media_token; - } - - if (!!request.base64_image) { - mutableRequest.base64_image = request.base64_image; - } - - if (!!request.frontend_caller) { - mutableRequest.frontend_caller = request.frontend_caller; - } - - if (!!request.frontend_subscriber_id) { - mutableRequest.frontend_subscriber_id = request.frontend_subscriber_id; - } - - const result = await invoke("enqueue_image_bg_removal_command", { - request: mutableRequest, - }); - - return (result as EnqueueImageBgRemovalResult); -} diff --git a/frontend/libs/tauri-api/src/lib/media_files/MediaFileDeleteCommand.ts b/frontend/libs/tauri-api/src/lib/media_files/MediaFileDeleteCommand.ts deleted file mode 100644 index d8269572..00000000 --- a/frontend/libs/tauri-api/src/lib/media_files/MediaFileDeleteCommand.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { invoke } from "@tauri-apps/api/core"; -import { CommandResult } from "../common/CommandStatus"; - -export interface MediaFileDeleteError extends CommandResult { - error_message?: string; -} - -export interface MediaFileDeletePayload { - success: boolean; -} - -export interface MediaFileDeleteSuccess extends CommandResult { - payload: MediaFileDeletePayload; -} - -export type MediaFileDeleteResult = MediaFileDeleteSuccess | MediaFileDeleteError; - -export const MediaFileDelete = async (media_file_token: string) : Promise => { - const result = await invoke("media_file_delete_command", { - request: { - media_file_token: media_file_token, - } - }); - - return (result as MediaFileDeleteResult); -} diff --git a/frontend/libs/tauri-api/src/lib/providers/GetProviderOrder.ts b/frontend/libs/tauri-api/src/lib/providers/GetProviderOrder.ts deleted file mode 100644 index d7acff65..00000000 --- a/frontend/libs/tauri-api/src/lib/providers/GetProviderOrder.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { invoke } from "@tauri-apps/api/core"; -import { CommandResult } from "../common/CommandStatus"; -import { Provider } from "./Provider"; - -export interface GetProviderOrderSuccess extends CommandResult { - payload: GetProviderOrderPayload; -} - -export interface GetProviderOrderPayload { - providers: Provider[]; -} - -// Returns the Success and Error variants directly. -// Throws on Network/Tauri errors. -export const GetProviderOrder = async () : Promise => { - try { - return await invoke("get_provider_order_command") as GetProviderOrderSuccess; - } catch (error) { - // NB: Endpoint should be infalliable - throw error; - } -} diff --git a/frontend/libs/tauri-api/src/lib/providers/SetProviderOrder.ts b/frontend/libs/tauri-api/src/lib/providers/SetProviderOrder.ts deleted file mode 100644 index 60799dca..00000000 --- a/frontend/libs/tauri-api/src/lib/providers/SetProviderOrder.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { invoke } from "@tauri-apps/api/core"; -import { CommandResult } from "../common/CommandStatus"; -import { Provider } from "./Provider"; - -export interface SetProviderOrderRequest { - providers: Provider[]; -} - -export const SetProviderOrder = async (request: SetProviderOrderRequest) : Promise => { - const result = await invoke("set_provider_order_command", { - request: { - providers: request.providers, - } - }); - - return (result as CommandResult); -}