This commit is contained in:
Brandon Thomas committed 2026-04-23 06:28:24 -04:00
1 parent baf4a8f7de
commit 6c5b1a466a
6 files changed
+39 -119

No files matched your search

@@ -176,12 +176,14 @@ pub async fn omni_gen_video_generate_handler(
kinovi_character_id_map: &kinovi_character_id_map,
}).await?
} else {
let empty_map = HashMap::new();
let media_url_map = media_file_hydration_map.as_ref().unwrap_or(&empty_map);
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,
media_url_map,
kinovi_character_id_map: &kinovi_character_id_map,
}).await?
};
@@ -32,7 +32,7 @@ pub struct RunPipelineV1Args<'a> {
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 media_url_map: &'a HashMap<MediaFileToken, Url>,
pub kinovi_character_id_map: &'a Option<HashMap<CharacterToken, String>>,
}
@@ -64,7 +64,7 @@ pub async fn run_pipeline_v1(args: RunPipelineV1Args<'_>) -> Result<PipelineResu
server_state,
mysql_connection,
user_token,
media_file_hydration_map,
media_url_map,
kinovi_character_id_map,
} = args;
@@ -79,7 +79,7 @@ pub async fn run_pipeline_v1(args: RunPipelineV1Args<'_>) -> Result<PipelineResu
_ => Provider::Fal,
};
// ── Distill: cost estimate (Artcraft provider — what we bill on) ──
// ── Cost estimate (Artcraft provider — what we bill on) ──
let initial = hydrate_to_router_request(request)?;
@@ -95,38 +95,18 @@ pub async fn run_pipeline_v1(args: RunPipelineV1Args<'_>) -> Result<PipelineResu
cost_plan.estimate_costs()
};
// ── Distill: resolve media tokens to URLs for the execution request ──
let hydration_map = media_file_hydration_map.as_ref();
let start_frame_url = resolve_single_media_token(
request.start_frame_image_media_token.as_ref(), hydration_map,
)?;
let end_frame_url = resolve_single_media_token(
request.end_frame_image_media_token.as_ref(), hydration_map,
)?;
let reference_image_urls = resolve_media_token_list(
request.reference_image_media_tokens.as_ref(), hydration_map,
)?;
let reference_video_urls = resolve_media_token_list(
request.reference_video_media_tokens.as_ref(), hydration_map,
)?;
let reference_audio_urls = resolve_media_token_list(
request.reference_audio_media_tokens.as_ref(), hydration_map,
)?;
// ── Distill: build the execution request with resolved URLs ──
// ── Build the execution request (resolve media tokens → URLs from handler map) ──
let exec_request = GenerateVideoRequestBuilder {
model: initial.model,
provider: execution_provider,
prompt: initial.prompt,
negative_prompt: initial.negative_prompt,
start_frame: start_frame_url.map(ImageRef::Url),
end_frame: end_frame_url.map(ImageRef::Url),
reference_images: reference_image_urls.map(ImageListRef::Urls),
reference_videos: reference_video_urls.map(VideoListRef::Urls),
reference_audio: reference_audio_urls.map(AudioListRef::Urls),
start_frame: lookup_url(media_url_map, request.start_frame_image_media_token.as_ref()).map(ImageRef::Url),
end_frame: lookup_url(media_url_map, request.end_frame_image_media_token.as_ref()).map(ImageRef::Url),
reference_images: lookup_urls(media_url_map, request.reference_image_media_tokens.as_ref()).map(ImageListRef::Urls),
reference_videos: lookup_urls(media_url_map, request.reference_video_media_tokens.as_ref()).map(VideoListRef::Urls),
reference_audio: lookup_urls(media_url_map, request.reference_audio_media_tokens.as_ref()).map(AudioListRef::Urls),
reference_character_tokens: None,
resolution: initial.resolution,
aspect_ratio: initial.aspect_ratio,
@@ -155,7 +135,7 @@ pub async fn run_pipeline_v1(args: RunPipelineV1Args<'_>) -> Result<PipelineResu
Provider::Seedance2Pro => {
execute_generation_kinovi(
request, server_state,
media_file_hydration_map.as_ref(), kinovi_character_ids,
Some(media_url_map), kinovi_character_ids,
billing.maybe_wallet_ledger_entry_token.as_ref(), mysql_connection,
).await?
}
@@ -167,16 +147,27 @@ pub async fn run_pipeline_v1(args: RunPipelineV1Args<'_>) -> Result<PipelineResu
Ok(PipelineResult { billing, response })
}
// ── Helpers ──
fn lookup_url(map: &HashMap<MediaFileToken, Url>, token: Option<&MediaFileToken>) -> Option<String> {
token.and_then(|t| map.get(t)).map(|u| u.to_string())
}
fn lookup_urls(map: &HashMap<MediaFileToken, Url>, tokens: Option<&Vec<MediaFileToken>>) -> Option<Vec<String>> {
tokens
.filter(|v| !v.is_empty())
.map(|tokens| tokens.iter().filter_map(|t| map.get(t).map(|u| u.to_string())).collect())
}
// ── Distillation (kept public for tests) ──
pub fn distill_video_request(
request: &OmniGenVideoCostAndGenerateRequest,
media_file_hydration_map: Option<&HashMap<MediaFileToken, Url>>,
media_url_map: &HashMap<MediaFileToken, Url>,
execution_provider: Provider,
) -> Result<DistilledVideoRequest, AdvancedCommonWebError> {
let initial = hydrate_to_router_request(request)?;
// Cost estimate (Artcraft provider — what we bill on).
let cost: VideoGenerationCostEstimate = {
let cost_request = GenerateVideoRequestBuilder {
provider: Provider::Artcraft,
@@ -189,34 +180,16 @@ pub fn distill_video_request(
cost_plan.estimate_costs()
};
// Resolve media tokens to URLs for the execution request.
let start_frame_url = resolve_single_media_token(
request.start_frame_image_media_token.as_ref(), media_file_hydration_map,
)?;
let end_frame_url = resolve_single_media_token(
request.end_frame_image_media_token.as_ref(), media_file_hydration_map,
)?;
let reference_image_urls = resolve_media_token_list(
request.reference_image_media_tokens.as_ref(), media_file_hydration_map,
)?;
let reference_video_urls = resolve_media_token_list(
request.reference_video_media_tokens.as_ref(), media_file_hydration_map,
)?;
let reference_audio_urls = resolve_media_token_list(
request.reference_audio_media_tokens.as_ref(), media_file_hydration_map,
)?;
// Build the execution request with resolved URLs.
let exec_request = GenerateVideoRequestBuilder {
model: initial.model,
provider: execution_provider,
prompt: initial.prompt,
negative_prompt: initial.negative_prompt,
start_frame: start_frame_url.map(ImageRef::Url),
end_frame: end_frame_url.map(ImageRef::Url),
reference_images: reference_image_urls.map(ImageListRef::Urls),
reference_videos: reference_video_urls.map(VideoListRef::Urls),
reference_audio: reference_audio_urls.map(AudioListRef::Urls),
start_frame: lookup_url(media_url_map, request.start_frame_image_media_token.as_ref()).map(ImageRef::Url),
end_frame: lookup_url(media_url_map, request.end_frame_image_media_token.as_ref()).map(ImageRef::Url),
reference_images: lookup_urls(media_url_map, request.reference_image_media_tokens.as_ref()).map(ImageListRef::Urls),
reference_videos: lookup_urls(media_url_map, request.reference_video_media_tokens.as_ref()).map(VideoListRef::Urls),
reference_audio: lookup_urls(media_url_map, request.reference_audio_media_tokens.as_ref()).map(AudioListRef::Urls),
reference_character_tokens: None,
resolution: initial.resolution,
aspect_ratio: initial.aspect_ratio,
@@ -239,58 +212,3 @@ pub fn distill_video_request(
execution_provider,
})
}
// ── Token resolution helpers ──
fn resolve_single_media_token(
token: Option<&MediaFileToken>,
hydration_map: Option<&HashMap<MediaFileToken, Url>>,
) -> Result<Option<String>, AdvancedCommonWebError> {
let token = match token {
Some(t) => t,
None => return Ok(None),
};
let map = hydration_map.ok_or_else(|| {
AdvancedCommonWebError::BadInputWithSimpleMessage(
"media token supplied but no hydration map was provided".to_string(),
)
})?;
match map.get(token) {
Some(url) => Ok(Some(url.to_string())),
None => Err(AdvancedCommonWebError::BadInputWithSimpleMessage(format!(
"Media token not found in hydration map: {:?}", token
))),
}
}
fn resolve_media_token_list(
tokens: Option<&Vec<MediaFileToken>>,
hydration_map: Option<&HashMap<MediaFileToken, Url>>,
) -> Result<Option<Vec<String>>, AdvancedCommonWebError> {
let tokens = match tokens {
Some(tokens) if !tokens.is_empty() => tokens,
_ => return Ok(None),
};
let map = hydration_map.ok_or_else(|| {
AdvancedCommonWebError::BadInputWithSimpleMessage(
"media tokens supplied but no hydration map was provided".to_string(),
)
})?;
let mut urls: Vec<String> = Vec::with_capacity(tokens.len());
for token in tokens {
match map.get(token) {
Some(url) => urls.push(url.to_string()),
None => {
return Err(AdvancedCommonWebError::BadInputWithSimpleMessage(format!(
"Media token not found in hydration map: {:?}", token
)));
}
}
}
Ok(Some(urls))
}
@@ -83,7 +83,7 @@ mod tests {
fn distill_text(request: &OmniGenVideoCostAndGenerateRequest) -> DistilledVideoRequest {
let empty: HashMap<MediaFileToken, Url> = HashMap::new();
distill_video_request(request, Some(&empty), Provider::Seedance2Pro)
distill_video_request(request, &empty, Provider::Seedance2Pro)
.expect("distill should succeed for Seedance 2.0 (text)")
}
@@ -91,7 +91,7 @@ mod tests {
request: &OmniGenVideoCostAndGenerateRequest,
hydration: &HashMap<MediaFileToken, Url>,
) -> DistilledVideoRequest {
distill_video_request(request, Some(hydration), Provider::Seedance2Pro)
distill_video_request(request, hydration, Provider::Seedance2Pro)
.expect("distill should succeed for Seedance 2.0 (with media)")
}
@@ -76,7 +76,7 @@ mod tests {
fn distill_text(request: &OmniGenVideoCostAndGenerateRequest) -> DistilledVideoRequest {
let empty: HashMap<MediaFileToken, Url> = HashMap::new();
distill_video_request(request, Some(&empty), Provider::Fal)
distill_video_request(request, &empty, Provider::Fal)
.expect("distill_video_request should succeed for Seedance 1.5 Pro (text)")
}
@@ -84,7 +84,7 @@ mod tests {
request: &OmniGenVideoCostAndGenerateRequest,
hydration: &HashMap<MediaFileToken, Url>,
) -> DistilledVideoRequest {
distill_video_request(request, Some(hydration), Provider::Fal)
distill_video_request(request, hydration, Provider::Fal)
.expect("distill_video_request should succeed for Seedance 1.5 Pro (image)")
}
@@ -63,7 +63,7 @@ mod tests {
fn distill_text(request: &OmniGenVideoCostAndGenerateRequest) -> DistilledVideoRequest {
let empty: HashMap<MediaFileToken, Url> = HashMap::new();
distill_video_request(request, Some(&empty), Provider::Fal)
distill_video_request(request, &empty, Provider::Fal)
.expect("distill_video_request should succeed for Veo 2 (text)")
}
@@ -71,7 +71,7 @@ mod tests {
request: &OmniGenVideoCostAndGenerateRequest,
hydration: &HashMap<MediaFileToken, Url>,
) -> DistilledVideoRequest {
distill_video_request(request, Some(hydration), Provider::Fal)
distill_video_request(request, hydration, Provider::Fal)
.expect("distill_video_request should succeed for Veo 2 (image)")
}
@@ -69,7 +69,7 @@ mod tests {
fn distill_text(request: &OmniGenVideoCostAndGenerateRequest) -> DistilledVideoRequest {
let empty: HashMap<MediaFileToken, Url> = HashMap::new();
distill_video_request(request, Some(&empty), Provider::Fal)
distill_video_request(request, &empty, Provider::Fal)
.expect("distill should succeed for Veo 3 (text)")
}
@@ -77,7 +77,7 @@ mod tests {
request: &OmniGenVideoCostAndGenerateRequest,
hydration: &HashMap<MediaFileToken, Url>,
) -> DistilledVideoRequest {
distill_video_request(request, Some(hydration), Provider::Fal)
distill_video_request(request, hydration, Provider::Fal)
.expect("distill should succeed for Veo 3 (image)")
}