拆分大文件

This commit is contained in:
2026-04-23 23:38:00 +08:00
parent 53a9cdd791
commit 8df502b2a7
506 changed files with 11312 additions and 13069 deletions

View File

@@ -104,11 +104,11 @@ pub async fn generate_character_visual(
text_output: Some(prompt.clone()),
structured_payload_json: Some(
json!({
"characterId": character_id,
"sourceMode": payload.source_mode,
"size": size,
"referenceImageCount": payload.reference_image_data_urls.len(),
})
"characterId": character_id,
"sourceMode": payload.source_mode,
"size": size,
"referenceImageCount": payload.reference_image_data_urls.len(),
})
.to_string(),
),
warning_messages: Vec::new(),
@@ -832,12 +832,9 @@ async fn resolve_reference_image_as_data_url(
.and_then(|value| value.to_str().ok())
.unwrap_or("image/png")
.to_string();
let body = response
.bytes()
.await
.map_err(|error| {
map_dashscope_request_error(format!("读取角色主形象参考图内容失败:{error}"))
})?;
let body = response.bytes().await.map_err(|error| {
map_dashscope_request_error(format!("读取角色主形象参考图内容失败:{error}"))
})?;
if !status.is_success() {
return Err(
AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({
@@ -911,9 +908,7 @@ async fn create_character_visual_generation(
}))
.send()
.await
.map_err(|error| {
map_dashscope_request_error(format!("创建角色主形象任务失败:{error}"))
})?;
.map_err(|error| map_dashscope_request_error(format!("创建角色主形象任务失败:{error}")))?;
let response_status = response.status();
let response_text = response.text().await.map_err(|error| {
map_dashscope_request_error(format!("读取角色主形象任务响应失败:{error}"))
@@ -963,19 +958,23 @@ async fn create_character_visual_generation(
if task_status == "SUCCEEDED" {
let image_urls = extract_image_urls(&poll_json.payload);
if image_urls.is_empty() {
return Err(AppError::from_status(StatusCode::BAD_GATEWAY).with_details(
json!({
return Err(
AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({
"provider": "dashscope",
"message": "角色主形象生成成功,但没有返回可下载图片。",
}),
));
})),
);
}
let mut images = Vec::with_capacity(image_urls.len());
for image_url in image_urls {
images.push(
download_generated_image(http_client, image_url.as_str(), "下载角色主形象候选图失败。")
.await?,
download_generated_image(
http_client,
image_url.as_str(),
"下载角色主形象候选图失败。",
)
.await?,
);
}
@@ -992,13 +991,18 @@ async fn create_character_visual_generation(
));
}
sleep(Duration::from_millis(CHARACTER_VISUAL_TASK_POLL_INTERVAL_MS)).await;
sleep(Duration::from_millis(
CHARACTER_VISUAL_TASK_POLL_INTERVAL_MS,
))
.await;
}
Err(AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({
"provider": "dashscope",
"message": "角色主形象任务执行超时,请稍后重试。",
})))
Err(
AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({
"provider": "dashscope",
"message": "角色主形象任务执行超时,请稍后重试。",
})),
)
}
async fn download_generated_image(
@@ -1023,11 +1027,13 @@ async fn download_generated_image(
.await
.map_err(|error| map_dashscope_request_error(format!("{fallback_message}{error}")))?;
if !status.is_success() {
return Err(AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({
"provider": "dashscope",
"message": fallback_message,
"status": status.as_u16(),
})));
return Err(
AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({
"provider": "dashscope",
"message": fallback_message,
"status": status.as_u16(),
})),
);
}
let normalized_mime_type = normalize_downloaded_image_mime_type(content_type.as_str());
@@ -1244,7 +1250,10 @@ fn map_character_visual_oss_error(error: platform_oss::OssError) -> AppError {
}))
}
fn parse_json_payload(raw_text: &str, fallback_message: &str) -> Result<ParsedJsonPayload, AppError> {
fn parse_json_payload(
raw_text: &str,
fallback_message: &str,
) -> Result<ParsedJsonPayload, AppError> {
serde_json::from_str::<Value>(raw_text)
.map(|payload| ParsedJsonPayload { payload })
.map_err(|error| {
@@ -1541,11 +1550,7 @@ fn collect_foreground_neighbor_color(
))
}
pub(crate) fn remove_background_from_rgba(
pixels: &mut [u8],
width: usize,
height: usize,
) -> bool {
pub(crate) fn remove_background_from_rgba(pixels: &mut [u8], width: usize, height: usize) -> bool {
const SOFT_EDGE_ALPHA_THRESHOLD: u8 = 224;
const FOREGROUND_NEIGHBOR_ALPHA_THRESHOLD: u8 = 96;
@@ -1574,26 +1579,24 @@ pub(crate) fn remove_background_from_rgba(
green_scores[pixel_index] = green_score;
white_scores[pixel_index] = white_score;
background_hints[pixel_index] =
green_score.max(white_score).max(transparency_hint);
background_hints[pixel_index] = green_score.max(white_score).max(transparency_hint);
}
let try_seed_background =
|pixel_index: usize, background_mask: &mut [u8], queue: &mut Vec<usize>| {
if background_mask[pixel_index] != 0 {
return;
}
let offset = pixel_index * 4;
let alpha = pixels[offset + 3];
let strong_candidate = alpha < 40
|| green_scores[pixel_index] > 0.12
|| white_scores[pixel_index] > 0.32;
if !strong_candidate {
return;
}
background_mask[pixel_index] = 1;
queue.push(pixel_index);
};
if background_mask[pixel_index] != 0 {
return;
}
let offset = pixel_index * 4;
let alpha = pixels[offset + 3];
let strong_candidate =
alpha < 40 || green_scores[pixel_index] > 0.12 || white_scores[pixel_index] > 0.32;
if !strong_candidate {
return;
}
background_mask[pixel_index] = 1;
queue.push(pixel_index);
};
for x in 0..width {
try_seed_background(x, &mut background_mask, &mut queue);
@@ -1612,9 +1615,21 @@ pub(crate) fn remove_background_from_rgba(
let y = pixel_index / width;
let neighbor_indexes = [
if x > 0 { Some(pixel_index - 1) } else { None },
if x + 1 < width { Some(pixel_index + 1) } else { None },
if y > 0 { Some(pixel_index - width) } else { None },
if y + 1 < height { Some(pixel_index + width) } else { None },
if x + 1 < width {
Some(pixel_index + 1)
} else {
None
},
if y > 0 {
Some(pixel_index - width)
} else {
None
},
if y + 1 < height {
Some(pixel_index + width)
} else {
None
},
];
for next_pixel_index in neighbor_indexes.into_iter().flatten() {
@@ -1628,9 +1643,7 @@ pub(crate) fn remove_background_from_rgba(
let next_hint = background_hints[next_pixel_index];
let reachable_soft_edge = next_hint > 0.08
&& next_alpha < SOFT_EDGE_ALPHA_THRESHOLD
&& (next_green_score > 0.04
|| next_white_score > 0.08
|| next_alpha < 180);
&& (next_green_score > 0.04 || next_white_score > 0.08 || next_alpha < 180);
if next_alpha < 40
|| next_green_score > 0.12
@@ -1678,8 +1691,7 @@ pub(crate) fn remove_background_from_rgba(
}
}
if adjacent_background_count >= 2
|| (adjacent_background_count >= 1 && hint > 0.18)
if adjacent_background_count >= 2 || (adjacent_background_count >= 1 && hint > 0.18)
{
expanded_mask[pixel_index] = 1;
}
@@ -1712,10 +1724,7 @@ pub(crate) fn remove_background_from_rgba(
}
let next_x = x as i32 + offset_x;
let next_y = y as i32 + offset_y;
if next_x < 0
|| next_x >= width as i32
|| next_y < 0
|| next_y >= height as i32
if next_x < 0 || next_x >= width as i32 || next_y < 0 || next_y >= height as i32
{
continue;
}
@@ -1770,10 +1779,7 @@ pub(crate) fn remove_background_from_rgba(
}
let next_x = x as i32 + offset_x;
let next_y = y as i32 + offset_y;
if next_x < 0
|| next_x >= width as i32
|| next_y < 0
|| next_y >= height as i32
if next_x < 0 || next_x >= width as i32 || next_y < 0 || next_y >= height as i32
{
touches_transparent_edge = true;
continue;
@@ -1795,7 +1801,11 @@ pub(crate) fn remove_background_from_rgba(
let white_score = white_scores[pixel_index];
let contamination = green_score
.max(white_score)
.max(if background_mask[pixel_index] != 0 { 0.35 } else { 0.0 })
.max(if background_mask[pixel_index] != 0 {
0.35
} else {
0.0
})
.max(if alpha < 220 {
((220 - alpha) as f32 / 220.0) * 0.25
} else {
@@ -1818,7 +1828,8 @@ pub(crate) fn remove_background_from_rgba(
&background_mask,
&background_hints,
);
let blend = clamp01(contamination.max(if touches_transparent_edge { 0.22 } else { 0.0 }));
let blend =
clamp01(contamination.max(if touches_transparent_edge { 0.22 } else { 0.0 }));
if let Some((sample_red, sample_green, sample_blue)) = sample {
red = lerp(red, sample_red as f32, blend);
@@ -1835,7 +1846,8 @@ pub(crate) fn remove_background_from_rgba(
}
} else {
if green_score > 0.04 {
green = green.max(red.max(blue))
green = green
.max(red.max(blue))
.max((green - (green - red.max(blue)) * 0.78).round());
}