mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 17:38:10 +00:00
refactor, move handlers
This commit is contained in:
1 parent
fbb65df591
commit
04ffb75de9
12 files changed
+46
-548
No files matched your search
-129
@@ -1,129 +0,0 @@
|
||||
use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_image_cost_and_generate_request::OmniGenImageCostAndGenerateRequest;
|
||||
use artcraft_client::endpoints::omni_gen::generate::image::omni_gen_image::omni_gen_image_generate;
|
||||
use enums::common::generation::common_image_model::CommonImageModel;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use enums::tauri::tasks::task_type::TaskType;
|
||||
use log::{error, info};
|
||||
|
||||
use crate::core::commands::enqueue::generate_error::{GenerateError, MissingCredentialsReason};
|
||||
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
|
||||
use crate::core::commands::generate::generate_image::tauri_generate_image_request::TauriGenerateImageRequest;
|
||||
use crate::core::commands::generate::generate_image::tauri_image_model::TauriImageModel;
|
||||
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;
|
||||
|
||||
pub async fn handle_artcraft_via_omni_endpoint(
|
||||
request: &TauriGenerateImageRequest,
|
||||
app_env_configs: &AppEnvConfigs,
|
||||
storyteller_creds_manager: &StorytellerCredentialManager,
|
||||
) -> Result<TaskEnqueueSuccess, GenerateError> {
|
||||
let model = request.model.ok_or(GenerateError::no_model_specified())?;
|
||||
|
||||
let omni_model = map_to_common_image_model(model)
|
||||
.ok_or(GenerateError::NotYetImplemented(
|
||||
format!("Model {:?} is not supported via the omni endpoint", model),
|
||||
))?;
|
||||
|
||||
let generation_model = map_to_generation_model(model);
|
||||
|
||||
let creds = match storyteller_creds_manager.get_credentials()? {
|
||||
Some(creds) => creds,
|
||||
None => return Err(GenerateError::MissingCredentials(MissingCredentialsReason::NeedsStorytellerCredentials)),
|
||||
};
|
||||
|
||||
// Build the omni gen request.
|
||||
let mut image_media_tokens = request.image_media_tokens.clone().unwrap_or_default();
|
||||
|
||||
// Prepend canvas image if present.
|
||||
if let Some(canvas_token) = &request.canvas_image_media_token {
|
||||
image_media_tokens.insert(0, canvas_token.clone());
|
||||
}
|
||||
|
||||
let image_media_tokens = if image_media_tokens.is_empty() { None } else { Some(image_media_tokens) };
|
||||
|
||||
let omni_request = OmniGenImageCostAndGenerateRequest {
|
||||
idempotency_token: None,
|
||||
model: Some(omni_model),
|
||||
prompt: request.prompt.clone(),
|
||||
image_media_tokens,
|
||||
resolution: None, // TODO: Convert from request.resolution
|
||||
aspect_ratio: None, // TODO: Convert from request.aspect_ratio
|
||||
quality: request.quality,
|
||||
image_batch_count: request.batch_size.map(|n| n as u16),
|
||||
adjust_horizontal_angle: request.adjust_horizontal_angle,
|
||||
adjust_vertical_angle: request.adjust_vertical_angle,
|
||||
adjust_zoom: request.adjust_zoom,
|
||||
};
|
||||
|
||||
info!("Sending image generation via omni endpoint: model={:?}", omni_model);
|
||||
|
||||
let response = omni_gen_image_generate(
|
||||
&app_env_configs.storyteller_host,
|
||||
Some(&creds),
|
||||
omni_request,
|
||||
).await.map_err(|err| {
|
||||
error!("Omni image generation failed: {:?}", err);
|
||||
GenerateError::from(err)
|
||||
})?;
|
||||
|
||||
info!("Omni image generation succeeded: job_token={}", response.inference_job_token.as_str());
|
||||
|
||||
Ok(TaskEnqueueSuccess {
|
||||
task_type: TaskType::ImageGeneration,
|
||||
model: Some(generation_model),
|
||||
provider: GenerationProvider::Artcraft,
|
||||
provider_job_id: Some(response.inference_job_token.to_string()),
|
||||
})
|
||||
}
|
||||
|
||||
// ── Model mapping helpers ──
|
||||
|
||||
fn map_to_common_image_model(model: TauriImageModel) -> Option<CommonImageModel> {
|
||||
match model {
|
||||
TauriImageModel::Flux1Dev => Some(CommonImageModel::Flux1Dev),
|
||||
TauriImageModel::Flux1Schnell => Some(CommonImageModel::Flux1Schnell),
|
||||
TauriImageModel::FluxPro11 => Some(CommonImageModel::FluxPro11),
|
||||
TauriImageModel::FluxPro11Ultra => Some(CommonImageModel::FluxPro11Ultra),
|
||||
TauriImageModel::Gemini25Flash => Some(CommonImageModel::NanoBanana), // NB: Alias for Nano Banana
|
||||
TauriImageModel::GptImage1 => Some(CommonImageModel::GptImage1),
|
||||
TauriImageModel::GptImage1p5 => Some(CommonImageModel::GptImage1p5),
|
||||
TauriImageModel::GptImage2 => Some(CommonImageModel::GptImage2),
|
||||
TauriImageModel::NanoBanana => Some(CommonImageModel::NanoBanana),
|
||||
TauriImageModel::NanoBanana2 => Some(CommonImageModel::NanoBanana2),
|
||||
TauriImageModel::NanoBananaPro => Some(CommonImageModel::NanoBananaPro),
|
||||
TauriImageModel::Seedream4 => Some(CommonImageModel::Seedream4),
|
||||
TauriImageModel::Seedream4p5 => Some(CommonImageModel::Seedream4p5),
|
||||
TauriImageModel::Seedream5Lite => Some(CommonImageModel::Seedream5Lite),
|
||||
// Models not in CommonImageModel (Grok, Recraft, Midjourney, edit-only, inpaint-only)
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_to_generation_model(model: TauriImageModel) -> GenerationModel {
|
||||
match model {
|
||||
TauriImageModel::Flux1Dev => GenerationModel::Flux1Dev,
|
||||
TauriImageModel::Flux1Schnell => GenerationModel::Flux1Schnell,
|
||||
TauriImageModel::Flux2LoraAngles => GenerationModel::Flux2LoraAngles,
|
||||
TauriImageModel::FluxDevJuggernaut => GenerationModel::FluxDevJuggernaut,
|
||||
TauriImageModel::FluxPro1 => GenerationModel::FluxPro1,
|
||||
TauriImageModel::FluxPro11 => GenerationModel::FluxPro11,
|
||||
TauriImageModel::FluxPro11Ultra => GenerationModel::FluxPro11Ultra,
|
||||
TauriImageModel::FluxProKontextMax => GenerationModel::FluxProKontextMax,
|
||||
TauriImageModel::Gemini25Flash => GenerationModel::NanoBanana, // NB: Alias for Nano Banana
|
||||
TauriImageModel::GptImage1 => GenerationModel::GptImage1,
|
||||
TauriImageModel::GptImage1p5 => GenerationModel::GptImage1p5,
|
||||
TauriImageModel::GptImage2 => GenerationModel::GptImage2,
|
||||
TauriImageModel::GrokImage => GenerationModel::GrokImage,
|
||||
TauriImageModel::NanoBanana => GenerationModel::NanoBanana,
|
||||
TauriImageModel::NanoBanana2 => GenerationModel::NanoBanana2,
|
||||
TauriImageModel::NanoBananaPro => GenerationModel::NanoBananaPro,
|
||||
TauriImageModel::QwenEdit2511Angles => GenerationModel::QwenEdit2511Angles,
|
||||
TauriImageModel::Seedream4 => GenerationModel::Seedream4,
|
||||
TauriImageModel::Seedream4p5 => GenerationModel::Seedream4p5,
|
||||
TauriImageModel::Seedream5Lite => GenerationModel::Seedream5Lite,
|
||||
// TODO:
|
||||
TauriImageModel::Midjourney => GenerationModel::Flux1Dev, // Fallback
|
||||
TauriImageModel::Recraft3 => GenerationModel::Flux1Dev, // Fallback
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub(super) mod handle_artcraft_via_omni_endpoint;
|
||||
@@ -1,92 +0,0 @@
|
||||
use crate::core::api_adapters::aspect_ratio::convert::aspect_ratio_to_grok_image::aspect_ratio_to_grok_image;
|
||||
use crate::core::commands::enqueue::generate_error::GenerateError;
|
||||
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::generation_events::common::GenerationModel;
|
||||
use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs;
|
||||
use crate::services::grok::state::grok_credential_manager::GrokCredentialManager;
|
||||
use crate::services::grok::state::grok_image_prompt_queue::{GrokImagePromptQueue, PromptItem};
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use enums::tauri::tasks::task_type::TaskType;
|
||||
use grok_client::requests::image_websocket::messages::websocket_client_message::ClientMessageAspectRatio;
|
||||
use uuid_utils::uuid::generate_random_uuid;
|
||||
use tauri::AppHandle;
|
||||
|
||||
pub async fn handle_grok(
|
||||
app: &AppHandle,
|
||||
request: &EnqueueTextToImageRequest,
|
||||
app_env_configs: &AppEnvConfigs,
|
||||
creds_manager: &GrokCredentialManager,
|
||||
grok_image_prompt_queue: &GrokImagePromptQueue,
|
||||
) -> Result<TaskEnqueueSuccess, GenerateError> {
|
||||
|
||||
|
||||
//// TODO: We can request population of the user info if absent or expired.
|
||||
//let websocket = get_websocket(
|
||||
// app,
|
||||
// creds_manager,
|
||||
// websocket_manager,
|
||||
//).await?;
|
||||
//
|
||||
//let _result = prompt_websocket_image(PromptWebsocketImageArgs {
|
||||
// websocket_wrapped: &websocket,
|
||||
// prompt: request.prompt.as_deref().unwrap_or_else(||""),
|
||||
//}).await?;
|
||||
//
|
||||
//let request_id = listen_for_websocket_request_id(ListenForWebsocketRequestIdArgs {
|
||||
// websocket: &websocket,
|
||||
// timeout: Duration::from_millis(10_000),
|
||||
//}).await?;
|
||||
//
|
||||
//let request_id = match request_id.request_id {
|
||||
// Some(request_id) => request_id.to_string(),
|
||||
// None => {
|
||||
// warn!("No request id from Grok image generation (websocket)");
|
||||
// return Err(GenerateError::ProviderFailure(ProviderFailureReason::GrokJobEnqueueFailed));
|
||||
// }
|
||||
//};
|
||||
//
|
||||
//info!("Successfully enqueued MidJourney. Job token: {}", request_id);
|
||||
|
||||
let job_id = generate_random_uuid();
|
||||
|
||||
let prompt = request.prompt
|
||||
.as_deref()
|
||||
.map(|prompt| prompt.trim().to_string())
|
||||
.unwrap_or_else(|| "".to_string());
|
||||
|
||||
let aspect_ratio = get_aspect_ratio(request);
|
||||
|
||||
grok_image_prompt_queue.enqueue(PromptItem {
|
||||
task_id: job_id.clone(),
|
||||
prompt,
|
||||
aspect_ratio: aspect_ratio.unwrap_or(ClientMessageAspectRatio::Square),
|
||||
})?;
|
||||
|
||||
Ok(TaskEnqueueSuccess {
|
||||
provider: GenerationProvider::Grok,
|
||||
model: Some(GenerationModel::GrokImage),
|
||||
provider_job_id: Some(job_id),
|
||||
task_type: TaskType::ImageGeneration,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_aspect_ratio(request: &EnqueueTextToImageRequest) -> Option<ClientMessageAspectRatio> {
|
||||
if let Some(common_aspect_ratio) = request.common_aspect_ratio {
|
||||
// Handle modern aspect ratio
|
||||
let aspect = aspect_ratio_to_grok_image(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(ClientMessageAspectRatio::Square),
|
||||
TextToImageSize::Square => Some(ClientMessageAspectRatio::Square),
|
||||
TextToImageSize::Wide => Some(ClientMessageAspectRatio::WideThreeByTwo),
|
||||
TextToImageSize::Tall => Some(ClientMessageAspectRatio::TallTwoByThree),
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub (super) mod handle_grok;
|
||||
-140
@@ -1,140 +0,0 @@
|
||||
use crate::core::commands::enqueue::generate_error::{GenerateError, MissingCredentialsReason, ProviderFailureReason};
|
||||
use crate::core::commands::enqueue::image_edit::enqueue_edit_image_command::{EditImageQuality, EditImageSize};
|
||||
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::functional_events::canvas_background_removal_complete_event::CanvasBackgroundRemovalCompleteEvent;
|
||||
use crate::core::events::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
|
||||
use crate::core::events::generation_events::common::{GenerationAction, GenerationModel, GenerationServiceProvider};
|
||||
use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent;
|
||||
use crate::core::events::warning_events::flash_user_input_error_event::FlashUserInputErrorEvent;
|
||||
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::midjourney::state::midjourney_credential_manager::MidjourneyCredentialManager;
|
||||
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::common::generation_provider::GenerationProvider;
|
||||
use enums::tauri::tasks::task_type::TaskType;
|
||||
use uuid_utils::uuid::generate_random_uuid;
|
||||
use log::{error, info};
|
||||
use midjourney_client::client::midjourney_hostname::MidjourneyHostname;
|
||||
use midjourney_client::endpoints::submit_job::{submit_job, SubmitJobRequest};
|
||||
use midjourney_client::error::midjourney_api_error::MidjourneyApiError;
|
||||
use midjourney_client::recipes::channel_id::ChannelId;
|
||||
use midjourney_client::recipes::text_to_image::{text_to_image, TextToImageError, TextToImageRequest};
|
||||
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 tauri::AppHandle;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
pub async fn handle_midjourney(
|
||||
app: &AppHandle,
|
||||
request: &EnqueueTextToImageRequest,
|
||||
app_env_configs: &AppEnvConfigs,
|
||||
mj_creds_manager: &MidjourneyCredentialManager,
|
||||
) -> Result<TaskEnqueueSuccess, GenerateError> {
|
||||
|
||||
let creds = match mj_creds_manager.maybe_copy_cookie_store() {
|
||||
Ok(Some(creds)) => creds,
|
||||
Ok(None) => {
|
||||
error!("Midjourney credentials not found.");
|
||||
ShowProviderLoginModalEvent::send_for_provider(GenerationProvider::Midjourney, &app);
|
||||
return Err(GenerateError::needs_midjourney_credentials());
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Error reading Midjourney credentials: {:?}", err);
|
||||
ShowProviderLoginModalEvent::send_for_provider(GenerationProvider::Midjourney, &app);
|
||||
return Err(GenerateError::needs_midjourney_credentials());
|
||||
},
|
||||
};
|
||||
|
||||
// TODO: We can request population of the user info if absent or expired.
|
||||
|
||||
let user_info = match mj_creds_manager.maybe_copy_user_info() {
|
||||
Ok(Some(user_info)) => user_info,
|
||||
Ok(None) => {
|
||||
return Err(GenerateError::MissingCredentials(MissingCredentialsReason::NeedsMidjourneyUserInfo));
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Error reading Midjourney user info: {:?}", err);
|
||||
return Err(GenerateError::MissingCredentials(MissingCredentialsReason::NeedsMidjourneyUserInfo));
|
||||
},
|
||||
};
|
||||
|
||||
let channel_id = match user_info.user_id {
|
||||
Some(user_id) => ChannelId::UserId(user_id),
|
||||
None => {
|
||||
error!("Midjourney user info does not contain a user ID.");
|
||||
return Err(GenerateError::MissingCredentials(MissingCredentialsReason::NeedsMidjourneyUserId));
|
||||
}
|
||||
};
|
||||
|
||||
info!("Calling midjourney ...");
|
||||
|
||||
let cookie_header = creds.to_cookie_string();
|
||||
|
||||
let prompt = request.prompt
|
||||
.as_deref()
|
||||
.unwrap_or("");
|
||||
|
||||
let result = text_to_image(TextToImageRequest {
|
||||
prompt,
|
||||
channel_id: &channel_id,
|
||||
hostname: MidjourneyHostname::Standard,
|
||||
cookie_header,
|
||||
}).await;
|
||||
|
||||
let result = match result {
|
||||
Ok(result) => result,
|
||||
Err(err) => {
|
||||
error!("Failed to use MidJourney: {:?}", err);
|
||||
return Err(GenerateError::from(err));
|
||||
}
|
||||
};
|
||||
|
||||
let job_id = match result.maybe_job_id {
|
||||
Some(job_id) => job_id,
|
||||
None => {
|
||||
error!("Failed to enqueue MidJourney: No job ID returned.");
|
||||
return handle_midjourney_errors(app, result.maybe_errors);
|
||||
}
|
||||
};
|
||||
|
||||
info!("Successfully enqueued MidJourney. Job token: {}", job_id);
|
||||
|
||||
Ok(TaskEnqueueSuccess {
|
||||
provider: GenerationProvider::Midjourney,
|
||||
model: Some(GenerationModel::Midjourney),
|
||||
provider_job_id: Some(job_id),
|
||||
task_type: TaskType::ImageGeneration,
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_midjourney_errors(
|
||||
app: &AppHandle,
|
||||
maybe_errors: Option<Vec<TextToImageError>>
|
||||
) -> Result<TaskEnqueueSuccess, GenerateError> {
|
||||
if let Some(errors) = maybe_errors {
|
||||
if !errors.is_empty() {
|
||||
let messages: Vec<String> = errors.iter()
|
||||
.map(|e| format!("{:?}", e))
|
||||
.collect();
|
||||
|
||||
let combined_message = messages.join("; ");
|
||||
|
||||
let event = FlashUserInputErrorEvent {
|
||||
message: format!("Midjourney Error: {}", combined_message),
|
||||
};
|
||||
|
||||
if let Err(err) = event.send(&app) {
|
||||
error!("Failed to send FlashUserInputErrorEvent: {:?}", err); // Fail open
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(GenerateError::ProviderFailure(ProviderFailureReason::MidjourneyJobEnqueueFailed))
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub (super) mod handle_midjourney;
|
||||
@@ -1,4 +1,3 @@
|
||||
mod artcraft;
|
||||
pub mod generate_image_command;
|
||||
pub mod providers;
|
||||
pub mod tauri_generate_image_request;
|
||||
|
||||
+45
-24
@@ -3,47 +3,37 @@ use artcraft_client::endpoints::omni_gen::generate::image::omni_gen_image::omni_
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use enums::tauri::tasks::task_type::TaskType;
|
||||
use log::{error, info};
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
use uuid_utils::uuid::generate_random_uuid;
|
||||
use crate::core::commands::enqueue::generate_error::{GenerateError, MissingCredentialsReason};
|
||||
use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet;
|
||||
use crate::core::commands::enqueue::generate_error::GenerateError;
|
||||
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
|
||||
use crate::core::commands::generate::generate_image::providers::artcraft::model_mapping::{
|
||||
map_to_generation_model, map_to_omni_aspect_ratio, map_to_omni_image_model, map_to_omni_resolution,
|
||||
};
|
||||
use crate::core::api_adapters::models::image::tauri_image_model_to_enums_model::tauri_image_model_to_enums_model;
|
||||
use crate::core::api_adapters::models::image::tauri_image_model_to_generation_model::tauri_image_model_to_generation_model;
|
||||
use crate::core::commands::generate::generate_image::tauri_generate_image_request::TauriGenerateImageRequest;
|
||||
use crate::core::commands::generate::generate_image::utils::parse_semantic_media_files::SemanticMediaFiles;
|
||||
use crate::core::state::app_env_configs::app_env_configs::AppEnvConfigs;
|
||||
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
|
||||
|
||||
pub async fn handle_artcraft_via_omni_endpoint(
|
||||
request: &TauriGenerateImageRequest,
|
||||
semantic_media_files: &SemanticMediaFiles,
|
||||
creds: &StorytellerCredentialSet,
|
||||
app_env_configs: &AppEnvConfigs,
|
||||
storyteller_creds_manager: &StorytellerCredentialManager,
|
||||
) -> Result<TaskEnqueueSuccess, GenerateError> {
|
||||
let tauri_model = request.model.ok_or(GenerateError::no_model_specified())?;
|
||||
|
||||
let omni_model = map_to_omni_image_model(tauri_model)
|
||||
let omni_api_model = tauri_image_model_to_enums_model(tauri_model)
|
||||
.ok_or(GenerateError::NotYetImplemented(
|
||||
format!("Model {:?} is not supported via the omni endpoint", tauri_model),
|
||||
))?;
|
||||
|
||||
let generation_model = map_to_generation_model(tauri_model);
|
||||
|
||||
let creds = match storyteller_creds_manager.get_credentials()? {
|
||||
Some(creds) => creds,
|
||||
None => return Err(GenerateError::MissingCredentials(MissingCredentialsReason::NeedsStorytellerCredentials)),
|
||||
};
|
||||
|
||||
let uuid_idempotency_token = generate_random_uuid();
|
||||
|
||||
// Build image_media_tokens: prepend canvas image if present.
|
||||
let mut image_media_tokens = request.image_media_tokens.clone().unwrap_or_default();
|
||||
if let Some(canvas_token) = &request.canvas_image_media_token {
|
||||
image_media_tokens.insert(0, canvas_token.clone());
|
||||
}
|
||||
let image_media_tokens = if image_media_tokens.is_empty() { None } else { Some(image_media_tokens) };
|
||||
|
||||
let image_media_tokens = get_image_media_tokens(request, semantic_media_files);
|
||||
|
||||
let omni_request = OmniGenImageCostAndGenerateRequest {
|
||||
idempotency_token: Some(uuid_idempotency_token),
|
||||
model: Some(omni_model),
|
||||
model: Some(omni_api_model),
|
||||
prompt: request.prompt.clone(),
|
||||
image_media_tokens,
|
||||
resolution: request.resolution,
|
||||
@@ -55,11 +45,11 @@ pub async fn handle_artcraft_via_omni_endpoint(
|
||||
adjust_zoom: request.adjust_zoom,
|
||||
};
|
||||
|
||||
info!("Sending image generation via omni endpoint: model={:?}", omni_model);
|
||||
info!("Sending image generation via omni endpoint: model={:?}", omni_api_model);
|
||||
|
||||
let response = omni_gen_image_generate(
|
||||
&app_env_configs.storyteller_host,
|
||||
Some(&creds),
|
||||
Some(creds),
|
||||
omni_request,
|
||||
).await.map_err(|err| {
|
||||
error!("Omni image generation failed: {:?}", err);
|
||||
@@ -68,6 +58,8 @@ pub async fn handle_artcraft_via_omni_endpoint(
|
||||
|
||||
info!("Omni image generation succeeded: job_token={}", response.inference_job_token.as_str());
|
||||
|
||||
let generation_model = tauri_image_model_to_generation_model(tauri_model);
|
||||
|
||||
Ok(TaskEnqueueSuccess {
|
||||
task_type: TaskType::ImageGeneration,
|
||||
model: Some(generation_model),
|
||||
@@ -75,3 +67,32 @@ pub async fn handle_artcraft_via_omni_endpoint(
|
||||
provider_job_id: Some(response.inference_job_token.to_string()),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_image_media_tokens(
|
||||
request: &TauriGenerateImageRequest,
|
||||
semantic_media_files: &SemanticMediaFiles,
|
||||
) -> Option<Vec<MediaFileToken>> {
|
||||
let num_images = request.image_media_tokens.as_deref()
|
||||
.map(|t| t.len())
|
||||
.unwrap_or(0);
|
||||
|
||||
let mut image_media_tokens = Vec::with_capacity(num_images + 2);
|
||||
|
||||
if let Some(canvas_token) = &semantic_media_files.canvas_image_media_token {
|
||||
image_media_tokens.push(canvas_token.clone());
|
||||
}
|
||||
|
||||
if let Some(scene_token) = &semantic_media_files.scene_image_media_token {
|
||||
image_media_tokens.push(scene_token.clone());
|
||||
}
|
||||
|
||||
if let Some(media_tokens) = &request.image_media_tokens {
|
||||
image_media_tokens.extend(media_tokens.clone());
|
||||
}
|
||||
|
||||
if image_media_tokens.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(image_media_tokens)
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
mod handle_artcraft;
|
||||
mod handle_artcraft_via_legacy;
|
||||
mod handle_artcraft_via_omni_endpoint;
|
||||
mod model_mapping;
|
||||
mod legacy;
|
||||
|
||||
pub use handle_artcraft::handle_artcraft;
|
||||
-135
@@ -1,135 +0,0 @@
|
||||
use crate::core::api_adapters::aspect_ratio::convert::aspect_ratio_to_grok_image::aspect_ratio_to_grok_image;
|
||||
use crate::core::api_adapters::aspect_ratio::convert::aspect_ratio_to_sora_native_gpt_image_1::aspect_ratio_to_sora_native_gpt_image_1;
|
||||
use crate::core::commands::enqueue::generate_error::GenerateError;
|
||||
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::functional_events::show_provider_login_modal_event::ShowProviderLoginModalEvent;
|
||||
use crate::core::events::generation_events::common::{GenerationAction, GenerationModel, GenerationServiceProvider};
|
||||
use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent;
|
||||
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
|
||||
use crate::services::sora::state::sora_task_queue::SoraTaskQueue;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use enums::tauri::tasks::task_type::TaskType;
|
||||
use errors::AnyhowResult;
|
||||
use grok_client::requests::image_websocket::messages::websocket_client_message::ClientMessageAspectRatio;
|
||||
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 tauri::AppHandle;
|
||||
|
||||
const SORA_SIMPLE_IMAGE_GEN_TIMEOUT : Duration = Duration::from_millis(1000 * 30); // 30 seconds
|
||||
|
||||
pub async fn handle_gpt_image_1_sora_text_to_image(
|
||||
request: &EnqueueTextToImageRequest,
|
||||
app: &AppHandle,
|
||||
sora_creds_manager: &SoraCredentialManager,
|
||||
sora_task_queue: &SoraTaskQueue,
|
||||
) -> Result<TaskEnqueueSuccess, GenerateError> {
|
||||
|
||||
let mut creds = match sora_creds_manager.get_credentials() {
|
||||
Ok(Some(creds)) => creds,
|
||||
Ok(None) => {
|
||||
error!("Sora credentials not found.");
|
||||
ShowProviderLoginModalEvent::send_for_provider(GenerationProvider::Sora, &app);
|
||||
return Err(GenerateError::needs_sora_credentials());
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Error reading Sora credentials: {:?}", err);
|
||||
ShowProviderLoginModalEvent::send_for_provider(GenerationProvider::Sora, &app);
|
||||
return Err(GenerateError::needs_sora_credentials());
|
||||
}
|
||||
};
|
||||
|
||||
let credential_updated = maybe_upgrade_or_renew_session(&mut creds)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Failed to upgrade or renew session: {:?}", err);
|
||||
err
|
||||
})?;
|
||||
|
||||
if credential_updated {
|
||||
info!("Storing updated credentials");
|
||||
sora_creds_manager.set_credentials(&creds)?;
|
||||
}
|
||||
|
||||
let prompt = request.prompt.as_deref().unwrap_or("");
|
||||
|
||||
let aspect_ratio = get_aspect_ratio(request)
|
||||
.unwrap_or(ImageSize::Square);
|
||||
|
||||
let num_images = match request.number_images {
|
||||
None => NumImages::One,
|
||||
Some(1) => NumImages::One,
|
||||
Some(2) => NumImages::Two,
|
||||
Some(3) => NumImages::Two, // NB: There is no option for three images!
|
||||
Some(4) => NumImages::Four,
|
||||
_ => NumImages::One,
|
||||
};
|
||||
|
||||
let result =
|
||||
simple_image_gen_with_session_auto_renew(SimpleImageGenAutoRenewRequest {
|
||||
prompt: prompt.to_string(),
|
||||
num_images,
|
||||
image_size: aspect_ratio,
|
||||
credentials: &creds,
|
||||
request_timeout: Some(SORA_SIMPLE_IMAGE_GEN_TIMEOUT),
|
||||
}).await;
|
||||
|
||||
let (response, maybe_new_creds) =
|
||||
match result {
|
||||
Ok((response, maybe_new_creds)) => (response, maybe_new_creds),
|
||||
Err(err) => {
|
||||
let event = GenerationEnqueueFailureEvent {
|
||||
action: GenerationAction::GenerateImage,
|
||||
service: GenerationServiceProvider::Sora,
|
||||
model: None,
|
||||
reason: None,
|
||||
};
|
||||
|
||||
if let Err(err) = event.send(app) {
|
||||
error!("Failed to emit event: {:?}", err); // Fail open.
|
||||
}
|
||||
|
||||
return Err(GenerateError::from(err));
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(new_creds) = maybe_new_creds {
|
||||
info!("Storing updated credentials.");
|
||||
sora_creds_manager.set_credentials(&new_creds)?;
|
||||
}
|
||||
|
||||
info!("New Sora Task ID: {:?} ", response.task_id);
|
||||
|
||||
sora_task_queue.insert(&response.task_id)?;
|
||||
|
||||
Ok(TaskEnqueueSuccess {
|
||||
provider: GenerationProvider::Sora,
|
||||
task_type: TaskType::ImageGeneration,
|
||||
model: Some(GenerationModel::GptImage1),
|
||||
provider_job_id: Some(response.task_id.to_string()),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_aspect_ratio(request: &EnqueueTextToImageRequest) -> Option<ImageSize> {
|
||||
if let Some(common_aspect_ratio) = request.common_aspect_ratio {
|
||||
// Handle modern aspect ratio
|
||||
let aspect = aspect_ratio_to_sora_native_gpt_image_1(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(ImageSize::Square),
|
||||
TextToImageSize::Square => Some(ImageSize::Square),
|
||||
TextToImageSize::Wide => Some(ImageSize::Wide),
|
||||
TextToImageSize::Tall => Some(ImageSize::Tall),
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
use crate::core::commands::enqueue::generate_error::GenerateError;
|
||||
use crate::core::commands::enqueue::task_enqueue_success::TaskEnqueueSuccess;
|
||||
use crate::core::commands::enqueue::text_to_image::enqueue_text_to_image_command::EnqueueTextToImageRequest;
|
||||
use crate::core::commands::generate::generate_image::sora::handle_gpt_image_1_sora_text_to_image::handle_gpt_image_1_sora_text_to_image;
|
||||
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
|
||||
use crate::services::sora::state::sora_task_queue::SoraTaskQueue;
|
||||
use tauri::AppHandle;
|
||||
|
||||
pub async fn handle_text_to_image_sora(
|
||||
request: &EnqueueTextToImageRequest,
|
||||
app: &AppHandle,
|
||||
sora_creds_manager: &SoraCredentialManager,
|
||||
sora_task_queue: &SoraTaskQueue,
|
||||
) -> Result<TaskEnqueueSuccess, GenerateError> {
|
||||
handle_gpt_image_1_sora_text_to_image(
|
||||
request,
|
||||
app,
|
||||
sora_creds_manager,
|
||||
sora_task_queue,
|
||||
).await
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
pub (super) mod handle_text_to_image_sora;
|
||||
mod handle_gpt_image_1_sora_text_to_image;
|
||||
Reference in new issue
Block a user