diff --git a/Cargo.lock b/Cargo.lock index e06af591d1..ae7e174eed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -791,6 +791,7 @@ dependencies = [ "seedance2pro", "serde", "serde_derive", + "strum 0.28.0", "test_data", "tokens", "tokio", @@ -1523,7 +1524,7 @@ dependencies = [ "bitflags 2.11.0", "cexpr", "clang-sys", - "itertools 0.11.0", + "itertools 0.13.0", "proc-macro2", "quote", "regex", @@ -3471,7 +3472,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.7.4", + "libloading 0.8.6", ] [[package]] @@ -3776,7 +3777,7 @@ dependencies = [ "serde_json", "sqlx", "storyteller_root", - "strum", + "strum 0.26.2", "tokens", "tokio", "workspace-build-acceleration", @@ -3938,7 +3939,7 @@ dependencies = [ "sqlx", "sqlx-core", "sqlx-mysql", - "strum", + "strum 0.26.2", "toml 0.8.23", "utoipa", "workspace-build-acceleration", @@ -3952,7 +3953,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "strum", + "strum 0.26.2", "toml 0.8.23", "utoipa", "workspace-build-acceleration", @@ -6501,7 +6502,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -7066,7 +7067,7 @@ dependencies = [ "serde_json", "sqlx", "storyteller_root", - "strum", + "strum 0.26.2", "tempdir", "tokens", "tokio", @@ -11581,8 +11582,8 @@ dependencies = [ "server_environment", "speculoos", "sqlx", - "strum", - "strum_macros", + "strum 0.26.2", + "strum_macros 0.26.4", "tempdir", "tempfile", "testing", @@ -11667,7 +11668,16 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" dependencies = [ - "strum_macros", + "strum_macros 0.26.4", +] + +[[package]] +name = "strum" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" +dependencies = [ + "strum_macros 0.28.0", ] [[package]] @@ -11683,6 +11693,18 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "strum_macros" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "subprocess" version = "0.2.9" @@ -12679,7 +12701,7 @@ dependencies = [ "sqlx", "sqlx-core", "sqlx-mysql", - "strum", + "strum 0.26.2", "utoipa", "workspace-build-acceleration", ] @@ -14029,7 +14051,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "strum", + "strum 0.26.2", "workspace-build-acceleration", ] diff --git a/Cargo.toml b/Cargo.toml index 059031e9f4..a0668a4955 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -283,12 +283,13 @@ redis = { version = "1.0.2", features = ["r2d2", "tokio-rustls-comp", "tokio-com regex = "1.12.3" reqwest = { version = "0.12.23", default-features = false, features = [ "charset", "http2", "system-proxy", "json", "cookies", "rustls-tls", "gzip" ] } reqwest-websocket = { version = "0.5.0" } -serde = { version = "1.0.219", features = ["derive"] } +serde = { version = "1.0.219", features = ["derive"] } serde_derive = "1.0.219" serde_json = "1.0.140" serde_yaml = "0.9.34+deprecated" sha2 = "0.11.0-rc.2" sha3 = "0.10.8" +strum = { version = "0.28.0", features = ["derive"] } tauri = { version = "2.8.3", features = ["unstable", "devtools"] } # NB: "devtools" prevents App Store distribution; "ubstable" is needed for window access tauri-plugin-dialog = "2.3.3" tauri-plugin-fs = "2.4.2" diff --git a/crates/api_clients/artcraft/artcraft_router/Cargo.toml b/crates/api_clients/artcraft/artcraft_router/Cargo.toml index 8d45dc735e..806ff036e7 100644 --- a/crates/api_clients/artcraft/artcraft_router/Cargo.toml +++ b/crates/api_clients/artcraft/artcraft_router/Cargo.toml @@ -32,3 +32,5 @@ uuid.workspace = true [dev-dependencies] test_data.workspace = true +strum.workspace = true + diff --git a/crates/api_clients/artcraft/artcraft_router/src/api/common_aspect_ratio.rs b/crates/api_clients/artcraft/artcraft_router/src/api/common_aspect_ratio.rs index c16d63e159..e206b15e36 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/api/common_aspect_ratio.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/api/common_aspect_ratio.rs @@ -1,9 +1,12 @@ use serde_derive::{Deserialize, Serialize}; +#[cfg(test)] +use strum::EnumIter; /// This is a comprehensive list of common aspect ratios you can specify when enqueuing a generation. /// Not every model will support every aspect ratio. /// In the case a model doesn't support the aspect ratio, gracefully pick the nearest option. #[derive(Copy, Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(test, derive(EnumIter))] #[serde(rename_all = "snake_case")] pub enum CommonAspectRatio { // Auto (eg. for image editing to use the source; used by Nano Banana Pro edit image, but not text-to-image) diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_image/execute/artcraft/generate_image_artcraft_seedream_4.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_image/execute/artcraft/generate_image_artcraft_seedream_4.rs index 7a7e6209e6..379d19cf4b 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_image/execute/artcraft/generate_image_artcraft_seedream_4.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_image/execute/artcraft/generate_image_artcraft_seedream_4.rs @@ -38,9 +38,11 @@ pub async fn execute_artcraft_seedream_4( mod tests { use crate::api::common_aspect_ratio::CommonAspectRatio; use crate::api::image_list_ref::ImageListRef; + use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy; use crate::generate::generate_image::generate_image_request::GenerateImageRequest; use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan; use crate::test_helpers::{base_seedream_4_image_request, get_artcraft_client}; + use strum::IntoEnumIterator; use tokens::tokens::media_files::MediaFileToken; #[tokio::test] @@ -92,4 +94,67 @@ mod tests { assert_eq!(1, 2); // NB: Intentional failure to inspect the response above. } + + #[tokio::test] + #[ignore] // manually run — fires one real API request per aspect ratio variant (expensive) + async fn test_text_to_image_seedream_4_all_aspect_ratios() { + let client = get_artcraft_client(); + + for ar in CommonAspectRatio::iter() { + println!("--- text-to-image aspect ratio: {:?} ---", ar); + let request = GenerateImageRequest { + aspect_ratio: Some(ar), + image_batch_count: Some(1), + prompt: Some("a shiba walking through a cyberpunk city at night"), + request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade, + ..base_seedream_4_image_request() + }; + match request.build() { + Err(e) => println!(" plan error: {:?}", e), + Ok(plan) => match plan.generate_image(&client).await { + Ok(response) => { + let payload = response.get_artcraft_payload().expect("expected Artcraft payload"); + println!(" job token: {:?}", payload.inference_job_token); + } + Err(e) => println!(" generate error: {:?}", e), + }, + } + } + + assert_eq!(1, 2); // NB: Intentional failure to inspect the responses above. + } + + #[tokio::test] + #[ignore] // manually run — fires one real API request per aspect ratio variant (expensive) + async fn test_edit_image_seedream_4_all_aspect_ratios() { + let client = get_artcraft_client(); + + let image_tokens = vec![ + MediaFileToken::new_from_str("m_r45apt2swza6wp8j2z10237t92kkr8"), + ]; + + for ar in CommonAspectRatio::iter() { + println!("--- image-edit aspect ratio: {:?} ---", ar); + let request = GenerateImageRequest { + prompt: Some("Change the background to a sunny beach"), + image_inputs: Some(ImageListRef::MediaFileTokens(&image_tokens)), + aspect_ratio: Some(ar), + image_batch_count: Some(1), + request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade, + ..base_seedream_4_image_request() + }; + match request.build() { + Err(e) => println!(" plan error: {:?}", e), + Ok(plan) => match plan.generate_image(&client).await { + Ok(response) => { + let payload = response.get_artcraft_payload().expect("expected Artcraft payload"); + println!(" job token: {:?}", payload.inference_job_token); + } + Err(e) => println!(" generate error: {:?}", e), + }, + } + } + + assert_eq!(1, 2); // NB: Intentional failure to inspect the responses above. + } } diff --git a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_image/execute/artcraft/generate_image_artcraft_seedream_4p5.rs b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_image/execute/artcraft/generate_image_artcraft_seedream_4p5.rs index 819c9b361a..7b4bca8e19 100644 --- a/crates/api_clients/artcraft/artcraft_router/src/generate/generate_image/execute/artcraft/generate_image_artcraft_seedream_4p5.rs +++ b/crates/api_clients/artcraft/artcraft_router/src/generate/generate_image/execute/artcraft/generate_image_artcraft_seedream_4p5.rs @@ -38,9 +38,11 @@ pub async fn execute_artcraft_seedream_4p5( mod tests { use crate::api::common_aspect_ratio::CommonAspectRatio; use crate::api::image_list_ref::ImageListRef; + use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy; use crate::generate::generate_image::generate_image_request::GenerateImageRequest; use crate::generate::generate_image::image_generation_plan::ImageGenerationPlan; use crate::test_helpers::{base_seedream_4p5_image_request, get_artcraft_client}; + use strum::IntoEnumIterator; use tokens::tokens::media_files::MediaFileToken; #[tokio::test] @@ -92,4 +94,67 @@ mod tests { assert_eq!(1, 2); // NB: Intentional failure to inspect the response above. } + + #[tokio::test] + #[ignore] // manually run — fires one real API request per aspect ratio variant (expensive) + async fn test_text_to_image_seedream_4p5_all_aspect_ratios() { + let client = get_artcraft_client(); + + for ar in CommonAspectRatio::iter() { + println!("--- text-to-image aspect ratio: {:?} ---", ar); + let request = GenerateImageRequest { + aspect_ratio: Some(ar), + image_batch_count: Some(1), + prompt: Some("a corgi walking through a cyberpunk city at night"), + request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade, + ..base_seedream_4p5_image_request() + }; + match request.build() { + Err(e) => println!(" plan error: {:?}", e), + Ok(plan) => match plan.generate_image(&client).await { + Ok(response) => { + let payload = response.get_artcraft_payload().expect("expected Artcraft payload"); + println!(" job token: {:?}", payload.inference_job_token); + } + Err(e) => println!(" generate error: {:?}", e), + }, + } + } + + assert_eq!(1, 2); // NB: Intentional failure to inspect the responses above. + } + + #[tokio::test] + #[ignore] // manually run — fires one real API request per aspect ratio variant (expensive) + async fn test_edit_image_seedream_4p5_all_aspect_ratios() { + let client = get_artcraft_client(); + + let image_tokens = vec![ + MediaFileToken::new_from_str("m_r45apt2swza6wp8j2z10237t92kkr8"), + ]; + + for ar in CommonAspectRatio::iter() { + println!("--- image-edit aspect ratio: {:?} ---", ar); + let request = GenerateImageRequest { + prompt: Some("Change the background to a spooky haunted house"), + image_inputs: Some(ImageListRef::MediaFileTokens(&image_tokens)), + aspect_ratio: Some(ar), + image_batch_count: Some(1), + request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade, + ..base_seedream_4p5_image_request() + }; + match request.build() { + Err(e) => println!(" plan error: {:?}", e), + Ok(plan) => match plan.generate_image(&client).await { + Ok(response) => { + let payload = response.get_artcraft_payload().expect("expected Artcraft payload"); + println!(" job token: {:?}", payload.inference_job_token); + } + Err(e) => println!(" generate error: {:?}", e), + }, + } + } + + assert_eq!(1, 2); // NB: Intentional failure to inspect the responses above. + } }