Simplify custom world result editing controls

This commit is contained in:
2026-04-08 19:07:46 +08:00
parent bd9fdcbe31
commit a02f7b6414
125 changed files with 8804 additions and 1462 deletions

View File

@@ -201,9 +201,30 @@ function createPlayableNpc(index: number) {
{ name: `技能${index + 1}-3`, summary: '技能说明3', style: '爆发终结' },
],
initialItems: [
{ name: `物品${index + 1}-1`, category: '武器', quantity: 1, rarity: 'rare', description: '物品说明1', tags: ['物品标签1'] },
{ name: `物品${index + 1}-2`, category: '消耗品', quantity: 2, rarity: 'uncommon', description: '物品说明2', tags: ['物品标签2'] },
{ name: `物品${index + 1}-3`, category: '专属物品', quantity: 1, rarity: 'rare', description: '物品说明3', tags: ['物品标签3'] },
{
name: `物品${index + 1}-1`,
category: '武器',
quantity: 1,
rarity: 'rare',
description: '物品说明1',
tags: ['物品标签1'],
},
{
name: `物品${index + 1}-2`,
category: '消耗品',
quantity: 2,
rarity: 'uncommon',
description: '物品说明2',
tags: ['物品标签2'],
},
{
name: `物品${index + 1}-3`,
category: '专属物品',
quantity: 1,
rarity: 'rare',
description: '物品说明3',
tags: ['物品标签3'],
},
],
};
}
@@ -259,14 +280,47 @@ function createStoryNpc(index: number) {
],
},
skills: [
{ name: `世界技能${index + 1}-1`, summary: '技能说明1', style: '起手压制' },
{ name: `世界技能${index + 1}-2`, summary: '技能说明2', style: '机动周旋' },
{ name: `世界技能${index + 1}-3`, summary: '技能说明3', style: '爆发终结' },
{
name: `世界技能${index + 1}-1`,
summary: '技能说明1',
style: '起手压制',
},
{
name: `世界技能${index + 1}-2`,
summary: '技能说明2',
style: '机动周旋',
},
{
name: `世界技能${index + 1}-3`,
summary: '技能说明3',
style: '爆发终结',
},
],
initialItems: [
{ name: `世界物品${index + 1}-1`, category: '武器', quantity: 1, rarity: 'rare', description: '物品说明1', tags: ['物品标签1'] },
{ name: `世界物品${index + 1}-2`, category: '消耗品', quantity: 2, rarity: 'uncommon', description: '物品说明2', tags: ['物品标签2'] },
{ name: `世界物品${index + 1}-3`, category: '专属物品', quantity: 1, rarity: 'rare', description: '物品说明3', tags: ['物品标签3'] },
{
name: `世界物品${index + 1}-1`,
category: '武器',
quantity: 1,
rarity: 'rare',
description: '物品说明1',
tags: ['物品标签1'],
},
{
name: `世界物品${index + 1}-2`,
category: '消耗品',
quantity: 2,
rarity: 'uncommon',
description: '物品说明2',
tags: ['物品标签2'],
},
{
name: `世界物品${index + 1}-3`,
category: '专属物品',
quantity: 1,
rarity: 'rare',
description: '物品说明3',
tags: ['物品标签3'],
},
],
};
}
@@ -692,15 +746,12 @@ describe('ai orchestration fallbacks', () => {
it('passes abort signals through custom world generation and rejects when interrupted', async () => {
requestPlainTextCompletionMock.mockImplementation(
(
_system: string,
_user: string,
options?: { signal?: AbortSignal },
) =>
(_system: string, _user: string, options?: { signal?: AbortSignal }) =>
new Promise((_resolve, reject) => {
options?.signal?.addEventListener(
'abort',
() => reject(options.signal?.reason ?? new Error('世界生成已中断。')),
() =>
reject(options.signal?.reason ?? new Error('世界生成已中断。')),
{ once: true },
);
}),
@@ -786,7 +837,9 @@ describe('ai orchestration fallbacks', () => {
expect(requestPlainTextCompletionMock).toHaveBeenNthCalledWith(
2,
expect.stringContaining('你是 JSON 修复器'),
expect.stringContaining('不要输出 playableNpcs、storyNpcs、landmarks、items'),
expect.stringContaining(
'不要输出 playableNpcs、storyNpcs、landmarks、items',
),
expect.objectContaining({
debugLabel: 'custom-world-framework-json-repair',
}),
@@ -836,7 +889,9 @@ describe('ai orchestration fallbacks', () => {
expect(profile.creatorIntent?.sourceMode).toBe('card');
expect(profile.creatorIntent?.keyCharacters[0]?.name).toBe('沈砺');
expect(profile.anchorPack?.keyCharacterAnchors[0]?.name).toBe('沈砺');
expect(profile.anchorPack?.lockedAnchorIds).toContain('creator-character-1');
expect(profile.anchorPack?.lockedAnchorIds).toContain(
'creator-character-1',
);
});
it('generates a custom world scene image through the local proxy and returns the saved asset path', async () => {
@@ -846,10 +901,10 @@ describe('ai orchestration fallbacks', () => {
JSON.stringify({
imageSrc: '/generated-custom-world-scenes/world/landmark/scene.png',
assetId: 'custom-scene-1',
model: 'wan2.2-t2i-flash',
model: 'wan2.7-image',
size: '1280*720',
taskId: 'task-123',
prompt: '用于测试的提示词',
prompt: '系统整理后的提示词',
actualPrompt: '扩写后的提示词',
}),
} as Response);
@@ -870,9 +925,9 @@ describe('ai orchestration fallbacks', () => {
description: '被潮雾与旧升降机包围的码头。',
dangerLevel: 'high',
},
prompt: '用于测试的提示词',
negativePrompt: '文字,水印',
userPrompt: '雨夜的栈桥横跨黑色海沟,塔楼灯火被潮雾吞没。',
size: '1280*720',
referenceImageSrc: '/scene_bg/reference-layout.png',
});
expect(fetchMock).toHaveBeenCalledOnce();
@@ -883,13 +938,30 @@ describe('ai orchestration fallbacks', () => {
headers: { 'Content-Type': 'application/json' },
}),
);
const [, request] = fetchMock.mock.calls[0] as [string, RequestInit];
const requestBody = JSON.parse(String(request.body)) as {
prompt: string;
referenceImageSrc?: string;
};
expect(requestBody.referenceImageSrc).toBe(
'/scene_bg/reference-layout.png',
);
expect(requestBody.prompt).toContain('像素风场景背景');
expect(requestBody.prompt).toContain('画面构图必须严格按上下 1:1 分区');
expect(requestBody.prompt).toContain('下半部分严格占据整张图的 1/2 高度');
expect(requestBody.prompt).toContain('模拟 3D 游戏视角的地面近景');
expect(requestBody.prompt).toContain(
'下半部分的内容必须是明确可站立的地面本体',
);
expect(requestBody.prompt).toContain('已提供一张自定义参考图');
expect(requestBody.prompt).toContain('雨夜的栈桥横跨黑色海沟');
expect(result).toEqual({
imageSrc: '/generated-custom-world-scenes/world/landmark/scene.png',
assetId: 'custom-scene-1',
model: 'wan2.2-t2i-flash',
model: 'wan2.7-image',
size: '1280*720',
taskId: 'task-123',
prompt: '用于测试的提示词',
prompt: '系统整理后的提示词',
actualPrompt: '扩写后的提示词',
});
});