接入资产生成发布叙世币消耗
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-27 23:32:34 +08:00
parent 1348b2e940
commit abe44948ee
11 changed files with 548 additions and 130 deletions

View File

@@ -42,8 +42,6 @@ use crate::{
state::AppState,
};
const ASSET_GENERATION_POINTS_COST: u64 = 1;
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct CustomWorldEntityRequest {
@@ -443,14 +441,14 @@ pub async fn generate_custom_world_scene_image(
let normalized = normalize_scene_image_request(payload)
.map_err(|error| custom_world_ai_error_response(&request_context, error))?;
let asset_id = format!("custom-scene-{}", current_utc_millis());
consume_asset_generation_points(
crate::asset_billing::consume_asset_operation_points(
&state,
&owner_user_id,
"scene_image",
asset_id.as_str(),
&request_context,
)
.await?;
.await
.map_err(|error| custom_world_ai_error_response(&request_context, error))?;
let asset_result = async {
let settings = require_dashscope_settings(&state)?;
let http_client = build_dashscope_http_client(&settings)?;
@@ -553,7 +551,13 @@ pub async fn generate_custom_world_scene_image(
let asset = match asset_result {
Ok(asset) => asset,
Err(error) => {
refund_asset_generation_points(&state, &owner_user_id, "scene_image", &asset_id).await;
crate::asset_billing::refund_asset_operation_points(
&state,
&owner_user_id,
"scene_image",
&asset_id,
)
.await;
return Err(custom_world_ai_error_response(&request_context, error));
}
};
@@ -713,14 +717,14 @@ pub async fn generate_custom_world_cover_image(
let entity_id = profile_id.clone().unwrap_or_else(|| world_name.clone());
let size = trim_to_option(payload.size.as_deref()).unwrap_or_else(|| "1600*900".to_string());
let asset_id = format!("custom-cover-{}", current_utc_millis());
consume_asset_generation_points(
crate::asset_billing::consume_asset_operation_points(
&state,
&owner_user_id,
"custom_world_cover",
asset_id.as_str(),
&request_context,
)
.await?;
.await
.map_err(|error| custom_world_ai_error_response(&request_context, error))?;
let asset_result = async {
let settings = require_dashscope_settings(&state)?;
let http_client = build_dashscope_http_client(&settings)?;
@@ -824,8 +828,13 @@ pub async fn generate_custom_world_cover_image(
let asset = match asset_result {
Ok(asset) => asset,
Err(error) => {
refund_asset_generation_points(&state, &owner_user_id, "custom_world_cover", &asset_id)
.await;
crate::asset_billing::refund_asset_operation_points(
&state,
&owner_user_id,
"custom_world_cover",
&asset_id,
)
.await;
return Err(custom_world_ai_error_response(&request_context, error));
}
};
@@ -903,81 +912,6 @@ pub async fn upload_custom_world_cover_image(
Ok(json_success_body(Some(&request_context), asset))
}
async fn consume_asset_generation_points(
state: &AppState,
owner_user_id: &str,
asset_kind: &str,
asset_id: &str,
request_context: &RequestContext,
) -> Result<(), Response> {
let ledger_id = format!(
"asset_generation_consume:{}:{}:{}",
owner_user_id, asset_kind, asset_id
);
let created_at_micros = current_utc_micros();
state
.spacetime_client()
.consume_profile_wallet_points(
owner_user_id.to_string(),
ASSET_GENERATION_POINTS_COST,
ledger_id,
created_at_micros,
)
.await
.map(|_| ())
.map_err(|error| {
custom_world_ai_error_response(
request_context,
map_asset_generation_wallet_error(error),
)
})
}
async fn refund_asset_generation_points(
state: &AppState,
owner_user_id: &str,
asset_kind: &str,
asset_id: &str,
) {
let ledger_id = format!(
"asset_generation_refund:{}:{}:{}",
owner_user_id, asset_kind, asset_id
);
if let Err(error) = state
.spacetime_client()
.refund_profile_wallet_points(
owner_user_id.to_string(),
ASSET_GENERATION_POINTS_COST,
ledger_id,
current_utc_micros(),
)
.await
{
tracing::error!(
owner_user_id,
asset_kind,
asset_id,
error = %error,
"资产生成失败后的叙世币退款失败"
);
}
}
fn map_asset_generation_wallet_error(error: SpacetimeClientError) -> AppError {
let status = match &error {
SpacetimeClientError::Runtime(_) => StatusCode::BAD_REQUEST,
SpacetimeClientError::Procedure(message) if message.contains("叙世币余额不足") => {
StatusCode::CONFLICT
}
_ => StatusCode::BAD_GATEWAY,
};
AppError::from_status(status).with_details(json!({
"provider": "profile-wallet",
"message": error.to_string(),
}))
}
async fn persist_custom_world_asset(
state: &AppState,
owner_user_id: &str,