mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-31 07:45:55 -04:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf09c7f689 | ||
|
|
59ea176d4c |
+1
@@ -62,6 +62,7 @@ pub async fn insert_generic_inference_job_for_fal_queue<'e, 'c : 'e, E>(args: In
|
||||
maybe_avt_token: args.maybe_avt_token,
|
||||
creator_ip_address: args.creator_ip_address,
|
||||
creator_set_visibility: args.creator_set_visibility,
|
||||
starting_job_status_override: None,
|
||||
mysql_executor: args.mysql_executor,
|
||||
phantom: args.phantom,
|
||||
};
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
use idempotency::uuid::generate_random_uuid;
|
||||
use sqlx::{Executor, MySql};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use enums::common::job_status_plus::JobStatusPlus;
|
||||
use enums::common::visibility::Visibility;
|
||||
use tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken;
|
||||
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
|
||||
use tokens::tokens::prompts::PromptToken;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::errors::database_query_error::DatabaseQueryError;
|
||||
use crate::payloads::generic_inference_args::generic_inference_args::GenericInferenceArgs;
|
||||
use crate::queries::generic_inference::fal::insert_generic_inference_job_for_fal_queue::FalCategory;
|
||||
use crate::queries::generic_inference::fal::insert_generic_inference_job_for_fal_queue_with_apriori_job_token::{
|
||||
insert_generic_inference_job_for_fal_queue_with_apriori_job_token,
|
||||
InsertGenericInferenceForFalWithAprioriJobTokenArgs,
|
||||
};
|
||||
|
||||
/// Same as [`InsertGenericInferenceForFalArgs`] but without `maybe_external_third_party_id`,
|
||||
/// since no external Fal call was made. The inserted job will have status
|
||||
/// [`JobStatusPlus::CompleteFailure`] immediately, making it a synthetic failed job useful
|
||||
/// for testing error-handling paths on the frontend without touching real inference services.
|
||||
pub struct InsertGenericInferenceForFalMockFailureArgs<'e, 'c, E>
|
||||
where E: 'e + Executor<'c, Database = MySql>
|
||||
{
|
||||
pub uuid_idempotency_token: &'e str,
|
||||
|
||||
pub fal_category: FalCategory,
|
||||
|
||||
pub maybe_inference_args: Option<GenericInferenceArgs>,
|
||||
|
||||
pub maybe_prompt_token: Option<&'e PromptToken>,
|
||||
|
||||
pub maybe_creator_user_token: Option<&'e UserToken>,
|
||||
pub maybe_avt_token: Option<&'e AnonymousVisitorTrackingToken>,
|
||||
pub creator_ip_address: &'e str,
|
||||
pub creator_set_visibility: Visibility,
|
||||
|
||||
pub mysql_executor: E,
|
||||
|
||||
pub phantom: PhantomData<&'c E>,
|
||||
}
|
||||
|
||||
pub async fn insert_generic_inference_job_for_fal_queue_mock_failure<'e, 'c: 'e, E>(
|
||||
args: InsertGenericInferenceForFalMockFailureArgs<'e, 'c, E>,
|
||||
) -> Result<InferenceJobToken, DatabaseQueryError>
|
||||
where E: 'e + Executor<'c, Database = MySql>
|
||||
{
|
||||
let job_token = InferenceJobToken::generate();
|
||||
let synthetic_external_id = format!("synthetic_{}", generate_random_uuid());
|
||||
|
||||
let inner_args = InsertGenericInferenceForFalWithAprioriJobTokenArgs {
|
||||
uuid_idempotency_token: args.uuid_idempotency_token,
|
||||
apriori_job_token: &job_token,
|
||||
maybe_external_third_party_id: &synthetic_external_id,
|
||||
fal_category: args.fal_category,
|
||||
maybe_inference_args: args.maybe_inference_args,
|
||||
maybe_prompt_token: args.maybe_prompt_token,
|
||||
maybe_creator_user_token: args.maybe_creator_user_token,
|
||||
maybe_avt_token: args.maybe_avt_token,
|
||||
creator_ip_address: args.creator_ip_address,
|
||||
creator_set_visibility: args.creator_set_visibility,
|
||||
starting_job_status_override: Some(JobStatusPlus::CompleteFailure),
|
||||
mysql_executor: args.mysql_executor,
|
||||
phantom: args.phantom,
|
||||
};
|
||||
|
||||
insert_generic_inference_job_for_fal_queue_with_apriori_job_token(inner_args).await
|
||||
}
|
||||
+6
-2
@@ -46,6 +46,10 @@ pub struct InsertGenericInferenceForFalWithAprioriJobTokenArgs<'e, 'c, E>
|
||||
pub creator_ip_address: &'e str,
|
||||
pub creator_set_visibility: Visibility,
|
||||
|
||||
/// Override the initial job status. Defaults to `Pending` when `None`.
|
||||
/// Set to `Some(JobStatusPlus::CompleteFailure)` for mock/test failure jobs.
|
||||
pub starting_job_status_override: Option<JobStatusPlus>,
|
||||
|
||||
pub mysql_executor: E,
|
||||
|
||||
// TODO: Not sure if this works to tell the compiler we need the lifetime annotation.
|
||||
@@ -86,7 +90,7 @@ pub async fn insert_generic_inference_job_for_fal_queue_with_apriori_job_token<'
|
||||
|
||||
let maybe_external_third_party = InferenceJobExternalThirdParty::Fal;
|
||||
|
||||
const STATUS : JobStatusPlus = JobStatusPlus::Pending;
|
||||
let status = args.starting_job_status_override.unwrap_or(JobStatusPlus::Pending);
|
||||
|
||||
let query = sqlx::query!(
|
||||
r#"
|
||||
@@ -152,7 +156,7 @@ SET
|
||||
args.creator_ip_address,
|
||||
args.creator_set_visibility.to_str(),
|
||||
|
||||
STATUS.to_str(),
|
||||
status.to_str(),
|
||||
);
|
||||
|
||||
let query_result = query.execute(args.mysql_executor)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod get_inference_job_by_fal_id;
|
||||
pub mod insert_generic_inference_job_for_fal_queue;
|
||||
pub mod insert_generic_inference_job_for_fal_queue_mock_failure;
|
||||
pub mod insert_generic_inference_job_for_fal_queue_with_apriori_job_token;
|
||||
pub mod mark_fal_generic_inference_job_successfully_done;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
/// Returns `true` if the prompt contains the secret test phrase that triggers
|
||||
/// a synthetic job failure. The job record is inserted with
|
||||
/// `JobStatusPlus::CompleteFailure` immediately, without calling any external
|
||||
/// inference service or performing billing.
|
||||
pub fn is_job_failure_test(prompt: &str) -> bool {
|
||||
prompt.to_ascii_lowercase().contains("artcraft_test_job_failure")
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
pub mod job_failure_test;
|
||||
pub mod payments_error_test;
|
||||
+1
@@ -278,6 +278,7 @@ pub async fn gemini_25_flash_edit_image_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -300,6 +300,7 @@ pub async fn gpt_image_1_edit_image_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -252,6 +252,7 @@ pub async fn qwen_edit_image_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+93
@@ -2,6 +2,7 @@ use std::sync::Arc;
|
||||
|
||||
use crate::billing::wallets::temporary_test_wallet_deduction::temporary_test_wallet_deduction;
|
||||
use crate::http_server::common_responses::common_web_error::CommonWebError;
|
||||
use crate::http_server::endpoints::generate::common::job_failure_test::is_job_failure_test;
|
||||
use crate::http_server::endpoints::generate::common::payments_error_test::payments_error_test;
|
||||
use crate::http_server::validations::validate_idempotency_token_format::validate_idempotency_token_format;
|
||||
use crate::state::server_state::ServerState;
|
||||
@@ -20,9 +21,12 @@ use log::{error, info, warn};
|
||||
use mysql_queries::queries::generic_inference::fal::insert_generic_inference_job_for_fal_queue::insert_generic_inference_job_for_fal_queue;
|
||||
use mysql_queries::queries::generic_inference::fal::insert_generic_inference_job_for_fal_queue::FalCategory;
|
||||
use mysql_queries::queries::generic_inference::fal::insert_generic_inference_job_for_fal_queue::InsertGenericInferenceForFalArgs;
|
||||
use mysql_queries::queries::generic_inference::fal::insert_generic_inference_job_for_fal_queue_mock_failure::{insert_generic_inference_job_for_fal_queue_mock_failure, InsertGenericInferenceForFalMockFailureArgs};
|
||||
use mysql_queries::queries::idepotency_tokens::insert_idempotency_token::insert_idempotency_token;
|
||||
use mysql_queries::queries::prompts::insert_prompt::{insert_prompt, InsertPromptArgs};
|
||||
use sqlx::Acquire;
|
||||
use tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken;
|
||||
use tokens::tokens::users::UserToken;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Flux 1 Dev text to image
|
||||
@@ -90,6 +94,18 @@ pub async fn generate_flux_1_dev_text_to_image_handler(
|
||||
CommonWebError::BadInputWithSimpleMessage("repeated idempotency token".to_string())
|
||||
})?;
|
||||
|
||||
// Secret test hook: insert a synthetic "complete_failure" job without calling Fal.
|
||||
if is_job_failure_test(request.prompt.as_deref().unwrap_or("")) {
|
||||
return insert_mock_failure_job(
|
||||
&http_request,
|
||||
request.prompt.as_deref(),
|
||||
&request.uuid_idempotency_token,
|
||||
maybe_user_session.as_ref().map(|s| &s.user_token),
|
||||
maybe_avt_token.as_ref(),
|
||||
&mut mysql_connection,
|
||||
).await;
|
||||
}
|
||||
|
||||
// // TODO: This is test code
|
||||
// let credits = match request.num_images {
|
||||
// Some(GenerateFlux1DevTextToImageNumImages::One) => 100,
|
||||
@@ -227,3 +243,80 @@ pub async fn generate_flux_1_dev_text_to_image_handler(
|
||||
inference_job_token: job_token,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Inserts a synthetic `CompleteFailure` job without calling Fal.
|
||||
/// Used when the prompt triggers the secret job-failure test phrase.
|
||||
async fn insert_mock_failure_job(
|
||||
http_request: &HttpRequest,
|
||||
prompt: Option<&str>,
|
||||
uuid_idempotency_token: &str,
|
||||
maybe_creator_user_token: Option<&UserToken>,
|
||||
maybe_avt_token: Option<&AnonymousVisitorTrackingToken>,
|
||||
mysql_connection: &mut sqlx::pool::PoolConnection<sqlx::MySql>,
|
||||
) -> Result<Json<GenerateFlux1DevTextToImageResponse>, CommonWebError> {
|
||||
let ip_address = get_request_ip(http_request);
|
||||
|
||||
let mut transaction = mysql_connection
|
||||
.begin()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Error starting MySQL transaction: {:?}", err);
|
||||
CommonWebError::ServerError
|
||||
})?;
|
||||
|
||||
let prompt_result = insert_prompt(InsertPromptArgs {
|
||||
maybe_apriori_prompt_token: None,
|
||||
prompt_type: PromptType::ArtcraftApp,
|
||||
maybe_creator_user_token,
|
||||
maybe_model_type: Some(ModelType::Flux1Dev),
|
||||
maybe_generation_provider: Some(GenerationProvider::Artcraft),
|
||||
maybe_positive_prompt: prompt,
|
||||
maybe_negative_prompt: None,
|
||||
maybe_other_args: None,
|
||||
creator_ip_address: &ip_address,
|
||||
mysql_executor: &mut *transaction,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
let prompt_token = match prompt_result {
|
||||
Ok(token) => Some(token),
|
||||
Err(err) => {
|
||||
warn!("Error inserting prompt for mock failure job: {:?}", err);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let mock_result = insert_generic_inference_job_for_fal_queue_mock_failure(InsertGenericInferenceForFalMockFailureArgs {
|
||||
uuid_idempotency_token,
|
||||
fal_category: FalCategory::ImageGeneration,
|
||||
maybe_inference_args: None,
|
||||
maybe_prompt_token: prompt_token.as_ref(),
|
||||
maybe_creator_user_token,
|
||||
maybe_avt_token,
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
let job_token = match mock_result {
|
||||
Ok(token) => token,
|
||||
Err(err) => {
|
||||
warn!("Error inserting mock failure job: {:?}", err);
|
||||
return Err(CommonWebError::ServerError);
|
||||
}
|
||||
};
|
||||
|
||||
transaction
|
||||
.commit()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Error committing mock failure transaction: {:?}", err);
|
||||
CommonWebError::ServerError
|
||||
})?;
|
||||
|
||||
Ok(Json(GenerateFlux1DevTextToImageResponse {
|
||||
success: true,
|
||||
inference_job_token: job_token,
|
||||
}))
|
||||
}
|
||||
|
||||
+1
@@ -187,6 +187,7 @@ pub async fn generate_flux_pro_11_text_to_image_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -191,6 +191,7 @@ pub async fn generate_flux_pro_11_ultra_text_to_image_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -234,6 +234,7 @@ pub async fn generate_gpt_image_1_text_to_image_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -299,6 +299,7 @@ pub async fn bytedance_seedream_v4_multi_function_image_gen_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -297,6 +297,7 @@ pub async fn bytedance_seedream_v4p5_multi_function_image_gen_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -387,6 +387,7 @@ pub async fn gpt_image_1p5_multi_function_image_gen_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -330,6 +330,7 @@ pub async fn nano_banana_multi_function_image_gen_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -345,6 +345,7 @@ pub async fn nano_banana_pro_multi_function_image_gen_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -248,6 +248,7 @@ pub async fn generate_kling_1_6_pro_video_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -233,6 +233,7 @@ pub async fn generate_kling_2_1_master_video_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -248,6 +248,7 @@ pub async fn generate_kling_2_1_pro_video_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -263,6 +263,7 @@ pub async fn generate_seedance_1_0_lite_image_to_video_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -240,6 +240,7 @@ pub async fn generate_seedance_1_0_pro_image_to_video_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -246,6 +246,7 @@ pub async fn generate_veo_2_image_to_video_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -239,6 +239,7 @@ pub async fn generate_veo_3_fast_image_to_video_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -247,6 +247,7 @@ pub async fn generate_veo_3_image_to_video_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -317,6 +317,7 @@ pub async fn kling_2p5_turbo_pro_multi_function_video_gen_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -316,6 +316,7 @@ pub async fn kling_2p6_pro_multi_function_video_gen_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -336,6 +336,7 @@ pub async fn sora_2_multi_function_video_gen_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -338,6 +338,7 @@ pub async fn sora_2_pro_multi_function_video_gen_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -401,6 +401,7 @@ pub async fn veo_3p1_fast_multi_function_video_gen_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
+1
@@ -401,6 +401,7 @@ pub async fn veo_3p1_multi_function_video_gen_handler(
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: Visibility::Public,
|
||||
mysql_executor: &mut *transaction,
|
||||
starting_job_status_override: None,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user