cerevox 2.16.3 → 2.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/ai.d.ts +15 -1
- package/dist/core/ai.d.ts.map +1 -1
- package/dist/core/ai.js.map +1 -1
- package/dist/mcp/servers/prompts/character-prompt-optimizer.md +38 -0
- package/dist/mcp/servers/prompts/reasonings/image_aligner.md +186 -0
- package/dist/mcp/servers/prompts/zerocut-core.md +2 -0
- package/dist/mcp/servers/zerocut.d.ts.map +1 -1
- package/dist/mcp/servers/zerocut.js +300 -29
- package/dist/mcp/servers/zerocut.js.map +1 -1
- package/package.json +1 -1
- package/dist/mcp/servers/prompts/scisnap.tpl.md +0 -288
|
@@ -679,7 +679,7 @@ server.registerTool('generate-character-image', {
|
|
|
679
679
|
isTurnaround: zod_1.z
|
|
680
680
|
.boolean()
|
|
681
681
|
.default(true)
|
|
682
|
-
.describe('是否生成三视图。true: 生成
|
|
682
|
+
.describe('是否生成三视图。true: 生成4096x3072的三视图,false: 生成2304x4096的竖版人物正视图'),
|
|
683
683
|
saveToFileName: zod_1.z.string().describe('The filename to save.'),
|
|
684
684
|
},
|
|
685
685
|
}, async ({ name, gender, age, appearance, clothing, personality, style, saveToFileName, referenceImage, referenceImagePrompt, isTurnaround, }) => {
|
|
@@ -690,39 +690,58 @@ server.registerTool('generate-character-image', {
|
|
|
690
690
|
// 根据 isTurnaround 参数生成不同的提示词和尺寸
|
|
691
691
|
let prompt;
|
|
692
692
|
let size;
|
|
693
|
-
|
|
694
|
-
// 生成三视图
|
|
695
|
-
prompt = `
|
|
696
|
-
你是一个专业的角色设计师,请根据设定生成角色全身三视图,图片为白底,图中不带任何文字。设定为:
|
|
697
|
-
|
|
698
|
-
角色名称:${name}
|
|
693
|
+
let roleDescriptionPrompt = `角色名称:${name}
|
|
699
694
|
角色性别:${gender}
|
|
700
695
|
角色年龄:${age}
|
|
701
696
|
角色外观:${appearance}
|
|
702
697
|
角色服装:${clothing}
|
|
703
698
|
角色性格:${personality}
|
|
704
699
|
构图风格:${style}
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
700
|
+
`;
|
|
701
|
+
const ai = currentSession.ai;
|
|
702
|
+
try {
|
|
703
|
+
const promptOptimizer = await (0, promises_1.readFile)((0, node_path_1.resolve)(__dirname, './prompts/character-prompt-optimizer.md'), 'utf8');
|
|
704
|
+
const completion = await ai.getCompletions({
|
|
705
|
+
model: 'Doubao-Seed-1.6-flash',
|
|
706
|
+
messages: [
|
|
707
|
+
{
|
|
708
|
+
role: 'system',
|
|
709
|
+
content: promptOptimizer,
|
|
710
|
+
},
|
|
711
|
+
{
|
|
712
|
+
role: 'user',
|
|
713
|
+
content: roleDescriptionPrompt,
|
|
714
|
+
},
|
|
715
|
+
],
|
|
716
|
+
});
|
|
717
|
+
const optimizedPrompt = completion.choices[0]?.message?.content.trim();
|
|
718
|
+
if (optimizedPrompt) {
|
|
719
|
+
roleDescriptionPrompt = `${optimizedPrompt} 8K,超高细节,逼真质感。`;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
catch (error) {
|
|
723
|
+
console.warn('Failed to optimize character prompt');
|
|
724
|
+
}
|
|
725
|
+
if (referenceImage) {
|
|
726
|
+
roleDescriptionPrompt = `${referenceImagePrompt}${roleDescriptionPrompt}`;
|
|
727
|
+
}
|
|
728
|
+
if (isTurnaround) {
|
|
729
|
+
// 生成三视图
|
|
730
|
+
prompt = `
|
|
731
|
+
你是一个专业的角色设计师,请根据角色设定生成角色全身三视图,画面左1/3部分是人物侧视图,中间1/3部分是人物正视图,右侧1/3部分是人物背视图,三部分都必须包括人物全身(从头到脚),构图远近、大小均相同,平面排布无透视,外表、服饰、形象保持完全一致,确保是由三部相机分别**同时**从同一角色侧面、正面和背面进行拍摄的画面。除了这三个人物形象构图外,不再有任何其他元素。图片为白底,图中不带任何文字。
|
|
732
|
+
|
|
733
|
+
角色设定为:
|
|
734
|
+
${roleDescriptionPrompt}
|
|
735
|
+
`.trim();
|
|
736
|
+
size = '4096x3072';
|
|
709
737
|
}
|
|
710
738
|
else {
|
|
711
739
|
// 生成竖版人物正视图
|
|
712
740
|
prompt = `
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
角色年龄:${age}
|
|
718
|
-
角色外观:${appearance}
|
|
719
|
-
角色服装:${clothing}
|
|
720
|
-
角色性格:${personality}
|
|
721
|
-
构图风格:${style}
|
|
722
|
-
${referenceImagePrompt}
|
|
723
|
-
请生成一张完整的全身正视图,角色面向观众,展现完整的身体比例和服装细节。
|
|
724
|
-
`;
|
|
725
|
-
size = '720x1280';
|
|
741
|
+
你是一个专业的角色设计师,请根据角色设定生成完整的全身正视图,角色面向观众,展现完整的身体比例和服装细节。图片为白底,图中不带任何文字。设定为:
|
|
742
|
+
${roleDescriptionPrompt}
|
|
743
|
+
`.trim();
|
|
744
|
+
size = '2304x4096';
|
|
726
745
|
}
|
|
727
746
|
let imageBase64Array;
|
|
728
747
|
if (referenceImage) {
|
|
@@ -750,7 +769,6 @@ ${referenceImagePrompt}
|
|
|
750
769
|
return createErrorResponse(`Failed to load reference image ${referenceImage}: ${error}`, 'generate-image');
|
|
751
770
|
}
|
|
752
771
|
}
|
|
753
|
-
const ai = currentSession.ai;
|
|
754
772
|
const res = await ai.generateImage({
|
|
755
773
|
prompt,
|
|
756
774
|
size,
|
|
@@ -882,8 +900,26 @@ server.registerTool('generate-image', {
|
|
|
882
900
|
'832x1248',
|
|
883
901
|
'1248x832',
|
|
884
902
|
'1512x648',
|
|
903
|
+
// 2K
|
|
904
|
+
'2048x2048',
|
|
905
|
+
'1728x2304',
|
|
906
|
+
'2304x1728',
|
|
907
|
+
'2560x1440',
|
|
908
|
+
'1440x2560',
|
|
909
|
+
'1664x2496',
|
|
910
|
+
'2496x1664',
|
|
911
|
+
'3024x1456',
|
|
912
|
+
// 4K
|
|
913
|
+
'4096x4096',
|
|
914
|
+
'3072x4096',
|
|
915
|
+
'4096x3072',
|
|
916
|
+
'4096x2304',
|
|
917
|
+
'2304x4096',
|
|
918
|
+
'2731x4096',
|
|
919
|
+
'4096x2731',
|
|
920
|
+
'4096x1968',
|
|
885
921
|
])
|
|
886
|
-
.
|
|
922
|
+
.default('720x1280')
|
|
887
923
|
.describe('The size of the image.'),
|
|
888
924
|
saveToFileName: zod_1.z.string().describe('The filename to save.'),
|
|
889
925
|
watermark: zod_1.z
|
|
@@ -920,7 +956,7 @@ server.registerTool('generate-image', {
|
|
|
920
956
|
\`\`\`
|
|
921
957
|
`),
|
|
922
958
|
},
|
|
923
|
-
}, async ({ prompt, sceneIndex, storyBoardFile = 'story_board.json', skipConsistencyCheck = false, size, saveToFileName, watermark, referenceImages, optimizePrompt, }) => {
|
|
959
|
+
}, async ({ prompt, sceneIndex, storyBoardFile = 'story_board.json', skipConsistencyCheck = false, size = '720x1280', saveToFileName, watermark, referenceImages, optimizePrompt, }) => {
|
|
924
960
|
try {
|
|
925
961
|
// 验证session状态
|
|
926
962
|
const currentSession = await validateSession('generate-image');
|
|
@@ -946,6 +982,49 @@ server.registerTool('generate-image', {
|
|
|
946
982
|
if (prompt !== startFrame && prompt !== endFrame) {
|
|
947
983
|
return createErrorResponse('图片提示词必须严格遵照story_board的设定,如果用户明确指出不需要遵守,请将skipConsistencyCheck设置为true后再次调用', 'generate-image');
|
|
948
984
|
}
|
|
985
|
+
// 校验 size 参数与 story_board 的 orientation 属性一致性
|
|
986
|
+
if (size && storyBoard.orientation) {
|
|
987
|
+
const isLandscapeSize = [
|
|
988
|
+
'1152x864',
|
|
989
|
+
'1280x720',
|
|
990
|
+
'1248x832',
|
|
991
|
+
'1512x648',
|
|
992
|
+
'2304x1728',
|
|
993
|
+
'2560x1440',
|
|
994
|
+
'2496x1664',
|
|
995
|
+
'3024x1456',
|
|
996
|
+
'4096x3072',
|
|
997
|
+
'4096x2304',
|
|
998
|
+
'4096x2731',
|
|
999
|
+
'4096x1968',
|
|
1000
|
+
].includes(size);
|
|
1001
|
+
const isPortraitSize = [
|
|
1002
|
+
'864x1152',
|
|
1003
|
+
'720x1280',
|
|
1004
|
+
'832x1248',
|
|
1005
|
+
'1728x2304',
|
|
1006
|
+
'1440x2560',
|
|
1007
|
+
'1664x2496',
|
|
1008
|
+
'3072x4096',
|
|
1009
|
+
'2304x4096',
|
|
1010
|
+
'2731x4096',
|
|
1011
|
+
].includes(size);
|
|
1012
|
+
const isSquareSize = [
|
|
1013
|
+
'1024x1024',
|
|
1014
|
+
'2048x2048',
|
|
1015
|
+
'4096x4096',
|
|
1016
|
+
].includes(size);
|
|
1017
|
+
if (storyBoard.orientation === 'landscape' &&
|
|
1018
|
+
!isLandscapeSize &&
|
|
1019
|
+
!isSquareSize) {
|
|
1020
|
+
return createErrorResponse(`故事板设定为横屏模式(orientation: landscape),但生图尺寸 ${size} 为竖屏格式,请使用横屏尺寸如 1280x720、2560x1440、4096x2304 等`, 'generate-image');
|
|
1021
|
+
}
|
|
1022
|
+
if (storyBoard.orientation === 'portrait' &&
|
|
1023
|
+
!isPortraitSize &&
|
|
1024
|
+
!isSquareSize) {
|
|
1025
|
+
return createErrorResponse(`故事板设定为竖屏模式(orientation: portrait),但生图尺寸 ${size} 为横屏格式,请使用竖屏尺寸如 720x1280、1440x2560、2304x4096 等`, 'generate-image');
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
949
1028
|
}
|
|
950
1029
|
else {
|
|
951
1030
|
console.warn(`Scene index ${sceneIndex} not found in story_board.json`);
|
|
@@ -1146,9 +1225,27 @@ server.registerTool('generate-image-series', {
|
|
|
1146
1225
|
'832x1248',
|
|
1147
1226
|
'1248x832',
|
|
1148
1227
|
'1512x648',
|
|
1228
|
+
// 2K
|
|
1229
|
+
'2048x2048',
|
|
1230
|
+
'1728x2304',
|
|
1231
|
+
'2304x1728',
|
|
1232
|
+
'2560x1440',
|
|
1233
|
+
'1440x2560',
|
|
1234
|
+
'1664x2496',
|
|
1235
|
+
'2496x1664',
|
|
1236
|
+
'3024x1456',
|
|
1237
|
+
// 4K
|
|
1238
|
+
'4096x4096',
|
|
1239
|
+
'3072x4096',
|
|
1240
|
+
'4096x3072',
|
|
1241
|
+
'4096x2304',
|
|
1242
|
+
'2304x4096',
|
|
1243
|
+
'2731x4096',
|
|
1244
|
+
'4096x2731',
|
|
1245
|
+
'4096x1968',
|
|
1149
1246
|
])
|
|
1150
|
-
.
|
|
1151
|
-
.describe('The size of the
|
|
1247
|
+
.default('720x1280')
|
|
1248
|
+
.describe('The size of the image.'),
|
|
1152
1249
|
watermark: zod_1.z
|
|
1153
1250
|
.boolean()
|
|
1154
1251
|
.optional()
|
|
@@ -2840,6 +2937,180 @@ server.registerTool('search-voices', {
|
|
|
2840
2937
|
return createErrorResponse(error, 'search-voices');
|
|
2841
2938
|
}
|
|
2842
2939
|
});
|
|
2940
|
+
server.registerTool('image-aligner', {
|
|
2941
|
+
title: 'Image Aligner',
|
|
2942
|
+
description: 'Analyze image quality and alignment with prompt using AI Image Quality Inspector.',
|
|
2943
|
+
inputSchema: {
|
|
2944
|
+
imageFileName: zod_1.z
|
|
2945
|
+
.string()
|
|
2946
|
+
.describe('The image file name in materials directory to analyze.'),
|
|
2947
|
+
sceneIndex: zod_1.z.number().min(1).describe('场景索引,从1开始的下标'),
|
|
2948
|
+
storyBoardFile: zod_1.z
|
|
2949
|
+
.string()
|
|
2950
|
+
.optional()
|
|
2951
|
+
.default('story_board.json')
|
|
2952
|
+
.describe('故事板文件路径'),
|
|
2953
|
+
imagePrompt: zod_1.z
|
|
2954
|
+
.string()
|
|
2955
|
+
.optional()
|
|
2956
|
+
.describe('可选的图片提示词,如果提供则覆盖story_board中的提示词'),
|
|
2957
|
+
customPrompt: zod_1.z
|
|
2958
|
+
.string()
|
|
2959
|
+
.optional()
|
|
2960
|
+
.describe('可选的额外用户要求,用于补充图片质量评估的特定需求'),
|
|
2961
|
+
},
|
|
2962
|
+
}, async ({ imageFileName, sceneIndex, storyBoardFile = 'story_board.json', imagePrompt, customPrompt, }) => {
|
|
2963
|
+
try {
|
|
2964
|
+
const currentSession = await validateSession('image-aligner');
|
|
2965
|
+
// 验证图片文件
|
|
2966
|
+
validateImageFile(imageFileName);
|
|
2967
|
+
// 获取图片 URL
|
|
2968
|
+
const imageUrl = getMaterialUri(currentSession, imageFileName);
|
|
2969
|
+
// 确定要使用的提示词
|
|
2970
|
+
let finalPrompt = imagePrompt;
|
|
2971
|
+
// 如果没有提供imagePrompt,则从story_board中获取
|
|
2972
|
+
if (!imagePrompt) {
|
|
2973
|
+
try {
|
|
2974
|
+
const storyBoardPath = (0, node_path_1.resolve)(process.env.ZEROCUT_PROJECT_CWD || process.cwd(), projectLocalDir, storyBoardFile);
|
|
2975
|
+
if ((0, node_fs_1.existsSync)(storyBoardPath)) {
|
|
2976
|
+
const storyBoardContent = await (0, promises_1.readFile)(storyBoardPath, 'utf8');
|
|
2977
|
+
const storyBoard = JSON.parse(storyBoardContent);
|
|
2978
|
+
if (storyBoard.scenes && Array.isArray(storyBoard.scenes)) {
|
|
2979
|
+
const scene = storyBoard.scenes[sceneIndex - 1]; // sceneIndex 从1开始,数组从0开始
|
|
2980
|
+
if (scene) {
|
|
2981
|
+
// 根据文件名判断优先级:若end_frame存在且imageFileName包含"_end"则优先取end_frame,否则取start_frame
|
|
2982
|
+
if (scene.end_frame && imageFileName.includes('_end')) {
|
|
2983
|
+
finalPrompt = scene.end_frame;
|
|
2984
|
+
}
|
|
2985
|
+
else {
|
|
2986
|
+
finalPrompt = scene.start_frame || scene.end_frame;
|
|
2987
|
+
}
|
|
2988
|
+
if (!finalPrompt) {
|
|
2989
|
+
return createErrorResponse(`场景 ${sceneIndex} 中未找到 start_frame 或 end_frame 提示词`, 'image-aligner');
|
|
2990
|
+
}
|
|
2991
|
+
}
|
|
2992
|
+
else {
|
|
2993
|
+
return createErrorResponse(`在 ${storyBoardFile} 中未找到场景索引 ${sceneIndex}`, 'image-aligner');
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
else {
|
|
2997
|
+
return createErrorResponse(`${storyBoardFile} 文件格式不正确,缺少 scenes 数组`, 'image-aligner');
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
else {
|
|
3001
|
+
return createErrorResponse(`故事板文件不存在: ${storyBoardPath}`, 'image-aligner');
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
3004
|
+
catch (error) {
|
|
3005
|
+
return createErrorResponse(`读取或解析故事板文件失败: ${error}`, 'image-aligner');
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
// 如果仍然没有提示词,返回错误
|
|
3009
|
+
if (!finalPrompt) {
|
|
3010
|
+
return createErrorResponse('未提供 imagePrompt 且无法从故事板中获取提示词', 'image-aligner');
|
|
3011
|
+
}
|
|
3012
|
+
// 读取图片质量检查指南
|
|
3013
|
+
const alignerGuidelinePath = (0, node_path_1.resolve)(__dirname, './prompts/reasonings/image_aligner.md');
|
|
3014
|
+
let alignerGuideline = '';
|
|
3015
|
+
try {
|
|
3016
|
+
alignerGuideline = await (0, promises_1.readFile)(alignerGuidelinePath, 'utf8');
|
|
3017
|
+
}
|
|
3018
|
+
catch (error) {
|
|
3019
|
+
console.warn('无法读取图片质量检查指南:', error);
|
|
3020
|
+
alignerGuideline =
|
|
3021
|
+
'请对图片质量进行评估,包括构图、色彩、清晰度等方面。';
|
|
3022
|
+
}
|
|
3023
|
+
// 构建系统提示
|
|
3024
|
+
const systemPrompt = `你是一个专业的AI图片质量检查员。请根据以下指南对图片进行评估:
|
|
3025
|
+
|
|
3026
|
+
${alignerGuideline}
|
|
3027
|
+
|
|
3028
|
+
请严格按照指南中的JSON格式返回评估结果。`;
|
|
3029
|
+
// 构建用户提示
|
|
3030
|
+
const userPrompt = `请对这张图片进行质量评估。
|
|
3031
|
+
|
|
3032
|
+
原始提示词:${finalPrompt}${customPrompt
|
|
3033
|
+
? `
|
|
3034
|
+
|
|
3035
|
+
额外要求:${customPrompt}`
|
|
3036
|
+
: ''}
|
|
3037
|
+
|
|
3038
|
+
请按照指南要求,返回包含评分、问题列表和优化建议的JSON格式结果。`;
|
|
3039
|
+
// 调用AI模型进行图片质量评估
|
|
3040
|
+
const ai = currentSession.ai;
|
|
3041
|
+
const completion = await ai.getCompletions({
|
|
3042
|
+
model: 'Doubao-Seed-1.6',
|
|
3043
|
+
messages: [
|
|
3044
|
+
{
|
|
3045
|
+
role: 'system',
|
|
3046
|
+
content: systemPrompt,
|
|
3047
|
+
},
|
|
3048
|
+
{
|
|
3049
|
+
role: 'user',
|
|
3050
|
+
content: [
|
|
3051
|
+
{
|
|
3052
|
+
type: 'image_url',
|
|
3053
|
+
image_url: {
|
|
3054
|
+
url: imageUrl,
|
|
3055
|
+
},
|
|
3056
|
+
},
|
|
3057
|
+
{
|
|
3058
|
+
type: 'text',
|
|
3059
|
+
text: userPrompt,
|
|
3060
|
+
},
|
|
3061
|
+
],
|
|
3062
|
+
},
|
|
3063
|
+
],
|
|
3064
|
+
});
|
|
3065
|
+
const result = completion.choices[0]?.message?.content;
|
|
3066
|
+
if (!result) {
|
|
3067
|
+
throw new Error('No response from AI model');
|
|
3068
|
+
}
|
|
3069
|
+
// 解析AI响应
|
|
3070
|
+
let alignmentResult;
|
|
3071
|
+
try {
|
|
3072
|
+
// 尝试从响应中提取JSON
|
|
3073
|
+
const jsonMatch = result.match(/```json\s*([\s\S]*?)\s*```/) ||
|
|
3074
|
+
result.match(/\{[\s\S]*\}/);
|
|
3075
|
+
if (jsonMatch) {
|
|
3076
|
+
alignmentResult = JSON.parse(jsonMatch[1] || jsonMatch[0]);
|
|
3077
|
+
}
|
|
3078
|
+
else {
|
|
3079
|
+
// 如果没有找到JSON格式,尝试直接解析整个响应
|
|
3080
|
+
alignmentResult = JSON.parse(result);
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
catch (error) {
|
|
3084
|
+
// 如果解析失败,返回原始响应
|
|
3085
|
+
alignmentResult = {
|
|
3086
|
+
error: 'JSON解析失败',
|
|
3087
|
+
raw_response: result,
|
|
3088
|
+
};
|
|
3089
|
+
}
|
|
3090
|
+
return {
|
|
3091
|
+
content: [
|
|
3092
|
+
{
|
|
3093
|
+
type: 'text',
|
|
3094
|
+
text: JSON.stringify({
|
|
3095
|
+
success: true,
|
|
3096
|
+
imageFileName,
|
|
3097
|
+
sceneIndex,
|
|
3098
|
+
storyBoardFile,
|
|
3099
|
+
imagePrompt: finalPrompt,
|
|
3100
|
+
customPrompt,
|
|
3101
|
+
promptSource: imagePrompt ? 'manual_override' : 'story_board',
|
|
3102
|
+
analysis: alignmentResult,
|
|
3103
|
+
imageUrl,
|
|
3104
|
+
nextActionSuggest: '可根据分析结果调整提示词,修改story_board后,重新生成图片。',
|
|
3105
|
+
}),
|
|
3106
|
+
},
|
|
3107
|
+
],
|
|
3108
|
+
};
|
|
3109
|
+
}
|
|
3110
|
+
catch (error) {
|
|
3111
|
+
return createErrorResponse(error, 'image-aligner');
|
|
3112
|
+
}
|
|
3113
|
+
});
|
|
2843
3114
|
server.registerTool('lip-sync', {
|
|
2844
3115
|
title: 'Lip Sync',
|
|
2845
3116
|
description: 'Generate lip-synced video by matching video with audio.',
|