@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user