feat: add wooden fish play template

This commit is contained in:
2026-05-21 23:34:07 +08:00
parent ef09a23c35
commit 5b0f9f3763
121 changed files with 11580 additions and 159 deletions

View File

@@ -233,13 +233,15 @@ pub async fn create_visual_novel_sound_effect_task(
}
pub async fn create_sound_effect_task(
State(_state): State<AppState>,
State(state): State<AppState>,
axum::extract::Extension(request_context): axum::extract::Extension<RequestContext>,
payload: Result<Json<creation_audio::CreateSoundEffectRequest>, JsonRejection>,
) -> Result<Json<Value>, Response> {
let _ = parse_json_payload(&request_context, payload)?;
Err(creation_audio_generation_disabled_error()
.into_response_with_context(Some(&request_context)))
let Json(payload) = parse_json_payload(&request_context, payload)?;
create_sound_effect_task_response(&state, payload.prompt, payload.duration, payload.seed)
.await
.map(|task| json_success_body(Some(&request_context), task))
.map_err(|error| error.into_response_with_context(Some(&request_context)))
}
pub(crate) async fn generate_sound_effect_asset_for_creation(
@@ -518,15 +520,25 @@ pub async fn publish_background_music_asset(
}
pub async fn publish_sound_effect_asset(
State(_state): State<AppState>,
Path(_task_id): Path<String>,
State(state): State<AppState>,
Path(task_id): Path<String>,
axum::extract::Extension(request_context): axum::extract::Extension<RequestContext>,
axum::extract::Extension(_authenticated): axum::extract::Extension<AuthenticatedAccessToken>,
axum::extract::Extension(authenticated): axum::extract::Extension<AuthenticatedAccessToken>,
payload: Result<Json<creation_audio::PublishGeneratedAudioAssetRequest>, JsonRejection>,
) -> Result<Json<Value>, Response> {
let payload = parse_json_payload(&request_context, payload)?.0;
Err(creation_audio_generation_disabled_error_for_target(payload)
.into_response_with_context(Some(&request_context)))
let target = build_creation_audio_target(payload, AudioAssetSlot::SoundEffect)
.map_err(|error| error.into_response_with_context(Some(&request_context)))?;
publish_generated_audio_asset(
&state,
authenticated.claims().user_id(),
task_id,
AudioAssetSlot::SoundEffect,
target,
)
.await
.map(|payload| json_success_body(Some(&request_context), payload))
.map_err(|error| error.into_response_with_context(Some(&request_context)))
}
async fn publish_generated_audio_asset(
@@ -860,10 +872,36 @@ fn build_visual_novel_audio_target(
})
}
fn build_creation_audio_target(
payload: creation_audio::PublishGeneratedAudioAssetRequest,
slot: AudioAssetSlot,
) -> Result<AudioAssetBindingTarget, AppError> {
if matches!(slot, AudioAssetSlot::SoundEffect)
&& payload.entity_kind.trim() == "wooden_fish_work"
&& payload.slot.trim() == "hit_sound"
&& payload.asset_kind.trim() == "wooden_fish_hit_sound"
&& payload.storage_prefix
== Some(creation_audio::CreationAudioStoragePrefix::WoodenFishAssets)
{
let entity_id = normalize_limited_text(&payload.entity_id, "entityId", 160)?;
return Ok(AudioAssetBindingTarget {
storage_scope: payload.entity_kind.trim().to_string(),
entity_kind: payload.entity_kind.trim().to_string(),
entity_id,
slot: payload.slot.trim().to_string(),
asset_kind: payload.asset_kind.trim().to_string(),
profile_id: normalize_optional_text(payload.profile_id.as_deref()),
storage_prefix: LegacyAssetPrefix::WoodenFishAssets,
});
}
Err(creation_audio_generation_disabled_error_for_target(payload))
}
fn creation_audio_generation_disabled_error() -> AppError {
AppError::from_status(StatusCode::GONE).with_details(json!({
"provider": VECTOR_ENGINE_PROVIDER,
"message": "拼图与抓大鹅音频生成入口已临时关闭",
"message": "当前创作音频目标未开放",
}))
}
@@ -872,8 +910,9 @@ fn creation_audio_generation_disabled_error_for_target(
) -> AppError {
creation_audio_generation_disabled_error().with_details(json!({
"provider": VECTOR_ENGINE_PROVIDER,
"message": "拼图与抓大鹅音频生成入口已临时关闭",
"message": "当前创作音频目标未开放",
"entityKind": payload.entity_kind.trim(),
"slot": payload.slot.trim(),
}))
}
@@ -1434,7 +1473,7 @@ mod tests {
}
#[test]
fn disabled_creation_audio_targets_return_gone() {
fn disabled_creation_audio_targets_return_gone_except_wooden_fish_sound_effects() {
let payload = creation_audio::PublishGeneratedAudioAssetRequest {
entity_kind: "puzzle_work".to_string(),
entity_id: "puzzle-profile-1".to_string(),
@@ -1467,6 +1506,22 @@ mod tests {
};
let error = creation_audio_generation_disabled_error_for_target(payload);
assert_eq!(error.status_code(), StatusCode::GONE);
let payload = creation_audio::PublishGeneratedAudioAssetRequest {
entity_kind: "wooden_fish_work".to_string(),
entity_id: "wooden-fish-profile-1".to_string(),
slot: "hit_sound".to_string(),
asset_kind: "wooden_fish_hit_sound".to_string(),
profile_id: Some("wooden-fish-profile-1".to_string()),
storage_prefix: Some(creation_audio::CreationAudioStoragePrefix::WoodenFishAssets),
};
let target = build_creation_audio_target(payload, AudioAssetSlot::SoundEffect)
.expect("wooden fish hit sound target should be enabled");
assert_eq!(target.entity_kind, "wooden_fish_work");
assert_eq!(target.slot, "hit_sound");
assert_eq!(target.storage_prefix, LegacyAssetPrefix::WoodenFishAssets);
assert_eq!(target.storage_scope, "wooden_fish_work");
}
#[test]