Enable Parallel image Gen
This commit is contained in:
@@ -1186,24 +1186,34 @@ async fn maybe_prepare_puzzle_clear_assets_inner(
|
|||||||
let http_client = build_openai_image_http_client(&settings).map_err(|error| {
|
let http_client = build_openai_image_http_client(&settings).map_err(|error| {
|
||||||
puzzle_clear_error_response(request_context, PUZZLE_CLEAR_CREATION_PROVIDER, error)
|
puzzle_clear_error_response(request_context, PUZZLE_CLEAR_CREATION_PROVIDER, error)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
// 中文注释:5 张 sheet 并行生成,每张内部最多重试 4 次上游错误
|
||||||
|
let theme_prompt = payload.theme_prompt.as_deref().unwrap_or_default();
|
||||||
let mut generated_sheets = Vec::with_capacity(sheet_specs.len());
|
let mut generated_sheets = Vec::with_capacity(sheet_specs.len());
|
||||||
for sheet_spec in sheet_specs {
|
{
|
||||||
let sheet_prompt = build_puzzle_clear_atlas_prompt(
|
let futures: Vec<_> = sheet_specs
|
||||||
payload.theme_prompt.as_deref().unwrap_or_default(),
|
.iter()
|
||||||
&sheet_spec,
|
.map(|sheet_spec| {
|
||||||
);
|
let sheet_prompt = build_puzzle_clear_atlas_prompt(theme_prompt, sheet_spec);
|
||||||
let mut accepted_sheet = None;
|
let client = http_client.clone();
|
||||||
|
let settings = settings.clone();
|
||||||
|
let debug_run = image_debug_run.clone();
|
||||||
|
async move {
|
||||||
for attempt_index in 0..PUZZLE_CLEAR_SHEET_GENERATION_MAX_ATTEMPTS {
|
for attempt_index in 0..PUZZLE_CLEAR_SHEET_GENERATION_MAX_ATTEMPTS {
|
||||||
let failure_context = format!(
|
let failure_context = format!(
|
||||||
"拼消消素材 {} 生成失败,第 {} 次",
|
"拼消消素材 {} 生成失败,第 {} 次",
|
||||||
sheet_spec.sheet_id,
|
sheet_spec.sheet_id,
|
||||||
attempt_index + 1
|
attempt_index + 1
|
||||||
);
|
);
|
||||||
if let Some(debug_run) = image_debug_run.as_ref() {
|
if let Some(ref debug_run) = debug_run {
|
||||||
debug_run.record_sheet_request(&sheet_spec, attempt_index, sheet_prompt.as_str());
|
debug_run.record_sheet_request(
|
||||||
|
sheet_spec,
|
||||||
|
attempt_index,
|
||||||
|
sheet_prompt.as_str(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let generated = match create_openai_image_generation(
|
let generated = match create_openai_image_generation(
|
||||||
&http_client,
|
&client,
|
||||||
&settings,
|
&settings,
|
||||||
sheet_prompt.as_str(),
|
sheet_prompt.as_str(),
|
||||||
Some(PUZZLE_CLEAR_ATLAS_NEGATIVE_PROMPT),
|
Some(PUZZLE_CLEAR_ATLAS_NEGATIVE_PROMPT),
|
||||||
@@ -1216,11 +1226,16 @@ async fn maybe_prepare_puzzle_clear_assets_inner(
|
|||||||
{
|
{
|
||||||
Ok(generated) => generated,
|
Ok(generated) => generated,
|
||||||
Err(error)
|
Err(error)
|
||||||
if attempt_index + 1 < PUZZLE_CLEAR_SHEET_GENERATION_MAX_ATTEMPTS
|
if attempt_index + 1
|
||||||
|
< PUZZLE_CLEAR_SHEET_GENERATION_MAX_ATTEMPTS
|
||||||
&& is_retryable_puzzle_clear_sheet_generation_error(&error) =>
|
&& is_retryable_puzzle_clear_sheet_generation_error(&error) =>
|
||||||
{
|
{
|
||||||
if let Some(debug_run) = image_debug_run.as_ref() {
|
if let Some(ref debug_run) = debug_run {
|
||||||
debug_run.record_sheet_generation_error(&sheet_spec, attempt_index, &error);
|
debug_run.record_sheet_generation_error(
|
||||||
|
sheet_spec,
|
||||||
|
attempt_index,
|
||||||
|
&error,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
provider = PUZZLE_CLEAR_CREATION_PROVIDER,
|
provider = PUZZLE_CLEAR_CREATION_PROVIDER,
|
||||||
@@ -1232,57 +1247,59 @@ async fn maybe_prepare_puzzle_clear_assets_inner(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
if let Some(debug_run) = image_debug_run.as_ref() {
|
return Err(error);
|
||||||
debug_run.record_sheet_generation_error(&sheet_spec, attempt_index, &error);
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
let task_id = generated.task_id;
|
||||||
|
let actual_prompt = generated.actual_prompt;
|
||||||
|
let image = generated.images.into_iter().next().ok_or_else(|| {
|
||||||
|
AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({
|
||||||
|
"provider": "vector-engine",
|
||||||
|
"message": format!("拼消消素材 {} 生成成功但未返回图片。", sheet_spec.sheet_id),
|
||||||
|
}))
|
||||||
|
})?;
|
||||||
|
if let Some(ref debug_run) = debug_run {
|
||||||
|
debug_run.record_sheet_attempt_image(
|
||||||
|
sheet_spec,
|
||||||
|
attempt_index,
|
||||||
|
task_id.as_str(),
|
||||||
|
actual_prompt.as_deref(),
|
||||||
|
&image,
|
||||||
|
);
|
||||||
|
debug_run.record_sheet_accepted(
|
||||||
|
sheet_spec,
|
||||||
|
task_id.as_str(),
|
||||||
|
&image,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Ok(PuzzleClearGeneratedSheet {
|
||||||
|
spec: *sheet_spec,
|
||||||
|
prompt: sheet_prompt.clone(),
|
||||||
|
task_id,
|
||||||
|
image,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({
|
||||||
|
"provider": PUZZLE_CLEAR_CREATION_PROVIDER,
|
||||||
|
"message": format!("拼消消素材 {} 多次生成后仍未得到可切图集。", sheet_spec.sheet_id),
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let results = futures_util::future::join_all(futures).await;
|
||||||
|
for result in results {
|
||||||
|
match result {
|
||||||
|
Ok(sheet) => generated_sheets.push(sheet),
|
||||||
|
Err(error) => {
|
||||||
return Err(puzzle_clear_error_response(
|
return Err(puzzle_clear_error_response(
|
||||||
request_context,
|
request_context,
|
||||||
PUZZLE_CLEAR_CREATION_PROVIDER,
|
PUZZLE_CLEAR_CREATION_PROVIDER,
|
||||||
error,
|
error,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
|
||||||
let task_id = generated.task_id;
|
|
||||||
let actual_prompt = generated.actual_prompt;
|
|
||||||
let image = generated.images.into_iter().next().ok_or_else(|| {
|
|
||||||
puzzle_clear_error_response(
|
|
||||||
request_context,
|
|
||||||
PUZZLE_CLEAR_CREATION_PROVIDER,
|
|
||||||
AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({
|
|
||||||
"provider": "vector-engine",
|
|
||||||
"message": format!("拼消消素材 {} 生成成功但未返回图片。", sheet_spec.sheet_id),
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
if let Some(debug_run) = image_debug_run.as_ref() {
|
|
||||||
debug_run.record_sheet_attempt_image(
|
|
||||||
&sheet_spec,
|
|
||||||
attempt_index,
|
|
||||||
task_id.as_str(),
|
|
||||||
actual_prompt.as_deref(),
|
|
||||||
&image,
|
|
||||||
);
|
|
||||||
debug_run.record_sheet_accepted(&sheet_spec, task_id.as_str(), &image);
|
|
||||||
}
|
}
|
||||||
accepted_sheet = Some(PuzzleClearGeneratedSheet {
|
|
||||||
spec: sheet_spec,
|
|
||||||
prompt: sheet_prompt.clone(),
|
|
||||||
task_id,
|
|
||||||
image,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
let Some(accepted_sheet) = accepted_sheet else {
|
|
||||||
return Err(puzzle_clear_error_response(
|
|
||||||
request_context,
|
|
||||||
PUZZLE_CLEAR_CREATION_PROVIDER,
|
|
||||||
AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({
|
|
||||||
"provider": PUZZLE_CLEAR_CREATION_PROVIDER,
|
|
||||||
"message": format!("拼消消素材 {} 多次生成后仍未得到可切图集。", sheet_spec.sheet_id),
|
|
||||||
})),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
generated_sheets.push(accepted_sheet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut slices = Vec::new();
|
let mut slices = Vec::new();
|
||||||
|
|||||||
Reference in New Issue
Block a user