实现 SFX V2 T1 契约与提示词基础

统一前后端 SFX Prompt Unicode canonicalization、字符计数和 2048 边界
固化 52 个音效预设、追加规则及跨语言测试向量
演进共享音频请求响应、duration、Loop 和 V2 metadata 契约
增加 External model 输入矩阵纯函数并保持正式接线归属 T5
补齐前端提交、读取、深拷贝与请求边界回归测试
更新共享计划并标记 T1 完成且当前不可发布
This commit is contained in:
2026-08-06 13:05:48 +00:00
parent 6fd731f56c
commit cd80c085ff
24 changed files with 1559 additions and 97 deletions
@@ -1,6 +1,10 @@
import type {
BackgroundMusicPromptAssistRequest,
BackgroundMusicPromptAssistResponse,
import {
type BackgroundMusicPromptAssistRequest,
type BackgroundMusicPromptAssistResponse,
type EditorSoundEffectGenerationMetadataV2,
type EditorSoundEffectGenerationRequest,
SOUND_EFFECT_DURATION_MAX_SECONDS,
SOUND_EFFECT_DURATION_MIN_SECONDS,
} from '../../../packages/shared/src/contracts/editorAudio';
import type { ExternalGenerationJobStatusRecord } from '../../../packages/shared/src/contracts/externalGeneration';
import { requestJson } from '../apiClient';
@@ -125,6 +129,7 @@ export type EditorAssetGenerationInputReference = {
export type EditorAssetGenerationInputs = {
fields: EditorAssetGenerationInputField[];
references: EditorAssetGenerationInputReference[];
soundEffect?: EditorSoundEffectGenerationMetadataV2;
[key: string]: unknown;
};
@@ -547,16 +552,14 @@ export type EditorVideoGenerationResult = {
queueState?: ExternalGenerationJobStatusRecord | null;
};
export type EditorSoundEffectGenerationInput = {
prompt: string;
model: 'audio1.0';
duration: number;
projectId?: string | null;
canvasCompletion?: EditorCanvasGenerationCompletionInput | null;
generationInputs?: EditorAssetGenerationInputs | null;
assetFolderId?: string | null;
assetLabel?: string | null;
};
export type EditorSoundEffectGenerationInput =
EditorSoundEffectGenerationRequest & {
projectId?: string | null;
canvasCompletion?: EditorCanvasGenerationCompletionInput | null;
generationInputs?: EditorAssetGenerationInputs | null;
assetFolderId?: string | null;
assetLabel?: string | null;
};
export type EditorBackgroundMusicGenerationInput = {
gptDescriptionPrompt: string;
@@ -582,10 +585,12 @@ export type EditorAudioGenerationResult = {
prompt: string;
actualPrompt?: string | null;
model: string;
provider: string;
taskId: string;
priceMudPoints: number;
audioKind: 'sound-effect' | 'background-music';
durationSeconds?: number | null;
loop?: boolean | null;
resource?: EditorProjectResourceSnapshot | null;
asset?: EditorAssetSnapshot | null;
project?: EditorProjectSnapshot | null;
@@ -1353,12 +1358,22 @@ export async function generateEditorVideo(input: EditorVideoGenerationInput) {
export async function generateEditorSoundEffect(
input: EditorSoundEffectGenerationInput,
) {
const duration = input.duration ?? null;
if (
duration !== null &&
(!Number.isFinite(duration) ||
duration < SOUND_EFFECT_DURATION_MIN_SECONDS ||
duration > SOUND_EFFECT_DURATION_MAX_SECONDS)
) {
throw new Error('游戏音效时长必须在 0.5-30 秒之间');
}
return requestJson<EditorAudioGenerationResponse>(
EDITOR_SOUND_EFFECT_GENERATION_API,
jsonRequest('POST', {
prompt: input.prompt,
model: input.model,
duration: input.duration,
duration,
loop: input.loop ?? false,
...(input.projectId ? { projectId: input.projectId } : {}),
...(input.canvasCompletion
? { canvasCompletion: input.canvasCompletion }