统一SFX提示词 trim 规范化
将 SFX Prompt 首尾规范化改为 ECMAScript String.trim 语义并同步 Rust 等值实现 更新共享边界 fixture、前后端与 Worker 回归测试 同步权威设计、实施计划、决策日志和 External OpenAPI 描述
This commit is contained in:
@@ -991,6 +991,7 @@ describe('ImageCanvasEditorModel', () => {
|
||||
{ ...soundEffect, schemaVersion: 1 },
|
||||
{ ...soundEffect, model: 'audio1.0' },
|
||||
{ ...soundEffect, userPrompt: ' 金币落地' },
|
||||
{ ...soundEffect, userPrompt: '\uFEFF金币落地,轻快可爱' },
|
||||
{ ...soundEffect, actualDurationSeconds: 600.1 },
|
||||
{
|
||||
...soundEffect,
|
||||
|
||||
@@ -248,15 +248,15 @@ describe('ImageCanvasSoundEffectPresetModel', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('canonicalizes and appends with the frozen Unicode punctuation rule', () => {
|
||||
it('canonicalizes and appends with the frozen ECMAScript trim rule', () => {
|
||||
const preset = SOUND_EFFECT_PROMPT_PRESETS[40];
|
||||
expect(appendSoundEffectPromptPreset('\u0085\u2003', preset)).toBe(
|
||||
expect(appendSoundEffectPromptPreset('\uFEFF\u2003', preset)).toBe(
|
||||
preset.prompt,
|
||||
);
|
||||
expect(appendSoundEffectPromptPreset('金币落地', preset)).toBe(
|
||||
`金币落地,${preset.prompt}`,
|
||||
);
|
||||
expect(appendSoundEffectPromptPreset('金币落地!\u0085', preset)).toBe(
|
||||
expect(appendSoundEffectPromptPreset('金币落地!\uFEFF', preset)).toBe(
|
||||
`金币落地!${preset.prompt}`,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -39,7 +39,7 @@ describe('ImageCanvasSoundEffectPromptModel', () => {
|
||||
});
|
||||
|
||||
it('accepts 2048 code points and rejects 2049 without truncating', () => {
|
||||
const maximum = `\u0085${'😀'.repeat(
|
||||
const maximum = `\uFEFF${'😀'.repeat(
|
||||
SOUND_EFFECT_PROMPT_MAX_CODE_POINTS,
|
||||
)}\u2003`;
|
||||
const accepted = validateSoundEffectPrompt(maximum);
|
||||
@@ -59,7 +59,7 @@ describe('ImageCanvasSoundEffectPromptModel', () => {
|
||||
});
|
||||
|
||||
it('rejects empty canonical prompts without adding a default description', () => {
|
||||
for (const prompt of ['', ' \t\r\n', '\u0085\u2003\u00a0']) {
|
||||
for (const prompt of ['', ' \t\r\n', '\uFEFF\u2003\u00a0']) {
|
||||
expect(validateSoundEffectPrompt(prompt)).toEqual({
|
||||
ok: false,
|
||||
prompt: '',
|
||||
@@ -74,7 +74,7 @@ describe('ImageCanvasSoundEffectPromptModel', () => {
|
||||
const started = model.beginOperation({
|
||||
dialogId: 'dialog-a',
|
||||
status: 'optimizing',
|
||||
prompt: '\u0085金币落地声\u3000',
|
||||
prompt: '\uFEFF金币落地声\u3000',
|
||||
});
|
||||
expect(started.started).toBe(true);
|
||||
expect(started.canonicalPrompt).toBe('金币落地声');
|
||||
|
||||
@@ -6,9 +6,6 @@ import type {
|
||||
export const SOUND_EFFECT_PROMPT_MAX_CODE_POINTS = 2048;
|
||||
const SOUND_EFFECT_PROMPT_OPERATION_ID_PREFIX = 'sound-effect-prompt-operation';
|
||||
|
||||
const LEADING_UNICODE_WHITE_SPACE = /^\p{White_Space}+/u;
|
||||
const TRAILING_UNICODE_WHITE_SPACE = /\p{White_Space}+$/u;
|
||||
|
||||
export type SoundEffectPromptValidationResult =
|
||||
| {
|
||||
ok: true;
|
||||
@@ -57,13 +54,11 @@ export function toSoundEffectGenerationDialog(
|
||||
}
|
||||
|
||||
/**
|
||||
* 只删除首尾 Unicode `White_Space`。内部空白、组合字符、ZWJ、U+200B、U+FEFF
|
||||
* 及其它 code point 均原样保留;不能替换为语义不同的原生 `trim()`。
|
||||
* 按 JavaScript `String.trim()` 删除首尾 ECMAScript 空白和行终止符。内部空白、组合字符、
|
||||
* ZWJ、U+200B 及其它 code point 均原样保留;首尾 U+FEFF 会被删除,U+0085 则保留。
|
||||
*/
|
||||
export function canonicalizeSoundEffectPrompt(prompt: string) {
|
||||
return prompt
|
||||
.replace(LEADING_UNICODE_WHITE_SPACE, '')
|
||||
.replace(TRAILING_UNICODE_WHITE_SPACE, '');
|
||||
return prompt.trim();
|
||||
}
|
||||
|
||||
export function countSoundEffectPromptCodePoints(prompt: string) {
|
||||
|
||||
@@ -1938,7 +1938,7 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
initialDialog={{
|
||||
id: 'dialog-sound',
|
||||
mode: 'audio-sound-effect',
|
||||
prompt: '\u0085\uFEFF金币掉落叮当声\uFEFF\u0085',
|
||||
prompt: '\uFEFF金币掉落叮当声\uFEFF',
|
||||
status: 'idle',
|
||||
composerOpen: true,
|
||||
soundDurationSeconds: 7,
|
||||
@@ -1960,7 +1960,7 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
await waitFor(() => {
|
||||
expect(generateEditorSoundEffectMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
prompt: '\uFEFF金币掉落叮当声\uFEFF',
|
||||
prompt: '金币掉落叮当声',
|
||||
duration: 7,
|
||||
projectId: 'editor-project-audio',
|
||||
assetFolderId: 'project',
|
||||
@@ -1999,7 +1999,7 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
initialDialog={{
|
||||
id: 'dialog-sound-empty',
|
||||
mode: 'audio-sound-effect',
|
||||
prompt: '\u0085 \n\t\u0085',
|
||||
prompt: '\uFEFF \n\t\uFEFF',
|
||||
status: 'idle',
|
||||
composerOpen: true,
|
||||
}}
|
||||
@@ -2031,7 +2031,7 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
initialDialog={{
|
||||
id: 'dialog-sfx-claim',
|
||||
mode: 'audio-sound-effect',
|
||||
prompt: '\u0085循环环境声\u3000',
|
||||
prompt: '\uFEFF循环环境声\u3000',
|
||||
status: 'idle',
|
||||
composerOpen: true,
|
||||
soundModel: 'eleven_text_to_sound_v2',
|
||||
|
||||
@@ -148,7 +148,7 @@ describe('useImageCanvasSoundEffectPromptAssist', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useHarness({
|
||||
initialDialogs: [
|
||||
createDialog('dialog-a', '\u0085金币落地声\u3000', {
|
||||
createDialog('dialog-a', '\uFEFF金币落地声\u3000', {
|
||||
status: 'failed',
|
||||
errorMessage: '旧错误',
|
||||
}),
|
||||
@@ -319,7 +319,7 @@ describe('useImageCanvasSoundEffectPromptAssist', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useHarness({
|
||||
initialDialogs: [
|
||||
createDialog('dialog-a', ' \u0085循环环境声\u3000', {
|
||||
createDialog('dialog-a', ' \uFEFF循环环境声\u3000', {
|
||||
soundDurationMode: 'auto',
|
||||
soundDurationSeconds: 7.3,
|
||||
soundLoop: true,
|
||||
|
||||
Reference in New Issue
Block a user