cerevox 2.38.2 → 2.38.4
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 +11 -0
- package/dist/core/ai.d.ts.map +1 -1
- package/dist/core/ai.js +42 -93
- package/dist/core/ai.js.map +1 -1
- package/dist/mcp/servers/prompts/zerocut-core.md +2 -2
- package/dist/mcp/servers/zerocut.d.ts.map +1 -1
- package/dist/mcp/servers/zerocut.js +153 -176
- package/dist/mcp/servers/zerocut.js.map +1 -1
- package/package.json +1 -1
|
@@ -409,7 +409,7 @@ const cerevox = new index_1.default({
|
|
|
409
409
|
logLevel: 'error',
|
|
410
410
|
});
|
|
411
411
|
let session = null;
|
|
412
|
-
let projectLocalDir = '.';
|
|
412
|
+
let projectLocalDir = process.env.ZEROCUT_PROJECT_CWD || process.cwd() || '.';
|
|
413
413
|
let checkStoryboardFlag = false;
|
|
414
414
|
let checkAudioVideoDurationFlag = false;
|
|
415
415
|
let checkStoryboardSubtitlesFlag = false;
|
|
@@ -553,6 +553,7 @@ server.registerTool('retrieve-rules-context', {
|
|
|
553
553
|
text: JSON.stringify({
|
|
554
554
|
type: 'project_rules',
|
|
555
555
|
content: promptContent,
|
|
556
|
+
projectRulesFile,
|
|
556
557
|
}),
|
|
557
558
|
},
|
|
558
559
|
],
|
|
@@ -820,58 +821,6 @@ server.registerTool('list-project-files', {
|
|
|
820
821
|
return createErrorResponse(error, 'list-project-files');
|
|
821
822
|
}
|
|
822
823
|
});
|
|
823
|
-
server.registerTool('search-context', {
|
|
824
|
-
title: 'Search Context',
|
|
825
|
-
description: 'Search the context.',
|
|
826
|
-
inputSchema: {
|
|
827
|
-
query: zod_1.z.string().describe('The query to search.'),
|
|
828
|
-
},
|
|
829
|
-
}, async ({ query }) => {
|
|
830
|
-
try {
|
|
831
|
-
// 验证session状态
|
|
832
|
-
const currentSession = await validateSession('search-context');
|
|
833
|
-
if (!query || query.trim() === '') {
|
|
834
|
-
throw new Error('Search query cannot be empty');
|
|
835
|
-
}
|
|
836
|
-
const ai = currentSession.ai;
|
|
837
|
-
const res = await ai.searchText({ q: query });
|
|
838
|
-
if (!res) {
|
|
839
|
-
throw new Error('No search results returned from AI service');
|
|
840
|
-
}
|
|
841
|
-
return {
|
|
842
|
-
content: [{ type: 'text', text: JSON.stringify(res) }],
|
|
843
|
-
};
|
|
844
|
-
}
|
|
845
|
-
catch (error) {
|
|
846
|
-
return createErrorResponse(error, 'search-context');
|
|
847
|
-
}
|
|
848
|
-
});
|
|
849
|
-
server.registerTool('search-image', {
|
|
850
|
-
title: 'Search Image',
|
|
851
|
-
description: 'Search the image.',
|
|
852
|
-
inputSchema: {
|
|
853
|
-
query: zod_1.z.string().describe('The query to search.'),
|
|
854
|
-
},
|
|
855
|
-
}, async ({ query }) => {
|
|
856
|
-
try {
|
|
857
|
-
// 验证session状态
|
|
858
|
-
const currentSession = await validateSession('search-image');
|
|
859
|
-
if (!query || query.trim() === '') {
|
|
860
|
-
throw new Error('Search query cannot be empty');
|
|
861
|
-
}
|
|
862
|
-
const ai = currentSession.ai;
|
|
863
|
-
const res = await ai.searchImage({ q: query });
|
|
864
|
-
if (!res) {
|
|
865
|
-
throw new Error('No search results returned from AI service');
|
|
866
|
-
}
|
|
867
|
-
return {
|
|
868
|
-
content: [{ type: 'text', text: JSON.stringify(res) }],
|
|
869
|
-
};
|
|
870
|
-
}
|
|
871
|
-
catch (error) {
|
|
872
|
-
return createErrorResponse(error, 'search-image');
|
|
873
|
-
}
|
|
874
|
-
});
|
|
875
824
|
server.registerTool('generate-character-image', {
|
|
876
825
|
title: 'Generate Character Image',
|
|
877
826
|
description: 'Generate a turnaround image or portrait for any character.',
|
|
@@ -1748,7 +1697,7 @@ server.registerTool('generate-video', {
|
|
|
1748
1697
|
end_frame: zod_1.z
|
|
1749
1698
|
.string()
|
|
1750
1699
|
.optional()
|
|
1751
|
-
.describe('The image file name of the end frame.'),
|
|
1700
|
+
.describe('The image file name of the end frame (for non-zero models) or highlight frame (for zero models).'),
|
|
1752
1701
|
saveLastFrameAs: zod_1.z
|
|
1753
1702
|
.string()
|
|
1754
1703
|
.optional()
|
|
@@ -3671,127 +3620,6 @@ server.registerTool('audio-video-sync', {
|
|
|
3671
3620
|
return createErrorResponse(error, 'lip-sync');
|
|
3672
3621
|
}
|
|
3673
3622
|
});
|
|
3674
|
-
server.registerTool('build-capcat-draft', {
|
|
3675
|
-
title: 'Build CapCut Draft',
|
|
3676
|
-
description: 'Read draft_content.json file, parse JSON and generate URIs for all assets in timeline tracks, then output the processed JSON string.',
|
|
3677
|
-
inputSchema: {
|
|
3678
|
-
draftContentFile: zod_1.z
|
|
3679
|
-
.string()
|
|
3680
|
-
.optional()
|
|
3681
|
-
.default('draft_content.json')
|
|
3682
|
-
.describe('The draft content file name to read (defaults to draft_content.json).'),
|
|
3683
|
-
},
|
|
3684
|
-
}, async ({ draftContentFile }) => {
|
|
3685
|
-
try {
|
|
3686
|
-
await validateSession('build-capcat-draft');
|
|
3687
|
-
if (!session) {
|
|
3688
|
-
throw new Error('No active session');
|
|
3689
|
-
}
|
|
3690
|
-
// 读取 draft_content.json 文件
|
|
3691
|
-
const draftContentPath = (0, node_path_1.join)(projectLocalDir, draftContentFile);
|
|
3692
|
-
if (!(0, node_fs_1.existsSync)(draftContentPath)) {
|
|
3693
|
-
throw new Error(`${draftContentFile} file not found in project directory`);
|
|
3694
|
-
}
|
|
3695
|
-
const draftContentRaw = await (0, promises_1.readFile)(draftContentPath, 'utf-8');
|
|
3696
|
-
const draftContent = JSON.parse(draftContentRaw);
|
|
3697
|
-
const videoInfos = [];
|
|
3698
|
-
const audioInfos = [];
|
|
3699
|
-
// 为 timeline 中的所有视频资源生成 URI 和视频信息
|
|
3700
|
-
if (draftContent.timeline && draftContent.timeline.tracks) {
|
|
3701
|
-
for (const track of draftContent.timeline.tracks) {
|
|
3702
|
-
if (track.type === 'video' && track.clips) {
|
|
3703
|
-
for (const clip of track.clips) {
|
|
3704
|
-
if (clip.assetId) {
|
|
3705
|
-
// 在 assets 中找到对应的资源
|
|
3706
|
-
const asset = draftContent.assets?.find((a) => a.id === clip.assetId);
|
|
3707
|
-
if (asset && asset.uri && asset.type === 'video') {
|
|
3708
|
-
// 获取本地文件路径并上传到 coze
|
|
3709
|
-
const localPath = (0, node_path_1.join)(projectLocalDir, 'materials', (0, node_path_1.basename)(asset.uri));
|
|
3710
|
-
const uploadResult = await (0, coze_1.uploadFile)(localPath);
|
|
3711
|
-
const videoUrl = uploadResult.url;
|
|
3712
|
-
// 构建视频信息对象
|
|
3713
|
-
const videoInfo = {
|
|
3714
|
-
video_url: videoUrl,
|
|
3715
|
-
duration: clip.durationMs
|
|
3716
|
-
? clip.durationMs * 1000
|
|
3717
|
-
: asset.durationMs
|
|
3718
|
-
? asset.durationMs * 1000
|
|
3719
|
-
: 0, // 转换为微秒
|
|
3720
|
-
width: draftContent.settings?.resolution?.width || 1920,
|
|
3721
|
-
height: draftContent.settings?.resolution?.height || 1080,
|
|
3722
|
-
start: clip.startMs ? clip.startMs * 1000 : 0, // 转换为微秒
|
|
3723
|
-
end: ((clip.startMs ?? 0) + (clip.durationMs ?? 0)) * 1000,
|
|
3724
|
-
};
|
|
3725
|
-
videoInfos.push(videoInfo);
|
|
3726
|
-
}
|
|
3727
|
-
}
|
|
3728
|
-
}
|
|
3729
|
-
}
|
|
3730
|
-
else if (track.type === 'audio' && track.clips) {
|
|
3731
|
-
for (const clip of track.clips) {
|
|
3732
|
-
if (clip.assetId) {
|
|
3733
|
-
// 在 assets 中找到对应的资源
|
|
3734
|
-
const asset = draftContent.assets?.find((a) => a.id === clip.assetId);
|
|
3735
|
-
if (asset && asset.uri && asset.type === 'audio') {
|
|
3736
|
-
// 获取本地文件路径并上传到 coze
|
|
3737
|
-
const localPath = (0, node_path_1.join)(projectLocalDir, 'materials', (0, node_path_1.basename)(asset.uri));
|
|
3738
|
-
const uploadResult = await (0, coze_1.uploadFile)(localPath);
|
|
3739
|
-
const audioUrl = uploadResult.url;
|
|
3740
|
-
// 构建音频信息对象
|
|
3741
|
-
const audioInfo = {
|
|
3742
|
-
audio_url: audioUrl,
|
|
3743
|
-
duration: clip.durationMs
|
|
3744
|
-
? Math.round(clip.durationMs / 1000)
|
|
3745
|
-
: asset.durationMs
|
|
3746
|
-
? Math.round(asset.durationMs / 1000)
|
|
3747
|
-
: 0, // 转换为秒
|
|
3748
|
-
start: clip.startMs ? clip.startMs * 1000 : 0, // 转换为微秒
|
|
3749
|
-
end: ((clip.startMs ?? 0) + (clip.durationMs ?? 0)) * 1000,
|
|
3750
|
-
audio_effect: '',
|
|
3751
|
-
};
|
|
3752
|
-
audioInfos.push(audioInfo);
|
|
3753
|
-
}
|
|
3754
|
-
}
|
|
3755
|
-
}
|
|
3756
|
-
}
|
|
3757
|
-
}
|
|
3758
|
-
}
|
|
3759
|
-
// 处理字幕信息
|
|
3760
|
-
const captionInfos = [];
|
|
3761
|
-
if (draftContent.subtitles && Array.isArray(draftContent.subtitles)) {
|
|
3762
|
-
for (const subtitle of draftContent.subtitles) {
|
|
3763
|
-
captionInfos.push({
|
|
3764
|
-
text: subtitle.text || '',
|
|
3765
|
-
start: (subtitle.startMs || 0) * 1000, // 转换为微秒
|
|
3766
|
-
end: (subtitle.endMs || 0) * 1000, // 转换为微秒
|
|
3767
|
-
keyword: '',
|
|
3768
|
-
});
|
|
3769
|
-
}
|
|
3770
|
-
}
|
|
3771
|
-
const parameters = {
|
|
3772
|
-
video_infos: JSON.stringify(videoInfos),
|
|
3773
|
-
audio_infos: JSON.stringify(audioInfos),
|
|
3774
|
-
caption_infos: JSON.stringify(captionInfos),
|
|
3775
|
-
width: draftContent.settings?.resolution?.width || 720,
|
|
3776
|
-
height: draftContent.settings?.resolution?.height || 1280,
|
|
3777
|
-
};
|
|
3778
|
-
const workflow_id = '7559885633272758313';
|
|
3779
|
-
const result = await (0, coze_1.runWorkflow)(workflow_id, parameters);
|
|
3780
|
-
// 返回 video_infos、audio_infos、captions、width 和 height 对象
|
|
3781
|
-
return {
|
|
3782
|
-
content: [
|
|
3783
|
-
{
|
|
3784
|
-
type: 'text',
|
|
3785
|
-
text: JSON.stringify(result, null, 2),
|
|
3786
|
-
},
|
|
3787
|
-
],
|
|
3788
|
-
};
|
|
3789
|
-
}
|
|
3790
|
-
catch (error) {
|
|
3791
|
-
console.error('Error building CapCut draft:', error);
|
|
3792
|
-
return createErrorResponse(error, 'build-capcat-draft');
|
|
3793
|
-
}
|
|
3794
|
-
});
|
|
3795
3623
|
server.registerTool('generate-video-by-ref', {
|
|
3796
3624
|
title: 'Generate Video by Reference Images',
|
|
3797
3625
|
description: 'Generate video using reference images. Supports sora2, veo3.1, veo3.1-pro (1 image max), lite and pro (4 images max), vidu (7 images max). Can work without reference images (0 images).',
|
|
@@ -4250,7 +4078,7 @@ server.registerTool('run-ffmpeg-command', {
|
|
|
4250
4078
|
console.log('Command execution completed');
|
|
4251
4079
|
let downloadedFile = null;
|
|
4252
4080
|
// 如果指定了保存文件名,下载文件到本地materials目录
|
|
4253
|
-
if (saveToFileName) {
|
|
4081
|
+
if (saveToFileName && result.exitCode === 0) {
|
|
4254
4082
|
try {
|
|
4255
4083
|
const validatedFileName = validateFileName(saveToFileName);
|
|
4256
4084
|
const files = currentSession.files;
|
|
@@ -4294,6 +4122,155 @@ server.registerTool('run-ffmpeg-command', {
|
|
|
4294
4122
|
return createErrorResponse(error, 'run-ffmpeg-command');
|
|
4295
4123
|
}
|
|
4296
4124
|
});
|
|
4125
|
+
server.registerTool('search-context', {
|
|
4126
|
+
title: 'Search Context',
|
|
4127
|
+
description: 'Search the context.',
|
|
4128
|
+
inputSchema: {
|
|
4129
|
+
query: zod_1.z.string().describe('The query to search.'),
|
|
4130
|
+
type: zod_1.z.enum(['text', 'image']).optional().default('text'),
|
|
4131
|
+
},
|
|
4132
|
+
}, async ({ query, type }) => {
|
|
4133
|
+
try {
|
|
4134
|
+
// 验证session状态
|
|
4135
|
+
const currentSession = await validateSession('search-context');
|
|
4136
|
+
if (!query || query.trim() === '') {
|
|
4137
|
+
throw new Error('Search query cannot be empty');
|
|
4138
|
+
}
|
|
4139
|
+
const searchApi = type === 'text' ? 'searchText' : 'searchImage';
|
|
4140
|
+
const ai = currentSession.ai;
|
|
4141
|
+
const res = await ai[searchApi]({ q: query });
|
|
4142
|
+
if (!res) {
|
|
4143
|
+
throw new Error('No search results returned from AI service');
|
|
4144
|
+
}
|
|
4145
|
+
return {
|
|
4146
|
+
content: [{ type: 'text', text: JSON.stringify(res) }],
|
|
4147
|
+
};
|
|
4148
|
+
}
|
|
4149
|
+
catch (error) {
|
|
4150
|
+
return createErrorResponse(error, 'search-context');
|
|
4151
|
+
}
|
|
4152
|
+
});
|
|
4153
|
+
server.registerTool('build-capcat-draft', {
|
|
4154
|
+
title: 'Build CapCut Draft',
|
|
4155
|
+
description: 'Read draft_content.json file, parse JSON and generate URIs for all assets in timeline tracks, then output the processed JSON string.',
|
|
4156
|
+
inputSchema: {
|
|
4157
|
+
draftContentFile: zod_1.z
|
|
4158
|
+
.string()
|
|
4159
|
+
.optional()
|
|
4160
|
+
.default('draft_content.json')
|
|
4161
|
+
.describe('The draft content file name to read (defaults to draft_content.json).'),
|
|
4162
|
+
},
|
|
4163
|
+
}, async ({ draftContentFile }) => {
|
|
4164
|
+
try {
|
|
4165
|
+
await validateSession('build-capcat-draft');
|
|
4166
|
+
if (!session) {
|
|
4167
|
+
throw new Error('No active session');
|
|
4168
|
+
}
|
|
4169
|
+
// 读取 draft_content.json 文件
|
|
4170
|
+
const draftContentPath = (0, node_path_1.join)(projectLocalDir, draftContentFile);
|
|
4171
|
+
if (!(0, node_fs_1.existsSync)(draftContentPath)) {
|
|
4172
|
+
throw new Error(`${draftContentFile} file not found in project directory`);
|
|
4173
|
+
}
|
|
4174
|
+
const draftContentRaw = await (0, promises_1.readFile)(draftContentPath, 'utf-8');
|
|
4175
|
+
const draftContent = JSON.parse(draftContentRaw);
|
|
4176
|
+
const videoInfos = [];
|
|
4177
|
+
const audioInfos = [];
|
|
4178
|
+
// 为 timeline 中的所有视频资源生成 URI 和视频信息
|
|
4179
|
+
if (draftContent.timeline && draftContent.timeline.tracks) {
|
|
4180
|
+
for (const track of draftContent.timeline.tracks) {
|
|
4181
|
+
if (track.type === 'video' && track.clips) {
|
|
4182
|
+
for (const clip of track.clips) {
|
|
4183
|
+
if (clip.assetId) {
|
|
4184
|
+
// 在 assets 中找到对应的资源
|
|
4185
|
+
const asset = draftContent.assets?.find((a) => a.id === clip.assetId);
|
|
4186
|
+
if (asset && asset.uri && asset.type === 'video') {
|
|
4187
|
+
// 获取本地文件路径并上传到 coze
|
|
4188
|
+
const localPath = (0, node_path_1.join)(projectLocalDir, 'materials', (0, node_path_1.basename)(asset.uri));
|
|
4189
|
+
const uploadResult = await (0, coze_1.uploadFile)(localPath);
|
|
4190
|
+
const videoUrl = uploadResult.url;
|
|
4191
|
+
// 构建视频信息对象
|
|
4192
|
+
const videoInfo = {
|
|
4193
|
+
video_url: videoUrl,
|
|
4194
|
+
duration: clip.durationMs
|
|
4195
|
+
? clip.durationMs * 1000
|
|
4196
|
+
: asset.durationMs
|
|
4197
|
+
? asset.durationMs * 1000
|
|
4198
|
+
: 0, // 转换为微秒
|
|
4199
|
+
width: draftContent.settings?.resolution?.width || 1920,
|
|
4200
|
+
height: draftContent.settings?.resolution?.height || 1080,
|
|
4201
|
+
start: clip.startMs ? clip.startMs * 1000 : 0, // 转换为微秒
|
|
4202
|
+
end: ((clip.startMs ?? 0) + (clip.durationMs ?? 0)) * 1000,
|
|
4203
|
+
};
|
|
4204
|
+
videoInfos.push(videoInfo);
|
|
4205
|
+
}
|
|
4206
|
+
}
|
|
4207
|
+
}
|
|
4208
|
+
}
|
|
4209
|
+
else if (track.type === 'audio' && track.clips) {
|
|
4210
|
+
for (const clip of track.clips) {
|
|
4211
|
+
if (clip.assetId) {
|
|
4212
|
+
// 在 assets 中找到对应的资源
|
|
4213
|
+
const asset = draftContent.assets?.find((a) => a.id === clip.assetId);
|
|
4214
|
+
if (asset && asset.uri && asset.type === 'audio') {
|
|
4215
|
+
// 获取本地文件路径并上传到 coze
|
|
4216
|
+
const localPath = (0, node_path_1.join)(projectLocalDir, 'materials', (0, node_path_1.basename)(asset.uri));
|
|
4217
|
+
const uploadResult = await (0, coze_1.uploadFile)(localPath);
|
|
4218
|
+
const audioUrl = uploadResult.url;
|
|
4219
|
+
// 构建音频信息对象
|
|
4220
|
+
const audioInfo = {
|
|
4221
|
+
audio_url: audioUrl,
|
|
4222
|
+
duration: clip.durationMs
|
|
4223
|
+
? Math.round(clip.durationMs / 1000)
|
|
4224
|
+
: asset.durationMs
|
|
4225
|
+
? Math.round(asset.durationMs / 1000)
|
|
4226
|
+
: 0, // 转换为秒
|
|
4227
|
+
start: clip.startMs ? clip.startMs * 1000 : 0, // 转换为微秒
|
|
4228
|
+
end: ((clip.startMs ?? 0) + (clip.durationMs ?? 0)) * 1000,
|
|
4229
|
+
audio_effect: '',
|
|
4230
|
+
};
|
|
4231
|
+
audioInfos.push(audioInfo);
|
|
4232
|
+
}
|
|
4233
|
+
}
|
|
4234
|
+
}
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4237
|
+
}
|
|
4238
|
+
// 处理字幕信息
|
|
4239
|
+
const captionInfos = [];
|
|
4240
|
+
if (draftContent.subtitles && Array.isArray(draftContent.subtitles)) {
|
|
4241
|
+
for (const subtitle of draftContent.subtitles) {
|
|
4242
|
+
captionInfos.push({
|
|
4243
|
+
text: subtitle.text || '',
|
|
4244
|
+
start: (subtitle.startMs || 0) * 1000, // 转换为微秒
|
|
4245
|
+
end: (subtitle.endMs || 0) * 1000, // 转换为微秒
|
|
4246
|
+
keyword: '',
|
|
4247
|
+
});
|
|
4248
|
+
}
|
|
4249
|
+
}
|
|
4250
|
+
const parameters = {
|
|
4251
|
+
video_infos: JSON.stringify(videoInfos),
|
|
4252
|
+
audio_infos: JSON.stringify(audioInfos),
|
|
4253
|
+
caption_infos: JSON.stringify(captionInfos),
|
|
4254
|
+
width: draftContent.settings?.resolution?.width || 720,
|
|
4255
|
+
height: draftContent.settings?.resolution?.height || 1280,
|
|
4256
|
+
};
|
|
4257
|
+
const workflow_id = '7559885633272758313';
|
|
4258
|
+
const result = await (0, coze_1.runWorkflow)(workflow_id, parameters);
|
|
4259
|
+
// 返回 video_infos、audio_infos、captions、width 和 height 对象
|
|
4260
|
+
return {
|
|
4261
|
+
content: [
|
|
4262
|
+
{
|
|
4263
|
+
type: 'text',
|
|
4264
|
+
text: JSON.stringify(result, null, 2),
|
|
4265
|
+
},
|
|
4266
|
+
],
|
|
4267
|
+
};
|
|
4268
|
+
}
|
|
4269
|
+
catch (error) {
|
|
4270
|
+
console.error('Error building CapCut draft:', error);
|
|
4271
|
+
return createErrorResponse(error, 'build-capcat-draft');
|
|
4272
|
+
}
|
|
4273
|
+
});
|
|
4297
4274
|
// server.registerTool(
|
|
4298
4275
|
// 'custom-edit-draft',
|
|
4299
4276
|
// {
|