From aef14b46878389ca72eb852dda1470d9bd267ee6 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Mon, 26 May 2025 02:01:12 -0400 Subject: [PATCH] enrich fal error --- .../src/error/classify_fal_error.rs | 20 +++++++++++++++++++ .../src/{ => error}/fal_error_plus.rs | 6 +++++- .../api_clients/fal_client/src/error/mod.rs | 2 ++ crates/lib/api_clients/fal_client/src/lib.rs | 2 +- .../requests/enqueue_hunyuan2_image_to_3d.rs | 16 +++++++-------- .../enqueue_kling_16_image_to_video.rs | 17 ++++++++-------- .../src/requests/remove_background_rembg.rs | 16 +++++++-------- .../src/utils/queue_status_checker.rs | 2 +- 8 files changed, 53 insertions(+), 28 deletions(-) create mode 100644 crates/lib/api_clients/fal_client/src/error/classify_fal_error.rs rename crates/lib/api_clients/fal_client/src/{ => error}/fal_error_plus.rs (84%) create mode 100644 crates/lib/api_clients/fal_client/src/error/mod.rs diff --git a/crates/lib/api_clients/fal_client/src/error/classify_fal_error.rs b/crates/lib/api_clients/fal_client/src/error/classify_fal_error.rs new file mode 100644 index 0000000000..33d529bafc --- /dev/null +++ b/crates/lib/api_clients/fal_client/src/error/classify_fal_error.rs @@ -0,0 +1,20 @@ +use crate::error::fal_error_plus::FalErrorPlus; + +/// Better classify the `fal::FalError` into a more user-friendly `FalErrorPlus`. +pub fn classify_fal_error(err: fal::FalError) -> FalErrorPlus { + match err { + fal::FalError::RequestError(_) => FalErrorPlus::FalError(err), + fal::FalError::ImageError(_) => FalErrorPlus::FalError(err), + fal::FalError::SerializeError(_) => FalErrorPlus::FalError(err), + fal::FalError::StreamError(_) => FalErrorPlus::FalError(err), + fal::FalError::Other(ref inner) => { + if inner.contains("Invalid Key Authorization header format") { + FalErrorPlus::FalApiKeyError(inner.to_string()) + } else if inner.contains("No user found for Key ID and Secret") { + FalErrorPlus::FalApiKeyError(inner.to_string()) + } else { + FalErrorPlus::FalError(err) + } + } + } +} diff --git a/crates/lib/api_clients/fal_client/src/fal_error_plus.rs b/crates/lib/api_clients/fal_client/src/error/fal_error_plus.rs similarity index 84% rename from crates/lib/api_clients/fal_client/src/fal_error_plus.rs rename to crates/lib/api_clients/fal_client/src/error/fal_error_plus.rs index 57259243b6..40afb5aa27 100644 --- a/crates/lib/api_clients/fal_client/src/fal_error_plus.rs +++ b/crates/lib/api_clients/fal_client/src/error/fal_error_plus.rs @@ -1,3 +1,4 @@ +use crate::error::classify_fal_error::classify_fal_error; use std::error::Error; use std::fmt::{Display, Formatter}; @@ -6,6 +7,8 @@ use std::fmt::{Display, Formatter}; pub enum FalErrorPlus { /// An error arising in the `fal` crate. FalError(fal::FalError), + /// The fal API key is invalid. + FalApiKeyError(String), /// Another error we didn't handle. AnyhowError(anyhow::Error), /// URL parse errors. @@ -18,6 +21,7 @@ impl Display for FalErrorPlus { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Self::FalError(err) => write!(f, "FalErrorPlus::FalError: {:?}", err), + Self::FalApiKeyError(reason) => write!(f, "FalErrorPlus::FalApiKeyError: {}", reason), Self::AnyhowError(err) => write!(f, "FalErrorPlus::AnyhowError: {:?}", err), Self::UrlParseError(err) => write!(f, "FalErrorPlus::UrlParseError: {:?}", err), Self::UnhandledEndpoint(endpoint) => write!(f, "FalErrorPlus::UnhandledEndpoint: {:?}", endpoint), @@ -29,7 +33,7 @@ impl Error for FalErrorPlus {} impl From for FalErrorPlus { fn from(err: fal::FalError) -> Self { - FalErrorPlus::FalError(err) + classify_fal_error(err) } } diff --git a/crates/lib/api_clients/fal_client/src/error/mod.rs b/crates/lib/api_clients/fal_client/src/error/mod.rs new file mode 100644 index 0000000000..2d6986b84f --- /dev/null +++ b/crates/lib/api_clients/fal_client/src/error/mod.rs @@ -0,0 +1,2 @@ +pub mod classify_fal_error; +pub mod fal_error_plus; \ No newline at end of file diff --git a/crates/lib/api_clients/fal_client/src/lib.rs b/crates/lib/api_clients/fal_client/src/lib.rs index 2524e89e74..e68f45d794 100644 --- a/crates/lib/api_clients/fal_client/src/lib.rs +++ b/crates/lib/api_clients/fal_client/src/lib.rs @@ -8,7 +8,7 @@ pub mod export { } pub mod creds; -pub mod fal_error_plus; +pub mod error; pub mod model; pub mod requests; pub mod utils; diff --git a/crates/lib/api_clients/fal_client/src/requests/enqueue_hunyuan2_image_to_3d.rs b/crates/lib/api_clients/fal_client/src/requests/enqueue_hunyuan2_image_to_3d.rs index 546f8862f4..6b60173b35 100644 --- a/crates/lib/api_clients/fal_client/src/requests/enqueue_hunyuan2_image_to_3d.rs +++ b/crates/lib/api_clients/fal_client/src/requests/enqueue_hunyuan2_image_to_3d.rs @@ -1,5 +1,6 @@ use crate::creds::fal_api_key::FalApiKey; -use crate::fal_error_plus::FalErrorPlus; +use crate::error::classify_fal_error::classify_fal_error; +use crate::error::fal_error_plus::FalErrorPlus; use crate::model::enqueued_request::EnqueuedRequest; use fal::endpoints::fal_ai::hunyuan3d::v2::v2; use fal::endpoints::fal_ai::hunyuan3d::v2::Hunyuan3DInput; @@ -16,12 +17,6 @@ pub struct Hunyuan2Args<'a, P: AsRef> { pub async fn enqueue_hunyuan2_image_to_3d>(args: Hunyuan2Args<'_, P>) -> Result { let image_url = file_to_base64_url(args.image_path)?; - /* - TODO: Handle error messages - - FalError(FalError(Other("{\"detail\": \"Invalid Key Authorization header format. Expected ':'.\"}"))) - FalError(FalError(Other("{\"detail\": \"No user found for Key ID and Secret\"}"))) - */ - let request = Hunyuan3DInput { input_image_url: image_url, textured_mesh: Some(true), @@ -34,7 +29,12 @@ pub async fn enqueue_hunyuan2_image_to_3d>(args: Hunyuan2Args<'_, let result = v2(request) .with_api_key(&args.api_key.0) .queue() - .await?; + .await; + + let result = match result { + Ok(result) => result, + Err(err) => return Err(classify_fal_error(err)), + }; Ok(EnqueuedRequest::from_queue_response(&result)?) } diff --git a/crates/lib/api_clients/fal_client/src/requests/enqueue_kling_16_image_to_video.rs b/crates/lib/api_clients/fal_client/src/requests/enqueue_kling_16_image_to_video.rs index 73282628bf..a88755b3cb 100644 --- a/crates/lib/api_clients/fal_client/src/requests/enqueue_kling_16_image_to_video.rs +++ b/crates/lib/api_clients/fal_client/src/requests/enqueue_kling_16_image_to_video.rs @@ -1,12 +1,12 @@ use crate::creds::fal_api_key::FalApiKey; -use crate::fal_error_plus::FalErrorPlus; +use crate::error::classify_fal_error::classify_fal_error; +use crate::error::fal_error_plus::FalErrorPlus; use crate::model::enqueued_request::EnqueuedRequest; use fal::endpoints::fal_ai::kling_video::v1_6::pro::image_to_video::{image_to_video, ProImageToVideoRequest}; use fal_client::file_to_base64_url::file_to_base64_url; use futures::StreamExt; use std::io::Write; use std::path::Path; -use url::Url; pub struct Kling16Args<'a, P: AsRef> { pub image_path: P, @@ -24,12 +24,6 @@ pub enum Kling16Duration { pub async fn enqueue_kling_16_image_to_video>(args: Kling16Args<'_, P>) -> Result { let image_url = file_to_base64_url(args.image_path)?; - /* - TODO: Handle error messages - - FalError(FalError(Other("{\"detail\": \"Invalid Key Authorization header format. Expected ':'.\"}"))) - FalError(FalError(Other("{\"detail\": \"No user found for Key ID and Secret\"}"))) - */ - let duration = match args.duration{ Kling16Duration::Default => None, Kling16Duration::FiveSeconds => Some("5".to_string()), // Gross... @@ -49,7 +43,12 @@ pub async fn enqueue_kling_16_image_to_video>(args: Kling16Args<' let result = image_to_video(request) .with_api_key(&args.api_key.0) .queue() - .await?; + .await; + + let result = match result { + Ok(result) => result, + Err(err) => return Err(classify_fal_error(err)), + }; Ok(EnqueuedRequest::from_queue_response(&result)?) } diff --git a/crates/lib/api_clients/fal_client/src/requests/remove_background_rembg.rs b/crates/lib/api_clients/fal_client/src/requests/remove_background_rembg.rs index c82b1b2d9b..fc2b37b8b7 100644 --- a/crates/lib/api_clients/fal_client/src/requests/remove_background_rembg.rs +++ b/crates/lib/api_clients/fal_client/src/requests/remove_background_rembg.rs @@ -1,5 +1,6 @@ use crate::creds::fal_api_key::FalApiKey; -use crate::fal_error_plus::FalErrorPlus; +use crate::error::classify_fal_error::classify_fal_error; +use crate::error::fal_error_plus::FalErrorPlus; use fal::endpoints::fal_ai::imageutils::rembg::RemoveBackgroundInput; use fal::prelude::fal_ai::imageutils::rembg::rembg; use fal::prelude::*; @@ -21,12 +22,6 @@ pub struct RemBgResponse { pub async fn remove_background_rembg>(image_path: P, api_key: &FalApiKey) -> Result { let image_url = file_to_base64_url(image_path)?; - /* - TODO: Handle error messages - - FalError(FalError(Other("{\"detail\": \"Invalid Key Authorization header format. Expected ':'.\"}"))) - FalError(FalError(Other("{\"detail\": \"No user found for Key ID and Secret\"}"))) - */ - let request = RemoveBackgroundInput { image_url, crop_to_bbox: None, @@ -36,7 +31,12 @@ pub async fn remove_background_rembg>(image_path: P, api_key: &Fa let result = rembg(request) .with_api_key(&api_key.0) .queue() - .await?; + .await; + + let result = match result { + Ok(result) => result, + Err(err) => return Err(classify_fal_error(err)), + }; let mut stream = result.stream(true).await?; diff --git a/crates/lib/api_clients/fal_client/src/utils/queue_status_checker.rs b/crates/lib/api_clients/fal_client/src/utils/queue_status_checker.rs index e93e300cf3..61eb64ea63 100644 --- a/crates/lib/api_clients/fal_client/src/utils/queue_status_checker.rs +++ b/crates/lib/api_clients/fal_client/src/utils/queue_status_checker.rs @@ -1,5 +1,5 @@ use crate::creds::fal_api_key::FalApiKey; -use crate::fal_error_plus::FalErrorPlus; +use crate::error::fal_error_plus::FalErrorPlus; use crate::model::enqueued_request::EnqueuedRequest; use crate::model::fal_endpoint::FalEndpoint; use fal::endpoints::fal_ai::hunyuan3d::v2::ObjectOutput;