mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-08 11:01:35 +00:00
NBP via artcraft_router in Tauri; image cost estimates in tauri (#1075)
This commit is contained in:
1 parent
bc91785628
commit
aab8cbdfe1
16 files changed
+387
-298
No files matched your search
+20
@@ -0,0 +1,20 @@
|
||||
use crate::credentials::storyteller_credential_set::StorytellerCredentialSet;
|
||||
use crate::error::storyteller_error::StorytellerError;
|
||||
use crate::utils::api_host::ApiHost;
|
||||
use crate::utils::basic_json_post_request::basic_json_post_request;
|
||||
use artcraft_api_defs::generate::cost_estimate::estimate_image_cost::{
|
||||
EstimateImageCostRequest, EstimateImageCostResponse, ESTIMATE_IMAGE_COST_PATH,
|
||||
};
|
||||
|
||||
pub async fn estimate_image_cost(
|
||||
api_host: &ApiHost,
|
||||
maybe_creds: Option<&StorytellerCredentialSet>,
|
||||
request: EstimateImageCostRequest,
|
||||
) -> Result<EstimateImageCostResponse, StorytellerError> {
|
||||
Ok(basic_json_post_request(
|
||||
api_host,
|
||||
ESTIMATE_IMAGE_COST_PATH,
|
||||
maybe_creds,
|
||||
request,
|
||||
).await?)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
pub mod estimate_image_cost;
|
||||
+1
@@ -1 +1,2 @@
|
||||
pub mod image;
|
||||
pub mod video;
|
||||
@@ -19,7 +19,16 @@ pub async fn basic_json_post_request<Req: Serialize, Res: DeserializeOwned>(
|
||||
|
||||
let url = get_route(api_host, route_path);
|
||||
|
||||
info!("Requesting {:?}", &url);
|
||||
// NB: We record lightweight analytics telemetry to understand which areas
|
||||
// of the tool are useful and which models and services are important.
|
||||
let debug_log = url.ends_with("/v1/analytics/active_user_v2");
|
||||
|
||||
// Suppress "spammy" logs at the debug level.
|
||||
if debug_log {
|
||||
debug!("Requesting {:?}", &url);
|
||||
} else {
|
||||
info!("Requesting {:?}", &url);
|
||||
}
|
||||
|
||||
let client = Client::builder()
|
||||
.gzip(true)
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
use crate::core::commands::response::failure_response_wrapper::{CommandErrorResponseWrapper, CommandErrorStatus};
|
||||
use crate::core::commands::response::shorthand::ResponseOrError;
|
||||
use crate::core::commands::response::success_response_wrapper::SerializeMarker;
|
||||
use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs;
|
||||
use artcraft_api_defs::generate::cost_estimate::estimate_image_cost::{
|
||||
EstimateImageCostError, EstimateImageCostErrorType, EstimateImageCostRequest,
|
||||
EstimateImageCostResponse,
|
||||
};
|
||||
use log::info;
|
||||
use artcraft_client::endpoints::generate::cost_estimate::image::estimate_image_cost::estimate_image_cost;
|
||||
use tauri::State;
|
||||
|
||||
impl SerializeMarker for EstimateImageCostResponse {}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn estimate_image_cost_command(
|
||||
request: EstimateImageCostRequest,
|
||||
app_env_configs: State<'_, AppEnvConfigs>,
|
||||
) -> ResponseOrError<EstimateImageCostResponse, EstimateImageCostError> {
|
||||
info!("estimate_image_cost_command called");
|
||||
|
||||
let result = estimate_image_cost(
|
||||
&app_env_configs.storyteller_host,
|
||||
None, // Credentials are not required for this endpoint.
|
||||
request,
|
||||
)
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(response) => Ok(response.into()),
|
||||
Err(err) => Err(CommandErrorResponseWrapper {
|
||||
status: CommandErrorStatus::BadRequest,
|
||||
error_message: None,
|
||||
error_type: None,
|
||||
error_details: Some(EstimateImageCostError {
|
||||
success: false,
|
||||
error_type: EstimateImageCostErrorType::InvalidInput,
|
||||
error_message: err.to_string(),
|
||||
}),
|
||||
}),
|
||||
}
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
pub mod estimate_image_cost_command;
|
||||
pub mod estimate_video_cost_command;
|
||||
-148
@@ -1,148 +0,0 @@
|
||||
use crate::core::api_adapters::aspect_ratio::convert::aspect_ratio_to_artcraft_nano_banana_pro::aspect_ratio_to_artcraft_nano_banana_pro;
|
||||
use crate::core::commands::enqueue::generate_error::{BadInputReason, GenerateError};
|
||||
use crate::core::commands::enqueue::image_edit::enqueue_edit_image_command::ImageEditModel::NanoBanana;
|
||||
use crate::core::commands::enqueue::image_edit::enqueue_edit_image_command::{EditImageQuality, EditImageResolution, EditImageSize, EnqueueEditImageCommand};
|
||||
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
|
||||
use crate::core::commands::enqueue::text_to_image::enqueue_text_to_image_command::{EnqueueTextToImageRequest, TextToImageSize};
|
||||
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
|
||||
use crate::core::events::generation_events::common::{GenerationAction, GenerationModel, GenerationServiceProvider};
|
||||
use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent;
|
||||
use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs;
|
||||
use crate::core::state::data_dir::app_data_root::AppDataRoot;
|
||||
use crate::core::state::provider_priority::ProviderPriorityStore;
|
||||
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
|
||||
use crate::services::sora::state::sora_task_queue::SoraTaskQueue;
|
||||
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
|
||||
use anyhow::anyhow;
|
||||
use artcraft_api_defs::generate::image::edit::flux_pro_kontext_max_edit_image::{FluxProKontextMaxEditImageNumImages, FluxProKontextMaxEditImageRequest};
|
||||
use artcraft_api_defs::generate::image::edit::gemini_25_flash_edit_image::{Gemini25FlashEditImageNumImages, Gemini25FlashEditImageRequest};
|
||||
use artcraft_api_defs::generate::image::edit::gpt_image_1_edit_image::{GptImage1EditImageImageQuality, GptImage1EditImageImageSize, GptImage1EditImageNumImages, GptImage1EditImageRequest};
|
||||
use artcraft_api_defs::generate::image::multi_function::nano_banana_pro_multi_function_image_gen::{NanoBananaProMultiFunctionImageGenAspectRatio, NanoBananaProMultiFunctionImageGenImageResolution, NanoBananaProMultiFunctionImageGenNumImages, NanoBananaProMultiFunctionImageGenRequest};
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use enums::tauri::tasks::task_type::TaskType;
|
||||
use idempotency::uuid::generate_random_uuid;
|
||||
use log::{error, info};
|
||||
use artcraft_client::endpoints::generate::image::edit::flux_pro_kontext_max_edit_image::flux_pro_kontext_max_edit_image;
|
||||
use artcraft_client::endpoints::generate::image::edit::gemini_25_flash_edit_image::gemini_25_flash_edit_image;
|
||||
use artcraft_client::endpoints::generate::image::edit::gpt_image_1_edit_image::gpt_image_1_edit_image;
|
||||
use artcraft_client::endpoints::generate::image::multi_function::nano_banana_pro_multi_function_image_gen_image::nano_banana_pro_multi_function_image_gen;
|
||||
use tauri::AppHandle;
|
||||
|
||||
pub(super) const MAX_IMAGES: usize = 10;
|
||||
|
||||
pub async fn handle_artcraft_nano_banana_pro_edit(
|
||||
request: &EnqueueEditImageCommand,
|
||||
app: &AppHandle,
|
||||
app_data_root: &AppDataRoot,
|
||||
app_env_configs: &AppEnvConfigs,
|
||||
storyteller_creds_manager: &StorytellerCredentialManager,
|
||||
) -> Result<TaskEnqueueSuccess, GenerateError> {
|
||||
|
||||
let creds = match storyteller_creds_manager.get_credentials()? {
|
||||
Some(creds) => creds,
|
||||
None => {
|
||||
return Err(GenerateError::needs_storyteller_credentials());
|
||||
},
|
||||
};
|
||||
|
||||
info!("Calling Artcraft Nano Banana (edit) ...");
|
||||
|
||||
let uuid_idempotency_token = generate_random_uuid();
|
||||
|
||||
let num_images = match request.image_count {
|
||||
None => None,
|
||||
Some(1) => Some(NanoBananaProMultiFunctionImageGenNumImages::One),
|
||||
Some(2) => Some(NanoBananaProMultiFunctionImageGenNumImages::Two),
|
||||
Some(3) => Some(NanoBananaProMultiFunctionImageGenNumImages::Three),
|
||||
Some(4) => Some(NanoBananaProMultiFunctionImageGenNumImages::Four),
|
||||
Some(other) => {
|
||||
return Err(GenerateError::BadInput(BadInputReason::InvalidNumberOfRequestedImages {
|
||||
min: 1,
|
||||
max: 4,
|
||||
requested: other,
|
||||
}));
|
||||
},
|
||||
};
|
||||
|
||||
let aspect_ratio = get_aspect_ratio(request);
|
||||
|
||||
let resolution = request.image_resolution
|
||||
.map(|image_resolution| match image_resolution {
|
||||
EditImageResolution::OneK => NanoBananaProMultiFunctionImageGenImageResolution::OneK,
|
||||
EditImageResolution::TwoK => NanoBananaProMultiFunctionImageGenImageResolution::TwoK,
|
||||
EditImageResolution::FourK => NanoBananaProMultiFunctionImageGenImageResolution::FourK,
|
||||
});
|
||||
|
||||
let mut media_tokens = Vec::with_capacity(10);
|
||||
|
||||
if let Some(scene_image_media_token) = request.scene_image_media_token.clone() {
|
||||
media_tokens.push(scene_image_media_token);
|
||||
}
|
||||
|
||||
if let Some(image_media_tokens) = request.image_media_tokens.as_ref() {
|
||||
media_tokens.extend_from_slice(image_media_tokens);
|
||||
}
|
||||
|
||||
if media_tokens.len() > MAX_IMAGES {
|
||||
return Err(GenerateError::BadInput(BadInputReason::InvalidNumberOfInputImages {
|
||||
min: 1,
|
||||
max: MAX_IMAGES as u32,
|
||||
provided: media_tokens.len() as u32,
|
||||
}));
|
||||
}
|
||||
|
||||
let request = NanoBananaProMultiFunctionImageGenRequest {
|
||||
uuid_idempotency_token,
|
||||
prompt: Some(request.prompt.clone()),
|
||||
image_media_tokens: Some(media_tokens),
|
||||
num_images,
|
||||
resolution,
|
||||
aspect_ratio,
|
||||
};
|
||||
|
||||
let result = nano_banana_pro_multi_function_image_gen(
|
||||
&app_env_configs.storyteller_host,
|
||||
Some(&creds),
|
||||
request,
|
||||
).await;
|
||||
|
||||
let job_id = match result {
|
||||
Ok(enqueued) => {
|
||||
// TODO(bt,2025-07-05): Enqueue job token?
|
||||
info!("Successfully enqueued Artcraft Nano Banana. Job token: {}",
|
||||
enqueued.inference_job_token);
|
||||
enqueued.inference_job_token
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Failed to use Artcraft Nano Banana: {:?}", err);
|
||||
return Err(GenerateError::from(err));
|
||||
}
|
||||
};
|
||||
|
||||
Ok(TaskEnqueueSuccess {
|
||||
provider: GenerationProvider::Artcraft,
|
||||
model: Some(GenerationModel::NanoBananaPro),
|
||||
provider_job_id: Some(job_id.to_string()),
|
||||
task_type: TaskType::ImageGeneration,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_aspect_ratio(request: &EnqueueEditImageCommand) -> Option<NanoBananaProMultiFunctionImageGenAspectRatio> {
|
||||
if let Some(common_aspect_ratio) = request.common_aspect_ratio {
|
||||
// Handle modern aspect ratio
|
||||
let aspect = aspect_ratio_to_artcraft_nano_banana_pro(common_aspect_ratio);
|
||||
return Some(aspect);
|
||||
}
|
||||
|
||||
if let Some(aspect_ratio) = request.aspect_ratio {
|
||||
// Handle deprecated aspect ratio
|
||||
return match aspect_ratio {
|
||||
EditImageSize::Auto => Some(NanoBananaProMultiFunctionImageGenAspectRatio::Auto),
|
||||
EditImageSize::Square => Some(NanoBananaProMultiFunctionImageGenAspectRatio::OneByOne),
|
||||
EditImageSize::Wide => Some(NanoBananaProMultiFunctionImageGenAspectRatio::SixteenByNine),
|
||||
EditImageSize::Tall => Some(NanoBananaProMultiFunctionImageGenAspectRatio::NineBySixteen),
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
+4
-2
@@ -3,14 +3,16 @@ use crate::core::commands::enqueue::image_edit::artcraft::handle_artcraft_flux_k
|
||||
use crate::core::commands::enqueue::image_edit::artcraft::handle_artcraft_gpt_image_1_edit::handle_artcraft_gpt_image_1_edit;
|
||||
use crate::core::commands::enqueue::image_edit::artcraft::handle_artcraft_gpt_image_1p5_edit::handle_artcraft_gpt_image_1p5_edit;
|
||||
use crate::core::commands::enqueue::image_edit::artcraft::handle_artcraft_nano_banana_edit::handle_artcraft_nano_banana_edit;
|
||||
use crate::core::commands::enqueue::image_edit::artcraft::handle_artcraft_nano_banana_pro_edit::handle_artcraft_nano_banana_pro_edit;
|
||||
use crate::core::commands::enqueue::image_edit::artcraft::handle_image_edit_artcraft_via_router::handle_image_edit_artcraft_via_router;
|
||||
use crate::core::commands::enqueue::image_edit::artcraft::handle_artcraft_seedream_4_edit::handle_artcraft_seedream_4_edit;
|
||||
use crate::core::commands::enqueue::image_edit::artcraft::handle_artcraft_seedream_4p5_edit::handle_artcraft_seedream_4p5_edit;
|
||||
use crate::core::commands::enqueue::image_edit::enqueue_edit_image_command::{EnqueueEditImageCommand, ImageEditModel};
|
||||
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
|
||||
use crate::core::events::generation_events::common::GenerationModel;
|
||||
use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs;
|
||||
use crate::core::state::data_dir::app_data_root::AppDataRoot;
|
||||
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
|
||||
use artcraft_router::api::common_image_model::CommonImageModel;
|
||||
use tauri::AppHandle;
|
||||
|
||||
pub async fn handle_image_edit_artcraft(
|
||||
@@ -27,7 +29,7 @@ pub async fn handle_image_edit_artcraft(
|
||||
ImageEditModel::Gemini25Flash | ImageEditModel::NanoBanana => {
|
||||
handle_artcraft_nano_banana_edit( request, app, app_data_root, app_env_configs, storyteller_creds_manager).await
|
||||
},
|
||||
ImageEditModel::NanoBananaPro => handle_artcraft_nano_banana_pro_edit(request, app, app_data_root, app_env_configs, storyteller_creds_manager).await,
|
||||
ImageEditModel::NanoBananaPro => handle_image_edit_artcraft_via_router(request, app_env_configs, storyteller_creds_manager, CommonImageModel::NanaBananaPro, GenerationModel::NanoBananaPro).await,
|
||||
ImageEditModel::GptImage1 => handle_artcraft_gpt_image_1_edit(request, app, app_data_root, app_env_configs, storyteller_creds_manager).await,
|
||||
ImageEditModel::GptImage1p5 => handle_artcraft_gpt_image_1p5_edit(request, app, app_data_root, app_env_configs, storyteller_creds_manager).await,
|
||||
ImageEditModel::Seedream4 => handle_artcraft_seedream_4_edit(request, app, app_data_root, app_env_configs, storyteller_creds_manager).await,
|
||||
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
use crate::core::api_adapters::aspect_ratio::common_aspect_ratio::CommonAspectRatio as DesktopCommonAspectRatio;
|
||||
use crate::core::commands::enqueue::generate_error::{BadInputReason, GenerateError, MissingCredentialsReason};
|
||||
use crate::core::commands::enqueue::image_edit::enqueue_edit_image_command::{
|
||||
EditImageResolution, EditImageSize, EnqueueEditImageCommand,
|
||||
};
|
||||
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
|
||||
use crate::core::events::generation_events::common::GenerationModel;
|
||||
use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs;
|
||||
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
|
||||
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::image_list_ref::ImageListRef;
|
||||
use artcraft_router::api::provider::Provider;
|
||||
use artcraft_router::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use artcraft_router::client::router_artcraft_client::RouterArtcraftClient;
|
||||
use artcraft_router::client::router_client::RouterClient;
|
||||
use artcraft_router::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use enums::tauri::tasks::task_type::TaskType;
|
||||
use log::{error, info};
|
||||
|
||||
pub(super) const MAX_EDIT_IMAGES: usize = 10;
|
||||
|
||||
pub(super) async fn handle_image_edit_artcraft_via_router(
|
||||
request: &EnqueueEditImageCommand,
|
||||
app_env_configs: &AppEnvConfigs,
|
||||
storyteller_creds_manager: &StorytellerCredentialManager,
|
||||
model: CommonImageModel,
|
||||
generation_model: GenerationModel,
|
||||
) -> Result<TaskEnqueueSuccess, GenerateError> {
|
||||
let creds = match storyteller_creds_manager.get_credentials()? {
|
||||
Some(creds) => creds,
|
||||
None => return Err(GenerateError::MissingCredentials(MissingCredentialsReason::NeedsStorytellerCredentials)),
|
||||
};
|
||||
|
||||
let client = RouterClient::Artcraft(RouterArtcraftClient::new(
|
||||
app_env_configs.storyteller_host.clone(),
|
||||
creds,
|
||||
));
|
||||
|
||||
let mut media_tokens = Vec::with_capacity(MAX_EDIT_IMAGES);
|
||||
|
||||
if let Some(scene_token) = request.scene_image_media_token.clone() {
|
||||
media_tokens.push(scene_token);
|
||||
}
|
||||
if let Some(tokens) = request.image_media_tokens.as_ref() {
|
||||
media_tokens.extend_from_slice(tokens);
|
||||
}
|
||||
|
||||
if media_tokens.len() > MAX_EDIT_IMAGES {
|
||||
return Err(GenerateError::BadInput(BadInputReason::InvalidNumberOfInputImages {
|
||||
min: 1,
|
||||
max: MAX_EDIT_IMAGES as u32,
|
||||
provided: media_tokens.len() as u32,
|
||||
}));
|
||||
}
|
||||
|
||||
let image_inputs = if media_tokens.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(ImageListRef::MediaFileTokens(&media_tokens))
|
||||
};
|
||||
|
||||
let aspect_ratio = get_aspect_ratio_edit(request);
|
||||
let resolution = get_resolution_edit(request);
|
||||
|
||||
let router_request = GenerateImageRequest {
|
||||
model,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: Some(request.prompt.as_str()),
|
||||
image_inputs,
|
||||
resolution,
|
||||
aspect_ratio,
|
||||
image_batch_count: request.image_count.map(|n| n as u16),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
idempotency_token: None,
|
||||
};
|
||||
|
||||
let plan = router_request.build()?;
|
||||
|
||||
info!("Image Generation Plan: {:?}", plan);
|
||||
|
||||
let response = match plan.generate_image(&client).await {
|
||||
Ok(resp) => {
|
||||
info!("Successfully enqueued.");
|
||||
resp
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Failed to enqueue: {:?}", err);
|
||||
return Err(GenerateError::from(err));
|
||||
}
|
||||
};
|
||||
|
||||
let job_id = response
|
||||
.get_artcraft_payload()
|
||||
.map(|p| p.inference_job_token.to_string())
|
||||
.ok_or(GenerateError::ResponseHadNoJobTokens)?;
|
||||
|
||||
info!("Job token: {}", job_id);
|
||||
|
||||
Ok(TaskEnqueueSuccess {
|
||||
task_type: TaskType::ImageGeneration,
|
||||
model: Some(generation_model),
|
||||
provider: GenerationProvider::Artcraft,
|
||||
provider_job_id: Some(job_id),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_aspect_ratio_edit(request: &EnqueueEditImageCommand) -> Option<RouterCommonAspectRatio> {
|
||||
if let Some(ar) = request.common_aspect_ratio {
|
||||
return Some(convert_desktop_aspect_ratio(ar));
|
||||
}
|
||||
if let Some(ar) = request.aspect_ratio {
|
||||
return Some(match ar {
|
||||
EditImageSize::Auto => RouterCommonAspectRatio::Auto,
|
||||
EditImageSize::Square => RouterCommonAspectRatio::Square,
|
||||
EditImageSize::Wide => RouterCommonAspectRatio::Wide,
|
||||
EditImageSize::Tall => RouterCommonAspectRatio::Tall,
|
||||
});
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn get_resolution_edit(request: &EnqueueEditImageCommand) -> Option<RouterCommonResolution> {
|
||||
request.image_resolution.map(|res| match res {
|
||||
EditImageResolution::OneK => RouterCommonResolution::OneK,
|
||||
EditImageResolution::TwoK => RouterCommonResolution::TwoK,
|
||||
EditImageResolution::FourK => RouterCommonResolution::FourK,
|
||||
})
|
||||
}
|
||||
|
||||
fn convert_desktop_aspect_ratio(ar: DesktopCommonAspectRatio) -> RouterCommonAspectRatio {
|
||||
match ar {
|
||||
DesktopCommonAspectRatio::Auto => RouterCommonAspectRatio::Auto,
|
||||
DesktopCommonAspectRatio::Square => RouterCommonAspectRatio::Square,
|
||||
DesktopCommonAspectRatio::WideThreeByTwo => RouterCommonAspectRatio::WideThreeByTwo,
|
||||
DesktopCommonAspectRatio::WideFourByThree => RouterCommonAspectRatio::WideFourByThree,
|
||||
DesktopCommonAspectRatio::WideFiveByFour => RouterCommonAspectRatio::WideFiveByFour,
|
||||
DesktopCommonAspectRatio::WideSixteenByNine => RouterCommonAspectRatio::WideSixteenByNine,
|
||||
DesktopCommonAspectRatio::WideTwentyOneByNine => RouterCommonAspectRatio::WideTwentyOneByNine,
|
||||
DesktopCommonAspectRatio::TallTwoByThree => RouterCommonAspectRatio::TallTwoByThree,
|
||||
DesktopCommonAspectRatio::TallThreeByFour => RouterCommonAspectRatio::TallThreeByFour,
|
||||
DesktopCommonAspectRatio::TallFourByFive => RouterCommonAspectRatio::TallFourByFive,
|
||||
DesktopCommonAspectRatio::TallNineBySixteen => RouterCommonAspectRatio::TallNineBySixteen,
|
||||
DesktopCommonAspectRatio::TallNineByTwentyOne => RouterCommonAspectRatio::TallNineByTwentyOne,
|
||||
DesktopCommonAspectRatio::Wide => RouterCommonAspectRatio::Wide,
|
||||
DesktopCommonAspectRatio::Tall => RouterCommonAspectRatio::Tall,
|
||||
DesktopCommonAspectRatio::Auto2k => RouterCommonAspectRatio::Auto2k,
|
||||
DesktopCommonAspectRatio::Auto4k => RouterCommonAspectRatio::Auto4k,
|
||||
DesktopCommonAspectRatio::SquareHd => RouterCommonAspectRatio::SquareHd,
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
mod handle_image_edit_artcraft_via_router;
|
||||
mod handle_artcraft_flux_kontext_edit;
|
||||
mod handle_artcraft_gpt_image_1_edit;
|
||||
mod handle_artcraft_gpt_image_1p5_edit;
|
||||
mod handle_artcraft_nano_banana_edit;
|
||||
mod handle_artcraft_nano_banana_pro_edit;
|
||||
mod handle_artcraft_seedream_4_edit;
|
||||
mod handle_artcraft_seedream_4p5_edit;
|
||||
|
||||
|
||||
-141
@@ -1,141 +0,0 @@
|
||||
use crate::core::api_adapters::aspect_ratio::common_aspect_ratio::CommonAspectRatio;
|
||||
use crate::core::api_adapters::aspect_ratio::convert::aspect_ratio_to_artcraft_nano_banana_pro::aspect_ratio_to_artcraft_nano_banana_pro;
|
||||
use crate::core::api_adapters::resolution::common_resolution::CommonResolution;
|
||||
use crate::core::api_adapters::resolution::convert::resolution_to_artcraft_nano_banana_pro::resolution_to_artcraft_nano_banana_pro;
|
||||
use crate::core::commands::enqueue::generate_error::{BadInputReason, GenerateError, MissingCredentialsReason, ProviderFailureReason};
|
||||
use crate::core::commands::enqueue::image_edit::enqueue_edit_image_command::{EditImageQuality, EditImageResolution, EditImageSize};
|
||||
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
|
||||
use crate::core::commands::enqueue::text_to_image::enqueue_text_to_image_command::{EnqueueTextToImageRequest, TextToImageResolution, TextToImageSize};
|
||||
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
|
||||
use crate::core::events::generation_events::common::{GenerationAction, GenerationModel, GenerationServiceProvider};
|
||||
use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent;
|
||||
use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs;
|
||||
use crate::core::state::data_dir::app_data_root::AppDataRoot;
|
||||
use crate::core::state::provider_priority::ProviderPriorityStore;
|
||||
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_api_defs::generate::image::edit::gemini_25_flash_edit_image::{Gemini25FlashEditImageNumImages, Gemini25FlashEditImageRequest};
|
||||
use artcraft_api_defs::generate::image::multi_function::nano_banana_pro_multi_function_image_gen::{NanoBananaProMultiFunctionImageGenAspectRatio, NanoBananaProMultiFunctionImageGenImageResolution, NanoBananaProMultiFunctionImageGenNumImages, NanoBananaProMultiFunctionImageGenRequest};
|
||||
use artcraft_api_defs::generate::image::text::generate_gpt_image_1_text_to_image::{GenerateGptImage1TextToImageImageQuality, GenerateGptImage1TextToImageImageSize, GenerateGptImage1TextToImageNumImages, GenerateGptImage1TextToImageRequest};
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use enums::tauri::tasks::task_type::TaskType;
|
||||
use idempotency::uuid::generate_random_uuid;
|
||||
use log::{error, info};
|
||||
use openai_sora_client::recipes::maybe_upgrade_or_renew_session::maybe_upgrade_or_renew_session;
|
||||
use openai_sora_client::recipes::simple_image_gen_with_session_auto_renew::{simple_image_gen_with_session_auto_renew, SimpleImageGenAutoRenewRequest};
|
||||
use openai_sora_client::requests::image_gen::common::{ImageSize, NumImages};
|
||||
use std::time::Duration;
|
||||
use artcraft_client::endpoints::generate::image::edit::gemini_25_flash_edit_image::gemini_25_flash_edit_image;
|
||||
use artcraft_client::endpoints::generate::image::multi_function::nano_banana_pro_multi_function_image_gen_image::nano_banana_pro_multi_function_image_gen;
|
||||
use tauri::AppHandle;
|
||||
|
||||
pub async fn handle_artcraft_nano_banana_pro_text_to_image(
|
||||
request: &EnqueueTextToImageRequest,
|
||||
app_env_configs: &AppEnvConfigs,
|
||||
storyteller_creds_manager: &StorytellerCredentialManager,
|
||||
) -> Result<TaskEnqueueSuccess, GenerateError> {
|
||||
|
||||
let creds = match storyteller_creds_manager.get_credentials()? {
|
||||
Some(creds) => creds,
|
||||
None => {
|
||||
return Err(GenerateError::MissingCredentials(MissingCredentialsReason::NeedsStorytellerCredentials));
|
||||
},
|
||||
};
|
||||
|
||||
info!("Calling Artcraft Nano Banana Pro...");
|
||||
|
||||
let uuid_idempotency_token = generate_random_uuid();
|
||||
|
||||
let num_images = match request.number_images {
|
||||
None => None,
|
||||
Some(1) => Some(NanoBananaProMultiFunctionImageGenNumImages::One),
|
||||
Some(2) => Some(NanoBananaProMultiFunctionImageGenNumImages::Two),
|
||||
Some(3) => Some(NanoBananaProMultiFunctionImageGenNumImages::Three),
|
||||
Some(4) => Some(NanoBananaProMultiFunctionImageGenNumImages::Four),
|
||||
Some(other) => {
|
||||
return Err(GenerateError::BadInput(BadInputReason::InvalidNumberOfRequestedImages {
|
||||
min: 1,
|
||||
max: 4,
|
||||
requested: other,
|
||||
}));
|
||||
},
|
||||
};
|
||||
|
||||
let aspect_ratio = get_aspect_ratio(request);
|
||||
let resolution = get_resolution(request);
|
||||
|
||||
let request = NanoBananaProMultiFunctionImageGenRequest {
|
||||
uuid_idempotency_token,
|
||||
prompt: request.prompt.clone(),
|
||||
image_media_tokens: request.image_media_tokens.clone(),
|
||||
num_images,
|
||||
resolution,
|
||||
aspect_ratio,
|
||||
};
|
||||
|
||||
info!("Calling Artcraft with request {:?}", request);
|
||||
|
||||
let result = nano_banana_pro_multi_function_image_gen(
|
||||
&app_env_configs.storyteller_host,
|
||||
Some(&creds),
|
||||
request,
|
||||
).await;
|
||||
|
||||
let job_id = match result {
|
||||
Ok(enqueued) => {
|
||||
// TODO(bt,2025-07-05): Enqueue job token?
|
||||
info!("Successfully enqueued Artcraft Nano Banana. Job token: {}",
|
||||
enqueued.inference_job_token);
|
||||
enqueued.inference_job_token
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Failed to use Artcraft Nano Banana: {:?}", err);
|
||||
return Err(GenerateError::ProviderFailure(ProviderFailureReason::StorytellerError(err)));
|
||||
}
|
||||
};
|
||||
|
||||
Ok(TaskEnqueueSuccess {
|
||||
provider: GenerationProvider::Artcraft,
|
||||
model: Some(GenerationModel::NanoBananaPro),
|
||||
provider_job_id: Some(job_id.to_string()),
|
||||
task_type: TaskType::ImageGeneration,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_aspect_ratio(request: &EnqueueTextToImageRequest) -> Option<NanoBananaProMultiFunctionImageGenAspectRatio> {
|
||||
if let Some(common_aspect_ratio) = request.common_aspect_ratio {
|
||||
// Handle modern aspect ratio
|
||||
let aspect = aspect_ratio_to_artcraft_nano_banana_pro(common_aspect_ratio);
|
||||
return Some(aspect);
|
||||
}
|
||||
|
||||
if let Some(aspect_ratio) = request.aspect_ratio {
|
||||
// Handle deprecated aspect ratio
|
||||
return match aspect_ratio {
|
||||
TextToImageSize::Auto => Some(NanoBananaProMultiFunctionImageGenAspectRatio::Auto),
|
||||
TextToImageSize::Square => Some(NanoBananaProMultiFunctionImageGenAspectRatio::OneByOne),
|
||||
TextToImageSize::Wide => Some(NanoBananaProMultiFunctionImageGenAspectRatio::SixteenByNine),
|
||||
TextToImageSize::Tall => Some(NanoBananaProMultiFunctionImageGenAspectRatio::NineBySixteen),
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn get_resolution(request: &EnqueueTextToImageRequest) -> Option<NanoBananaProMultiFunctionImageGenImageResolution> {
|
||||
if let Some(common_resolution) = request.common_resolution {
|
||||
return Some(resolution_to_artcraft_nano_banana_pro(common_resolution));
|
||||
}
|
||||
|
||||
if let Some(resolution) = request.image_resolution {
|
||||
// Deprecated resolution
|
||||
return Some(match resolution {
|
||||
TextToImageResolution::OneK => NanoBananaProMultiFunctionImageGenImageResolution::OneK,
|
||||
TextToImageResolution::TwoK => NanoBananaProMultiFunctionImageGenImageResolution::TwoK,
|
||||
TextToImageResolution::FourK => NanoBananaProMultiFunctionImageGenImageResolution::FourK,
|
||||
})
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
+4
-2
@@ -6,15 +6,17 @@ use crate::core::commands::enqueue::text_to_image::artcraft::handle_artcraft_flu
|
||||
use crate::core::commands::enqueue::text_to_image::artcraft::handle_artcraft_flux_pro_1p1_ultra_text_to_image::handle_artcraft_flux_pro_1p1_ultra_text_to_image;
|
||||
use crate::core::commands::enqueue::text_to_image::artcraft::handle_artcraft_gpt_image_1_text_to_image::handle_artcraft_gpt_image_1_text_to_image;
|
||||
use crate::core::commands::enqueue::text_to_image::artcraft::handle_artcraft_gpt_image_1p5_text_to_image::handle_artcraft_gpt_image_1p5_text_to_image;
|
||||
use crate::core::commands::enqueue::text_to_image::artcraft::handle_artcraft_nano_banana_pro_text_to_image::handle_artcraft_nano_banana_pro_text_to_image;
|
||||
use crate::core::commands::enqueue::text_to_image::artcraft::handle_text_to_image_artcraft_via_router::handle_text_to_image_artcraft_via_router;
|
||||
use crate::core::commands::enqueue::text_to_image::artcraft::handle_artcraft_nano_banana_text_to_image::handle_artcraft_nano_banana_text_to_image;
|
||||
use crate::core::commands::enqueue::text_to_image::artcraft::handle_artcraft_seedream_4_text_to_image::handle_artcraft_seedream_4_text_to_image;
|
||||
use crate::core::commands::enqueue::text_to_image::artcraft::handle_artcraft_seedream_4p5_text_to_image::handle_artcraft_seedream_4p5_text_to_image;
|
||||
use crate::core::commands::enqueue::text_to_image::enqueue_text_to_image_command::{EnqueueTextToImageRequest, TextToImageModel};
|
||||
use crate::core::commands::enqueue::text_to_image::text_to_image_models::text_to_image_model_to_model_type;
|
||||
use crate::core::events::generation_events::common::GenerationModel;
|
||||
use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs;
|
||||
use crate::core::state::data_dir::app_data_root::AppDataRoot;
|
||||
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
|
||||
use artcraft_router::api::common_image_model::CommonImageModel;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use tauri::AppHandle;
|
||||
|
||||
@@ -46,7 +48,7 @@ pub async fn handle_text_to_image_artcraft(
|
||||
TextToImageModel::Gemini25Flash | TextToImageModel::NanoBanana => {
|
||||
handle_artcraft_nano_banana_text_to_image(request, app_env_configs, storyteller_creds_manager).await
|
||||
},
|
||||
TextToImageModel::NanoBananaPro => handle_artcraft_nano_banana_pro_text_to_image(request, app_env_configs, storyteller_creds_manager).await,
|
||||
TextToImageModel::NanoBananaPro => handle_text_to_image_artcraft_via_router(request, app_env_configs, storyteller_creds_manager, CommonImageModel::NanaBananaPro, GenerationModel::NanoBananaPro).await,
|
||||
TextToImageModel::Seedream4 => handle_artcraft_seedream_4_text_to_image(request, app_env_configs, storyteller_creds_manager).await,
|
||||
TextToImageModel::Seedream4p5 => handle_artcraft_seedream_4p5_text_to_image(request, app_env_configs, storyteller_creds_manager).await,
|
||||
}
|
||||
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
use crate::core::api_adapters::aspect_ratio::common_aspect_ratio::CommonAspectRatio as CommonAspectRatio2;
|
||||
use crate::core::api_adapters::resolution::common_resolution::CommonResolution as CommonResolution2;
|
||||
use crate::core::commands::enqueue::generate_error::{GenerateError, MissingCredentialsReason};
|
||||
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
|
||||
use crate::core::commands::enqueue::text_to_image::enqueue_text_to_image_command::{
|
||||
EnqueueTextToImageRequest, TextToImageResolution, TextToImageSize,
|
||||
};
|
||||
use crate::core::events::generation_events::common::GenerationModel;
|
||||
use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs;
|
||||
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
|
||||
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::image_list_ref::ImageListRef;
|
||||
use artcraft_router::api::provider::Provider;
|
||||
use artcraft_router::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use artcraft_router::client::router_artcraft_client::RouterArtcraftClient;
|
||||
use artcraft_router::client::router_client::RouterClient;
|
||||
use artcraft_router::generate::generate_image::generate_image_request::GenerateImageRequest;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use enums::tauri::tasks::task_type::TaskType;
|
||||
use log::{error, info};
|
||||
|
||||
pub(super) async fn handle_text_to_image_artcraft_via_router(
|
||||
request: &EnqueueTextToImageRequest,
|
||||
app_env_configs: &AppEnvConfigs,
|
||||
storyteller_creds_manager: &StorytellerCredentialManager,
|
||||
model: CommonImageModel,
|
||||
generation_model: GenerationModel,
|
||||
) -> Result<TaskEnqueueSuccess, GenerateError> {
|
||||
let creds = match storyteller_creds_manager.get_credentials()? {
|
||||
Some(creds) => creds,
|
||||
None => return Err(GenerateError::MissingCredentials(MissingCredentialsReason::NeedsStorytellerCredentials)),
|
||||
};
|
||||
|
||||
let client = RouterClient::Artcraft(RouterArtcraftClient::new(
|
||||
app_env_configs.storyteller_host.clone(),
|
||||
creds,
|
||||
));
|
||||
|
||||
let image_inputs = request.image_media_tokens.as_ref().map(ImageListRef::MediaFileTokens);
|
||||
|
||||
let aspect_ratio = get_aspect_ratio_t2i(request);
|
||||
let resolution = get_resolution_t2i(request);
|
||||
|
||||
let router_request = GenerateImageRequest {
|
||||
model,
|
||||
provider: Provider::Artcraft,
|
||||
prompt: request.prompt.as_deref(),
|
||||
image_inputs,
|
||||
resolution,
|
||||
aspect_ratio,
|
||||
image_batch_count: request.number_images.map(|n| n as u16),
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
idempotency_token: None,
|
||||
};
|
||||
|
||||
let plan = router_request.build()?;
|
||||
|
||||
info!("Image Generation Plan: {:?}", plan);
|
||||
|
||||
let response = match plan.generate_image(&client).await {
|
||||
Ok(resp) => {
|
||||
info!("Successfully enqueued.");
|
||||
resp
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Failed to enqueue: {:?}", err);
|
||||
return Err(GenerateError::from(err));
|
||||
}
|
||||
};
|
||||
|
||||
let job_id = response
|
||||
.get_artcraft_payload()
|
||||
.map(|p| p.inference_job_token.to_string())
|
||||
.ok_or(GenerateError::ResponseHadNoJobTokens)?;
|
||||
|
||||
Ok(TaskEnqueueSuccess {
|
||||
task_type: TaskType::ImageGeneration,
|
||||
model: Some(generation_model),
|
||||
provider: GenerationProvider::Artcraft,
|
||||
provider_job_id: Some(job_id),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_aspect_ratio_t2i(request: &EnqueueTextToImageRequest) -> Option<RouterCommonAspectRatio> {
|
||||
if let Some(ar) = request.common_aspect_ratio {
|
||||
return Some(convert_desktop_aspect_ratio(ar));
|
||||
}
|
||||
if let Some(ar) = request.aspect_ratio {
|
||||
return Some(match ar {
|
||||
TextToImageSize::Auto => RouterCommonAspectRatio::Auto,
|
||||
TextToImageSize::Square => RouterCommonAspectRatio::Square,
|
||||
TextToImageSize::Wide => RouterCommonAspectRatio::Wide,
|
||||
TextToImageSize::Tall => RouterCommonAspectRatio::Tall,
|
||||
});
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn get_resolution_t2i(request: &EnqueueTextToImageRequest) -> Option<RouterCommonResolution> {
|
||||
if let Some(res) = request.common_resolution {
|
||||
return Some(convert_desktop_resolution(res));
|
||||
}
|
||||
if let Some(res) = request.image_resolution {
|
||||
return Some(match res {
|
||||
TextToImageResolution::OneK => RouterCommonResolution::OneK,
|
||||
TextToImageResolution::TwoK => RouterCommonResolution::TwoK,
|
||||
TextToImageResolution::FourK => RouterCommonResolution::FourK,
|
||||
});
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn convert_desktop_aspect_ratio(ar: CommonAspectRatio2) -> RouterCommonAspectRatio {
|
||||
match ar {
|
||||
CommonAspectRatio2::Auto => RouterCommonAspectRatio::Auto,
|
||||
CommonAspectRatio2::Square => RouterCommonAspectRatio::Square,
|
||||
CommonAspectRatio2::WideThreeByTwo => RouterCommonAspectRatio::WideThreeByTwo,
|
||||
CommonAspectRatio2::WideFourByThree => RouterCommonAspectRatio::WideFourByThree,
|
||||
CommonAspectRatio2::WideFiveByFour => RouterCommonAspectRatio::WideFiveByFour,
|
||||
CommonAspectRatio2::WideSixteenByNine => RouterCommonAspectRatio::WideSixteenByNine,
|
||||
CommonAspectRatio2::WideTwentyOneByNine => RouterCommonAspectRatio::WideTwentyOneByNine,
|
||||
CommonAspectRatio2::TallTwoByThree => RouterCommonAspectRatio::TallTwoByThree,
|
||||
CommonAspectRatio2::TallThreeByFour => RouterCommonAspectRatio::TallThreeByFour,
|
||||
CommonAspectRatio2::TallFourByFive => RouterCommonAspectRatio::TallFourByFive,
|
||||
CommonAspectRatio2::TallNineBySixteen => RouterCommonAspectRatio::TallNineBySixteen,
|
||||
CommonAspectRatio2::TallNineByTwentyOne => RouterCommonAspectRatio::TallNineByTwentyOne,
|
||||
CommonAspectRatio2::Wide => RouterCommonAspectRatio::Wide,
|
||||
CommonAspectRatio2::Tall => RouterCommonAspectRatio::Tall,
|
||||
CommonAspectRatio2::Auto2k => RouterCommonAspectRatio::Auto2k,
|
||||
CommonAspectRatio2::Auto4k => RouterCommonAspectRatio::Auto4k,
|
||||
CommonAspectRatio2::SquareHd => RouterCommonAspectRatio::SquareHd,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_desktop_resolution(res: CommonResolution2) -> RouterCommonResolution {
|
||||
match res {
|
||||
CommonResolution2::OneK => RouterCommonResolution::OneK,
|
||||
CommonResolution2::TwoK => RouterCommonResolution::TwoK,
|
||||
CommonResolution2::ThreeK => RouterCommonResolution::ThreeK,
|
||||
CommonResolution2::FourK => RouterCommonResolution::FourK,
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
pub (super) mod handle_text_to_image_artcraft;
|
||||
|
||||
mod handle_text_to_image_artcraft_via_router;
|
||||
mod handle_artcraft_gpt_image_1_text_to_image;
|
||||
mod handle_artcraft_gpt_image_1p5_text_to_image;
|
||||
mod handle_artcraft_nano_banana_pro_text_to_image;
|
||||
mod handle_artcraft_nano_banana_text_to_image;
|
||||
mod handle_artcraft_seedream_4_text_to_image;
|
||||
mod handle_artcraft_seedream_4p5_text_to_image;
|
||||
|
||||
@@ -13,7 +13,7 @@ use enums::tauri::tasks::task_model_type::TaskModelType;
|
||||
use enums::tauri::tasks::task_status::TaskStatus;
|
||||
use enums::tauri::tasks::task_type::TaskType;
|
||||
use errors::AnyhowResult;
|
||||
use log::{error, info, warn};
|
||||
use log::{debug, error, info, warn};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use sqlite_tasks::queries::list_tasks_for_frontend::list_tasks_for_frontend;
|
||||
use artcraft_client::endpoints::media_files::delete_media_file::delete_media_file;
|
||||
@@ -72,7 +72,8 @@ pub async fn get_task_queue_command(
|
||||
task_database: State<'_, TaskDatabase>,
|
||||
) -> ResponseOrErrorMessage<GetTaskQueueCommandResponse> {
|
||||
|
||||
info!("get_task_queue_command called");
|
||||
// NB: This is debug because it spams the logs.
|
||||
debug!("get_task_queue_command called");
|
||||
|
||||
let result = handle_request(
|
||||
&task_database,
|
||||
|
||||
@@ -6,6 +6,7 @@ use tauri::Manager;
|
||||
|
||||
use crate::core::commands::app_preferences::get_app_preferences_command::get_app_preferences_command;
|
||||
use crate::core::commands::app_preferences::update_app_preference_command::update_app_preferences_command;
|
||||
use crate::core::commands::cost_estimate::estimate_image_cost_command::estimate_image_cost_command;
|
||||
use crate::core::commands::cost_estimate::estimate_video_cost_command::estimate_video_cost_command;
|
||||
use crate::core::commands::download::download_directory_reveal_command::download_directory_reveal_command;
|
||||
use crate::core::commands::download::download_media_file_command::download_media_file_command;
|
||||
@@ -212,6 +213,7 @@ pub fn run() {
|
||||
enqueue_image_to_gaussian_command,
|
||||
enqueue_image_to_video_command,
|
||||
enqueue_text_to_image_command,
|
||||
estimate_image_cost_command,
|
||||
estimate_video_cost_command,
|
||||
flip_image,
|
||||
get_app_info_command,
|
||||
|
||||
Reference in new issue
Block a user