fix: polish bark battle creation flow

This commit is contained in:
kdletters
2026-05-22 05:00:07 +08:00
parent 01da85a577
commit bf82f04b64
73 changed files with 9362 additions and 2663 deletions

View File

@@ -1001,6 +1001,7 @@ mod tests {
"/generated-puzzle-assets/session-1/candidate/image.png",
"/generated-custom-world-scenes/world-1/camp/scene.png",
"/generated-custom-world-covers/world-1/cover.webp",
"/generated-bark-battle-assets/draft/player/image.webp",
"/generated-qwen-sprites/master/candidate-01.png",
] {
let response = app

File diff suppressed because it is too large Load Diff

View File

@@ -174,6 +174,25 @@ mod tests {
assert_eq!(resolve_creation_entry_route_id("/healthz"), None);
}
#[test]
fn test_creation_entry_config_response_opens_bark_battle() {
let config = test_creation_entry_config_response();
let bark_battle = config
.creation_types
.iter()
.find(|item| item.id == "bark-battle")
.expect("test creation entry config should include bark-battle");
assert_eq!(bark_battle.title, "汪汪声浪");
assert!(bark_battle.visible);
assert!(bark_battle.open);
assert_eq!(bark_battle.badge, "可创建");
assert_eq!(
bark_battle.image_src,
"/creation-type-references/bark-battle.webp"
);
}
#[test]
fn test_creation_entry_config_response_keeps_baby_object_match_coming_soon() {
let config = test_creation_entry_config_response();

View File

@@ -532,7 +532,9 @@ fn build_config_from_message(
}
}
pub(super) fn resolve_config_or_default(config: Option<&Match3DCreatorConfigRecord>) -> Match3DConfigJson {
pub(super) fn resolve_config_or_default(
config: Option<&Match3DCreatorConfigRecord>,
) -> Match3DConfigJson {
config
.map(|config| Match3DConfigJson {
theme_text: config.theme_text.clone(),
@@ -595,7 +597,10 @@ fn build_match3d_assistant_reply(config: &Match3DConfigJson) -> String {
)
}
pub(super) fn build_match3d_assistant_reply_for_turn(config: &Match3DConfigJson, current_turn: u32) -> String {
pub(super) fn build_match3d_assistant_reply_for_turn(
config: &Match3DConfigJson,
current_turn: u32,
) -> String {
match current_turn {
0 => MATCH3D_QUESTION_THEME.to_string(),
1 => MATCH3D_QUESTION_CLEAR_COUNT.to_string(),

View File

@@ -1040,7 +1040,10 @@ pub(super) fn build_fallback_match3d_background_prompt(config: &Match3DConfigJso
)
}
pub(super) fn build_fallback_match3d_item_sound_prompt(config: &Match3DConfigJson, item_name: &str) -> String {
pub(super) fn build_fallback_match3d_item_sound_prompt(
config: &Match3DConfigJson,
item_name: &str,
) -> String {
let theme = config.theme_text.trim();
let normalized_theme = if theme.is_empty() { "抓大鹅" } else { theme };
normalize_match3d_audio_prompt(
@@ -1416,7 +1419,9 @@ fn resolve_match3d_material_cell_crop(
crop.to_crop_tuple()
}
pub(super) fn crop_match3d_material_view_edge_matte(image: image::DynamicImage) -> image::DynamicImage {
pub(super) fn crop_match3d_material_view_edge_matte(
image: image::DynamicImage,
) -> image::DynamicImage {
let mut image = image.to_rgba8();
let (width, height) = image.dimensions();
remove_match3d_material_view_edge_matte(image.as_mut(), width as usize, height as usize);

View File

@@ -134,12 +134,11 @@ pub(super) fn map_match3d_draft_response(
draft: Match3DResultDraftRecord,
) -> Match3DResultDraftResponse {
// 中文注释session draft 自身也可能携带生成素材快照,不能只依赖 work detail 回读补齐 UI 背景和容器图。
let generated_item_assets = parse_match3d_generated_item_assets(
draft.generated_item_assets_json.as_deref(),
)
.into_iter()
.map(Match3DGeneratedItemAsset::from)
.collect::<Vec<_>>();
let generated_item_assets =
parse_match3d_generated_item_assets(draft.generated_item_assets_json.as_deref())
.into_iter()
.map(Match3DGeneratedItemAsset::from)
.collect::<Vec<_>>();
let background_asset = find_match3d_generated_background_asset(&generated_item_assets);
let mut response = Match3DResultDraftResponse {
profile_id: draft.profile_id,

File diff suppressed because it is too large Load Diff

View File

@@ -587,7 +587,10 @@ async fn load_match3d_container_reference_image() -> Result<OpenAiReferenceImage
})
}
pub(super) fn build_match3d_background_generation_prompt(config: &Match3DConfigJson, prompt: &str) -> String {
pub(super) fn build_match3d_background_generation_prompt(
config: &Match3DConfigJson,
prompt: &str,
) -> String {
let style_clause = resolve_match3d_asset_style_prompt(config)
.map(|style| format!("整体美术风格参考:{style}"))
.unwrap_or_default();
@@ -596,7 +599,10 @@ pub(super) fn build_match3d_background_generation_prompt(config: &Match3DConfigJ
)
}
pub(super) fn build_match3d_container_generation_prompt(config: &Match3DConfigJson, prompt: &str) -> String {
pub(super) fn build_match3d_container_generation_prompt(
config: &Match3DConfigJson,
prompt: &str,
) -> String {
let style_clause = resolve_match3d_asset_style_prompt(config)
.map(|style| format!("整体美术风格参考:{style}"))
.unwrap_or_default();
@@ -1183,7 +1189,9 @@ pub(super) async fn persist_match3d_generated_bytes(
})
}
pub(super) fn require_match3d_oss_client(state: &AppState) -> Result<&platform_oss::OssClient, AppError> {
pub(super) fn require_match3d_oss_client(
state: &AppState,
) -> Result<&platform_oss::OssClient, AppError> {
state
.oss_client()
.ok_or_else(|| match3d_oss_config_error(&state.config))

View File

@@ -7,7 +7,9 @@ use crate::{
auth::require_bearer_auth,
bark_battle::{
create_bark_battle_draft, finish_bark_battle_run, get_bark_battle_run,
get_bark_battle_runtime_config, publish_bark_battle_work, start_bark_battle_run,
generate_bark_battle_image_asset, get_bark_battle_runtime_config,
list_bark_battle_gallery, list_bark_battle_works, publish_bark_battle_work,
start_bark_battle_run, update_bark_battle_draft_config,
},
state::AppState,
};
@@ -21,6 +23,20 @@ pub fn router(state: AppState) -> Router<AppState> {
require_bearer_auth,
)),
)
.route(
"/api/creation/bark-battle/drafts/{draft_id}/config",
post(update_bark_battle_draft_config).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/creation/bark-battle/images/generate",
post(generate_bark_battle_image_asset).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/creation/bark-battle/works/publish",
post(publish_bark_battle_work).route_layer(middleware::from_fn_with_state(
@@ -28,6 +44,17 @@ pub fn router(state: AppState) -> Router<AppState> {
require_bearer_auth,
)),
)
.route(
"/api/runtime/bark-battle/works",
get(list_bark_battle_works).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/bark-battle/gallery",
get(list_bark_battle_gallery),
)
.route(
"/api/runtime/bark-battle/works/{work_id}/config",
get(get_bark_battle_runtime_config).route_layer(middleware::from_fn_with_state(

View File

@@ -199,11 +199,9 @@ fn cpu_usage_ratio_between_samples(
#[cfg(windows)]
fn collect_process_metrics() -> Result<ProcessMetricsSnapshot, String> {
use windows_sys::Win32::{
System::{
ProcessStatus::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS_EX},
Threading::{GetCurrentProcess, GetCurrentProcessId, GetProcessHandleCount},
},
use windows_sys::Win32::System::{
ProcessStatus::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS_EX},
Threading::{GetCurrentProcess, GetCurrentProcessId, GetProcessHandleCount},
};
let handle = unsafe { GetCurrentProcess() };
@@ -212,11 +210,7 @@ fn collect_process_metrics() -> Result<ProcessMetricsSnapshot, String> {
..Default::default()
};
let ok = unsafe {
GetProcessMemoryInfo(
handle,
std::ptr::addr_of_mut!(counters).cast(),
counters.cb,
)
GetProcessMemoryInfo(handle, std::ptr::addr_of_mut!(counters).cast(), counters.cb)
};
if ok == 0 {
return Err("GetProcessMemoryInfo returned false".to_string());
@@ -244,10 +238,7 @@ fn collect_process_metrics() -> Result<ProcessMetricsSnapshot, String> {
#[cfg(windows)]
fn windows_process_cpu_time_seconds(handle: windows_sys::Win32::Foundation::HANDLE) -> Option<f64> {
use windows_sys::Win32::{
Foundation::FILETIME,
System::Threading::GetProcessTimes,
};
use windows_sys::Win32::{Foundation::FILETIME, System::Threading::GetProcessTimes};
let mut creation_time = FILETIME::default();
let mut exit_time = FILETIME::default();
@@ -337,8 +328,8 @@ fn collect_process_metrics() -> Result<ProcessMetricsSnapshot, String> {
.ok_or_else(|| "missing VmSize/statm size field".to_string())?;
let private_bytes = parse_status_kb(&status, "VmData:").map(|value| value * 1024);
let cpu_time_seconds = linux_cpu_time_seconds(&stat)?;
let thread_count = parse_status_u64(&status, "Threads:")
.ok_or_else(|| "missing Threads field".to_string())?;
let thread_count =
parse_status_u64(&status, "Threads:").ok_or_else(|| "missing Threads field".to_string())?;
Ok(ProcessMetricsSnapshot {
rss_bytes,
@@ -427,11 +418,7 @@ fn parse_status_u64(status: &str, key: &str) -> Option<u64> {
#[cfg(target_os = "linux")]
fn parse_statm_pages(statm: &str, index: usize) -> Option<u64> {
statm
.split_whitespace()
.nth(index)?
.parse::<u64>()
.ok()
statm.split_whitespace().nth(index)?.parse::<u64>().ok()
}
#[cfg(not(any(windows, target_os = "linux")))]