cerevox 2.7.1 → 2.8.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 +9 -0
- package/dist/core/ai.d.ts.map +1 -1
- package/dist/core/ai.js +73 -0
- package/dist/core/ai.js.map +1 -1
- package/dist/mcp/servers/prompts/rules/anime-series.md +2 -2
- package/dist/mcp/servers/prompts/rules/creative-ad.md +111 -0
- package/dist/mcp/servers/prompts/rules/general-video.md +2 -2
- package/dist/mcp/servers/prompts/rules/music-video.md +1 -1
- package/dist/mcp/servers/prompts/rules/stage-play.md +1 -1
- package/dist/mcp/servers/prompts/rules/story-telling.md +69 -0
- package/dist/mcp/servers/prompts/zerocut-core.md +11 -8
- package/dist/mcp/servers/zerocut.d.ts.map +1 -1
- package/dist/mcp/servers/zerocut.js +308 -39
- package/dist/mcp/servers/zerocut.js.map +1 -1
- package/dist/utils/storyboard-schema.json +7 -3
- package/package.json +1 -1
- package/dist/mcp/servers/prompts/zerocut-guideline.md +0 -403
- package/dist/mcp/servers/prompts/zerodancer-guideline.md +0 -302
- package/dist/mcp/servers/prompts/zerosinger-guideline.md +0 -187
|
@@ -170,35 +170,41 @@ async function sendProgress(context, progress, total, message) {
|
|
|
170
170
|
params: { progressToken: token, progress, total, message },
|
|
171
171
|
});
|
|
172
172
|
}
|
|
173
|
-
async function
|
|
173
|
+
async function updateMediaLogs(session, fileName, result, mediaType = 'video') {
|
|
174
174
|
try {
|
|
175
|
-
const
|
|
176
|
-
let
|
|
175
|
+
const mediaLogsPath = node_path_1.default.resolve(projectLocalDir, 'media_logs.json');
|
|
176
|
+
let mediaLogs = [];
|
|
177
177
|
// 尝试读取现有文件
|
|
178
178
|
try {
|
|
179
|
-
const existingContent = await (0, promises_1.readFile)(
|
|
180
|
-
|
|
179
|
+
const existingContent = await (0, promises_1.readFile)(mediaLogsPath, 'utf-8');
|
|
180
|
+
mediaLogs = JSON.parse(existingContent);
|
|
181
181
|
}
|
|
182
182
|
catch (error) {
|
|
183
183
|
// 文件不存在或格式错误,使用空数组
|
|
184
|
-
|
|
184
|
+
mediaLogs = [];
|
|
185
185
|
}
|
|
186
186
|
// 检查是否已存在相同文件名的记录
|
|
187
|
-
const existingIndex =
|
|
187
|
+
const existingIndex = mediaLogs.findIndex(item => item.fileName === fileName);
|
|
188
|
+
const logEntry = {
|
|
189
|
+
fileName,
|
|
190
|
+
mediaType,
|
|
191
|
+
timestamp: new Date().toISOString(),
|
|
192
|
+
result,
|
|
193
|
+
};
|
|
188
194
|
if (existingIndex >= 0) {
|
|
189
195
|
// 更新现有记录
|
|
190
|
-
|
|
196
|
+
mediaLogs[existingIndex] = logEntry;
|
|
191
197
|
}
|
|
192
198
|
else {
|
|
193
199
|
// 添加新记录
|
|
194
|
-
|
|
200
|
+
mediaLogs.push(logEntry);
|
|
195
201
|
}
|
|
196
202
|
// 写入文件
|
|
197
|
-
await (0, promises_1.writeFile)(
|
|
198
|
-
console.log(`Updated
|
|
203
|
+
await (0, promises_1.writeFile)(mediaLogsPath, JSON.stringify(mediaLogs, null, 2));
|
|
204
|
+
console.log(`Updated media_logs.json: ${fileName} -> ${JSON.stringify(result)} (${mediaType})`);
|
|
199
205
|
}
|
|
200
206
|
catch (error) {
|
|
201
|
-
console.warn(`Failed to update
|
|
207
|
+
console.warn(`Failed to update media_logs.json for ${fileName}:`, error);
|
|
202
208
|
}
|
|
203
209
|
}
|
|
204
210
|
async function listFiles(dir) {
|
|
@@ -266,6 +272,8 @@ server.registerTool('retrieve-rules-context', {
|
|
|
266
272
|
'music-video',
|
|
267
273
|
'stage-play',
|
|
268
274
|
'anime-series',
|
|
275
|
+
'story-telling',
|
|
276
|
+
'creative-ad',
|
|
269
277
|
'custom',
|
|
270
278
|
])
|
|
271
279
|
.default('general-video')
|
|
@@ -285,7 +293,9 @@ server.registerTool('retrieve-rules-context', {
|
|
|
285
293
|
else if (purpose !== 'general-video' &&
|
|
286
294
|
purpose !== 'music-video' &&
|
|
287
295
|
purpose !== 'stage-play' &&
|
|
288
|
-
purpose !== 'anime-series'
|
|
296
|
+
purpose !== 'anime-series' &&
|
|
297
|
+
purpose !== 'story-telling' &&
|
|
298
|
+
purpose !== 'creative-ad') {
|
|
289
299
|
return createErrorResponse(`Project rules file not found: ${projectRulesFile}`, 'retrieve-rules-context');
|
|
290
300
|
}
|
|
291
301
|
try {
|
|
@@ -554,8 +564,8 @@ server.registerTool('search-image', {
|
|
|
554
564
|
}
|
|
555
565
|
});
|
|
556
566
|
server.registerTool('generate-character-image', {
|
|
557
|
-
title: 'Generate
|
|
558
|
-
description: 'Generate a turnaround image for any character.',
|
|
567
|
+
title: 'Generate Character Image',
|
|
568
|
+
description: 'Generate a turnaround image or portrait for any character.',
|
|
559
569
|
inputSchema: {
|
|
560
570
|
name: zod_1.z.string().describe('The name of the character.'),
|
|
561
571
|
gender: zod_1.z
|
|
@@ -576,14 +586,23 @@ server.registerTool('generate-character-image', {
|
|
|
576
586
|
.string()
|
|
577
587
|
.default('形象参考[图1]的人物形象\n')
|
|
578
588
|
.describe('形象参考图的提示文本.'),
|
|
589
|
+
isTurnaround: zod_1.z
|
|
590
|
+
.boolean()
|
|
591
|
+
.default(true)
|
|
592
|
+
.describe('是否生成三视图。true: 生成1280x720的三视图,false: 生成720x1280的竖版人物正视图'),
|
|
579
593
|
saveToFileName: zod_1.z.string().describe('The filename to save.'),
|
|
580
594
|
},
|
|
581
|
-
}, async ({ name, gender, age, appearance, clothing, personality, style, saveToFileName, referenceImage, referenceImagePrompt, }) => {
|
|
595
|
+
}, async ({ name, gender, age, appearance, clothing, personality, style, saveToFileName, referenceImage, referenceImagePrompt, isTurnaround, }) => {
|
|
582
596
|
try {
|
|
583
597
|
// 验证session状态
|
|
584
598
|
const currentSession = await validateSession('generate-character-image');
|
|
585
599
|
const validatedFileName = validateFileName(saveToFileName);
|
|
586
|
-
|
|
600
|
+
// 根据 isTurnaround 参数生成不同的提示词和尺寸
|
|
601
|
+
let prompt;
|
|
602
|
+
let size;
|
|
603
|
+
if (isTurnaround) {
|
|
604
|
+
// 生成三视图
|
|
605
|
+
prompt = `
|
|
587
606
|
你是一个专业的角色设计师,请根据设定生成角色全身三视图,图片为白底,图中不带任何文字。设定为:
|
|
588
607
|
|
|
589
608
|
角色名称:${name}
|
|
@@ -595,7 +614,26 @@ server.registerTool('generate-character-image', {
|
|
|
595
614
|
构图风格:${style}
|
|
596
615
|
${referenceImagePrompt}
|
|
597
616
|
三视图分别是指侧视图、正视图和背视图,从左到右按照这个顺序生成,三者都必须是全身图。
|
|
598
|
-
|
|
617
|
+
`;
|
|
618
|
+
size = '1280x720';
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
// 生成竖版人物正视图
|
|
622
|
+
prompt = `
|
|
623
|
+
你是一个专业的角色设计师,请根据设定生成角色全身正视图,图片为白底,图中不带任何文字。设定为:
|
|
624
|
+
|
|
625
|
+
角色名称:${name}
|
|
626
|
+
角色性别:${gender}
|
|
627
|
+
角色年龄:${age}
|
|
628
|
+
角色外观:${appearance}
|
|
629
|
+
角色服装:${clothing}
|
|
630
|
+
角色性格:${personality}
|
|
631
|
+
构图风格:${style}
|
|
632
|
+
${referenceImagePrompt}
|
|
633
|
+
请生成一张完整的全身正视图,角色面向观众,展现完整的身体比例和服装细节。
|
|
634
|
+
`;
|
|
635
|
+
size = '720x1280';
|
|
636
|
+
}
|
|
599
637
|
let imageBase64Array;
|
|
600
638
|
if (referenceImage) {
|
|
601
639
|
try {
|
|
@@ -623,7 +661,6 @@ ${referenceImagePrompt}
|
|
|
623
661
|
}
|
|
624
662
|
}
|
|
625
663
|
const ai = currentSession.ai;
|
|
626
|
-
const size = '1280x720';
|
|
627
664
|
const res = await ai.generateImage({
|
|
628
665
|
prompt,
|
|
629
666
|
size,
|
|
@@ -640,6 +677,7 @@ ${referenceImagePrompt}
|
|
|
640
677
|
// source: res.url,
|
|
641
678
|
uri,
|
|
642
679
|
prompt,
|
|
680
|
+
isTurnaround,
|
|
643
681
|
size,
|
|
644
682
|
timestamp: new Date().toISOString(),
|
|
645
683
|
};
|
|
@@ -763,7 +801,7 @@ server.registerTool('generate-image', {
|
|
|
763
801
|
.describe('Whether this is a turnaround image.如果是三视图,这个参数务必传true'),
|
|
764
802
|
}))
|
|
765
803
|
.optional()
|
|
766
|
-
.describe(`Array of reference images with character or object names.如果stage_atmosphere中有角色
|
|
804
|
+
.describe(`Array of reference images with character or object names.如果stage_atmosphere中有角色apply_reference_image,那么必须要传这个参数生成角色图片
|
|
767
805
|
|
|
768
806
|
传参示例
|
|
769
807
|
\`\`\`
|
|
@@ -867,7 +905,7 @@ server.registerTool('generate-image', {
|
|
|
867
905
|
}
|
|
868
906
|
}
|
|
869
907
|
const turnaroundMessage = hasTurnaround
|
|
870
|
-
? '⚠️ 注意**三视图**是指**同一个**人或物体的不同视角合成图,三部分都表示同一个人或物体,只能参考其信息画出**一个人或一个物体**,不要画成多个人或多个物体!\n
|
|
908
|
+
? '⚠️ 注意**三视图**是指**同一个**人或物体的不同视角合成图,三部分都表示同一个人或物体,只能参考其信息画出**一个人或一个物体**,不要画成多个人或多个物体!\n'
|
|
871
909
|
: '';
|
|
872
910
|
if (objectPrefix.length > 0) {
|
|
873
911
|
processedPrompt = `${objectPrefix.join('\n')}
|
|
@@ -927,6 +965,231 @@ ${processedPrompt}`.trim();
|
|
|
927
965
|
return createErrorResponse(error, 'generate-image');
|
|
928
966
|
}
|
|
929
967
|
});
|
|
968
|
+
server.registerTool('generate-image-series', {
|
|
969
|
+
title: 'Generate Image Series',
|
|
970
|
+
description: 'Generate a series of images based on prompts.',
|
|
971
|
+
inputSchema: {
|
|
972
|
+
prompts: zod_1.z
|
|
973
|
+
.union([zod_1.z.string(), zod_1.z.array(zod_1.z.string())])
|
|
974
|
+
.describe('The prompts to generate images. Can be a single string or array of strings.'),
|
|
975
|
+
size: zod_1.z
|
|
976
|
+
.enum([
|
|
977
|
+
'1024x1024',
|
|
978
|
+
'864x1152',
|
|
979
|
+
'1152x864',
|
|
980
|
+
'1280x720',
|
|
981
|
+
'720x1280',
|
|
982
|
+
'832x1248',
|
|
983
|
+
'1248x832',
|
|
984
|
+
'1512x648',
|
|
985
|
+
])
|
|
986
|
+
.optional()
|
|
987
|
+
.describe('The size of the images.'),
|
|
988
|
+
watermark: zod_1.z
|
|
989
|
+
.boolean()
|
|
990
|
+
.optional()
|
|
991
|
+
.default(false)
|
|
992
|
+
.describe('Whether to add watermark to the images.'),
|
|
993
|
+
max_count: zod_1.z
|
|
994
|
+
.number()
|
|
995
|
+
.min(1)
|
|
996
|
+
.max(15)
|
|
997
|
+
.optional()
|
|
998
|
+
.default(15)
|
|
999
|
+
.describe('Maximum number of images to generate (1-15).'),
|
|
1000
|
+
referenceImages: zod_1.z
|
|
1001
|
+
.array(zod_1.z.object({
|
|
1002
|
+
image: zod_1.z.string().describe('Local image file path'),
|
|
1003
|
+
type: zod_1.z
|
|
1004
|
+
.enum(['character', 'object', 'background'])
|
|
1005
|
+
.describe('Type of the reference image. 必须传,如果是参考角色三视图,传character,如果是参考背景图,传background,否则传object'),
|
|
1006
|
+
name: zod_1.z.string().describe('Name for this reference image'),
|
|
1007
|
+
isTurnaround: zod_1.z
|
|
1008
|
+
.boolean()
|
|
1009
|
+
.describe('Whether this is a turnaround image.如果是三视图,这个参数务必传true'),
|
|
1010
|
+
}))
|
|
1011
|
+
.optional()
|
|
1012
|
+
.describe(`Array of reference images with character or object names.如果stage_atmosphere中有角色apply_reference_image,那么必须要传这个参数生成角色图片
|
|
1013
|
+
|
|
1014
|
+
传参示例
|
|
1015
|
+
\`\`\`
|
|
1016
|
+
{
|
|
1017
|
+
"image": "latiao.jpeg",
|
|
1018
|
+
"type": "object",
|
|
1019
|
+
"name": "卫龙辣条",
|
|
1020
|
+
}
|
|
1021
|
+
\`\`\`
|
|
1022
|
+
`),
|
|
1023
|
+
saveToFileNames: zod_1.z
|
|
1024
|
+
.array(zod_1.z.string())
|
|
1025
|
+
.describe('Array of filenames to save the generated images.'),
|
|
1026
|
+
},
|
|
1027
|
+
}, async ({ prompts, size, watermark, max_count, referenceImages, saveToFileNames }, context) => {
|
|
1028
|
+
try {
|
|
1029
|
+
const currentSession = await validateSession('generate-image-series');
|
|
1030
|
+
// Validate file names
|
|
1031
|
+
const validatedFileNames = saveToFileNames.map(fileName => validateFileName(fileName));
|
|
1032
|
+
if (typeof prompts === 'string' && prompts.startsWith('[')) {
|
|
1033
|
+
try {
|
|
1034
|
+
prompts = JSON.parse(prompts);
|
|
1035
|
+
}
|
|
1036
|
+
catch (ex) {
|
|
1037
|
+
// 解析失败,保持原始字符串
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
console.log(`Generating image series with ${Array.isArray(prompts) ? prompts.length : 1} prompts...`);
|
|
1041
|
+
// 处理参考图片
|
|
1042
|
+
let imageBase64Array;
|
|
1043
|
+
let refPrefix = '';
|
|
1044
|
+
if (referenceImages && referenceImages.length > 0) {
|
|
1045
|
+
imageBase64Array = [];
|
|
1046
|
+
const objectPrefix = [];
|
|
1047
|
+
let index = 0;
|
|
1048
|
+
let hasTurnaround = false;
|
|
1049
|
+
for (const refImage of referenceImages) {
|
|
1050
|
+
const imagePath = (0, node_path_1.dirname)(refImage.image) !== '.'
|
|
1051
|
+
? refImage.image
|
|
1052
|
+
: `./materials/${refImage.image}`;
|
|
1053
|
+
// 需要得到当前项目的绝对路径
|
|
1054
|
+
const imageFilePath = (0, node_path_1.resolve)(process.env.ZEROCUT_PROJECT_CWD || process.cwd(), projectLocalDir, imagePath);
|
|
1055
|
+
try {
|
|
1056
|
+
// 直接读取本地文件
|
|
1057
|
+
if (!(0, node_fs_1.existsSync)(imageFilePath)) {
|
|
1058
|
+
return createErrorResponse(`Reference image not found: ${imageFilePath}`, 'generate-image-series');
|
|
1059
|
+
}
|
|
1060
|
+
const imageBuffer = await (0, promises_1.readFile)(imageFilePath);
|
|
1061
|
+
const fileName = (0, node_path_1.basename)(imagePath);
|
|
1062
|
+
const mimeType = fileName.toLowerCase().endsWith('.png')
|
|
1063
|
+
? 'image/png'
|
|
1064
|
+
: fileName.toLowerCase().endsWith('.jpg') ||
|
|
1065
|
+
fileName.toLowerCase().endsWith('.jpeg')
|
|
1066
|
+
? 'image/jpeg'
|
|
1067
|
+
: 'image/png';
|
|
1068
|
+
const base64String = `data:${mimeType};base64,${imageBuffer.toString('base64')}`;
|
|
1069
|
+
imageBase64Array.push(base64String);
|
|
1070
|
+
console.log(`Loaded reference image: ${imagePath} for character: ${refImage.name}`);
|
|
1071
|
+
if (refImage.type === 'character') {
|
|
1072
|
+
if (refImage.isTurnaround) {
|
|
1073
|
+
objectPrefix.push(`[参考图${++index}]是名为"${refImage.name}"的人物角色三视图`);
|
|
1074
|
+
hasTurnaround = true;
|
|
1075
|
+
}
|
|
1076
|
+
else {
|
|
1077
|
+
objectPrefix.push(`[参考图${++index}]是名为"${refImage.name}"的人物角色形象`);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
else if (refImage.type === 'object') {
|
|
1081
|
+
if (refImage.isTurnaround) {
|
|
1082
|
+
objectPrefix.push(`[参考图${++index}]是名为"${refImage.name}"的物件三视图`);
|
|
1083
|
+
hasTurnaround = true;
|
|
1084
|
+
}
|
|
1085
|
+
else {
|
|
1086
|
+
objectPrefix.push(`[参考图${++index}]是名为"${refImage.name}"的物件`);
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
else if (refImage.type === 'background') {
|
|
1090
|
+
objectPrefix.push(`[参考图${++index}]是背景图,描述了"${refImage.name}"`);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
catch (error) {
|
|
1094
|
+
console.error(`Failed to load reference image ${imageFilePath} for ${refImage.name}:`, error);
|
|
1095
|
+
return createErrorResponse(`Failed to load reference image ${imageFilePath} for ${refImage.name}: ${error}`, 'generate-image-series');
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
const turnaroundMessage = hasTurnaround
|
|
1099
|
+
? '\n\n⚠️ 注意**三视图**是指**同一个**人或物体的不同视角合成图,三部分都表示同一个人或物体,只能参考其信息画出**一个人或一个物体**,不要画成多个人或多个物体!\n'
|
|
1100
|
+
: '';
|
|
1101
|
+
if (objectPrefix.length > 0) {
|
|
1102
|
+
refPrefix = `${objectPrefix.join('\n')}${turnaroundMessage}`;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
const ai = currentSession.ai;
|
|
1106
|
+
let progress = 0;
|
|
1107
|
+
const res = await ai.generateImageSeries({
|
|
1108
|
+
prompts,
|
|
1109
|
+
refPrefix,
|
|
1110
|
+
size,
|
|
1111
|
+
watermark,
|
|
1112
|
+
image: imageBase64Array,
|
|
1113
|
+
max_count,
|
|
1114
|
+
onProgress: async (metaData) => {
|
|
1115
|
+
// 心跳机制,每分钟调用一次,传递空的 metaData
|
|
1116
|
+
try {
|
|
1117
|
+
await sendProgress(context, ++progress, undefined, JSON.stringify(metaData));
|
|
1118
|
+
}
|
|
1119
|
+
catch (progressError) {
|
|
1120
|
+
console.warn('Failed to send progress update:', progressError);
|
|
1121
|
+
}
|
|
1122
|
+
},
|
|
1123
|
+
});
|
|
1124
|
+
if (!res) {
|
|
1125
|
+
throw new Error('Failed to generate image series: no response from AI service');
|
|
1126
|
+
}
|
|
1127
|
+
if (res.urls && Array.isArray(res.urls)) {
|
|
1128
|
+
console.log(`Image series generated successfully (${res.urls.length} images), saving to materials...`);
|
|
1129
|
+
const results = [];
|
|
1130
|
+
const maxImages = Math.min(res.urls.length, validatedFileNames.length);
|
|
1131
|
+
for (let i = 0; i < maxImages; i++) {
|
|
1132
|
+
const url = res.urls[i];
|
|
1133
|
+
const fileName = validatedFileNames[i];
|
|
1134
|
+
try {
|
|
1135
|
+
const uri = await saveMaterial(currentSession, url, fileName);
|
|
1136
|
+
results.push({
|
|
1137
|
+
success: true,
|
|
1138
|
+
uri,
|
|
1139
|
+
fileName,
|
|
1140
|
+
index: i,
|
|
1141
|
+
timestamp: new Date().toISOString(),
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
catch (error) {
|
|
1145
|
+
console.error(`Failed to save image ${i + 1}:`, error);
|
|
1146
|
+
results.push({
|
|
1147
|
+
success: false,
|
|
1148
|
+
error: `Failed to save image ${i + 1}: ${error}`,
|
|
1149
|
+
fileName,
|
|
1150
|
+
index: i,
|
|
1151
|
+
timestamp: new Date().toISOString(),
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
const result = {
|
|
1156
|
+
success: true,
|
|
1157
|
+
prompt: res.prompt,
|
|
1158
|
+
totalGenerated: res.urls.length,
|
|
1159
|
+
totalSaved: results.filter(r => r.success).length,
|
|
1160
|
+
results,
|
|
1161
|
+
timestamp: new Date().toISOString(),
|
|
1162
|
+
};
|
|
1163
|
+
return {
|
|
1164
|
+
content: [
|
|
1165
|
+
{
|
|
1166
|
+
type: 'text',
|
|
1167
|
+
text: JSON.stringify(result),
|
|
1168
|
+
},
|
|
1169
|
+
],
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
else {
|
|
1173
|
+
console.warn('Image series generation completed but no URLs returned');
|
|
1174
|
+
return {
|
|
1175
|
+
content: [
|
|
1176
|
+
{
|
|
1177
|
+
type: 'text',
|
|
1178
|
+
text: JSON.stringify({
|
|
1179
|
+
success: false,
|
|
1180
|
+
error: 'No image URLs returned from AI service',
|
|
1181
|
+
response: res,
|
|
1182
|
+
timestamp: new Date().toISOString(),
|
|
1183
|
+
}),
|
|
1184
|
+
},
|
|
1185
|
+
],
|
|
1186
|
+
};
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
catch (error) {
|
|
1190
|
+
return createErrorResponse(error, 'generate-image-series');
|
|
1191
|
+
}
|
|
1192
|
+
});
|
|
930
1193
|
server.registerTool('edit-image', {
|
|
931
1194
|
title: 'Edit Image',
|
|
932
1195
|
description: 'Edit the image.',
|
|
@@ -1148,12 +1411,12 @@ server.registerTool('generate-video', {
|
|
|
1148
1411
|
timestamp: new Date().toISOString(),
|
|
1149
1412
|
...opts,
|
|
1150
1413
|
};
|
|
1151
|
-
// Update
|
|
1414
|
+
// Update media_logs.json
|
|
1152
1415
|
try {
|
|
1153
|
-
await
|
|
1416
|
+
await updateMediaLogs(currentSession, validatedFileName, result);
|
|
1154
1417
|
}
|
|
1155
1418
|
catch (error) {
|
|
1156
|
-
console.warn(`Failed to update
|
|
1419
|
+
console.warn(`Failed to update media_logs.json for ${validatedFileName}:`, error);
|
|
1157
1420
|
}
|
|
1158
1421
|
return {
|
|
1159
1422
|
content: [
|
|
@@ -1363,13 +1626,12 @@ server.registerTool('generate-sound-effect', {
|
|
|
1363
1626
|
});
|
|
1364
1627
|
if (res.url) {
|
|
1365
1628
|
const uri = await saveMaterial(currentSession, res.url, saveToFileName);
|
|
1366
|
-
// Update
|
|
1629
|
+
// Update media_logs.json
|
|
1367
1630
|
try {
|
|
1368
|
-
|
|
1369
|
-
await updateMediaDurations(currentSession, saveToFileName, durationMs);
|
|
1631
|
+
await updateMediaLogs(currentSession, saveToFileName, res, 'audio');
|
|
1370
1632
|
}
|
|
1371
1633
|
catch (error) {
|
|
1372
|
-
console.warn(`Failed to update
|
|
1634
|
+
console.warn(`Failed to update media_logs.json for ${saveToFileName}:`, error);
|
|
1373
1635
|
}
|
|
1374
1636
|
return {
|
|
1375
1637
|
content: [
|
|
@@ -1562,12 +1824,12 @@ server.registerTool('generate-song', {
|
|
|
1562
1824
|
timestamp: new Date().toISOString(),
|
|
1563
1825
|
...opts,
|
|
1564
1826
|
};
|
|
1565
|
-
// Update
|
|
1827
|
+
// Update media_logs.json
|
|
1566
1828
|
try {
|
|
1567
|
-
await
|
|
1829
|
+
await updateMediaLogs(currentSession, validatedFileName, result, 'audio');
|
|
1568
1830
|
}
|
|
1569
1831
|
catch (error) {
|
|
1570
|
-
console.warn(`Failed to update
|
|
1832
|
+
console.warn(`Failed to update media_logs.json for ${validatedFileName}:`, error);
|
|
1571
1833
|
}
|
|
1572
1834
|
return {
|
|
1573
1835
|
content: [
|
|
@@ -1648,12 +1910,12 @@ server.registerTool('generate-bgm', {
|
|
|
1648
1910
|
timestamp: new Date().toISOString(),
|
|
1649
1911
|
...opts,
|
|
1650
1912
|
};
|
|
1651
|
-
// Update
|
|
1913
|
+
// Update media_logs.json
|
|
1652
1914
|
try {
|
|
1653
|
-
await
|
|
1915
|
+
await updateMediaLogs(currentSession, validatedFileName, result, 'audio');
|
|
1654
1916
|
}
|
|
1655
1917
|
catch (error) {
|
|
1656
|
-
console.warn('Failed to update
|
|
1918
|
+
console.warn('Failed to update media_logs.json:', error);
|
|
1657
1919
|
}
|
|
1658
1920
|
return {
|
|
1659
1921
|
content: [
|
|
@@ -1809,12 +2071,12 @@ server.registerTool('generate-scene-tts', {
|
|
|
1809
2071
|
timestamp: new Date().toISOString(),
|
|
1810
2072
|
...opts,
|
|
1811
2073
|
};
|
|
1812
|
-
// Update
|
|
2074
|
+
// Update media_logs.json
|
|
1813
2075
|
try {
|
|
1814
|
-
await
|
|
2076
|
+
await updateMediaLogs(currentSession, validatedFileName, result, 'audio');
|
|
1815
2077
|
}
|
|
1816
2078
|
catch (error) {
|
|
1817
|
-
console.warn(`Failed to update
|
|
2079
|
+
console.warn(`Failed to update media_logs.json for ${validatedFileName}:`, error);
|
|
1818
2080
|
}
|
|
1819
2081
|
return {
|
|
1820
2082
|
content: [
|
|
@@ -2234,7 +2496,7 @@ server.registerTool('lip-sync', {
|
|
|
2234
2496
|
.string()
|
|
2235
2497
|
.describe('The filename to save the lip-synced video.'),
|
|
2236
2498
|
},
|
|
2237
|
-
}, async ({ videoFileName, audioFileName, saveToFileName }) => {
|
|
2499
|
+
}, async ({ videoFileName, audioFileName, saveToFileName }, context) => {
|
|
2238
2500
|
try {
|
|
2239
2501
|
// 验证session状态
|
|
2240
2502
|
const currentSession = await validateSession('lip-sync');
|
|
@@ -2252,11 +2514,18 @@ server.registerTool('lip-sync', {
|
|
|
2252
2514
|
console.log(`Video URL: ${videoUrl}`);
|
|
2253
2515
|
console.log(`Audio URL: ${audioUrl}`);
|
|
2254
2516
|
// 调用AI的lipSync方法,使用处理后的音频
|
|
2517
|
+
let progress = 0;
|
|
2255
2518
|
const result = await currentSession.ai.lipSync({
|
|
2256
2519
|
videoUrl,
|
|
2257
2520
|
audioUrl,
|
|
2258
|
-
onProgress: metaData => {
|
|
2521
|
+
onProgress: async (metaData) => {
|
|
2259
2522
|
console.log('Lip sync progress:', metaData);
|
|
2523
|
+
try {
|
|
2524
|
+
await sendProgress(context, ++progress, undefined, JSON.stringify(metaData));
|
|
2525
|
+
}
|
|
2526
|
+
catch (progressError) {
|
|
2527
|
+
console.warn('Failed to send progress update:', progressError);
|
|
2528
|
+
}
|
|
2260
2529
|
},
|
|
2261
2530
|
});
|
|
2262
2531
|
if (result.url) {
|