This commit is contained in:
Brandon Thomas committed 2026-04-23 05:40:07 -04:00
1 parent 5664705c7c
commit 7603bf2127
3 files changed
+83 -43

No files matched your search

@@ -28,9 +28,9 @@ use crate::http_server::common_responses::advanced_common_web_error::AdvancedCom
use crate::http_server::endpoints::generate::common::payments_error_test::payments_error_test;
use crate::http_server::endpoints::omni_gen::generate::video::helpers::insert_fal_job::insert_fal_job;
use crate::http_server::endpoints::omni_gen::generate::video::helpers::insert_seedance2pro_jobs::insert_seedance2pro_jobs;
use crate::http_server::endpoints::omni_gen::generate::video::pipeline_v1::run_pipeline_v1::{run_pipeline_v1, RunPipelineV1Args};
use crate::http_server::endpoints::omni_gen::generate::video::pipeline_v2::run_pipeline_v2::{run_pipeline_v2, RunPipelineV2Args};
use crate::http_server::endpoints::omni_gen::generate::video::request_helper::resolve_kinovi_character_ids::resolve_kinovi_character_ids;
use crate::http_server::endpoints::omni_gen::generate::video::pipeline_v1::run_pipeline_v1::run_pipeline_v1;
use crate::http_server::endpoints::omni_gen::generate::video::pipeline_v2::run_pipeline_v2::run_pipeline_v2;
use crate::http_server::validations::validate_idempotency_token_format::validate_idempotency_token_format;
use crate::state::server_state::ServerState;
use crate::util::lookup::lookup_image_urls_as_map::lookup_image_urls_as_map;
@@ -167,12 +167,23 @@ pub async fn omni_gen_video_generate_handler(
);
let pipeline_result = if use_v2 {
run_pipeline_v2(
&request, &server_state, &mut mysql_connection, user_token,
&media_file_hydration_map, &media_file_to_url_map, &kinovi_character_id_map,
).await?
run_pipeline_v2(RunPipelineV2Args {
request: &request,
server_state: &server_state,
mysql_connection: &mut mysql_connection,
user_token,
media_file_to_url_map: &media_file_to_url_map,
kinovi_character_id_map: &kinovi_character_id_map,
}).await?
} else {
run_pipeline_v1(&request, &server_state, &mut mysql_connection, user_token, &media_file_hydration_map).await?
run_pipeline_v1(RunPipelineV1Args {
request: &request,
server_state: &server_state,
mysql_connection: &mut mysql_connection,
user_token,
media_file_hydration_map: &media_file_hydration_map,
kinovi_character_id_map: &kinovi_character_id_map,
}).await?
};
// ==================== WRITE RESULT ==================== //
@@ -7,32 +7,40 @@ use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost
use artcraft_router::api::provider::Provider;
use artcraft_router::generate::generate_video::generate_video_response::GenerateVideoResponse;
use enums::common::generation::common_video_model::CommonVideoModel;
use tokens::tokens::characters::CharacterToken;
use tokens::tokens::media_files::MediaFileToken;
use tokens::tokens::users::UserToken;
use crate::http_server::common_responses::advanced_common_web_error::AdvancedCommonWebError;
use crate::http_server::endpoints::omni_gen::generate::video::helpers::bill_wallet::bill_wallet;
use crate::http_server::endpoints::omni_gen::generate::video::pipeline_result::PipelineResult;
use crate::http_server::endpoints::omni_gen::generate::video::hydrate_router_request::hydrate_to_router_request;
use crate::http_server::endpoints::omni_gen::generate::video::pipeline_v1::distill_video_request::distill_video_request;
use crate::http_server::endpoints::omni_gen::generate::video::pipeline_v1::execute::execute_generation::execute_generation;
use crate::http_server::endpoints::omni_gen::generate::video::request_helper::resolve_kinovi_character_ids::resolve_kinovi_character_ids;
use crate::state::server_state::ServerState;
pub async fn run_pipeline_v1(
request: &OmniGenVideoCostAndGenerateRequest,
server_state: &ServerState,
mysql_connection: &mut sqlx::pool::PoolConnection<sqlx::MySql>,
user_token: &tokens::tokens::users::UserToken,
media_file_hydration_map: &Option<HashMap<MediaFileToken, Url>>,
) -> Result<PipelineResult, AdvancedCommonWebError> {
let kinovi_character_id_map = resolve_kinovi_character_ids(
request.reference_character_tokens.as_deref(),
pub struct RunPipelineV1Args<'a> {
pub request: &'a OmniGenVideoCostAndGenerateRequest,
pub server_state: &'a ServerState,
pub mysql_connection: &'a mut sqlx::pool::PoolConnection<sqlx::MySql>,
pub user_token: &'a UserToken,
pub media_file_hydration_map: &'a Option<HashMap<MediaFileToken, Url>>,
pub kinovi_character_id_map: &'a Option<HashMap<CharacterToken, String>>,
}
pub async fn run_pipeline_v1(args: RunPipelineV1Args<'_>) -> Result<PipelineResult, AdvancedCommonWebError> {
let RunPipelineV1Args {
request,
server_state,
mysql_connection,
).await?;
user_token,
media_file_hydration_map,
kinovi_character_id_map,
} = args;
// v1 execute_generation expects a flat Vec<String> of kinovi IDs
let kinovi_character_ids: Option<Vec<String>> = kinovi_character_id_map
.map(|map| map.into_values().collect());
.as_ref()
.map(|map| map.values().cloned().collect());
let execution_provider = match request.model {
Some(CommonVideoModel::Seedance2p0) => Provider::Seedance2Pro,
@@ -51,7 +59,7 @@ pub async fn run_pipeline_v1(
kinovi_character_ids, billing.maybe_wallet_ledger_entry_token.as_ref(), mysql_connection,
).await?;
// Map v1 GenerationResult -> GenerateVideoResponse for the shared suffix
// Map v1 GenerationResult → GenerateVideoResponse for the shared suffix
let response = if gen_result.is_seedance2pro {
GenerateVideoResponse::Seedance2Pro(
artcraft_router::generate::generate_video::generate_video_response::Seedance2proVideoResponsePayload {
@@ -1,6 +1,7 @@
use std::collections::HashMap;
use log::{error, info, warn};
use sqlx::pool::PoolConnection;
use url::Url;
use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_video_cost_and_generate_request::OmniGenVideoCostAndGenerateRequest;
@@ -20,23 +21,34 @@ use crate::http_server::endpoints::omni_gen::generate::video::hydrate_router_req
use crate::http_server::endpoints::omni_gen::generate::video::pipeline_result::PipelineResult;
use crate::state::server_state::ServerState;
pub async fn run_pipeline_v2(
request: &OmniGenVideoCostAndGenerateRequest,
server_state: &ServerState,
mysql_connection: &mut sqlx::pool::PoolConnection<sqlx::MySql>,
user_token: &UserToken,
media_file_hydration_map: &Option<HashMap<MediaFileToken, Url>>,
media_file_to_url_map: &Option<HashMap<MediaFileToken, String>>,
kinovi_character_id_map: &Option<HashMap<CharacterToken, String>>,
) -> Result<PipelineResult, AdvancedCommonWebError> {
pub struct RunPipelineV2Args<'a> {
pub request: &'a OmniGenVideoCostAndGenerateRequest,
pub server_state: &'a ServerState,
pub mysql_connection: &'a mut PoolConnection<sqlx::MySql>,
pub user_token: &'a UserToken,
pub media_file_to_url_map: &'a Option<HashMap<MediaFileToken, String>>,
pub kinovi_character_id_map: &'a Option<HashMap<CharacterToken, String>>,
}
pub async fn run_pipeline_v2(args: RunPipelineV2Args<'_>) -> Result<PipelineResult, AdvancedCommonWebError> {
let RunPipelineV2Args {
request,
server_state,
mysql_connection,
user_token,
media_file_to_url_map,
kinovi_character_id_map,
} = args;
// 1. Build execution request (provider = Seedance2Pro for Kinovi)
let mut exec_builder = hydrate_to_router_request(request)?;
exec_builder.provider = Provider::Seedance2Pro;
let draft_or_request = exec_builder.build2().map_err(|e| {
warn!("Failed to build2 for v2 pipeline: {}", e);
AdvancedCommonWebError::from_error(e)
})?;
let draft_or_request = exec_builder.build2()
.map_err(|e| {
warn!("Failed to build2 for v2 pipeline: {}", e);
AdvancedCommonWebError::from_error(e)
})?;
let provider = draft_or_request.get_provider();
@@ -76,7 +88,10 @@ pub async fn run_pipeline_v2(
if matches!(provider, Provider::Seedance2Pro) {
if let Some(ledger_entry_token) = billing.maybe_wallet_ledger_entry_token.as_ref() {
warn!("Kinovi v2 generation failed, issuing refund for {}: {:?}", ledger_entry_token.as_str(), err);
if let Err(refund_err) = refund_wallet_after_api_failure(ledger_entry_token, mysql_connection).await {
let result = refund_wallet_after_api_failure(ledger_entry_token, mysql_connection).await;
if let Err(refund_err) = result {
error!("Failed to refund wallet after Kinovi v2 failure: {:?}", refund_err);
}
}
@@ -84,6 +99,7 @@ pub async fn run_pipeline_v2(
}
let response = result?;
info!("v2 generation response: {:?}", response);
Ok(PipelineResult { billing, response })
@@ -98,6 +114,7 @@ async fn upload_and_generate(
media_file_urls_by_token: Option<&HashMap<MediaFileToken, String>>,
kinovi_character_ids: Option<&HashMap<CharacterToken, String>>,
) -> Result<GenerateVideoResponse, AdvancedCommonWebError> {
let provider = draft_or_request.get_provider();
let client = build_router_client(provider, server_state)?;
@@ -110,15 +127,19 @@ async fn upload_and_generate(
character_token_to_kinovi_id_map: kinovi_character_ids,
};
draft.finalize(draft_context).await.map_err(|err| {
warn!("Failed to finalize v2 draft: {:?}", err);
AdvancedCommonWebError::from_error(err)
})?
draft.finalize(draft_context)
.await
.map_err(|err| {
warn!("Failed to finalize v2 draft: {:?}", err);
AdvancedCommonWebError::from_error(err)
})?
}
};
video_request.send_request(&client).await.map_err(|err| {
warn!("v2 video generation failed: {:?}", err);
AdvancedCommonWebError::from_error(err)
})
video_request.send_request(&client)
.await
.map_err(|err| {
warn!("v2 video generation failed: {:?}", err);
AdvancedCommonWebError::from_error(err)
})
}