better events (#646)

This commit is contained in:
Brandon Thomas
2025-05-29 05:03:32 -04:00
committed by GitHub
parent 9cf87cda5b
commit ab72551ee7
43 changed files with 781 additions and 535 deletions
+13 -4
View File
@@ -1,6 +1,15 @@
{
"files.exclude": {
"**/*~": true,
"frontend_old/**": true
}
"files.exclude": {
"**/*~": true,
".sqlx/**": true,
"_elasticsearch/**": true,
"_sql/**": true,
"frontend_old/**": true,
"includes/**": true,
"target/**": true,
"test_data/**": true,
"tmp/**": true,
"virtualenv/**": true,
"windows_dlls/**": true,
}
}
Generated
+47 -47
View File
@@ -12,7 +12,7 @@ dependencies = [
"actix-rt",
"actix_derive",
"bitflags 2.5.0",
"bytes 1.10.0",
"bytes 1.10.1",
"crossbeam-channel",
"futures-core",
"futures-sink",
@@ -34,7 +34,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a"
dependencies = [
"bitflags 2.5.0",
"bytes 1.10.0",
"bytes 1.10.1",
"futures-core",
"futures-sink",
"memchr",
@@ -73,7 +73,7 @@ dependencies = [
"base64 0.22.1",
"bitflags 2.5.0",
"brotli 6.0.0",
"bytes 1.10.0",
"bytes 1.10.1",
"bytestring",
"derive_more 0.99.17",
"encoding_rs",
@@ -117,7 +117,7 @@ dependencies = [
"actix-multipart-derive",
"actix-utils",
"actix-web",
"bytes 1.10.0",
"bytes 1.10.1",
"derive_more 0.99.17",
"futures-core",
"futures-util",
@@ -226,7 +226,7 @@ dependencies = [
"actix-utils",
"actix-web-codegen",
"ahash 0.8.11",
"bytes 1.10.0",
"bytes 1.10.1",
"bytestring",
"cfg-if 1.0.0",
"cookie 0.16.2",
@@ -261,7 +261,7 @@ dependencies = [
"actix-codec",
"actix-http",
"actix-web",
"bytes 1.10.0",
"bytes 1.10.1",
"bytestring",
"futures-core",
"pin-project-lite",
@@ -296,7 +296,7 @@ dependencies = [
"ahash 0.8.11",
"arc-swap",
"async-trait",
"bytes 1.10.0",
"bytes 1.10.1",
"bytestring",
"csv",
"derive_more 0.99.17",
@@ -650,7 +650,7 @@ dependencies = [
"anyhow",
"base64 0.22.1",
"build_metadata",
"bytes 1.10.0",
"bytes 1.10.1",
"chrono",
"directories",
"dirs",
@@ -1057,7 +1057,7 @@ dependencies = [
"async-trait",
"axum-core",
"bitflags 1.3.2",
"bytes 1.10.0",
"bytes 1.10.1",
"futures-util",
"http 0.2.11",
"http-body 0.4.6",
@@ -1083,7 +1083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c"
dependencies = [
"async-trait",
"bytes 1.10.0",
"bytes 1.10.1",
"futures-util",
"http 0.2.11",
"http-body 0.4.6",
@@ -1595,9 +1595,9 @@ dependencies = [
[[package]]
name = "bytes"
version = "1.10.0"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
dependencies = [
"serde",
]
@@ -1608,7 +1608,7 @@ version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
]
[[package]]
@@ -1947,7 +1947,7 @@ version = "4.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"memchr",
]
@@ -3165,7 +3165,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40d9bd57d914cc66ce878f098f63ed7b5d5b64c30644a5adb950b008f874a6c6"
dependencies = [
"base64 0.11.0",
"bytes 1.10.0",
"bytes 1.10.1",
"dyn-clone",
"lazy_static",
"percent-encoding",
@@ -4316,7 +4316,7 @@ version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"fnv",
"futures-core",
"futures-sink",
@@ -4336,7 +4336,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab"
dependencies = [
"atomic-waker",
"bytes 1.10.0",
"bytes 1.10.1",
"fnv",
"futures-core",
"futures-sink",
@@ -4546,7 +4546,7 @@ version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"fnv",
"itoa 1.0.11",
]
@@ -4557,7 +4557,7 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"fnv",
"itoa 1.0.11",
]
@@ -4568,7 +4568,7 @@ version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"http 0.2.11",
"pin-project-lite",
]
@@ -4579,7 +4579,7 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"http 1.1.0",
]
@@ -4589,7 +4589,7 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"futures-util",
"http 1.1.0",
"http-body 1.0.0",
@@ -4658,7 +4658,7 @@ version = "0.14.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"futures-channel",
"futures-core",
"futures-util",
@@ -4682,7 +4682,7 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"futures-channel",
"futures-util",
"h2 0.4.5",
@@ -4733,7 +4733,7 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"hyper 0.14.28",
"native-tls",
"tokio",
@@ -4746,7 +4746,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"http-body-util",
"hyper 1.6.0",
"hyper-util",
@@ -4762,7 +4762,7 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"futures-channel",
"futures-util",
"http 1.1.0",
@@ -6201,7 +6201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9ef834d5ed55e494a2ae350220314dc4aacd1c43a9498b00e320e0ea352a5c3"
dependencies = [
"byteorder",
"bytes 1.10.0",
"bytes 1.10.1",
"num-rational",
"serde",
"serde_json",
@@ -7603,7 +7603,7 @@ version = "0.12.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"prost-derive",
]
@@ -7755,7 +7755,7 @@ version = "0.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"pin-project-lite",
"quinn-proto",
"quinn-udp",
@@ -7773,7 +7773,7 @@ version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"rand 0.8.5",
"ring",
"rustc-hash",
@@ -8068,7 +8068,7 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6435842fc2fea44b528719eb8c32203bbc1bb2f5b619fbe0c0a3d8350fd8d2a8"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"futures 0.3.31",
"pin-project-lite",
]
@@ -8246,7 +8246,7 @@ checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
dependencies = [
"async-compression",
"base64 0.21.7",
"bytes 1.10.0",
"bytes 1.10.1",
"encoding_rs",
"futures-core",
"futures-util",
@@ -8288,7 +8288,7 @@ checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb"
dependencies = [
"async-compression",
"base64 0.22.1",
"bytes 1.10.0",
"bytes 1.10.1",
"cookie 0.18.1",
"cookie_store",
"encoding_rs",
@@ -8412,7 +8412,7 @@ checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b"
dependencies = [
"bitvec",
"bytecheck",
"bytes 1.10.0",
"bytes 1.10.1",
"hashbrown 0.12.3",
"ptr_meta",
"rend",
@@ -8551,7 +8551,7 @@ dependencies = [
"aws-creds",
"aws-region",
"base64 0.22.1",
"bytes 1.10.0",
"bytes 1.10.1",
"cfg-if 1.0.0",
"futures 0.3.31",
"hex",
@@ -8583,7 +8583,7 @@ checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555"
dependencies = [
"arrayvec",
"borsh",
"bytes 1.10.0",
"bytes 1.10.1",
"num-traits",
"rand 0.8.5",
"rkyv",
@@ -8743,7 +8743,7 @@ version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65bc94b580d0f5a6b7a2d604e597513d3c673154b52ddeccd1d5c32360d945ee"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"rxml_validation",
]
@@ -9565,7 +9565,7 @@ dependencies = [
"atoi",
"bigdecimal",
"byteorder",
"bytes 1.10.0",
"bytes 1.10.1",
"chrono",
"crc",
"crossbeam-queue",
@@ -9652,7 +9652,7 @@ dependencies = [
"bigdecimal",
"bitflags 2.5.0",
"byteorder",
"bytes 1.10.0",
"bytes 1.10.1",
"chrono",
"crc",
"digest 0.10.7",
@@ -10384,7 +10384,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d08db1ff9e011e04014e737ec022610d756c0eae0b3b3a9037bccaf3003173a"
dependencies = [
"anyhow",
"bytes 1.10.0",
"bytes 1.10.1",
"dirs",
"dunce",
"embed_plist",
@@ -10552,7 +10552,7 @@ dependencies = [
name = "tauri-plugin-http"
version = "2.4.3"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"cookie_store",
"data-url",
"http 1.1.0",
@@ -10926,7 +10926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
dependencies = [
"backtrace",
"bytes 1.10.0",
"bytes 1.10.1",
"libc",
"mio 1.0.2",
"parking_lot 0.12.2",
@@ -11102,7 +11102,7 @@ version = "0.7.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"futures-core",
"futures-sink",
"pin-project-lite",
@@ -11207,7 +11207,7 @@ dependencies = [
"async-trait",
"axum",
"base64 0.21.7",
"bytes 1.10.0",
"bytes 1.10.1",
"h2 0.3.26",
"http 0.2.11",
"http-body 0.4.6",
@@ -12068,7 +12068,7 @@ dependencies = [
name = "web_scrapers"
version = "0.0.1"
dependencies = [
"bytes 1.10.0",
"bytes 1.10.1",
"chrono",
"enums",
"errors",
@@ -12744,7 +12744,7 @@ dependencies = [
"block-buffer 0.9.0",
"bytemuck",
"byteorder",
"bytes 1.10.0",
"bytes 1.10.1",
"cc",
"chrono",
"clap",
+1 -1
View File
@@ -37,7 +37,7 @@ tokens = { workspace = true }
# External
anyhow = { workspace = true }
base64 = { workspace = true }
bytes = "1.10"
bytes = "1.10.1"
chrono = { workspace = true }
directories = "6.0.0"
dirs = "6.0.0"
@@ -14,8 +14,6 @@ use crate::core::utils::simple_http_download::simple_http_download;
use crate::core::utils::simple_http_download_to_tempfile::simple_http_download_to_tempfile;
use crate::services::fal::state::fal_credential_manager::FalCredentialManager;
use crate::services::fal::state::fal_task_queue::FalTaskQueue;
use crate::services::sora::events::sora_image_enqueue_failure_event::SoraImageEnqueueFailureEvent;
use crate::services::sora::events::sora_image_enqueue_success_event::SoraImageEnqueueSuccessEvent;
use crate::services::sora::state::read_sora_credentials_from_disk::read_sora_credentials_from_disk;
use crate::services::sora::state::sora_credential_holder::SoraCredentialHolder;
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
@@ -101,6 +99,7 @@ pub enum EnqueueTextToImageErrorType {
#[tauri::command]
pub async fn enqueue_text_to_image_command(
app: AppHandle,
request: EnqueueTextToImageRequest,
app_data_root: State<'_, AppDataRoot>,
fal_creds_manager: State<'_, FalCredentialManager>,
@@ -113,6 +112,7 @@ pub async fn enqueue_text_to_image_command(
info!("enqueue_text_to_image called");
let result = handle_request(
&app,
request,
&app_data_root,
&fal_creds_manager,
@@ -126,12 +126,6 @@ pub async fn enqueue_text_to_image_command(
Err(err) => {
error!("error: {:?}", err);
//let event = SoraImageEnqueueFailureEvent {};
//let result = event.send(&app);
//if let Err(err) = result {
// error!("Failed to emit event: {:?}", err);
//}
let mut status = CommandErrorStatus::ServerError;
let mut error_type = EnqueueTextToImageErrorType::ServerError;
let mut error_message = "A server error occurred. Please try again. If it continues, please tell our staff about the problem.";
@@ -157,21 +151,15 @@ pub async fn enqueue_text_to_image_command(
error_details: None,
})
}
Ok(result) => {
//let event = SoraImageEnqueueSuccessEvent {};
//let result = event.send(&app);
//if let Err(err) = result {
// error!("Failed to emit event: {:?}", err);
//}
Ok(EnqueueTextToImageSuccessResponse {
}.into())
Ok(()) => {
Ok(EnqueueTextToImageSuccessResponse {}.into())
}
}
}
pub async fn handle_request(
app: &AppHandle,
request: EnqueueTextToImageRequest,
app_data_root: &AppDataRoot,
fal_creds_manager: &FalCredentialManager,
@@ -186,10 +174,10 @@ pub async fn handle_request(
return Err(InternalImageError::NoModelSpecified);
}
Some(EnqueueTextToImageModel::FluxProUltra) | Some(EnqueueTextToImageModel::Recraft3) => {
handle_fal(request, fal_creds_manager, fal_task_queue).await?;
handle_fal(&app, request, fal_creds_manager, fal_task_queue).await?;
},
Some(EnqueueTextToImageModel::GptImage1) => {
handle_sora(request, sora_creds_manager, sora_task_queue).await?;
handle_sora(&app, request, sora_creds_manager, sora_task_queue).await?;
}
};
@@ -1,5 +1,9 @@
use crate::core::commands::enqueue::image::enqueue_text_to_image_command::{EnqueueTextToImageModel, EnqueueTextToImageRequest};
use crate::core::commands::enqueue::image::internal_image_error::InternalImageError;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceProvider};
use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent;
use crate::core::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent;
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::services::fal::state::fal_credential_manager::FalCredentialManager;
use crate::services::fal::state::fal_task_queue::FalTaskQueue;
@@ -10,8 +14,10 @@ use anyhow::anyhow;
use fal_client::requests::image_gen::enqueue_flux_pro_ultra_text_to_image::{enqueue_flux_pro_ultra_text_to_image, FluxProUltraTextToImageArgs};
use fal_client::requests::image_gen::enqueue_recraft3_text_to_image::{enqueue_recraft3_text_to_image, Recraft3TextToImageArgs};
use log::{error, info, warn};
use tauri::AppHandle;
pub async fn handle_fal(
app: &AppHandle,
request: EnqueueTextToImageRequest,
fal_creds_manager: &FalCredentialManager,
fal_task_queue: &FalTaskQueue,
@@ -52,6 +58,16 @@ pub async fn handle_fal(
Ok(enqueued) => {
info!("Successfully enqueued text to image");
let event = GenerationEnqueueSuccessEvent {
action: GenerationAction::GenerateImage,
service: GenerationServiceProvider::Fal,
model: None,
};
if let Err(err) = event.send(app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
if let Err(err) = fal_task_queue.insert(&enqueued) {
error!("Failed to enqueue task: {:?}", err);
return Err(InternalImageError::AnyhowError(anyhow!("Failed to enqueue task: {:?}", err)));
@@ -59,6 +75,18 @@ pub async fn handle_fal(
}
Err(err) => {
error!("Failed to enqueue text to image: {:?}", err);
let event = GenerationEnqueueFailureEvent {
action: GenerationAction::GenerateImage,
service: GenerationServiceProvider::Fal,
model: None,
reason: None,
};
if let Err(err) = event.send(app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
return Err(InternalImageError::FalError(err));
}
}
@@ -1,5 +1,9 @@
use crate::core::commands::enqueue::image::enqueue_text_to_image_command::{EnqueueTextToImageModel, EnqueueTextToImageRequest};
use crate::core::commands::enqueue::image::internal_image_error::InternalImageError;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceProvider};
use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent;
use crate::core::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent;
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::services::fal::state::fal_credential_manager::FalCredentialManager;
use crate::services::fal::state::fal_task_queue::FalTaskQueue;
@@ -17,10 +21,12 @@ use openai_sora_client::recipes::simple_image_gen_with_session_auto_renew::{simp
use openai_sora_client::requests::image_gen::common::{ImageSize, NumImages, SoraImageGenResponse};
use openai_sora_client::sora_error::SoraError;
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_sora(
app: &AppHandle,
request: EnqueueTextToImageRequest,
sora_creds_manager: &SoraCredentialManager,
sora_task_queue: &SoraTaskQueue,
@@ -60,6 +66,17 @@ pub async fn handle_sora(
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(InternalImageError::SoraError(err));
}
};
@@ -73,5 +90,15 @@ pub async fn handle_sora(
sora_task_queue.insert(&response.task_id)?;
let event = GenerationEnqueueSuccessEvent {
action: GenerationAction::GenerateImage,
service: GenerationServiceProvider::Sora,
model: None,
};
if let Err(err) = event.send(app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
Ok(())
}
@@ -0,0 +1,51 @@
use crate::core::events::sendable_event_error::SendableEventError;
use log::info;
use serde::Serialize;
use std::fmt::Debug;
use tauri::{AppHandle, Emitter};
// Tagged enums here are waaay too "Rustic"
// #[derive(Clone, Serialize)]
// #[serde(rename_all = "camelCase", rename_all_fields = "camelCase", tag = "event", content = "data")]
// pub enum BasicEvent<T: Serialize> {
// Success(T),
// Failure(T),
// }
#[derive(Copy, Clone, Debug, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum BasicEventStatus {
Success,
Failure,
}
/// Wrap the event with "status" and "data" fields.
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "snake_case")]
struct BasicEventWrapper<T: Serialize + Debug> {
status: BasicEventStatus,
data: T,
}
pub trait BasicSendableEvent : Clone + Debug + Serialize {
/// This is the name of the event that the frontend subscribes to.
const FRONTEND_EVENT_NAME: &'static str;
/// This is the status of the event: Success, Failure, etc.
const EVENT_STATUS: BasicEventStatus;
/// Default implementation of send().
/// This serializes and sends the event to the frontend.
fn send(&self, app: &AppHandle) -> Result<(), SendableEventError> {
let wrapped = BasicEventWrapper {
status: Self::EVENT_STATUS,
data: self.clone(),
};
info!("Sending event to frontend: {} ; payload = {:?}", Self::FRONTEND_EVENT_NAME, wrapped);
let result = app.emit(Self::FRONTEND_EVENT_NAME, wrapped);
if let Err(err) = result {
return Err(SendableEventError::from(err));
}
Ok(())
}
}
@@ -0,0 +1,28 @@
use serde::Serialize;
#[derive(Debug, Copy, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum GenerationServiceProvider {
Sora,
Fal,
}
#[derive(Debug, Copy, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum GenerationModel {
#[serde(rename = "kling_1.6")]
Kling1_6,
#[serde(rename = "kling_2.0")]
Kling2_0,
Sora,
}
#[derive(Debug, Copy, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum GenerationAction {
GenerateImage,
GenerateVideo,
RemoveBackground,
#[serde(rename = "image_to_3d")]
ImageTo3d,
}
@@ -0,0 +1,16 @@
use crate::core::events::basic_sendable_event_trait::{BasicEventStatus, BasicSendableEvent};
use crate::core::events::generation_events::common::{GenerationAction, GenerationModel, GenerationServiceProvider};
use serde_derive::Serialize;
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct GenerationCompleteEvent {
pub action: Option<GenerationAction>,
pub service: GenerationServiceProvider,
pub model: Option<GenerationModel>,
}
impl BasicSendableEvent for GenerationCompleteEvent {
const FRONTEND_EVENT_NAME: &'static str = "generation-complete-event";
const EVENT_STATUS: BasicEventStatus = BasicEventStatus::Success;
}
@@ -0,0 +1,19 @@
use crate::core::events::basic_sendable_event_trait::{BasicEventStatus, BasicSendableEvent};
use crate::core::events::generation_events::common::{GenerationAction, GenerationModel, GenerationServiceProvider};
use serde_derive::Serialize;
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct GenerationEnqueueFailureEvent {
pub action: GenerationAction,
pub service: GenerationServiceProvider,
pub model: Option<GenerationModel>,
/// User-facing reason for the failure, if available.
pub reason: Option<String>,
}
impl BasicSendableEvent for GenerationEnqueueFailureEvent {
const FRONTEND_EVENT_NAME: &'static str = "generation-enqueue-failure-event";
const EVENT_STATUS: BasicEventStatus = BasicEventStatus::Failure;
}
@@ -0,0 +1,16 @@
use crate::core::events::basic_sendable_event_trait::{BasicEventStatus, BasicSendableEvent};
use crate::core::events::generation_events::common::{GenerationAction, GenerationModel, GenerationServiceProvider};
use serde_derive::Serialize;
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct GenerationEnqueueSuccessEvent {
pub action: GenerationAction,
pub service: GenerationServiceProvider,
pub model: Option<GenerationModel>,
}
impl BasicSendableEvent for GenerationEnqueueSuccessEvent {
const FRONTEND_EVENT_NAME: &'static str = "generation-enqueue-success-event";
const EVENT_STATUS: BasicEventStatus = BasicEventStatus::Success;
}
@@ -0,0 +1,19 @@
use crate::core::events::basic_sendable_event_trait::{BasicEventStatus, BasicSendableEvent};
use crate::core::events::generation_events::common::{GenerationAction, GenerationModel, GenerationServiceProvider};
use serde_derive::Serialize;
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct GenerationFailedEvent {
pub action: GenerationAction,
pub service: GenerationServiceProvider,
pub model: Option<GenerationModel>,
/// User-facing reason for the failure, if available.
pub reason: Option<String>,
}
impl BasicSendableEvent for GenerationFailedEvent {
const FRONTEND_EVENT_NAME: &'static str = "generation-failed-event";
const EVENT_STATUS: BasicEventStatus = BasicEventStatus::Failure;
}
@@ -0,0 +1,5 @@
pub mod common;
pub mod generation_enqueue_failure_event;
pub mod generation_enqueue_success_event;
pub mod generation_complete_event;
pub mod generation_failed_event;
@@ -1,3 +1,4 @@
pub mod notification_event;
pub mod basic_sendable_event_trait;
pub mod generation_events;
pub mod sendable_event_error;
pub mod sendable_event_trait;
@@ -1,45 +0,0 @@
use serde::Serialize;
#[derive(Clone, Copy, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum NotificationModelType {
ImageSegmentation,
TextEncoder,
TextTokenizer,
Unet,
Vae,
Json,
ClipEncoder,
FluxModel,
}
#[derive(Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum NotificationEvent<'a> {
ModelDownloadStarted {
model_name: &'a str,
model_type: NotificationModelType,
},
ModelDownloadProgress {
model_name: &'a str,
model_type: NotificationModelType,
currently_downloaded_bytes: usize,
total_file_bytes: usize,
},
ModelDownloadComplete {
model_name: &'a str,
model_type: NotificationModelType,
},
ModelLoading {
model_name: String,
model_type: NotificationModelType,
},
ModelInference {
model_name: String,
model_type: NotificationModelType,
},
ModelInferenceComplete {
model_name: String,
model_type: NotificationModelType,
},
}
@@ -1,15 +1,17 @@
use log::info;
use crate::core::events::sendable_event_error::SendableEventError;
use log::info;
use serde::Serialize;
use tauri::{AppHandle, Emitter};
/// Implement this on a Serializable object to be able to send it as an event to the frontend.
#[deprecated(note = "Use BasicSendableEvent instead as it wraps the event with status and data fields.")]
pub trait SendableEvent : Serialize {
/// This is the name of the event that the frontend subscribes to.
const FRONTEND_EVENT_NAME: &'static str;
/// Default implementation of send().
/// This serializes and sends the event to the frontend.
#[deprecated(note = "Use BasicSendableEvent instead as it wraps the event with status and data fields.")]
fn send(&self, app: &AppHandle) -> Result<(), SendableEventError> {
info!("Sending event to frontend: {}", Self::FRONTEND_EVENT_NAME);
let result = app.emit(Self::FRONTEND_EVENT_NAME, self);
@@ -1,6 +1,10 @@
use crate::core::commands::response::failure_response_wrapper::{CommandErrorResponseWrapper, CommandErrorStatus};
use crate::core::commands::response::shorthand::Response;
use crate::core::commands::response::success_response_wrapper::SerializeMarker;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceProvider};
use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent;
use crate::core::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent;
use crate::core::events::sendable_event_trait::SendableEvent;
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::core::state::data_dir::trait_data_subdir::DataSubdir;
@@ -10,8 +14,6 @@ use crate::core::utils::save_base64_image_to_temp_dir::save_base64_image_to_temp
use crate::core::utils::simple_http_download::simple_http_download;
use crate::core::utils::simple_http_download_to_tempfile::simple_http_download_to_tempfile;
use crate::services::fal::state::fal_credential_manager::FalCredentialManager;
use crate::services::sora::events::sora_image_enqueue_failure_event::SoraImageEnqueueFailureEvent;
use crate::services::sora::events::sora_image_enqueue_success_event::SoraImageEnqueueSuccessEvent;
use crate::services::sora::state::read_sora_credentials_from_disk::read_sora_credentials_from_disk;
use crate::services::sora::state::sora_credential_holder::SoraCredentialHolder;
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
@@ -87,6 +89,7 @@ pub enum BackgroundRemovalErrorType {
#[tauri::command]
pub async fn fal_background_removal_command(
app: AppHandle,
request: FalBackgroundRemovalRequest,
app_data_root: State<'_, AppDataRoot>,
fal_creds_manager: State<'_, FalCredentialManager>,
@@ -109,6 +112,16 @@ pub async fn fal_background_removal_command(
});
}
let event = GenerationEnqueueSuccessEvent {
action: GenerationAction::RemoveBackground,
service: GenerationServiceProvider::Fal,
model: None,
};
if let Err(err) = event.send(&app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
let result = remove_background(
request,
&app_data_root,
@@ -120,20 +133,21 @@ pub async fn fal_background_removal_command(
Err(err) => {
error!("error: {:?}", err);
//let event = SoraImageEnqueueFailureEvent {};
//let result = event.send(&app);
//if let Err(err) = result {
// error!("Failed to emit event: {:?}", err);
//}
let event = GenerationEnqueueFailureEvent {
action: GenerationAction::RemoveBackground,
service: GenerationServiceProvider::Fal,
model: None,
reason: None,
};
if let Err(err) = event.send(&app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
let mut status = CommandErrorStatus::ServerError;
let mut error_type = BackgroundRemovalErrorType::ServerError;
let mut error_message = "A server error occurred. Please try again. If it continues, please tell our staff about the problem.";
//match (err) {
// _ => {},
//}
Err(CommandErrorResponseWrapper {
status,
error_message: Some(error_message.to_string()),
@@ -142,12 +156,6 @@ pub async fn fal_background_removal_command(
})
}
Ok(result) => {
//let event = SoraImageEnqueueSuccessEvent {};
//let result = event.send(&app);
//if let Err(err) = result {
// error!("Failed to emit event: {:?}", err);
//}
Ok(FalBackgroundRemovalSuccessResponse {
media_token: result.0.media_file.token,
cdn_url: result.0.media_file.media_links.cdn_url,
@@ -256,4 +264,3 @@ pub async fn remove_background(
Ok((response, base64_bytes))
}
@@ -1,3 +1,9 @@
use crate::core::commands::response::failure_response_wrapper::{CommandErrorResponseWrapper, CommandErrorStatus};
use crate::core::commands::response::shorthand::Response;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceProvider};
use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent;
use crate::core::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent;
use crate::core::events::sendable_event_trait::SendableEvent;
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::core::state::data_dir::trait_data_subdir::DataSubdir;
@@ -8,8 +14,6 @@ use crate::core::utils::simple_http_download::simple_http_download;
use crate::core::utils::simple_http_download_to_tempfile::simple_http_download_to_tempfile;
use crate::services::fal::state::fal_credential_manager::FalCredentialManager;
use crate::services::fal::state::fal_task_queue::FalTaskQueue;
use crate::services::sora::events::sora_image_enqueue_failure_event::SoraImageEnqueueFailureEvent;
use crate::services::sora::events::sora_image_enqueue_success_event::SoraImageEnqueueSuccessEvent;
use crate::services::sora::state::read_sora_credentials_from_disk::read_sora_credentials_from_disk;
use crate::services::sora::state::sora_credential_holder::SoraCredentialHolder;
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
@@ -52,8 +56,6 @@ use storyteller_client::utils::api_host::ApiHost;
use tauri::{AppHandle, Emitter, Manager, State};
use tempfile::NamedTempFile;
use tokens::tokens::media_files::MediaFileToken;
use crate::core::commands::response::failure_response_wrapper::{CommandErrorResponseWrapper, CommandErrorStatus};
use crate::core::commands::response::shorthand::Response;
#[derive(Deserialize)]
pub struct FalHunyuanImageTo3dRequest {
@@ -76,6 +78,7 @@ pub enum HunyuanErrorType {
#[tauri::command]
pub async fn fal_hunyuan_image_to_3d_command(
app: AppHandle,
request: FalHunyuanImageTo3dRequest,
app_data_root: State<'_, AppDataRoot>,
fal_creds_manager: State<'_, FalCredentialManager>,
@@ -110,20 +113,21 @@ pub async fn fal_hunyuan_image_to_3d_command(
if let Err(err) = result {
error!("error: {:?}", err);
//let event = SoraImageEnqueueFailureEvent {};
//let result = event.send(&app);
//if let Err(err) = result {
// error!("Failed to emit event: {:?}", err);
//}
let event = GenerationEnqueueFailureEvent {
action: GenerationAction::ImageTo3d,
service: GenerationServiceProvider::Fal,
model: None,
reason: None,
};
if let Err(err) = event.send(&app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
let mut status = CommandErrorStatus::ServerError;
let mut error_type = HunyuanErrorType::ServerError;
let mut error_message = "A server error occurred. Please try again. If it continues, please tell our staff about the problem.";
//match (err) {
// _ => {},
//}
return Err(CommandErrorResponseWrapper {
status,
error_message: Some(error_message.to_string()),
@@ -131,13 +135,17 @@ pub async fn fal_hunyuan_image_to_3d_command(
error_details: None,
})
}
//let event = SoraImageEnqueueSuccessEvent {};
//let result = event.send(&app);
//if let Err(err) = result {
// error!("Failed to emit event: {:?}", err);
//}
let event = GenerationEnqueueSuccessEvent {
action: GenerationAction::ImageTo3d,
service: GenerationServiceProvider::Fal,
model: None,
};
if let Err(err) = event.send(&app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
Ok(().into())
}
@@ -1,3 +1,9 @@
use crate::core::commands::response::failure_response_wrapper::{CommandErrorResponseWrapper, CommandErrorStatus};
use crate::core::commands::response::shorthand::Response;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceProvider};
use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent;
use crate::core::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent;
use crate::core::events::sendable_event_trait::SendableEvent;
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::core::state::data_dir::trait_data_subdir::DataSubdir;
@@ -8,8 +14,6 @@ use crate::core::utils::simple_http_download::simple_http_download;
use crate::core::utils::simple_http_download_to_tempfile::simple_http_download_to_tempfile;
use crate::services::fal::state::fal_credential_manager::FalCredentialManager;
use crate::services::fal::state::fal_task_queue::FalTaskQueue;
use crate::services::sora::events::sora_image_enqueue_failure_event::SoraImageEnqueueFailureEvent;
use crate::services::sora::events::sora_image_enqueue_success_event::SoraImageEnqueueSuccessEvent;
use crate::services::sora::state::read_sora_credentials_from_disk::read_sora_credentials_from_disk;
use crate::services::sora::state::sora_credential_holder::SoraCredentialHolder;
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
@@ -20,8 +24,8 @@ use base64::prelude::BASE64_STANDARD;
use base64::{DecodeError, Engine};
use errors::{AnyhowError, AnyhowResult};
use fal_client::error::fal_error_plus::FalErrorPlus;
use fal_client::requests::video_gen::enqueue_kling_16_image_to_video::{enqueue_kling_16_image_to_video, Kling16Args, Kling16Duration};
use fal_client::requests::remove_background_rembg::remove_background_rembg;
use fal_client::requests::video_gen::enqueue_kling_16_image_to_video::{enqueue_kling_16_image_to_video, Kling16Args, Kling16Duration};
use filesys::file_read_bytes::file_read_bytes;
use image::codecs::png::{CompressionType, FilterType, PngEncoder};
use image::{DynamicImage, EncodableLayout, ImageReader};
@@ -52,8 +56,6 @@ use storyteller_client::utils::api_host::ApiHost;
use tauri::{AppHandle, Emitter, Manager, State};
use tempfile::NamedTempFile;
use tokens::tokens::media_files::MediaFileToken;
use crate::core::commands::response::failure_response_wrapper::{CommandErrorResponseWrapper, CommandErrorStatus};
use crate::core::commands::response::shorthand::Response;
#[derive(Deserialize)]
pub struct FalKlingImageToVideoRequest {
@@ -81,6 +83,7 @@ pub enum KlingImageToVideoErrorType {
#[tauri::command]
pub async fn fal_kling_image_to_video_command(
app: AppHandle,
request: FalKlingImageToVideoRequest,
app_data_root: State<'_, AppDataRoot>,
fal_creds_manager: State<'_, FalCredentialManager>,
@@ -115,20 +118,21 @@ pub async fn fal_kling_image_to_video_command(
if let Err(err) = result {
error!("error: {:?}", err);
//let event = SoraImageEnqueueFailureEvent {};
//let result = event.send(&app);
//if let Err(err) = result {
// error!("Failed to emit event: {:?}", err);
//}
let event = GenerationEnqueueFailureEvent {
action: GenerationAction::GenerateVideo,
service: GenerationServiceProvider::Fal,
model: None,
reason: None,
};
if let Err(err) = event.send(&app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
let mut status = CommandErrorStatus::ServerError;
let mut error_type = KlingImageToVideoErrorType::ServerError;
let mut error_message = "A server error occurred. Please try again. If it continues, please tell our staff about the problem.";
//match (err) {
// _ => {},
//}
return Err(CommandErrorResponseWrapper {
status,
error_message: Some(error_message.to_string()),
@@ -137,12 +141,16 @@ pub async fn fal_kling_image_to_video_command(
})
}
//let event = SoraImageEnqueueSuccessEvent {};
//let result = event.send(&app);
//if let Err(err) = result {
// error!("Failed to emit event: {:?}", err);
//}
let event = GenerationEnqueueSuccessEvent {
action: GenerationAction::GenerateVideo,
service: GenerationServiceProvider::Fal,
model: None,
};
if let Err(err) = event.send(&app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
Ok(().into())
}
@@ -0,0 +1,37 @@
use crate::core::events::generation_events::common::GenerationAction;
use fal_client::model::fal_endpoint::FalEndpoint;
/// Adapter of generation types/categories for FAL
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FalGenerationType {
TextToImage,
ImageToImage,
TextToVideo,
ImageToVideo,
ImageTo3d,
ImageBackgroundRemoval,
}
impl FalGenerationType {
pub fn from_fal_endpoint(endpoint: &FalEndpoint) -> Option<Self> {
match endpoint {
FalEndpoint::FluxProUltraTextToImage => Some(Self::TextToImage),
FalEndpoint::Hunyuan3d2Base => Some(Self::ImageTo3d),
FalEndpoint::Kling16ImageToVideo => Some(Self::ImageToVideo),
FalEndpoint::Minimax01ImageToVideo => Some(Self::ImageToVideo),
FalEndpoint::RecraftV3TextToImage => Some(Self::TextToImage),
FalEndpoint::Other(_) => None,
}
}
pub fn to_event_generation_action(&self) -> GenerationAction {
match self {
Self::TextToImage => GenerationAction::GenerateImage,
Self::ImageToImage => GenerationAction::GenerateImage,
Self::TextToVideo => GenerationAction::GenerateVideo,
Self::ImageToVideo => GenerationAction::GenerateVideo,
Self::ImageTo3d => GenerationAction::ImageTo3d,
Self::ImageBackgroundRemoval => GenerationAction::RemoveBackground,
}
}
}
@@ -1,3 +1,4 @@
use crate::services::fal::state::fal_generation_type::FalGenerationType;
use chrono::{DateTime, Utc};
use errors::AnyhowResult;
use fal_client::model::enqueued_request::EnqueuedRequest;
@@ -10,12 +11,14 @@ use std::sync::{Arc, RwLock};
pub struct FalTaskDetails {
pub enqueue_time: DateTime<Utc>,
pub enqueued_request: EnqueuedRequest,
pub generation_type: Option<FalGenerationType>,
}
impl FalTaskDetails {
pub fn for_request(request: EnqueuedRequest) -> Self {
Self {
enqueue_time: Utc::now(),
generation_type: FalGenerationType::from_fal_endpoint(&request.fal_endpoint),
enqueued_request: request,
}
}
@@ -1,3 +1,4 @@
pub mod fal_credential_manager;
pub mod fal_task_queue;
pub mod read_fal_api_key_from_disk;
pub mod read_fal_api_key_from_disk;
mod fal_generation_type;
@@ -1,11 +1,11 @@
use crate::core::events::sendable_event_trait::SendableEvent;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceProvider};
use crate::core::events::generation_events::generation_complete_event::GenerationCompleteEvent;
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::core::state::data_dir::trait_data_subdir::DataSubdir;
use crate::core::utils::download_url_to_temp_dir::download_url_to_temp_dir;
use crate::services::fal::state::fal_credential_manager::FalCredentialManager;
use crate::services::fal::state::fal_task_queue::FalTaskQueue;
use crate::services::sora::events::sora_image_generation_complete_event::SoraImageGenerationCompleteEvent;
use crate::services::sora::events::sora_image_generation_failed_event::SoraImageGenerationFailedEvent;
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
use errors::AnyhowResult;
@@ -146,10 +146,17 @@ async fn polling_loop(
Ok(success) => {
info!("Uploaded to API backend: {:?}", success.media_file_token);
//let event = SoraImageGenerationCompleteEvent {
// media_file_token: success.media_file_token,
//};
//event.send(&app_handle)?;
let event = GenerationCompleteEvent {
//media_file_token: result.media_file_token,
action: task.generation_type
.map(|typ| typ.to_event_generation_action()),
service: GenerationServiceProvider::Fal,
model: None,
};
if let Err(err) = event.send(&app_handle) {
error!("Failed to send GenerationCompleteEvent: {:?}", err); // Fail open
}
succeeded_tasks.push(task_id);
}
@@ -158,7 +165,6 @@ async fn polling_loop(
continue;
}
}
}
@@ -228,7 +234,7 @@ async fn polling_loop(
fal_task_queue.remove_list(&succeeded_task_ids)?;
tokio::time::sleep(std::time::Duration::from_millis(6_000)).await;
tokio::time::sleep(std::time::Duration::from_millis(1_000)).await;
}
}
@@ -1,12 +1,14 @@
use crate::core::commands::response::failure_response_wrapper::{CommandErrorResponseWrapper, CommandErrorStatus};
use crate::core::commands::response::shorthand::Response;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceProvider};
use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent;
use crate::core::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent;
use crate::core::events::sendable_event_trait::SendableEvent;
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::core::state::data_dir::trait_data_subdir::DataSubdir;
use crate::core::utils::get_url_file_extension::get_url_file_extension;
use crate::core::utils::simple_http_download::simple_http_download;
use crate::services::sora::events::sora_image_enqueue_failure_event::SoraImageEnqueueFailureEvent;
use crate::services::sora::events::sora_image_enqueue_success_event::SoraImageEnqueueSuccessEvent;
use crate::services::sora::state::read_sora_credentials_from_disk::read_sora_credentials_from_disk;
use crate::services::sora::state::sora_credential_holder::SoraCredentialHolder;
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
@@ -108,9 +110,23 @@ pub async fn sora_image_remix_command(
if !has_credentials {
warn!("No apparently completed credentials found");
let error_message = "You need to log into Sora to continue. See the settings menu.";
let event = GenerationEnqueueFailureEvent {
action: GenerationAction::GenerateImage,
service: GenerationServiceProvider::Sora,
model: None,
reason: Some(error_message.to_string()),
};
if let Err(err) = event.send(&app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
return Err(CommandErrorResponseWrapper {
status: CommandErrorStatus::Unauthorized,
error_message: Some("You need to log into Sora to continue. See the settings menu.".to_string()),
error_message: Some(error_message.to_string()),
error_type: Some(SoraImageRemixErrorType::SoraLoginRequired),
error_details: None,
});
@@ -120,38 +136,42 @@ pub async fn sora_image_remix_command(
match result {
Err(err) => {
error!("error: {:?}", err);
error!("Sora image remix error: {:?}", err);
let event = SoraImageEnqueueFailureEvent {};
let result = event.send(&app);
if let Err(err) = result {
error!("Failed to emit event: {:?}", err);
}
let mut status = CommandErrorStatus::ServerError;
let mut error_type = SoraImageRemixErrorType::ServerError;
let mut error_message = "A server error occurred. Please try again. If it continues, please tell our staff about the problem.";
let mut error_message = "An error occurred. Please try again. If it continues, please tell our staff about the problem.";
match (err) {
InnerError::SoraError(SoraError::TooManyConcurrentTasks) => {
error_type = SoraImageRemixErrorType::TooManyConcurrentTasks;
status = CommandErrorStatus::ServerError;
error_message = "You already have work in progress. Please wait for it to finish.";
error_message = "You have too many Sora image generation tasks running. Please wait a moment.";
},
InnerError::SoraError(SoraError::SoraUsernameNotYetCreated) => {
error_type = SoraImageRemixErrorType::SoraUsernameNotYetCreated;
status = CommandErrorStatus::BadRequest;
error_message = "You need to create a username on Sora.com to continue.";
error_message = "Your Sora username is not yet created. Please visit the Sora.com website to create it first.";
},
InnerError::SoraError(SoraError::BadGateway(_) | SoraError::CloudFlareTimeout(_)) => {
error_type = SoraImageRemixErrorType::SoraIsHavingProblems;
status = CommandErrorStatus::ServerError;
error_message = "Sora is having problems. Please wait a moment and then retry.";
error_message = "Sora is having problems. Please try again later.";
}
_ => {},
}
let event = GenerationEnqueueFailureEvent {
action: GenerationAction::GenerateImage,
service: GenerationServiceProvider::Sora,
model: None,
reason: Some(error_message.to_string()),
};
if let Err(err) = event.send(&app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
Err(CommandErrorResponseWrapper {
status,
error_message: Some(error_message.to_string()),
@@ -160,11 +180,14 @@ pub async fn sora_image_remix_command(
})
}
Ok(_) => {
let event = SoraImageEnqueueSuccessEvent {};
let result = event.send(&app);
let event = GenerationEnqueueSuccessEvent {
action: GenerationAction::GenerateImage,
service: GenerationServiceProvider::Sora,
model: None,
};
if let Err(err) = result {
error!("Failed to emit event: {:?}", err);
if let Err(err) = event.send(&app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
Ok(().into())
@@ -1,5 +1 @@
pub mod sora_image_enqueue_failure_event;
pub mod sora_image_enqueue_success_event;
pub mod sora_image_generation_complete_event;
pub mod sora_image_generation_failed_event;
pub mod sora_login_success_event;
@@ -1,11 +0,0 @@
use crate::core::events::sendable_event_trait::SendableEvent;
use serde_derive::Serialize;
#[derive(Debug, Clone, Serialize)]
pub struct SoraImageEnqueueFailureEvent {
// TODO: Reason.
}
impl SendableEvent for SoraImageEnqueueFailureEvent {
const FRONTEND_EVENT_NAME: &'static str = "sora-image-enqueue-failure";
}
@@ -1,11 +0,0 @@
use crate::core::events::sendable_event_trait::SendableEvent;
use serde_derive::Serialize;
#[derive(Debug, Clone, Serialize)]
pub struct SoraImageEnqueueSuccessEvent {
// TODO: Token, etc.
}
impl SendableEvent for SoraImageEnqueueSuccessEvent {
const FRONTEND_EVENT_NAME: &'static str = "sora-image-enqueue-success";
}
@@ -1,12 +0,0 @@
use serde_derive::Serialize;
use tokens::tokens::media_files::MediaFileToken;
use crate::core::events::sendable_event_trait::SendableEvent;
#[derive(Debug, Clone, Serialize)]
pub struct SoraImageGenerationCompleteEvent {
pub media_file_token: MediaFileToken,
}
impl SendableEvent for SoraImageGenerationCompleteEvent {
const FRONTEND_EVENT_NAME: &'static str = "sora-image-generation-complete";
}
@@ -1,12 +0,0 @@
use serde_derive::Serialize;
use crate::core::events::sendable_event_trait::SendableEvent;
#[derive(Debug, Clone, Serialize)]
pub struct SoraImageGenerationFailedEvent {
pub prompt: String,
}
impl SendableEvent for SoraImageGenerationFailedEvent {
const FRONTEND_EVENT_NAME: &'static str = "sora-image-generation-failed";
}
@@ -1,6 +1,8 @@
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceProvider};
use crate::core::events::generation_events::generation_complete_event::GenerationCompleteEvent;
use crate::core::events::generation_events::generation_failed_event::GenerationFailedEvent;
use crate::core::events::sendable_event_trait::SendableEvent;
use crate::services::sora::events::sora_image_generation_complete_event::SoraImageGenerationCompleteEvent;
use crate::services::sora::events::sora_image_generation_failed_event::SoraImageGenerationFailedEvent;
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::core::state::data_dir::trait_data_subdir::DataSubdir;
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
@@ -95,13 +97,19 @@ async fn polling_loop(
for task in failed_tasks.iter() {
if sora_task_queue.contains_key(&task.id)? {
let event = SoraImageGenerationFailedEvent {
prompt: task.prompt
.as_deref()
.map(|s| s.to_string())
.unwrap_or_else(||"".to_string()),
let event = GenerationFailedEvent {
action: GenerationAction::GenerateImage,
service: GenerationServiceProvider::Sora,
model: None,
reason: None,
// prompt: task.prompt
// .as_deref()
// .map(|s| s.to_string())
// .unwrap_or_else(||"".to_string()),
};
event.send(&app_handle)?;
if let Err(err) = event.send(&app_handle) {
error!("Failed to send GenerationFailedEvent: {:?}", err); // Fail open
}
}
}
@@ -129,12 +137,17 @@ async fn polling_loop(
let result = upload_image_media_file_from_file(&api_host, Some(&creds), download_path).await?;
info!("Uploaded to API backend: {:?}", result.media_file_token);
let event = SoraImageGenerationCompleteEvent {
media_file_token: result.media_file_token,
let event = GenerationCompleteEvent {
//media_file_token: result.media_file_token,
action: Some(GenerationAction::GenerateImage),
service: GenerationServiceProvider::Sora,
model: None,
};
event.send(&app_handle)?;
if let Err(err) = event.send(&app_handle) {
error!("Failed to send GenerationCompleteEvent: {:?}", err); // Fail open
}
}
}
@@ -21,8 +21,10 @@ import {
showPrecisionSelector,
} from "./signals/precisionSelectorMenu";
import { InstallSounds } from "~/pages/PageEnigma/InstallSounds";
import { useImageGenerationFailureEvent } from "./TauriEvents/useImageGenerationFailureEvent";
import { useImageGenerationSuccessEvent } from "./TauriEvents/useImageGenerationSuccessEvent";
import { useGenerationEnqueueFailureEvent } from "./TauriEvents/generations/useGenerationEnqueueFailureEvent";
import { useGenerationEnqueueSuccessEvent } from "./TauriEvents/generations/useGenerationEnqueueSuccessEvent";
import { useGenerationFailedEvent } from "./TauriEvents/generations/useGenerationFailedEvent";
import { useGenerationCompleteEvent } from "./TauriEvents/generations/useGenerationCompleteEvent";
import { PageEditor } from "~/pages/PageEnigma/PageEditor";
import { GalleryDragComponent } from "@storyteller/ui-gallery-modal";
import { LoadingDots } from "@storyteller/ui-loading";
@@ -91,8 +93,10 @@ export const PageEnigma = ({ sceneToken }: { sceneToken?: string }) => {
});
});
useImageGenerationSuccessEvent();
useImageGenerationFailureEvent();
useGenerationEnqueueSuccessEvent();
useGenerationEnqueueFailureEvent();
useGenerationCompleteEvent();
useGenerationFailedEvent();
useEffect(() => {
console.log("installing event listeners");
@@ -0,0 +1,10 @@
export enum BasicEventStatus {
Success = "success",
Failure = "failure",
};
export interface BasicEventWrapper<T> {
status: BasicEventStatus,
data: T,
};
@@ -0,0 +1,18 @@
export enum GenerationServiceProvider {
Sora = "sora",
Fal = "fal",
}
export enum GenerationModel {
Kling1_6 = "kling_1.6",
Kling2_0 = "kling_2.0",
Sora = "sora",
}
export enum GenerationAction {
GenerateImage = "generate_image",
GenerateVideo = "generate_video",
RemoveBackground = "remove_background",
ImageTo3d = "image_to_3d",
}
@@ -0,0 +1,64 @@
import { useEffect } from "react";
import { listen, UnlistenFn } from '@tauri-apps/api/event';
import { SoundRegistry } from "@storyteller/soundboard";
import { GetAppPreferences } from "@storyteller/tauri-api";
import { toast } from "@storyteller/ui-toaster";
import { GenerationAction, GenerationModel, GenerationServiceProvider } from "./common";
import { BasicEventWrapper } from "../BasicEventWrapper";
type GenerationCompleteEvent = {
action?: GenerationAction,
service: GenerationServiceProvider,
model?: GenerationModel,
};
export const useGenerationCompleteEvent = () => {
useEffect(() => {
let isUnmounted = false;
let unlisten: Promise<UnlistenFn>;
const setup = async () => {
unlisten = listen<BasicEventWrapper<GenerationCompleteEvent>>('generation-complete-event', async (event) => {
console.log("Generation complete event received:", event);
const prefs = await GetAppPreferences();
const soundName = prefs.preferences?.generation_success_sound;
if (soundName !== undefined) {
const registry = SoundRegistry.getInstance();
registry.playSound(soundName);
}
const message = makeMessage(event.payload.data);
toast.success(message);
});
if (isUnmounted) {
unlisten.then(f => f()); // Unsubscribe if unmounted early.
}
};
setup();
return () => {
isUnmounted = true;
unlisten.then(f => f());
};
}, []);
}
const makeMessage = (event: GenerationCompleteEvent) => {
if (!event.action) {
return "Generation complete!";
}
switch (event.action) {
case GenerationAction.GenerateImage:
return "Image generation complete!";
case GenerationAction.GenerateVideo:
return "Video generation complete!";
case GenerationAction.RemoveBackground:
return "Background removal complete!";
case GenerationAction.ImageTo3d:
return "Image to 3D complete!";
default:
return "Generation complete!";
}
}
@@ -0,0 +1,65 @@
import { useEffect } from "react";
import { listen, UnlistenFn } from '@tauri-apps/api/event';
import { SoundRegistry } from "@storyteller/soundboard";
import { GetAppPreferences } from "@storyteller/tauri-api";
import { toast } from "@storyteller/ui-toaster";
import { GenerationAction, GenerationModel, GenerationServiceProvider } from "./common";
import { BasicEventWrapper } from "../BasicEventWrapper";
type GenerationEnqueueFailureEvent = {
action: GenerationAction,
service: GenerationServiceProvider,
model?: GenerationModel,
reason?: string,
};
export const useGenerationEnqueueFailureEvent = () => {
useEffect(() => {
let isUnmounted = false;
let unlisten: Promise<UnlistenFn>;
const setup = async () => {
unlisten = listen<BasicEventWrapper<GenerationEnqueueFailureEvent>>('generation-enqueue-failure-event', async (event) => {
console.log("Generation enqueue failure event received:", event);
const prefs = await GetAppPreferences();
const soundName = prefs.preferences?.enqueue_failure_sound;
if (soundName !== undefined) {
const registry = SoundRegistry.getInstance();
registry.playSound(soundName);
}
const message = makeMessage(event.payload.data);
toast.error(message);
});
if (isUnmounted) {
unlisten.then(f => f()); // Unsubscribe if unmounted early.
}
};
setup();
return () => {
isUnmounted = true;
unlisten.then(f => f());
};
}, []);
}
const makeMessage = (event: GenerationEnqueueFailureEvent) => {
if (!!event.reason) {
return event.reason;
}
switch (event.action) {
case GenerationAction.GenerateImage:
return "Couldn't enqueue image generation!";
case GenerationAction.GenerateVideo:
return "Couldn't enqueue video generation!";
case GenerationAction.RemoveBackground:
return "Couldn't enqueue background removal!";
case GenerationAction.ImageTo3d:
return "Couldn't enqueue image to 3D!";
default:
return "Couldn't enqueue generation!";
}
}
@@ -0,0 +1,61 @@
import { useEffect } from "react";
import { listen, UnlistenFn } from '@tauri-apps/api/event';
import { SoundRegistry } from "@storyteller/soundboard";
import { GetAppPreferences } from "@storyteller/tauri-api";
import { toast } from "@storyteller/ui-toaster";
import { GenerationAction, GenerationModel, GenerationServiceProvider } from "./common";
import { BasicEventWrapper } from "../BasicEventWrapper";
type GenerationEnqueueSuccessEvent = {
action: GenerationAction,
service: GenerationServiceProvider,
model?: GenerationModel,
};
export const useGenerationEnqueueSuccessEvent = () => {
useEffect(() => {
let isUnmounted = false;
let unlisten: Promise<UnlistenFn>;
const setup = async () => {
unlisten = listen<BasicEventWrapper<GenerationEnqueueSuccessEvent>>('generation-enqueue-success-event', async (event) => {
console.log("Generation enqueue success event received:", event);
const prefs = await GetAppPreferences();
const soundName = prefs.preferences?.enqueue_success_sound;
if (soundName !== undefined) {
const registry = SoundRegistry.getInstance();
registry.playSound(soundName);
}
const message = makeMessage(event.payload.data);
toast.success(message);
});
if (isUnmounted) {
unlisten.then(f => f()); // Unsubscribe if unmounted early.
}
};
setup();
return () => {
isUnmounted = true;
unlisten.then(f => f());
};
}, []);
}
const makeMessage = (event: GenerationEnqueueSuccessEvent) => {
switch (event.action) {
case GenerationAction.GenerateImage:
return "Image generation enqueued!";
case GenerationAction.GenerateVideo:
return "Video generation enqueued!";
case GenerationAction.RemoveBackground:
return "Background removal enqueued!";
case GenerationAction.ImageTo3d:
return "Image to 3D enqueued!";
default:
return "Generation enqueued!";
}
}
@@ -0,0 +1,65 @@
import { useEffect } from "react";
import { listen, UnlistenFn } from '@tauri-apps/api/event';
import { SoundRegistry } from "@storyteller/soundboard";
import { GetAppPreferences } from "@storyteller/tauri-api";
import { toast } from "@storyteller/ui-toaster";
import { GenerationAction, GenerationModel, GenerationServiceProvider } from "./common";
import { BasicEventWrapper } from "../BasicEventWrapper";
type GenerationFailedEvent = {
action: GenerationAction,
service: GenerationServiceProvider,
model?: GenerationModel,
reason?: string,
};
export const useGenerationFailedEvent = () => {
useEffect(() => {
let isUnmounted = false;
let unlisten: Promise<UnlistenFn>;
const setup = async () => {
unlisten = listen<BasicEventWrapper<GenerationFailedEvent>>('generation-failed-event', async (event) => {
console.log("Generation failed event received:", event);
const prefs = await GetAppPreferences();
const soundName = prefs.preferences?.generation_failure_sound;
if (soundName !== undefined) {
const registry = SoundRegistry.getInstance();
registry.playSound(soundName);
}
const message = makeMessage(event.payload.data);
toast.error(message);
});
if (isUnmounted) {
unlisten.then(f => f()); // Unsubscribe if unmounted early.
}
};
setup();
return () => {
isUnmounted = true;
unlisten.then(f => f());
};
}, []);
}
const makeMessage = (event: GenerationFailedEvent) => {
if (!!event.reason) {
return event.reason;
}
switch (event.action) {
case GenerationAction.GenerateImage:
return "Image generation failed!";
case GenerationAction.GenerateVideo:
return "Video generation failed!";
case GenerationAction.RemoveBackground:
return "Background removal failed!";
case GenerationAction.ImageTo3d:
return "Image to 3D failed!";
default:
return "Generation failed!";
}
}
@@ -1,41 +0,0 @@
import { useEffect } from "react";
import { listen, UnlistenFn } from '@tauri-apps/api/event';
import { SoundRegistry } from "@storyteller/soundboard";
import { GetAppPreferences } from "@storyteller/tauri-api";
import { toast } from "@storyteller/ui-toaster";
type SoraImageGenerationFailed = {
prompt: string,
};
export const useImageGenerationFailureEvent = () => {
useEffect(() => {
let isUnmounted = false;
let unlisten: Promise<UnlistenFn>;
const setup = async () => {
unlisten = listen<SoraImageGenerationFailed>('sora-image-generation-failed', async (event) => {
console.log("Image generation failure event received:", event);
const prefs = await GetAppPreferences();
const soundName = prefs.preferences?.generation_failure_sound;
if (soundName !== undefined) {
const registry = SoundRegistry.getInstance();
registry.playSound(soundName);
}
toast.error("Image generation failed!");
});
if (isUnmounted) {
unlisten.then(f => f()); // Unsubscribe if unmounted early.
}
};
setup();
return () => {
isUnmounted = true;
unlisten.then(f => f());
};
}, []);
}
@@ -1,41 +0,0 @@
import { useEffect } from "react";
import { listen, UnlistenFn } from '@tauri-apps/api/event';
import { SoundRegistry } from "@storyteller/soundboard";
import { GetAppPreferences } from "@storyteller/tauri-api";
import { toast } from "@storyteller/ui-toaster";
type ImageGenerationSuccess = {
media_file_token: string,
};
export const useImageGenerationSuccessEvent = () => {
useEffect(() => {
let isUnmounted = false;
let unlisten: Promise<UnlistenFn>;
const setup = async () => {
unlisten = listen<ImageGenerationSuccess>('sora-image-generation-complete', async (event) => {
console.log("Image generation success event received:", event);
const prefs = await GetAppPreferences();
const soundName = prefs.preferences?.generation_success_sound;
if (soundName !== undefined) {
const registry = SoundRegistry.getInstance();
registry.playSound(soundName);
}
toast.success("Image generated!");
});
if (isUnmounted) {
unlisten.then(f => f()); // Unsubscribe if unmounted early.
}
};
setup();
return () => {
isUnmounted = true;
unlisten.then(f => f());
};
}, []);
}
@@ -302,49 +302,6 @@ export const PromptBox2D = ({
});
console.log("generateResponse", generateResponse);
if (generateResponse.status === CommandSuccessStatus.Success) {
const prefs = await GetAppPreferences();
const soundName = prefs.preferences?.enqueue_success_sound;
if (soundName !== undefined) {
const registry = SoundRegistry.getInstance();
registry.playSound(soundName);
}
toast.success("Image added to queue");
} else {
const prefs = await GetAppPreferences();
const soundName = prefs.preferences?.enqueue_failure_sound;
if (soundName !== undefined) {
const registry = SoundRegistry.getInstance();
registry.playSound(soundName);
}
let errorMessage = "Failed to enqueue image";
if ("error_type" in generateResponse) {
switch (generateResponse.error_type) {
case SoraImageRemixErrorType.SoraLoginRequired:
errorMessage =
"You need to log into Sora to continue. See the settings menu.";
break;
case SoraImageRemixErrorType.ServerError:
errorMessage = "Server error. Failed to enqueue image.";
break;
case SoraImageRemixErrorType.TooManyConcurrentTasks:
errorMessage =
"You have too many Sora image generation tasks running. Please wait a moment.";
break;
case SoraImageRemixErrorType.SoraUsernameNotYetCreated:
errorMessage =
"Your Sora username is not yet created. Please visit the Sora.com website to create it first.";
break;
case SoraImageRemixErrorType.SoraIsHavingProblems:
errorMessage = "Sora is having problems. Please try again later.";
break;
}
}
toast.error(errorMessage);
}
};
const handleWebEnqueue = async () => {
@@ -429,49 +429,9 @@ export const PromptBox3D = ({
console.log("generateResponse", generateResponse);
if (generateResponse.status === CommandSuccessStatus.Success) {
const prefs = await GetAppPreferences();
const soundName = prefs.preferences?.enqueue_success_sound;
if (soundName !== undefined) {
const registry = SoundRegistry.getInstance();
registry.playSound(soundName);
}
toast.success("Image added to queue");
setisEnqueueing(false);
return;
} else {
const prefs = await GetAppPreferences();
const soundName = prefs.preferences?.enqueue_failure_sound;
if (soundName !== undefined) {
const registry = SoundRegistry.getInstance();
registry.playSound(soundName);
}
let errorMessage = "Failed to enqueue image";
if ("error_type" in generateResponse) {
switch (generateResponse.error_type) {
case SoraImageRemixErrorType.SoraLoginRequired:
errorMessage =
"You need to log into Sora to continue. See the settings menu.";
break;
case SoraImageRemixErrorType.ServerError:
errorMessage = "Server error. Failed to enqueue image.";
break;
case SoraImageRemixErrorType.TooManyConcurrentTasks:
errorMessage =
"You have too many Sora image generation tasks running. Please wait a moment.";
break;
case SoraImageRemixErrorType.SoraUsernameNotYetCreated:
errorMessage =
"Your Sora username is not yet created. Please visit the Sora.com website to create it first.";
break;
case SoraImageRemixErrorType.SoraIsHavingProblems:
errorMessage =
"Sora is having problems. Please try again later.";
break;
}
}
toast.error(errorMessage);
setisEnqueueing(false);
return;
}
@@ -1,6 +1,5 @@
import { useState, useRef, useEffect } from "react";
import { useSignals } from "@preact/signals-react/runtime";
import { toast } from "@storyteller/ui-toaster";
import { JobContextType } from "@storyteller/common";
import { downloadFileFromUrl } from "@storyteller/api";
import { PopoverMenu, PopoverItem } from "@storyteller/ui-popover";
@@ -25,11 +24,6 @@ import {
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { IsDesktopApp } from "@storyteller/tauri-utils";
import { GalleryItem, GalleryModal } from "@storyteller/ui-gallery-modal";
import {
CommandSuccessStatus,
GetAppPreferences,
} from "@storyteller/tauri-api";
import { SoundRegistry } from "@storyteller/soundboard";
interface ReferenceImage {
id: string;
@@ -209,48 +203,6 @@ export const PromptBoxImage = ({
console.log("generateResponse", generateResponse);
onEnqueuePressed?.();
if (generateResponse.status === CommandSuccessStatus.Success) {
const prefs = await GetAppPreferences();
const soundName = prefs.preferences?.enqueue_success_sound;
if (soundName !== undefined) {
const registry = SoundRegistry.getInstance();
registry.playSound(soundName);
}
toast.success("Image added to queue");
} else {
const prefs = await GetAppPreferences();
const soundName = prefs.preferences?.enqueue_failure_sound;
if (soundName !== undefined) {
const registry = SoundRegistry.getInstance();
registry.playSound(soundName);
}
}
// let errorMessage = "Failed to enqueue image";
// if ("error_type" in generateResponse) {
// switch (generateResponse.error_type) {
// case SoraImageRemixErrorType.SoraLoginRequired:
// errorMessage =
// "You need to log into Sora to continue. See the settings menu.";
// break;
// case SoraImageRemixErrorType.ServerError:
// errorMessage = "Server error. Failed to enqueue image.";
// break;
// case SoraImageRemixErrorType.TooManyConcurrentTasks:
// errorMessage =
// "You have too many Sora image generation tasks running. Please wait a moment.";
// break;
// case SoraImageRemixErrorType.SoraUsernameNotYetCreated:
// errorMessage =
// "Your Sora username is not yet created. Please visit the Sora.com website to create it first.";
// break;
// case SoraImageRemixErrorType.SoraIsHavingProblems:
// errorMessage = "Sora is having problems. Please try again later.";
// break;
// }
// }
// toast.error(errorMessage);
// }
setIsEnqueueing(false);
};
@@ -1,6 +1,5 @@
import { useState, useRef, useEffect } from "react";
import { useSignals } from "@preact/signals-react/runtime";
import { toast } from "@storyteller/ui-toaster";
import { JobContextType } from "@storyteller/common";
import { downloadFileFromUrl } from "@storyteller/api";
import { PopoverMenu, PopoverItem } from "@storyteller/ui-popover";
@@ -21,11 +20,6 @@ import { faRectangle } from "@fortawesome/pro-regular-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { IsDesktopApp } from "@storyteller/tauri-utils";
import { GalleryItem, GalleryModal } from "@storyteller/ui-gallery-modal";
import {
CommandSuccessStatus,
GetAppPreferences,
} from "@storyteller/tauri-api";
import { SoundRegistry } from "@storyteller/soundboard";
interface ReferenceImage {
id: string;
@@ -196,48 +190,6 @@ export const PromptBoxVideo = ({
console.log("generateResponse", generateResponse);
onEnqueuePressed?.();
if (generateResponse.status === CommandSuccessStatus.Success) {
const prefs = await GetAppPreferences();
const soundName = prefs.preferences?.enqueue_success_sound;
if (soundName !== undefined) {
const registry = SoundRegistry.getInstance();
registry.playSound(soundName);
}
toast.success("Image added to queue");
} else {
const prefs = await GetAppPreferences();
const soundName = prefs.preferences?.enqueue_failure_sound;
if (soundName !== undefined) {
const registry = SoundRegistry.getInstance();
registry.playSound(soundName);
}
}
// let errorMessage = "Failed to enqueue image";
// if ("error_type" in generateResponse) {
// switch (generateResponse.error_type) {
// case SoraImageRemixErrorType.SoraLoginRequired:
// errorMessage =
// "You need to log into Sora to continue. See the settings menu.";
// break;
// case SoraImageRemixErrorType.ServerError:
// errorMessage = "Server error. Failed to enqueue image.";
// break;
// case SoraImageRemixErrorType.TooManyConcurrentTasks:
// errorMessage =
// "You have too many Sora image generation tasks running. Please wait a moment.";
// break;
// case SoraImageRemixErrorType.SoraUsernameNotYetCreated:
// errorMessage =
// "Your Sora username is not yet created. Please visit the Sora.com website to create it first.";
// break;
// case SoraImageRemixErrorType.SoraIsHavingProblems:
// errorMessage = "Sora is having problems. Please try again later.";
// break;
// }
// }
// toast.error(errorMessage);
// }
setIsEnqueueing(false);
};