diff --git a/crates/lib/data/primitives/src/lazy_any_option_true.rs b/crates/lib/data/primitives/src/lazy_any_option_true.rs new file mode 100644 index 0000000000..05f97849ad --- /dev/null +++ b/crates/lib/data/primitives/src/lazy_any_option_true.rs @@ -0,0 +1,94 @@ + +//pub type LazyOptional = Box Option + Send>; +pub type LazyOptional<'a> = Box Option + 'a>; + +/// Lazily evaluate a list of boxed closures that return Option. +/// +/// - If any result in true, return Some(true). +/// The first true will end the evaluation. +/// +/// - If none are true, but any result in false, return Some(false). +/// +/// - Else, return None +pub fn lazy_any_option_true(functions: &[LazyOptional]) -> Option +{ + let mut opt_false_found = false; + for func in functions.iter() { + match func() { + Some(true) => return Some(true), + Some(false) => if !opt_false_found { opt_false_found = true }, + None => continue, + } + } + if opt_false_found { + Some(false) + } else { + None + } +} + +#[cfg(test)] +mod tests { + + #[test] + fn empty() { + let result = super::lazy_any_option_true(&[]); + assert_eq!(result, None); + } + + #[test] + fn all_empty() { + let result = super::lazy_any_option_true(&[ + Box::new(|| None), + Box::new(|| None), + ]); + assert_eq!(result, None); + } + + #[test] + fn all_false() { + let result = super::lazy_any_option_true(&[ + Box::new(|| Some(false)), + Box::new(|| Some(false)), + ]); + assert_eq!(result, Some(false)); + } + + #[test] + fn mix_false_none() { + let result = super::lazy_any_option_true(&[ + Box::new(|| None), + Box::new(|| Some(false)), + Box::new(|| Some(false)), + Box::new(|| None), + ]); + assert_eq!(result, Some(false)); + } + + #[test] + fn mix() { + let result = super::lazy_any_option_true(&[ + Box::new(|| None), + Box::new(|| Some(false)), + Box::new(|| Some(true)), + Box::new(|| Some(false)), + Box::new(|| None), + ]); + assert_eq!(result, Some(true)); + } + + #[test] + fn mix_closure_capture() { + let truthy = Some(true); + let falsy = Some(true); + + let result = super::lazy_any_option_true(&[ + Box::new(|| None), + Box::new(|| (&falsy).map(|inner| inner.clone())), + Box::new(|| (&truthy).map(|inner| inner.clone())), + Box::new(|| (&falsy).map(|inner| inner.clone())), + Box::new(|| None), + ]); + assert_eq!(result, Some(true)); + } +} diff --git a/crates/lib/data/primitives/src/lib.rs b/crates/lib/data/primitives/src/lib.rs index 549ffadd79..c2003b13d9 100644 --- a/crates/lib/data/primitives/src/lib.rs +++ b/crates/lib/data/primitives/src/lib.rs @@ -18,6 +18,7 @@ #![allow(dead_code)] #![allow(non_snake_case)] +pub mod lazy_any_option_true; pub mod str_to_bool; pub mod traits; pub mod trim_or_empty; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/workflows/enqueue_video_style_transfer_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/workflows/enqueue_video_style_transfer_handler.rs index 4902e9815d..f58d66a6fc 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/workflows/enqueue_video_style_transfer_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/workflows/enqueue_video_style_transfer_handler.rs @@ -22,6 +22,7 @@ use mysql_queries::payloads::generic_inference_args::generic_inference_args::{Ge use mysql_queries::payloads::generic_inference_args::workflow_payload::WorkflowArgs; use mysql_queries::queries::generic_inference::web::insert_generic_inference_job::{insert_generic_inference_job, InsertGenericInferenceArgs}; use mysql_queries::queries::idepotency_tokens::insert_idempotency_token::insert_idempotency_token; +use primitives::lazy_any_option_true::lazy_any_option_true; use primitives::str_to_bool::str_to_bool; use primitives::traits::trim_or_emptyable::TrimOrEmptyable; use primitives::try_str_to_num::try_str_to_num; @@ -92,6 +93,7 @@ pub struct EnqueueVideoStyleTransferRequest { enable_lipsync: Option, /// Use lipsync in the workflow + #[deprecated(note = "use enable_lipsync")] use_lipsync: Option, /// Remove watermark from the output @@ -319,28 +321,30 @@ pub async fn enqueue_video_style_transfer_handler( .transpose()?; let coordinated_args = CoordinatedWorkflowArgs { - use_lipsync: request.use_lipsync - .or_else(|| request.enable_lipsync) - .or_else(|| { - get_request_header_optional(&http_request, "LIPSYNC-ENABLED") - .map(|value| str_to_bool(&value)) - }), + use_lipsync: lazy_any_option_true(&[ + Box::new(|| request.enable_lipsync), + Box::new(|| request.use_lipsync), + Box::new(|| get_request_header_optional(&http_request, "LIPSYNC-ENABLED") + .map(|value| str_to_bool(&value))) + ]), + disable_lcm: lazy_any_option_true(&[ + Box::new(|| request.disable_lcm), + Box::new(|| get_request_header_optional(&http_request, "DISABLE-LCM") + .map(|value| str_to_bool(&value))) + ]), + use_cinematic: lazy_any_option_true(&[ + Box::new(|| request.use_cinematic), + Box::new(|| get_request_header_optional(&http_request, "USE-CINEMATIC") + .map(|value| str_to_bool(&value))) + ]), use_face_detailer: request.use_face_detailer, use_upscaler: request.use_upscaler, remove_watermark: request.remove_watermark, - disable_lcm: request.disable_lcm - .or_else(|| { - get_request_header_optional(&http_request, "DISABLE-LCM") - .map(|value| str_to_bool(&value)) - }), - use_cinematic: request.use_cinematic - .or_else(|| { - get_request_header_optional(&http_request, "USE-CINEMATIC") - .map(|value| str_to_bool(&value)) - }), }; - let coordinated_args = coordinate_workflow_args(coordinated_args, is_staff || has_paid_plan); + let is_allowed_expensive_generation = is_staff || has_paid_plan; + + let coordinated_args = coordinate_workflow_args(coordinated_args, is_allowed_expensive_generation); let inference_args = WorkflowArgs { maybe_input_file: Some(request.input_file.clone()),