From 3fd63103fd56abfa48eda0e47f1ff2adcc7798ee Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Wed, 22 Apr 2026 14:15:42 -0400 Subject: [PATCH] desktop enum, commands --- .../artcraft/src/core/api_adapters/mod.rs | 3 ++- .../api_adapters/quality/common_quality.rs | 21 +++++++++++++++++++ .../src/core/api_adapters/quality/mod.rs | 1 + .../image_edit/enqueue_edit_image_command.rs | 15 ++++++++----- .../enqueue_image_inpaint_command.rs | 15 ++++++++----- ...andle_text_to_image_artcraft_via_router.rs | 8 ++++++- .../enqueue_text_to_image_command.rs | 5 +++++ .../model-list/src/lib/classes/ImageModel.ts | 11 ++++++++++ .../lib/classes/properties/CommonQuality.ts | 8 +++++++ .../model-list/src/lib/lists/ImageModels.ts | 7 +++++++ 10 files changed, 82 insertions(+), 12 deletions(-) create mode 100644 crates/desktop/artcraft/src/core/api_adapters/quality/common_quality.rs create mode 100644 crates/desktop/artcraft/src/core/api_adapters/quality/mod.rs create mode 100644 frontend/libs/model-list/src/lib/classes/properties/CommonQuality.ts diff --git a/crates/desktop/artcraft/src/core/api_adapters/mod.rs b/crates/desktop/artcraft/src/core/api_adapters/mod.rs index 9bc267ec50..c2bab7a158 100644 --- a/crates/desktop/artcraft/src/core/api_adapters/mod.rs +++ b/crates/desktop/artcraft/src/core/api_adapters/mod.rs @@ -1,2 +1,3 @@ pub mod aspect_ratio; -pub mod resolution; \ No newline at end of file +pub mod resolution; +pub mod quality; \ No newline at end of file diff --git a/crates/desktop/artcraft/src/core/api_adapters/quality/common_quality.rs b/crates/desktop/artcraft/src/core/api_adapters/quality/common_quality.rs new file mode 100644 index 0000000000..dfc83ed79b --- /dev/null +++ b/crates/desktop/artcraft/src/core/api_adapters/quality/common_quality.rs @@ -0,0 +1,21 @@ +use serde_derive::{Deserialize, Serialize}; +use artcraft_router::api::common_quality::CommonQuality as RouterCommonQuality; + +/// Just cargo culting this. might not be necessary for standalone types anymore +#[derive(Copy, Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum CommonQuality { + High, + Medium, + Low, +} + +impl CommonQuality { + pub fn to_artcraft_router_type(&self) -> RouterCommonQuality { + match self { + CommonQuality::High => RouterCommonQuality::High, + CommonQuality::Medium => RouterCommonQuality::Medium, + CommonQuality::Low => RouterCommonQuality::Low, + } + } +} diff --git a/crates/desktop/artcraft/src/core/api_adapters/quality/mod.rs b/crates/desktop/artcraft/src/core/api_adapters/quality/mod.rs new file mode 100644 index 0000000000..1f4f0aaad0 --- /dev/null +++ b/crates/desktop/artcraft/src/core/api_adapters/quality/mod.rs @@ -0,0 +1 @@ +pub mod common_quality; \ No newline at end of file diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/image_edit/enqueue_edit_image_command.rs b/crates/desktop/artcraft/src/core/commands/enqueue/image_edit/enqueue_edit_image_command.rs index aa815dd5a3..4dabe4b047 100644 --- a/crates/desktop/artcraft/src/core/commands/enqueue/image_edit/enqueue_edit_image_command.rs +++ b/crates/desktop/artcraft/src/core/commands/enqueue/image_edit/enqueue_edit_image_command.rs @@ -1,4 +1,5 @@ use crate::core::api_adapters::aspect_ratio::common_aspect_ratio::CommonAspectRatio; +use crate::core::api_adapters::quality::common_quality::CommonQuality; use crate::core::commands::enqueue::common::notify_frontend_of_errors::notify_frontend_of_errors; use crate::core::commands::enqueue::generate_error::{BadInputReason, GenerateError}; use crate::core::commands::enqueue::image_edit::artcraft::handle_image_edit_artcraft::handle_image_edit_artcraft; @@ -15,6 +16,8 @@ use crate::core::events::generation_events::generation_enqueue_failure_event::Ge use crate::core::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent; use crate::core::events::sendable_event_trait::SendableEvent; use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs; +use crate::core::state::artcraft_usage_tracker::artcraft_usage_tracker::ArtcraftUsageTracker; +use crate::core::state::artcraft_usage_tracker::artcraft_usage_type::{ArtcraftUsagePage, ArtcraftUsageType}; use crate::core::state::data_dir::app_data_root::AppDataRoot; use crate::core::state::data_dir::trait_data_subdir::DataSubdir; use crate::core::state::provider_priority::ProviderPriorityStore; @@ -24,6 +27,9 @@ use crate::core::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 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 enums::common::generation_provider::GenerationProvider; use enums::tauri::tasks::task_type::TaskType; use enums::tauri::ux::tauri_command_caller::TauriCommandCaller; @@ -36,13 +42,8 @@ use openai_sora_client::requests::image_gen::common::{ImageSize, NumImages}; use serde_derive::{Deserialize, Serialize}; use sqlite_tasks::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; -use crate::core::state::artcraft_usage_tracker::artcraft_usage_tracker::ArtcraftUsageTracker; -use crate::core::state::artcraft_usage_tracker::artcraft_usage_type::{ArtcraftUsagePage, ArtcraftUsageType}; /// This is used in the Tauri command bridge. /// Don't change the serializations without coordinating with the frontend. @@ -134,6 +135,10 @@ pub struct EnqueueEditImageCommand { /// Image resolution pub image_resolution: Option, + /// Quality. + /// Tends to be used by OpenAI models. + pub quality: Option, + /// OPTIONAL. /// Only for image angle edit models. pub horizontal_angle: Option, diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/image_inpaint/enqueue_image_inpaint_command.rs b/crates/desktop/artcraft/src/core/commands/enqueue/image_inpaint/enqueue_image_inpaint_command.rs index 6601f0c018..3cd2a0eb05 100644 --- a/crates/desktop/artcraft/src/core/commands/enqueue/image_inpaint/enqueue_image_inpaint_command.rs +++ b/crates/desktop/artcraft/src/core/commands/enqueue/image_inpaint/enqueue_image_inpaint_command.rs @@ -1,3 +1,4 @@ +use crate::core::api_adapters::quality::common_quality::CommonQuality; use crate::core::commands::enqueue::common::notify_frontend_of_errors::notify_frontend_of_errors; use crate::core::commands::enqueue::generate_error::{BadInputReason, GenerateError}; use crate::core::commands::enqueue::image_edit::image_edit_models::image_edit_model_to_model_type; @@ -14,6 +15,8 @@ use crate::core::events::generation_events::generation_enqueue_failure_event::Ge use crate::core::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent; use crate::core::events::sendable_event_trait::SendableEvent; use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs; +use crate::core::state::artcraft_usage_tracker::artcraft_usage_tracker::ArtcraftUsageTracker; +use crate::core::state::artcraft_usage_tracker::artcraft_usage_type::{ArtcraftUsagePage, ArtcraftUsageType}; use crate::core::state::data_dir::app_data_root::AppDataRoot; use crate::core::state::data_dir::trait_data_subdir::DataSubdir; use crate::core::state::provider_priority::ProviderPriorityStore; @@ -23,6 +26,9 @@ use crate::core::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 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 enums::common::generation_provider::GenerationProvider; use enums::tauri::ux::tauri_command_caller::TauriCommandCaller; use errors::AnyhowError; @@ -34,13 +40,8 @@ use openai_sora_client::requests::image_gen::common::{ImageSize, NumImages}; use serde_derive::{Deserialize, Serialize}; use sqlite_tasks::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; -use crate::core::state::artcraft_usage_tracker::artcraft_usage_tracker::ArtcraftUsageTracker; -use crate::core::state::artcraft_usage_tracker::artcraft_usage_type::{ArtcraftUsagePage, ArtcraftUsageType}; #[derive(Deserialize, Debug, Copy, Clone)] #[serde(rename_all = "snake_case")] @@ -95,6 +96,10 @@ pub struct EnqueueInpaintImageCommand { /// Number of images to generate. pub image_count: Option, + + /// Quality. + /// Tends to be used by OpenAI models. + pub quality: Option, /// If true, force the dimensions of the source image and mask image to match. pub require_matching_dimensions: Option, diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/artcraft/handle_text_to_image_artcraft_via_router.rs b/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/artcraft/handle_text_to_image_artcraft_via_router.rs index 80353ee2c7..9094a42422 100644 --- a/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/artcraft/handle_text_to_image_artcraft_via_router.rs +++ b/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/artcraft/handle_text_to_image_artcraft_via_router.rs @@ -11,6 +11,7 @@ use crate::services::storyteller::state::storyteller_credential_manager::Storyte use artcraft_router::api::common_aspect_ratio::CommonAspectRatio as RouterCommonAspectRatio; use artcraft_router::api::common_image_model::CommonImageModel; use artcraft_router::api::common_resolution::CommonResolution as RouterCommonResolution; +use artcraft_router::api::common_quality::CommonQuality as RouterCommonQuality; use artcraft_router::api::image_list_ref::ImageListRef; use artcraft_router::api::provider::Provider; use artcraft_router::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy; @@ -42,6 +43,7 @@ pub(super) async fn handle_text_to_image_artcraft_via_router( let aspect_ratio = get_aspect_ratio_t2i(request); let resolution = get_resolution_t2i(request); + let quality = get_quality_t2i(request); let router_request = GenerateImageRequest { model, @@ -50,7 +52,7 @@ pub(super) async fn handle_text_to_image_artcraft_via_router( image_inputs, resolution, aspect_ratio, - quality: None, // TODO: Add quality + quality, image_batch_count: request.number_images.map(|n| n as u16), request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade, generation_mode_mismatch_strategy: None, @@ -117,6 +119,10 @@ fn get_resolution_t2i(request: &EnqueueTextToImageRequest) -> Option Option { + request.quality.map(|quality| quality.to_artcraft_router_type()) +} + fn convert_desktop_aspect_ratio(ar: CommonAspectRatio2) -> RouterCommonAspectRatio { match ar { CommonAspectRatio2::Auto => RouterCommonAspectRatio::Auto, diff --git a/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/enqueue_text_to_image_command.rs b/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/enqueue_text_to_image_command.rs index 399695b9d6..771db3599d 100644 --- a/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/enqueue_text_to_image_command.rs +++ b/crates/desktop/artcraft/src/core/commands/enqueue/text_to_image/enqueue_text_to_image_command.rs @@ -1,4 +1,5 @@ use crate::core::api_adapters::aspect_ratio::common_aspect_ratio::CommonAspectRatio; +use crate::core::api_adapters::quality::common_quality::CommonQuality; use crate::core::api_adapters::resolution::common_resolution::CommonResolution; use crate::core::commands::enqueue::common::notify_frontend_of_errors::notify_frontend_of_errors; use crate::core::commands::enqueue::generate_error::{BadInputReason, GenerateError, MissingCredentialsReason}; @@ -101,6 +102,10 @@ pub struct EnqueueTextToImageRequest { /// Not all models support each of these resolutions, but we can choose or interpolate sensibly. pub common_resolution: Option, + /// Quality. + /// Tends to be used by OpenAI models. + pub quality: Option, + /// Aspect ratio. #[deprecated(note="use common_aspect_ratio")] pub aspect_ratio: Option, diff --git a/frontend/libs/model-list/src/lib/classes/ImageModel.ts b/frontend/libs/model-list/src/lib/classes/ImageModel.ts index 18762c1112..380ce8fa26 100644 --- a/frontend/libs/model-list/src/lib/classes/ImageModel.ts +++ b/frontend/libs/model-list/src/lib/classes/ImageModel.ts @@ -5,6 +5,7 @@ import { ModelTag } from "./metadata/ModelTag.js"; import { GenerationProvider } from "@storyteller/api-enums"; import { CommonAspectRatio } from "./properties/CommonAspectRatio.js"; import { CommonResolution } from "./properties/CommonResolution.js"; +import { CommonQuality } from "./properties/CommonQuality.js"; export class ImageModel extends Model { // Typescript type discriminator property @@ -57,6 +58,8 @@ export class ImageModel extends Model { readonly aspectRatios: CommonAspectRatio[]; readonly resolutions: CommonResolution[]; + + readonly qualityOptions: CommonQuality[]; // Aspect ratio to use as default when nothing is selected. // Otherwise, use `aspectRatios[0]` as default. @@ -66,6 +69,10 @@ export class ImageModel extends Model { // Otherwise, use `resolutions[0]` as default. readonly defaultResolution?: CommonResolution; + // Quality to use as default when nothing is selected. + // Otherwise, use `qualityOptions[0]` as default. + readonly defaultQuality?: CommonQuality; + constructor(args: { id: string; tauriId: string; @@ -92,8 +99,10 @@ export class ImageModel extends Model { providers?: GenerationProvider[]; aspectRatios?: CommonAspectRatio[]; resolutions?: CommonResolution[]; + qualityOptions?: CommonQuality[]; defaultAspectRatio?: CommonAspectRatio; defaultResolution?: CommonResolution; + defaultQuality?: CommonQuality; maxPromptLength?: number; }) { if (args.maxGenerationCount < 1) { @@ -122,8 +131,10 @@ export class ImageModel extends Model { this.canChangeAspectRatio = args.canChangeAspectRatio ?? false; this.aspectRatios = args.aspectRatios ?? []; this.resolutions = args.resolutions ?? []; + this.qualityOptions = args.qualityOptions ?? []; this.defaultAspectRatio = args.defaultAspectRatio ?? (args.aspectRatios && args.aspectRatios.length > 0 ? args.aspectRatios[0] : undefined); this.defaultResolution = args.defaultResolution ?? (args.resolutions && args.resolutions.length > 0 ? args.resolutions[0] : undefined); + this.defaultQuality = args.defaultQuality ?? (args.qualityOptions && args.qualityOptions.length > 0 ? args.qualityOptions[0] : undefined); } // If the model is a "Nano Banana"-type model, we may want to enable certain features. diff --git a/frontend/libs/model-list/src/lib/classes/properties/CommonQuality.ts b/frontend/libs/model-list/src/lib/classes/properties/CommonQuality.ts new file mode 100644 index 0000000000..8649837fe4 --- /dev/null +++ b/frontend/libs/model-list/src/lib/classes/properties/CommonQuality.ts @@ -0,0 +1,8 @@ +/// Common quality Tauri API +/// Not all models have each of these qualities, +/// but Tauri will interpolate if a mistake is sent. +export enum CommonQuality { + High = "high", + Medium = "medium", + Low = "low", +} \ No newline at end of file diff --git a/frontend/libs/model-list/src/lib/lists/ImageModels.ts b/frontend/libs/model-list/src/lib/lists/ImageModels.ts index 55f38287a9..ee7e928f4a 100644 --- a/frontend/libs/model-list/src/lib/lists/ImageModels.ts +++ b/frontend/libs/model-list/src/lib/lists/ImageModels.ts @@ -4,6 +4,7 @@ import { ModelCreator } from "../classes/metadata/ModelCreator.js"; import { ModelTag } from "../classes/metadata/ModelTag.js"; import { CommonAspectRatio } from "../classes/properties/CommonAspectRatio.js"; import { CommonResolution } from "../classes/properties/CommonResolution.js"; +import { CommonQuality } from "../classes/properties/CommonQuality.js"; // TODO: Some of the model configs, such as generation counts, are authoritatively controlled in `legacy/Models.ts` @@ -355,6 +356,12 @@ export const IMAGE_MODELS: ImageModel[] = [ CommonAspectRatio.TallNineBySixteen, CommonAspectRatio.WideFourByThree, CommonAspectRatio.WideSixteenByNine, + ], + defaultQuality: CommonQuality.High, + qualityOptions: [ + CommonQuality.High, + CommonQuality.Medium, + CommonQuality.Low, ] }), new ImageModel({