e9c3dc1120
保留 SpacetimeDB 历史表、迁移白名单与旧业务源码 切换前端 active 入口并解除旧创作页面和路由编译链 移除旧后端路由、worker 与纯业务 crate 依赖 收敛 SpacetimeDB 模块为历史数据壳 同步 Nginx、Pingora、验证门禁与架构文档
152 lines
4.8 KiB
Rust
152 lines
4.8 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum CreationAudioGenerationKind {
|
|
BackgroundMusic,
|
|
SoundEffect,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[cfg(any())]
|
|
pub struct CreationAudioAsset {
|
|
pub task_id: String,
|
|
pub provider: String,
|
|
#[serde(default)]
|
|
pub asset_object_id: Option<String>,
|
|
#[serde(default)]
|
|
pub asset_kind: Option<String>,
|
|
pub audio_src: String,
|
|
#[serde(default)]
|
|
pub prompt: Option<String>,
|
|
#[serde(default)]
|
|
pub title: Option<String>,
|
|
#[serde(default)]
|
|
pub updated_at: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[cfg(any())]
|
|
pub struct CreateBackgroundMusicRequest {
|
|
pub prompt: String,
|
|
pub title: String,
|
|
#[serde(default)]
|
|
pub tags: Option<String>,
|
|
#[serde(default)]
|
|
pub model: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[cfg(any())]
|
|
pub struct CreateSoundEffectRequest {
|
|
pub prompt: String,
|
|
#[serde(default)]
|
|
pub duration: Option<u8>,
|
|
#[serde(default)]
|
|
pub seed: Option<u64>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[cfg(any())]
|
|
pub struct AudioGenerationTaskResponse {
|
|
pub kind: CreationAudioGenerationKind,
|
|
pub task_id: String,
|
|
pub provider: String,
|
|
pub status: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[cfg(any())]
|
|
pub enum CreationAudioStoragePrefix {
|
|
PuzzleAssets,
|
|
WoodenFishAssets,
|
|
CustomWorldScenes,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[cfg(any())]
|
|
pub struct PublishGeneratedAudioAssetRequest {
|
|
pub entity_kind: String,
|
|
pub entity_id: String,
|
|
pub slot: String,
|
|
pub asset_kind: String,
|
|
#[serde(default)]
|
|
pub profile_id: Option<String>,
|
|
#[serde(default)]
|
|
pub storage_prefix: Option<CreationAudioStoragePrefix>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct GeneratedAudioAssetResponse {
|
|
pub kind: CreationAudioGenerationKind,
|
|
pub task_id: String,
|
|
pub provider: String,
|
|
pub status: String,
|
|
#[serde(default)]
|
|
pub asset_object_id: Option<String>,
|
|
#[serde(default)]
|
|
pub object_key: Option<String>,
|
|
#[serde(default)]
|
|
pub asset_kind: Option<String>,
|
|
#[serde(default)]
|
|
pub audio_src: Option<String>,
|
|
}
|
|
|
|
#[cfg(any())]
|
|
mod tests {
|
|
use super::*;
|
|
use serde_json::json;
|
|
|
|
#[test]
|
|
fn creation_audio_contracts_use_camel_case_fields() {
|
|
let request = PublishGeneratedAudioAssetRequest {
|
|
entity_kind: "puzzle_work".to_string(),
|
|
entity_id: "puzzle-profile-1".to_string(),
|
|
slot: "background_music".to_string(),
|
|
asset_kind: "puzzle_background_music".to_string(),
|
|
profile_id: Some("profile-1".to_string()),
|
|
storage_prefix: Some(CreationAudioStoragePrefix::PuzzleAssets),
|
|
};
|
|
let payload = serde_json::to_value(request).expect("request should serialize");
|
|
assert_eq!(payload["entityKind"], json!("puzzle_work"));
|
|
assert_eq!(payload["storagePrefix"], json!("puzzle_assets"));
|
|
|
|
let asset = CreationAudioAsset {
|
|
task_id: "task-1".to_string(),
|
|
provider: "vector-engine-suno".to_string(),
|
|
asset_object_id: Some("assetobj_1".to_string()),
|
|
asset_kind: Some("puzzle_background_music".to_string()),
|
|
audio_src: "/generated-puzzle-assets/a.mp3".to_string(),
|
|
prompt: Some("轻快音乐".to_string()),
|
|
title: Some("拼图音乐".to_string()),
|
|
updated_at: Some("2026-05-11T00:00:00Z".to_string()),
|
|
};
|
|
let payload = serde_json::to_value(asset).expect("asset should serialize");
|
|
assert_eq!(payload["taskId"], json!("task-1"));
|
|
assert_eq!(payload["audioSrc"], json!("/generated-puzzle-assets/a.mp3"));
|
|
}
|
|
|
|
#[test]
|
|
fn creation_audio_contracts_support_wooden_fish_storage_prefix() {
|
|
let request = 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(CreationAudioStoragePrefix::WoodenFishAssets),
|
|
};
|
|
|
|
let payload = serde_json::to_value(request).expect("request should serialize");
|
|
|
|
assert_eq!(payload["storagePrefix"], json!("wooden_fish_assets"));
|
|
}
|
|
}
|