mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-25 02:29:37 +00:00
error categorization
This commit is contained in:
@@ -0,0 +1 @@
|
||||
{"error":{"code":7,"message":"Request rejected by anti-bot rules.","details":[]}}
|
||||
@@ -0,0 +1,37 @@
|
||||
use crate::error::grok_error::GrokError;
|
||||
use crate::error::grok_generic_api_error::GrokGenericApiError;
|
||||
use crate::error::grok_specific_api_error::GrokSpecificApiError;
|
||||
use cloudflare_errors::filter_cloudflare_errors::filter_cloudflare_errors;
|
||||
use wreq::StatusCode;
|
||||
|
||||
/// We know the response is an error at this point.
|
||||
/// We're just turning it into the right error.
|
||||
pub fn categorize_grok_http_error(status_code: StatusCode, maybe_body: Option<&str>) -> GrokError {
|
||||
|
||||
if let Some(body) = maybe_body {
|
||||
if let Err(err) = filter_cloudflare_errors(status_code.as_u16(), body) {
|
||||
return GrokGenericApiError::CloudflareError(err).into();
|
||||
}
|
||||
|
||||
let body = body.to_lowercase();
|
||||
let anti_bot = body.contains("anti-bot") || body.contains("rejected");
|
||||
|
||||
if anti_bot {
|
||||
return GrokSpecificApiError::AutomationBlocked.into();
|
||||
}
|
||||
|
||||
match status_code {
|
||||
StatusCode::TOO_MANY_REQUESTS => {
|
||||
return GrokSpecificApiError::TooManyVideos.into();
|
||||
}
|
||||
_ => {},
|
||||
}
|
||||
|
||||
return GrokGenericApiError::UncategorizedBadResponseWithStatusAndBody {
|
||||
status_code,
|
||||
body: body.to_string(),
|
||||
}.into();
|
||||
}
|
||||
|
||||
GrokGenericApiError::UncategorizedBadResponseWithStatus(status_code).into()
|
||||
}
|
||||
@@ -40,6 +40,9 @@ pub enum GrokGenericApiError {
|
||||
/// Specifically, this is for non-200 (error) responses.
|
||||
SerdeParseErrorWithBodyOnNon200(serde_json::Error, String),
|
||||
|
||||
/// An uncategorized bad HTTP response from Grok.
|
||||
UncategorizedBadResponseWithStatus(StatusCode),
|
||||
|
||||
/// An uncategorized bad HTTP response from Grok.
|
||||
UncategorizedBadResponseWithStatusAndBody {
|
||||
status_code: StatusCode,
|
||||
@@ -69,6 +72,7 @@ impl Display for GrokGenericApiError {
|
||||
Self::UnexpectedWebsocketUpgradeStatusCode(status) => write!(f, "Unexpected websocket upgrade status code: {}", status),
|
||||
Self::SerdeResponseParseErrorWithBody(err, body) => write!(f, "Failed to parse response body: {:?}. Body: {}", err, body),
|
||||
Self::SerdeParseErrorWithBodyOnNon200(err, body) => write!(f, "Failed to parse non-200 response body: {:?}. Body: {}", err, body),
|
||||
Self::UncategorizedBadResponseWithStatus(status) => write!(f, "Uncategorized with status code: {}", status),
|
||||
Self::UncategorizedBadResponseWithStatusAndBody { status_code, body } => write!(f, "Uncategorized bad response: status code {}, body: {}", status_code, body),
|
||||
Self::UploadFailed => write!(f, "Upload failed"),
|
||||
Self::WreqWebsocketUpgradeError(err) => write!(f, "Websocket upgrade error: {}", err),
|
||||
|
||||
@@ -3,7 +3,12 @@ use std::fmt::{Display, Formatter};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum GrokSpecificApiError {
|
||||
TodoError,
|
||||
/// Grok is detecting and blocking our bot, likely due to new secrets use.
|
||||
AutomationBlocked,
|
||||
|
||||
/// Too many videos are being generated.
|
||||
TooManyVideos,
|
||||
|
||||
|
||||
// /// Failed to generate a bearer token despite the `200 OK` response.
|
||||
// /// This has been generated by sending old/expired session cookies or empty cookies.
|
||||
@@ -55,7 +60,8 @@ impl Error for GrokSpecificApiError {}
|
||||
impl Display for GrokSpecificApiError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::TodoError => write!(f, "TodoError"),
|
||||
Self::AutomationBlocked => write!(f, "Automation blocked"),
|
||||
Self::TooManyVideos => write!(f, "Too many videos are being generated"),
|
||||
|
||||
//Self::FailedToGenerateBearerToken => write!(f, "Failed to generate bearer token. Probably invalid or expired session cookies."),
|
||||
//Self::InvalidJwt => write!(f, "Invalid JWT token. Please refresh the token."),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod grok_client_error;
|
||||
pub mod grok_error;
|
||||
pub mod grok_generic_api_error;
|
||||
pub mod grok_specific_api_error;
|
||||
pub mod grok_specific_api_error;
|
||||
pub (crate) mod categorize_grok_http_error;
|
||||
@@ -122,7 +122,7 @@ pub async fn upload_image_and_generate_video<P: AsRef<Path>>(args: UploadImageAn
|
||||
|
||||
if args.wait_for_generation {
|
||||
info!("Waiting for video generation...");
|
||||
let video_gen_result = request.send().await?;
|
||||
let video_gen_result = request.wait_for_video().await?;
|
||||
maybe_video_file_id = video_gen_result.video_file_id;
|
||||
generation_is_complete = true;
|
||||
} else {
|
||||
|
||||
+23
-6
@@ -6,6 +6,7 @@ use crate::datatypes::api::svg_path_data::SvgPathData;
|
||||
use crate::datatypes::api::user_id::UserId;
|
||||
use crate::datatypes::api::verification_token::VerificationToken;
|
||||
use crate::datatypes::api::xsid_numbers::XsidNumbers;
|
||||
use crate::error::categorize_grok_http_error::categorize_grok_http_error;
|
||||
use crate::error::grok_client_error::GrokClientError;
|
||||
use crate::error::grok_error::GrokError;
|
||||
use crate::error::grok_generic_api_error::GrokGenericApiError;
|
||||
@@ -111,7 +112,7 @@ impl <'a> GrokVideoGenChatConversationBuilder<'a> {
|
||||
}
|
||||
|
||||
|
||||
pub async fn send(&self) -> Result<GrokVideoGenChatConversationResponse, GrokError> {
|
||||
pub async fn wait_for_video(&self) -> Result<GrokVideoGenChatConversationResponse, GrokError> {
|
||||
info!("Configuring client and request...");
|
||||
let client = Self::build_client()?;
|
||||
let http_request = self.build_request(&client)?;
|
||||
@@ -139,7 +140,7 @@ impl <'a> GrokVideoGenChatConversationBuilder<'a> {
|
||||
|
||||
/// TODO: Handle anti-bot detection
|
||||
/// Body: {"error":{"code":7,"message":"Request rejected by anti-bot rules.","details":[]}}
|
||||
let response_body = &response.text()
|
||||
let response_body = response.text()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Error reading Grok create media response body: {:?}", err);
|
||||
@@ -266,13 +267,29 @@ impl <'a> GrokVideoGenChatConversationBuilder<'a> {
|
||||
Ok(http_request)
|
||||
}
|
||||
|
||||
async fn send_request(client: &Client, request: Request) -> Result<Response, GrokGenericApiError> {
|
||||
Ok(client.execute(request)
|
||||
async fn send_request(client: &Client, request: Request) -> Result<Response, GrokError> {
|
||||
let response = client.execute(request)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Error during create media: {:?}", err);
|
||||
GrokGenericApiError::WreqError(err)
|
||||
})?)
|
||||
})?;
|
||||
|
||||
let status = response.status();
|
||||
|
||||
if !status.is_success() {
|
||||
let maybe_body = response.text()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Error reading Grok video generation response body: {:?}", err);
|
||||
err
|
||||
})
|
||||
.ok();
|
||||
|
||||
return Err(categorize_grok_http_error(status, maybe_body.as_deref()))
|
||||
}
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,7 +352,7 @@ mod tests {
|
||||
request_timeout: None,
|
||||
};
|
||||
|
||||
let result = request.send().await?;
|
||||
let result = request.wait_for_video().await?;
|
||||
|
||||
println!("Result: {:?}", result);
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<head><title>301 Moved Permanently</title></head>
|
||||
<body>
|
||||
<center><h1>301 Moved Permanently</h1></center>
|
||||
<hr><center>cloudflare</center>
|
||||
</body>
|
||||
</html>
|
||||
@@ -22,39 +22,26 @@ pub fn filter_cloudflare_errors(status_code: u16, body: &str) -> Result<(), Clou
|
||||
let is_cloudflare = body.contains("cloudflare")
|
||||
|| body.contains("Cloudflare");
|
||||
|
||||
if status_code == 301 {
|
||||
/*
|
||||
<html>
|
||||
<head><title>301 Moved Permanently</title></head>
|
||||
<body>
|
||||
<center><h1>301 Moved Permanently</h1></center>
|
||||
<hr><center>cloudflare</center>
|
||||
</body>
|
||||
</html>
|
||||
*/
|
||||
if is_cloudflare {
|
||||
// TODO: Include location header.
|
||||
return Err(CloudflareError::MovedPermanently301);
|
||||
}
|
||||
}
|
||||
|
||||
// let is_cloudflare = body.contains("cloudflare.com")
|
||||
// || body.contains("Cloudflare Ray ID");
|
||||
|
||||
if is_cloudflare {
|
||||
match status_code {
|
||||
502 => return Err(CloudflareError::BadGateway502),
|
||||
504 => return Err(CloudflareError::GatewayTimeout504),
|
||||
524 => return Err(CloudflareError::TimeoutOccurred524),
|
||||
_ => {}, // Fall-through
|
||||
}
|
||||
if !is_cloudflare {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if body.contains("errorcode_504")
|
||||
|| body.contains("Gateway time-out")
|
||||
|| body.contains("Error code 504")
|
||||
{
|
||||
return Err(CloudflareError::GatewayTimeout504);
|
||||
}
|
||||
match status_code {
|
||||
301 => return Err(CloudflareError::MovedPermanently301), // TODO: Include location header.
|
||||
502 => return Err(CloudflareError::BadGateway502),
|
||||
504 => return Err(CloudflareError::GatewayTimeout504),
|
||||
524 => return Err(CloudflareError::TimeoutOccurred524),
|
||||
_ => {},
|
||||
}
|
||||
|
||||
if body.contains("errorcode_504")
|
||||
|| body.contains("Gateway time-out")
|
||||
|| body.contains("Error code 504")
|
||||
{
|
||||
return Err(CloudflareError::GatewayTimeout504);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user