修复精选提示词展示
精选卡片优先展示用户可见的生成输入 过滤系统内置和素材提取提示词 补充精选提示词外露回归测试
This commit is contained in:
@@ -260,6 +260,62 @@ describe('creationShowcaseModel', () => {
|
||||
expect(items[1]?.cost).toBe('12泥点');
|
||||
});
|
||||
|
||||
it('prefers user generation inputs over internal assembled prompts', () => {
|
||||
const items = buildCreationShowcaseItems({
|
||||
activeTab: 'all',
|
||||
projectResources: [
|
||||
createResource({
|
||||
resourceId: 'character-1',
|
||||
label: '角色主图',
|
||||
assetKind: 'character',
|
||||
prompt:
|
||||
'【系统内置】完整拼接提示词:用户的角色设定,自动添加视角、构图和抠图背景规则。',
|
||||
actualPrompt:
|
||||
'【系统内置】真正发送给模型的完整提示词,包含更多模型约束。',
|
||||
generationInputs: {
|
||||
fields: [
|
||||
{ title: '角色设定', value: '用户的角色设定' },
|
||||
{ title: '抠图背景色', value: '暖浅桃色 #FFD6C2' },
|
||||
{ title: 'model', value: 'gpt-image-2' },
|
||||
],
|
||||
references: [],
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
expect(items).toHaveLength(1);
|
||||
expect(items[0]?.prompt).toBe('用户的角色设定');
|
||||
});
|
||||
|
||||
it('does not expose built-in extraction prompts as showcase descriptions', () => {
|
||||
const items = buildCreationShowcaseItems({
|
||||
activeTab: 'all',
|
||||
projectResources: [
|
||||
createResource({
|
||||
resourceId: 'icon-sheet-1',
|
||||
label: '图标素材图集',
|
||||
assetKind: 'icon-spritesheet',
|
||||
prompt: '【系统内置】固定素材提取提示词',
|
||||
generationInputs: {
|
||||
fields: [
|
||||
{
|
||||
title: '提取提示词',
|
||||
value:
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用所选单一纯色抠图背景。',
|
||||
},
|
||||
{ title: 'model', value: 'gpt-image-2' },
|
||||
],
|
||||
references: [],
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
expect(items).toHaveLength(1);
|
||||
expect(items[0]?.prompt).toBe('-');
|
||||
});
|
||||
|
||||
it('keeps unset category visible in all tab and out of concrete category tabs', () => {
|
||||
const items = buildCreationShowcaseItems({
|
||||
activeTab: 'all',
|
||||
|
||||
@@ -65,6 +65,38 @@ const SHOWCASE_AUTHOR_KEYS = [
|
||||
'authorPublicUserCode',
|
||||
] as const;
|
||||
|
||||
const USER_PROMPT_INPUT_TITLES = new Set(
|
||||
[
|
||||
'生成提示词',
|
||||
'视频描述',
|
||||
'prompt',
|
||||
'sound',
|
||||
'gpt_description_prompt',
|
||||
'音效提示词',
|
||||
'背景音乐提示词',
|
||||
'角色设定',
|
||||
'用户输入',
|
||||
'素材描述',
|
||||
'自定义规范提示词',
|
||||
'修改要求',
|
||||
'快速编辑提示词',
|
||||
'重绘提示词',
|
||||
'动作描述',
|
||||
].map((title) => title.toLowerCase()),
|
||||
);
|
||||
|
||||
const STRUCTURED_USER_INPUT_TITLES = new Set(
|
||||
[
|
||||
'玩法设定',
|
||||
'美术风格',
|
||||
'头身比',
|
||||
'角色视角',
|
||||
'游戏名',
|
||||
'游戏分类',
|
||||
'一句话描述游戏',
|
||||
].map((title) => title.toLowerCase()),
|
||||
);
|
||||
|
||||
export const SHOWCASE_TABS: Array<{ id: ShowcaseTabId; label: string }> = [
|
||||
{ id: 'all', label: '全部' },
|
||||
{ id: 'characters', label: '角色' },
|
||||
@@ -89,6 +121,22 @@ function normalizeText(value: unknown) {
|
||||
return typeof value === 'string' && value.trim() ? value.trim() : '';
|
||||
}
|
||||
|
||||
function normalizeGenerationInputTitle(value: string) {
|
||||
return value.trim().toLowerCase();
|
||||
}
|
||||
|
||||
function isBuiltInPromptText(value: string) {
|
||||
const trimmedValue = value.trim();
|
||||
return (
|
||||
trimmedValue.startsWith('【系统内置】') ||
|
||||
trimmedValue.startsWith('【宣发素材类型】') ||
|
||||
trimmedValue.startsWith('参考图1的图标素材规范') ||
|
||||
trimmedValue.startsWith('生成玩法UI原型图') ||
|
||||
trimmedValue.includes('仅提取被红色框框选的素材') ||
|
||||
trimmedValue.includes('图集背景必须使用所选单一纯色抠图背景')
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeNumber(value: unknown) {
|
||||
if (typeof value === 'number' && Number.isFinite(value)) {
|
||||
return value;
|
||||
@@ -597,18 +645,80 @@ function getGroupsForTab(assets: EditorAssetSnapshot[], tab: ShowcaseTabId) {
|
||||
return [];
|
||||
}
|
||||
|
||||
function resolveAssetPrompt(asset: EditorAssetSnapshot) {
|
||||
const directPrompt = asset.prompt?.trim() || asset.actualPrompt?.trim();
|
||||
if (directPrompt) {
|
||||
return directPrompt;
|
||||
function resolveUserGenerationPrompt(asset: EditorAssetSnapshot) {
|
||||
const fields = asset.generationInputs?.fields ?? [];
|
||||
const promptField = fields.find((field) => {
|
||||
const value = field.value.trim();
|
||||
return (
|
||||
value &&
|
||||
USER_PROMPT_INPUT_TITLES.has(
|
||||
normalizeGenerationInputTitle(field.title),
|
||||
) &&
|
||||
!isBuiltInPromptText(value)
|
||||
);
|
||||
});
|
||||
const promptValue = promptField?.value.trim();
|
||||
if (promptValue) {
|
||||
return promptValue;
|
||||
}
|
||||
|
||||
const generationFields = asset.generationInputs?.fields ?? [];
|
||||
const firstPromptField =
|
||||
generationFields.find((field) =>
|
||||
/提示词|描述|设定|prompt/u.test(field.title),
|
||||
) ?? generationFields[0];
|
||||
return firstPromptField?.value?.trim() || UNKNOWN_META_VALUE;
|
||||
const structuredLines = fields.flatMap((field) => {
|
||||
if (
|
||||
!STRUCTURED_USER_INPUT_TITLES.has(
|
||||
normalizeGenerationInputTitle(field.title),
|
||||
)
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
const value = field.value.trim();
|
||||
return value && !isBuiltInPromptText(value)
|
||||
? [`${field.title.trim()}:${value}`]
|
||||
: [];
|
||||
});
|
||||
return structuredLines.join('\n');
|
||||
}
|
||||
|
||||
function extractUserPromptFromAssembledPrompt(value: string) {
|
||||
const trimmedValue = value.trim();
|
||||
const sectionMatch =
|
||||
trimmedValue.match(/【用户输入】\s*([\s\S]*?)(?=\n+【|$)/u) ??
|
||||
trimmedValue.match(/【游戏输入】\s*([\s\S]*?)(?=\n+【|$)/u);
|
||||
const sectionValue = sectionMatch?.[1]?.trim();
|
||||
if (sectionValue && !isBuiltInPromptText(sectionValue)) {
|
||||
return sectionValue;
|
||||
}
|
||||
|
||||
const roleSettingMatch = trimmedValue.match(
|
||||
/(?:^|\n)角色设定[::]\s*([^\n]+)/u,
|
||||
);
|
||||
const roleSettingValue = roleSettingMatch?.[1]?.trim();
|
||||
return roleSettingValue && !isBuiltInPromptText(roleSettingValue)
|
||||
? roleSettingValue
|
||||
: '';
|
||||
}
|
||||
|
||||
function resolveAssetPrompt(asset: EditorAssetSnapshot) {
|
||||
const userPrompt = resolveUserGenerationPrompt(asset);
|
||||
if (userPrompt) {
|
||||
return userPrompt;
|
||||
}
|
||||
|
||||
for (const value of [asset.prompt, asset.actualPrompt]) {
|
||||
const directPrompt = value?.trim() ?? '';
|
||||
if (!directPrompt) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const extractedPrompt = extractUserPromptFromAssembledPrompt(directPrompt);
|
||||
if (extractedPrompt) {
|
||||
return extractedPrompt;
|
||||
}
|
||||
if (!isBuiltInPromptText(directPrompt)) {
|
||||
return directPrompt;
|
||||
}
|
||||
}
|
||||
|
||||
return UNKNOWN_META_VALUE;
|
||||
}
|
||||
|
||||
function resolveGroupPrompt(assets: EditorAssetSnapshot[]) {
|
||||
|
||||
Reference in New Issue
Block a user