合并远端主分支更新
同步主分支音效生成与External v1契约更新 保留图标规范与图集生成链路 适配VectorEngine LLM客户端命名并解决前端提交语义冲突
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
||||
EDITOR_ICON_DESCRIPTIONS_MAX_TOTAL_CHARS,
|
||||
EDITOR_ICON_DESCRIPTIONS_MAX_TOTAL_UTF8_BYTES,
|
||||
EDITOR_ICON_SPEC_PROMPT_MAX_LENGTH,
|
||||
EDITOR_SOUND_EFFECT_PROMPT_OPTIMIZE_TIMEOUT_MS,
|
||||
extractEditorUiDesignAssets,
|
||||
generateEditorBackgroundMusic,
|
||||
generateEditorCharacterAnimation,
|
||||
@@ -33,6 +34,7 @@ import {
|
||||
loadOrCreateRecentEditorProject,
|
||||
refineEditorIconSpecArtStyle,
|
||||
refineEditorIconSpecPlaySetting,
|
||||
optimizeEditorSoundEffectPrompt,
|
||||
removeEditorImageBackground,
|
||||
renameEditorProject,
|
||||
saveEditorProjectLayout,
|
||||
@@ -112,6 +114,7 @@ describe('editorProjectClient', () => {
|
||||
prices: { '480p': 13, '720p': 26, '1080p': 52 },
|
||||
},
|
||||
'audio1.0': { unit: 'perGeneration', price: 15 },
|
||||
eleven_text_to_sound_v2: { unit: 'perGeneration', price: 16 },
|
||||
'chirp-v5': { unit: 'perGeneration', price: 9 },
|
||||
},
|
||||
});
|
||||
@@ -119,6 +122,7 @@ describe('editorProjectClient', () => {
|
||||
const pricing = await loadEditorGenerationPricing();
|
||||
|
||||
expect(pricing.models['gpt-image-2']?.prices?.['1K']).toBe(29);
|
||||
expect(pricing.models.eleven_text_to_sound_v2?.price).toBe(16);
|
||||
expect(requestJsonMock).toHaveBeenCalledWith(
|
||||
'/api/editor/generation-pricing',
|
||||
{ method: 'GET' },
|
||||
@@ -1988,9 +1992,8 @@ describe('editorProjectClient', () => {
|
||||
height: 120,
|
||||
sourceType: 'generated',
|
||||
prompt: '金币掉落叮当声',
|
||||
actualPrompt: '金币掉落叮当声',
|
||||
model: 'audio1.0',
|
||||
provider: 'VectorEngine',
|
||||
actualPrompt: 'A bright coin pickup chime',
|
||||
model: 'eleven_text_to_sound_v2',
|
||||
taskId: 'sound-task-1',
|
||||
audioKind: 'sound-effect',
|
||||
asset: {
|
||||
@@ -2007,8 +2010,9 @@ describe('editorProjectClient', () => {
|
||||
|
||||
const result = await generateEditorSoundEffect({
|
||||
prompt: '金币掉落叮当声',
|
||||
model: 'audio1.0',
|
||||
duration: 7,
|
||||
model: 'eleven_text_to_sound_v2',
|
||||
duration: 7.5,
|
||||
loop: true,
|
||||
assetFolderId: 'project',
|
||||
assetLabel: '游戏音效 1',
|
||||
});
|
||||
@@ -2022,38 +2026,34 @@ describe('editorProjectClient', () => {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
prompt: '金币掉落叮当声',
|
||||
model: 'audio1.0',
|
||||
duration: 7,
|
||||
model: 'eleven_text_to_sound_v2',
|
||||
duration: 7.5,
|
||||
loop: true,
|
||||
assetFolderId: 'project',
|
||||
assetLabel: '游戏音效 1',
|
||||
}),
|
||||
}),
|
||||
'生成游戏音效失败',
|
||||
expect.objectContaining({
|
||||
timeoutMs: 1_200_000,
|
||||
retry: editorRetryOptionsExpectation,
|
||||
}),
|
||||
{ timeoutMs: 1_200_000 },
|
||||
);
|
||||
});
|
||||
|
||||
it('sends editor sound effect duration to Vidu instead of legacy type and tempo', async () => {
|
||||
it('canonicalizes omitted duration to null and omitted loop to false', async () => {
|
||||
requestJsonMock.mockResolvedValueOnce({
|
||||
audioSrc: '/generated-character-drafts/editor-audios/sfx-null.mp3',
|
||||
width: 420,
|
||||
height: 120,
|
||||
sourceType: 'generated',
|
||||
prompt: '按钮确认短促音',
|
||||
actualPrompt: '按钮确认短促音',
|
||||
model: 'audio1.0',
|
||||
provider: 'VectorEngine',
|
||||
actualPrompt: 'A short confirmation click',
|
||||
model: 'eleven_text_to_sound_v2',
|
||||
taskId: 'sound-task-null',
|
||||
audioKind: 'sound-effect',
|
||||
});
|
||||
|
||||
await generateEditorSoundEffect({
|
||||
prompt: '按钮确认短促音',
|
||||
model: 'audio1.0',
|
||||
duration: 5,
|
||||
model: 'eleven_text_to_sound_v2',
|
||||
});
|
||||
|
||||
expect(requestJsonMock).toHaveBeenCalledWith(
|
||||
@@ -2061,8 +2061,9 @@ describe('editorProjectClient', () => {
|
||||
expect.objectContaining({
|
||||
body: JSON.stringify({
|
||||
prompt: '按钮确认短促音',
|
||||
model: 'audio1.0',
|
||||
duration: 5,
|
||||
model: 'eleven_text_to_sound_v2',
|
||||
duration: null,
|
||||
loop: false,
|
||||
}),
|
||||
}),
|
||||
'生成游戏音效失败',
|
||||
@@ -2070,6 +2071,66 @@ describe('editorProjectClient', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('accepts the 0.5 and 30 second sound effect duration boundaries', async () => {
|
||||
requestJsonMock.mockResolvedValue({});
|
||||
|
||||
for (const duration of [0.5, 30]) {
|
||||
await generateEditorSoundEffect({
|
||||
prompt: '按钮确认短促音',
|
||||
model: 'eleven_text_to_sound_v2',
|
||||
duration,
|
||||
});
|
||||
}
|
||||
|
||||
expect(requestJsonMock).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'/api/editor/audios/sound-effects/generations',
|
||||
expect.objectContaining({
|
||||
body: JSON.stringify({
|
||||
prompt: '按钮确认短促音',
|
||||
model: 'eleven_text_to_sound_v2',
|
||||
duration: 0.5,
|
||||
loop: false,
|
||||
}),
|
||||
}),
|
||||
'生成游戏音效失败',
|
||||
expect.any(Object),
|
||||
);
|
||||
expect(requestJsonMock).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
'/api/editor/audios/sound-effects/generations',
|
||||
expect.objectContaining({
|
||||
body: JSON.stringify({
|
||||
prompt: '按钮确认短促音',
|
||||
model: 'eleven_text_to_sound_v2',
|
||||
duration: 30,
|
||||
loop: false,
|
||||
}),
|
||||
}),
|
||||
'生成游戏音效失败',
|
||||
expect.any(Object),
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects invalid sound effect durations before the request', async () => {
|
||||
for (const duration of [
|
||||
0.49,
|
||||
30.01,
|
||||
Number.NaN,
|
||||
Number.POSITIVE_INFINITY,
|
||||
]) {
|
||||
await expect(
|
||||
generateEditorSoundEffect({
|
||||
prompt: '按钮确认短促音',
|
||||
model: 'eleven_text_to_sound_v2',
|
||||
duration,
|
||||
}),
|
||||
).rejects.toThrow('游戏音效时长必须在 0.5-30 秒之间');
|
||||
}
|
||||
|
||||
expect(requestJsonMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('generates editor background music through the backend BFF', async () => {
|
||||
const representativeComplexPromptCase =
|
||||
backgroundMusicPromptCanonicalizationCases.find(
|
||||
@@ -2087,7 +2148,6 @@ describe('editorProjectClient', () => {
|
||||
prompt: canonicalPrompt,
|
||||
actualPrompt: canonicalPrompt,
|
||||
model: 'chirp-v4',
|
||||
provider: 'VectorEngine',
|
||||
taskId: 'music-task-1',
|
||||
audioKind: 'background-music',
|
||||
});
|
||||
@@ -2168,7 +2228,9 @@ describe('editorProjectClient', () => {
|
||||
);
|
||||
expect(EDITOR_BACKGROUND_MUSIC_PROMPT_ASSIST_TIMEOUT_MS).toBe(180_000);
|
||||
expect(requestJsonMock.mock.calls[0]).toHaveLength(4);
|
||||
expect(requestJsonMock.mock.calls[0][3]).toEqual(promptAssistRequestOptions);
|
||||
expect(requestJsonMock.mock.calls[0][3]).toEqual(
|
||||
promptAssistRequestOptions,
|
||||
);
|
||||
});
|
||||
|
||||
it('simplifies a background music prompt without forwarding client-controlled limits', async () => {
|
||||
@@ -2206,7 +2268,47 @@ describe('editorProjectClient', () => {
|
||||
promptAssistRequestOptions,
|
||||
);
|
||||
expect(requestJsonMock.mock.calls[0]).toHaveLength(4);
|
||||
expect(requestJsonMock.mock.calls[0][3]).toEqual(promptAssistRequestOptions);
|
||||
expect(requestJsonMock.mock.calls[0][3]).toEqual(
|
||||
promptAssistRequestOptions,
|
||||
);
|
||||
});
|
||||
|
||||
it('optimizes an SFX prompt through the authenticated internal BFF without retries or client-controlled limits', async () => {
|
||||
requestJsonMock.mockResolvedValueOnce({
|
||||
prompt: '清脆明亮的金币落地声',
|
||||
charCount: 10,
|
||||
});
|
||||
const controller = new AbortController();
|
||||
|
||||
const result = await optimizeEditorSoundEffectPrompt(
|
||||
{
|
||||
currentPrompt: '金币落地声',
|
||||
targetChars: 2048,
|
||||
model: 'client-must-not-control',
|
||||
} as Parameters<typeof optimizeEditorSoundEffectPrompt>[0] & {
|
||||
targetChars: number;
|
||||
model: string;
|
||||
},
|
||||
{ signal: controller.signal },
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
prompt: '清脆明亮的金币落地声',
|
||||
charCount: 10,
|
||||
});
|
||||
expect(requestJsonMock).toHaveBeenCalledWith(
|
||||
'/api/editor/audios/sound-effects/prompts/optimizations',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ currentPrompt: '金币落地声' }),
|
||||
signal: controller.signal,
|
||||
},
|
||||
'优化游戏音效提示词失败',
|
||||
{ timeoutMs: EDITOR_SOUND_EFFECT_PROMPT_OPTIMIZE_TIMEOUT_MS },
|
||||
);
|
||||
expect(EDITOR_SOUND_EFFECT_PROMPT_OPTIMIZE_TIMEOUT_MS).toBe(180_000);
|
||||
expect(requestJsonMock.mock.calls[0]).toHaveLength(4);
|
||||
});
|
||||
|
||||
it.each([
|
||||
|
||||
Reference in New Issue
Block a user