cerevox 3.0.0-alpha.1 → 3.0.0-alpha.11
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 +16 -20
- package/dist/core/ai.d.ts.map +1 -1
- package/dist/core/ai.js +84 -11
- package/dist/core/ai.js.map +1 -1
- package/dist/mcp/servers/prompts/rules/creative-ad.md +2 -2
- package/dist/mcp/servers/prompts/rules/expert.md +2 -2
- package/dist/mcp/servers/prompts/rules/freeform.md +2 -2
- package/dist/mcp/servers/prompts/rules/general-video.md +2 -2
- package/dist/mcp/servers/prompts/rules/music-video.md +2 -2
- package/dist/mcp/servers/prompts/rules/stage-play.md +2 -2
- package/dist/mcp/servers/prompts/rules/story-telling.md +2 -2
- package/dist/mcp/servers/prompts/skills/workflows/general-video.md +2 -2
- package/dist/mcp/servers/prompts/skills/workflows/music-video.md +2 -2
- package/dist/mcp/servers/zerocut.d.ts.map +1 -1
- package/dist/mcp/servers/zerocut.js +110 -117
- package/dist/mcp/servers/zerocut.js.map +1 -1
- package/package.json +1 -1
|
@@ -14,11 +14,11 @@ description: 创作专业音乐MV,基于 Zerocut 自主完成音乐MV成片的
|
|
|
14
14
|
3. 音乐创作 → 根据主题构思音乐氛围 → 创作歌词 lyrics.txt
|
|
15
15
|
4. 音乐生成 → 根据 lyrics.txt 调用 `generate-music` → 获得歌曲和 captions
|
|
16
16
|
5. 分析歌曲 → 创建 timeline_analysis.json 得到 captions 的时间线
|
|
17
|
-
6. 设计分镜场景 → `get-schema
|
|
17
|
+
6. 设计分镜场景 → `get-schema(type: storyboard)` 获取分镜规范 → 创建初始 storyboard.json
|
|
18
18
|
7. 主要角色形象塑造 → `generate-character-image` → 生成主要角色形象参考图(三视图)
|
|
19
19
|
8. 分镜首帧生成 → `generate-image` → 生成各场景分镜首帧
|
|
20
20
|
9. 首尾帧视频生成 → `generate-video` → **可选择使用连续镜头方式**:根据创意需要,可以选择以下一场景的 start_frame 作为上一场景的 end_frame 来实现场景间连续性,或采用独立场景切换方式,每段视频的实际时长应匹配 timeline_analysis 中 proposed_video_scenes 对应场景的 video_duration_s
|
|
21
|
-
10. 技术规范 → 调用`get-schema
|
|
21
|
+
10. 技术规范 → 调用`get-schema(type: draft_content)`获取 draft_content 规范 → 根据规范创建 draft_content.json
|
|
22
22
|
11. 执行渲染 → `compile-and-run` 输出成品并自动下载到本地
|
|
23
23
|
12. 关闭项目 → `project-close`
|
|
24
24
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zerocut.d.ts","sourceRoot":"","sources":["../../../src/mcp/servers/zerocut.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"zerocut.d.ts","sourceRoot":"","sources":["../../../src/mcp/servers/zerocut.ts"],"names":[],"mappings":";AAy/KA,wBAAsB,GAAG,kBAKxB"}
|
|
@@ -53,86 +53,9 @@ const node_path_1 = __importStar(require("node:path"));
|
|
|
53
53
|
const doubao_voices_full_1 = require("./helper/doubao_voices_full");
|
|
54
54
|
const node_fs_1 = require("node:fs");
|
|
55
55
|
const coze_1 = require("../../utils/coze");
|
|
56
|
-
const node_child_process_1 = require("node:child_process");
|
|
57
|
-
const node_util_1 = require("node:util");
|
|
58
|
-
const os = __importStar(require("node:os"));
|
|
59
56
|
const mp3_duration_1 = __importDefault(require("mp3-duration"));
|
|
60
57
|
const image_size_1 = __importDefault(require("image-size"));
|
|
61
|
-
|
|
62
|
-
// 错误处理工具函数
|
|
63
|
-
const handleError = (error) => {
|
|
64
|
-
if (error instanceof Error) {
|
|
65
|
-
return error.message;
|
|
66
|
-
}
|
|
67
|
-
return String(error);
|
|
68
|
-
};
|
|
69
|
-
// 检查端口是否被占用 - 跨平台版本
|
|
70
|
-
const isPortInUse = async (port) => {
|
|
71
|
-
try {
|
|
72
|
-
const platform = os.platform();
|
|
73
|
-
let command;
|
|
74
|
-
if (platform === 'win32') {
|
|
75
|
-
// Windows 使用 netstat
|
|
76
|
-
command = `netstat -ano | findstr :${port}`;
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
// Unix/Linux/macOS 使用 lsof
|
|
80
|
-
command = `lsof -ti:${port}`;
|
|
81
|
-
}
|
|
82
|
-
const { stdout } = await execAsync(command);
|
|
83
|
-
return stdout.trim().length > 0;
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
// 停止占用端口的进程 - 跨平台版本
|
|
90
|
-
const killPortProcess = async (port) => {
|
|
91
|
-
try {
|
|
92
|
-
const platform = os.platform();
|
|
93
|
-
if (platform === 'win32') {
|
|
94
|
-
// Windows 版本
|
|
95
|
-
const { stdout } = await execAsync(`netstat -ano | findstr :${port}`);
|
|
96
|
-
const lines = stdout.trim().split('\n');
|
|
97
|
-
for (const line of lines) {
|
|
98
|
-
const parts = line.trim().split(/\s+/);
|
|
99
|
-
const pid = parts[parts.length - 1];
|
|
100
|
-
if (pid && /^\d+$/.test(pid)) {
|
|
101
|
-
try {
|
|
102
|
-
await execAsync(`taskkill /F /PID ${pid}`);
|
|
103
|
-
console.log(`Killed process ${pid} on port ${port}`);
|
|
104
|
-
}
|
|
105
|
-
catch (error) {
|
|
106
|
-
console.warn(`Failed to kill process ${pid}:`, error);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
// Unix/Linux/macOS 版本
|
|
113
|
-
const { stdout } = await execAsync(`lsof -ti:${port}`);
|
|
114
|
-
const pids = stdout
|
|
115
|
-
.trim()
|
|
116
|
-
.split('\n')
|
|
117
|
-
.filter(pid => pid);
|
|
118
|
-
for (const pid of pids) {
|
|
119
|
-
try {
|
|
120
|
-
await execAsync(`kill -9 ${pid}`);
|
|
121
|
-
console.log(`Killed process ${pid} on port ${port}`);
|
|
122
|
-
}
|
|
123
|
-
catch (error) {
|
|
124
|
-
console.warn(`Failed to kill process ${pid}:`, error);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
// 等待一下确保进程被杀死
|
|
129
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
130
|
-
}
|
|
131
|
-
catch (error) {
|
|
132
|
-
console.warn(`Failed to kill processes on port ${port}:`, error);
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
function createErrorResponse(error, operation) {
|
|
58
|
+
function createErrorResponse(error, operation, details) {
|
|
136
59
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
137
60
|
console.error(`[${operation}] Error:`, error);
|
|
138
61
|
return {
|
|
@@ -144,6 +67,7 @@ function createErrorResponse(error, operation) {
|
|
|
144
67
|
error: errorMessage,
|
|
145
68
|
operation,
|
|
146
69
|
timestamp: new Date().toISOString(),
|
|
70
|
+
details,
|
|
147
71
|
}),
|
|
148
72
|
},
|
|
149
73
|
],
|
|
@@ -159,6 +83,10 @@ async function validateSession(operation) {
|
|
|
159
83
|
session = null;
|
|
160
84
|
throw new Error(`Session not initialized. Please call 'project-open' first before using ${operation}.`);
|
|
161
85
|
}
|
|
86
|
+
const projectRulesFile = (0, node_path_1.resolve)(projectLocalDir, '.trae', 'rules', `project_rules.md`);
|
|
87
|
+
if (!(0, node_fs_1.existsSync)(projectRulesFile)) {
|
|
88
|
+
throw new Error(`Project rules file not found: ${projectRulesFile}. Please call 'retrieve-rules-context' first.`);
|
|
89
|
+
}
|
|
162
90
|
return session;
|
|
163
91
|
}
|
|
164
92
|
// 文件名验证
|
|
@@ -173,20 +101,6 @@ function validateFileName(fileName) {
|
|
|
173
101
|
}
|
|
174
102
|
return fileName.trim();
|
|
175
103
|
}
|
|
176
|
-
// 图片文件验证
|
|
177
|
-
function validateImageFile(localPath) {
|
|
178
|
-
if (!localPath || localPath.trim() === '') {
|
|
179
|
-
throw new Error('Local path cannot be empty');
|
|
180
|
-
}
|
|
181
|
-
const allowedExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp'];
|
|
182
|
-
const extension = localPath
|
|
183
|
-
.toLowerCase()
|
|
184
|
-
.substring(localPath.lastIndexOf('.'));
|
|
185
|
-
if (!allowedExtensions.includes(extension)) {
|
|
186
|
-
throw new Error(`Unsupported image format: ${extension}. Allowed formats: ${allowedExtensions.join(', ')}`);
|
|
187
|
-
}
|
|
188
|
-
return localPath.trim();
|
|
189
|
-
}
|
|
190
104
|
function getMaterialUri(session, fileName) {
|
|
191
105
|
return session.sandbox.getUrl(`/zerocut/${session.terminal.id}/materials/${(0, node_path_1.basename)(fileName)}`);
|
|
192
106
|
}
|
|
@@ -692,6 +606,7 @@ server.registerTool('project-open', {
|
|
|
692
606
|
}
|
|
693
607
|
const result = {
|
|
694
608
|
success: true,
|
|
609
|
+
nextActionSuggest: '检查规则上下文是否已召回,若未召回,调用 retrieve_rules 工具召回规则上下文',
|
|
695
610
|
sessionId: session.id,
|
|
696
611
|
workDir,
|
|
697
612
|
projectLocalDir,
|
|
@@ -825,7 +740,10 @@ server.registerTool('generate-character-image', {
|
|
|
825
740
|
title: 'Generate Character Image',
|
|
826
741
|
description: 'Generate a turnaround image or portrait for any character.',
|
|
827
742
|
inputSchema: {
|
|
828
|
-
type: zod_1.z
|
|
743
|
+
type: zod_1.z
|
|
744
|
+
.enum(['banana', 'banana-pro', 'seedream'])
|
|
745
|
+
.optional()
|
|
746
|
+
.default('banana'),
|
|
829
747
|
name: zod_1.z.string().describe('The name of the character.'),
|
|
830
748
|
gender: zod_1.z
|
|
831
749
|
.enum(['male', 'female'])
|
|
@@ -1155,7 +1073,10 @@ server.registerTool('generate-image', {
|
|
|
1155
1073
|
title: 'Generate Image',
|
|
1156
1074
|
description: `生成图片`,
|
|
1157
1075
|
inputSchema: {
|
|
1158
|
-
type: zod_1.z
|
|
1076
|
+
type: zod_1.z
|
|
1077
|
+
.enum(['banana', 'banana-pro', 'seedream'])
|
|
1078
|
+
.optional()
|
|
1079
|
+
.default('seedream'),
|
|
1159
1080
|
prompt: zod_1.z
|
|
1160
1081
|
.string()
|
|
1161
1082
|
.describe('The prompt to generate. 一般要严格对应 storyboard 中当前场景的 start_frame 或 end_frame 中的字段描述'),
|
|
@@ -1520,6 +1441,11 @@ server.registerTool('edit-image', {
|
|
|
1520
1441
|
description: 'Edit the image.',
|
|
1521
1442
|
inputSchema: {
|
|
1522
1443
|
prompt: zod_1.z.string().describe('要编辑图片的中文提示词'),
|
|
1444
|
+
type: zod_1.z
|
|
1445
|
+
.enum(['banana-pro', 'banana', 'seedream'])
|
|
1446
|
+
.optional()
|
|
1447
|
+
.default('seedream')
|
|
1448
|
+
.describe('The type of image model to use.'),
|
|
1523
1449
|
sourceImageFileName: zod_1.z.string().describe('The source image file name.'),
|
|
1524
1450
|
saveToFileName: zod_1.z.string().describe('The filename to save.'),
|
|
1525
1451
|
size: zod_1.z
|
|
@@ -1563,7 +1489,7 @@ server.registerTool('edit-image', {
|
|
|
1563
1489
|
.default(false)
|
|
1564
1490
|
.describe('Whether to add watermark to the image.'),
|
|
1565
1491
|
},
|
|
1566
|
-
}, async ({ prompt, sourceImageFileName, saveToFileName, size, watermark }) => {
|
|
1492
|
+
}, async ({ prompt, type, sourceImageFileName, saveToFileName, size, watermark, }) => {
|
|
1567
1493
|
try {
|
|
1568
1494
|
// 验证session状态
|
|
1569
1495
|
const currentSession = await validateSession('edit-image');
|
|
@@ -1589,8 +1515,9 @@ server.registerTool('edit-image', {
|
|
|
1589
1515
|
const base64String = `data:${mimeType};base64,${imageBuffer.toString('base64')}`;
|
|
1590
1516
|
imageBase64Array.push(base64String);
|
|
1591
1517
|
const ai = currentSession.ai;
|
|
1592
|
-
const processedPrompt =
|
|
1518
|
+
const processedPrompt = `转绘我提供的参考图片,${prompt}`;
|
|
1593
1519
|
const res = await ai.generateImage({
|
|
1520
|
+
type,
|
|
1594
1521
|
prompt: processedPrompt,
|
|
1595
1522
|
size,
|
|
1596
1523
|
watermark,
|
|
@@ -2091,7 +2018,7 @@ server.registerTool('generate-video', {
|
|
|
2091
2018
|
console.warn('Failed to send progress update:', progressError);
|
|
2092
2019
|
}
|
|
2093
2020
|
},
|
|
2094
|
-
waitForFinish:
|
|
2021
|
+
waitForFinish: true,
|
|
2095
2022
|
});
|
|
2096
2023
|
if (!res) {
|
|
2097
2024
|
throw new Error('Failed to generate video: no response from AI service');
|
|
@@ -2139,7 +2066,7 @@ server.registerTool('generate-video', {
|
|
|
2139
2066
|
type: 'text',
|
|
2140
2067
|
text: JSON.stringify({
|
|
2141
2068
|
success: true,
|
|
2142
|
-
message: '
|
|
2069
|
+
message: '该视频生成任务正在运行中,它是异步任务,且执行时间较长,你应立即调用工具 wait-for-task-finish 来等待任务结束,如该工具调用超时,你应立即再次重新调用直到任务结束。',
|
|
2143
2070
|
taskUrl: res.taskUrl,
|
|
2144
2071
|
}),
|
|
2145
2072
|
},
|
|
@@ -2194,6 +2121,7 @@ server.registerTool('wait-for-task-finish', {
|
|
|
2194
2121
|
console.warn('Failed to send progress update:', progressError);
|
|
2195
2122
|
}
|
|
2196
2123
|
},
|
|
2124
|
+
timeout: 300000,
|
|
2197
2125
|
});
|
|
2198
2126
|
if (res.url) {
|
|
2199
2127
|
const uri = await saveMaterial(currentSession, res.url, saveToFileName);
|
|
@@ -2478,7 +2406,9 @@ server.registerTool('generate-scene-tts', {
|
|
|
2478
2406
|
'ASMR',
|
|
2479
2407
|
])
|
|
2480
2408
|
.optional(),
|
|
2481
|
-
voiceID: zod_1.z
|
|
2409
|
+
voiceID: zod_1.z
|
|
2410
|
+
.string()
|
|
2411
|
+
.describe(`适合作为视频配音的音色ID,除非用户指定,否则你必须已通过 search_voice 工具检查确定该音色确实是存在的。`),
|
|
2482
2412
|
explicit_language: zod_1.z.enum(['zh', 'en', 'ja']).optional().default('zh'),
|
|
2483
2413
|
},
|
|
2484
2414
|
}, async ({ text, sceneIndex, storyBoardFile, skipConsistencyCheck, voiceID, saveToFileName, speed, pitch, volume, emotion, explicit_language, }) => {
|
|
@@ -2543,6 +2473,9 @@ server.registerTool('generate-scene-tts', {
|
|
|
2543
2473
|
}
|
|
2544
2474
|
console.log(`Generating TTS with voice: ${voiceID}, speed: ${finalSpeed}, text: ${text.substring(0, 100)}...`);
|
|
2545
2475
|
const ai = currentSession.ai;
|
|
2476
|
+
if (voiceID.startsWith('BV0')) {
|
|
2477
|
+
throw new Error(`BV0* 系列音色已弃用,你必须已通过 search_voice 工具检查确定该音色确实是存在的。`);
|
|
2478
|
+
}
|
|
2546
2479
|
const type = voiceID.startsWith('zh_') ||
|
|
2547
2480
|
voiceID.startsWith('en_') ||
|
|
2548
2481
|
voiceID.startsWith('multi_') ||
|
|
@@ -2841,7 +2774,9 @@ server.registerTool('get-schema', {
|
|
|
2841
2774
|
title: 'Get Storyboard Schema or Draft Content Schema',
|
|
2842
2775
|
description: 'Get the complete Storyboard or Draft Content JSON Schema definition. Use this schema to validate storyboard.json or draft_content.json files.',
|
|
2843
2776
|
inputSchema: {
|
|
2844
|
-
type: zod_1.z
|
|
2777
|
+
type: zod_1.z
|
|
2778
|
+
.enum(['storyboard', 'draft_content'])
|
|
2779
|
+
.describe('The type of schema to retrieve. Must be either "storyboard" or "draft_content". 用 type: storyboard 的 schema 生成 storyboard.json;用 type: draft_content 的 schema 生成 draft_content.json'),
|
|
2845
2780
|
},
|
|
2846
2781
|
}, async ({ type }) => {
|
|
2847
2782
|
try {
|
|
@@ -3631,6 +3566,11 @@ server.registerTool('generate-video-by-ref', {
|
|
|
3631
3566
|
prompt: zod_1.z
|
|
3632
3567
|
.string()
|
|
3633
3568
|
.describe('The prompt to generate video with or without reference images.'),
|
|
3569
|
+
rewritePrompt: zod_1.z
|
|
3570
|
+
.boolean()
|
|
3571
|
+
.optional()
|
|
3572
|
+
.default(true)
|
|
3573
|
+
.describe('Whether to rewrite the prompt.'),
|
|
3634
3574
|
referenceImages: zod_1.z
|
|
3635
3575
|
.array(zod_1.z.object({
|
|
3636
3576
|
name: zod_1.z
|
|
@@ -3694,7 +3634,7 @@ server.registerTool('generate-video-by-ref', {
|
|
|
3694
3634
|
.default(false)
|
|
3695
3635
|
.describe('Whether to optimize the prompt.'),
|
|
3696
3636
|
},
|
|
3697
|
-
}, async ({ prompt, referenceImages, duration, size, watermark, type, mute, saveToFileName, sceneIndex, storyBoardFile, skipConsistencyCheck, optimizePrompt, }, context) => {
|
|
3637
|
+
}, async ({ prompt, rewritePrompt, referenceImages, duration, size, watermark, type, mute, saveToFileName, sceneIndex, storyBoardFile, skipConsistencyCheck, optimizePrompt, }, context) => {
|
|
3698
3638
|
try {
|
|
3699
3639
|
// 验证session状态
|
|
3700
3640
|
const currentSession = await validateSession('generate-video-by-ref');
|
|
@@ -3861,14 +3801,17 @@ server.registerTool('generate-video-by-ref', {
|
|
|
3861
3801
|
url: imageUrl,
|
|
3862
3802
|
});
|
|
3863
3803
|
console.log(`Added reference image URL: ${imageUrl} (name: ${imageRef.name}, type: ${imageRef.type})`);
|
|
3864
|
-
|
|
3804
|
+
if (rewritePrompt) {
|
|
3805
|
+
promptPrefix += `参考“${imageRef.name}”(图${referenceImageUrls.length})${imageRef.type === 'subject' ? '主体形象' : '背景'}\n`;
|
|
3806
|
+
}
|
|
3865
3807
|
}
|
|
3866
3808
|
if (promptPrefix) {
|
|
3867
3809
|
promptPrefix += '\n';
|
|
3868
3810
|
}
|
|
3811
|
+
const finalPrompt = `${promptPrefix}${prompt}`;
|
|
3869
3812
|
// 调用 referencesToVideo 函数
|
|
3870
3813
|
const result = await currentSession.ai.referencesToVideo({
|
|
3871
|
-
prompt:
|
|
3814
|
+
prompt: finalPrompt,
|
|
3872
3815
|
reference_images: referenceImageUrls, // 使用URL数组而不是base64数组
|
|
3873
3816
|
duration,
|
|
3874
3817
|
size,
|
|
@@ -3883,9 +3826,23 @@ server.registerTool('generate-video-by-ref', {
|
|
|
3883
3826
|
if (result.error) {
|
|
3884
3827
|
return createErrorResponse(result.error, 'generate-video-by-ref');
|
|
3885
3828
|
}
|
|
3886
|
-
if (!result.url) {
|
|
3829
|
+
if (!result.url && !result.taskUrl) {
|
|
3887
3830
|
return createErrorResponse('Video generation failed: no video URL returned', 'generate-video-by-ref');
|
|
3888
3831
|
}
|
|
3832
|
+
else if (result.taskUrl) {
|
|
3833
|
+
return {
|
|
3834
|
+
content: [
|
|
3835
|
+
{
|
|
3836
|
+
type: 'text',
|
|
3837
|
+
text: JSON.stringify({
|
|
3838
|
+
success: true,
|
|
3839
|
+
message: '该视频生成任务正在运行中,它是异步任务,且执行时间较长,你应立即调用工具 wait-for-task-finish 来等待任务结束,如该工具调用超时,你应立即再次重新调用直到任务结束。',
|
|
3840
|
+
taskUrl: result.taskUrl,
|
|
3841
|
+
}),
|
|
3842
|
+
},
|
|
3843
|
+
],
|
|
3844
|
+
};
|
|
3845
|
+
}
|
|
3889
3846
|
// 下载生成的视频
|
|
3890
3847
|
await saveMaterial(currentSession, result.url, validatedFileName);
|
|
3891
3848
|
// 更新媒体日志
|
|
@@ -3911,6 +3868,8 @@ server.registerTool('generate-video-by-ref', {
|
|
|
3911
3868
|
ratio: result.ratio,
|
|
3912
3869
|
url: result.url,
|
|
3913
3870
|
last_frame_url: result.last_frame_url,
|
|
3871
|
+
referenceImageUrls,
|
|
3872
|
+
prompt: finalPrompt,
|
|
3914
3873
|
}, null, 2),
|
|
3915
3874
|
},
|
|
3916
3875
|
],
|
|
@@ -4036,9 +3995,7 @@ server.registerTool('generate-video-by-template', {
|
|
|
4036
3995
|
title: 'Generate Video by Template',
|
|
4037
3996
|
description: 'Generate a video based on a template. The template must be a valid JSON string.',
|
|
4038
3997
|
inputSchema: {
|
|
4039
|
-
|
|
4040
|
-
.string()
|
|
4041
|
-
.describe('The prompt to generate the video. 自动根据意图匹配模板'),
|
|
3998
|
+
user_request: zod_1.z.string().describe('用户请求,根据意图自动匹配模板'),
|
|
4042
3999
|
text_prompts: zod_1.z
|
|
4043
4000
|
.array(zod_1.z.string().describe('Text prompt for the template to build video.'))
|
|
4044
4001
|
.optional()
|
|
@@ -4051,30 +4008,52 @@ server.registerTool('generate-video-by-template', {
|
|
|
4051
4008
|
.string()
|
|
4052
4009
|
.describe('The filename to save the generated video.'),
|
|
4053
4010
|
},
|
|
4054
|
-
}, async ({
|
|
4011
|
+
}, async ({ user_request, text_prompts, saveToFileName, materials }) => {
|
|
4055
4012
|
try {
|
|
4056
|
-
const templates =
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4013
|
+
const templates = [
|
|
4014
|
+
{
|
|
4015
|
+
id: '7569583728302817331',
|
|
4016
|
+
name: '宠物唱歌',
|
|
4017
|
+
description: '用一张宠物照片,生成一段宠物唱歌的视频。',
|
|
4018
|
+
trigger: '根据{A图片}生成一段{宠物A}唱歌的视频',
|
|
4019
|
+
},
|
|
4020
|
+
{
|
|
4021
|
+
id: '7569605825011367976',
|
|
4022
|
+
name: '万圣节宠物弹吉他',
|
|
4023
|
+
description: '用一张宠物照片,生成一段宠物弹吉他的视频。',
|
|
4024
|
+
trigger: '根据{A图片}生成一段{宠物A}弹吉他的视频',
|
|
4025
|
+
},
|
|
4026
|
+
{
|
|
4027
|
+
id: '7572443489834844223',
|
|
4028
|
+
name: '图生动作模仿视频',
|
|
4029
|
+
description: '用一张图片和动作视频,生成一段图片主体模仿该动作视频的新视频。',
|
|
4030
|
+
trigger: '生成{A图片}模仿{B视频}的视频',
|
|
4031
|
+
},
|
|
4032
|
+
{
|
|
4033
|
+
id: '7575160546555674670',
|
|
4034
|
+
name: '文生动作模仿视频',
|
|
4035
|
+
description: '用一段提示词和视频,生成一段模仿该视频的新视频。',
|
|
4036
|
+
trigger: '生成一段{提示词A}模仿{B视频}的视频',
|
|
4037
|
+
},
|
|
4038
|
+
];
|
|
4060
4039
|
const currentSession = await validateSession('generate-video-by-template');
|
|
4061
4040
|
const validatedFileName = validateFileName(saveToFileName);
|
|
4062
4041
|
const ai = currentSession.ai;
|
|
4063
4042
|
let completion = await ai.getCompletions({
|
|
4064
|
-
model: 'Doubao-Seed-1.6
|
|
4043
|
+
model: 'Doubao-Seed-1.6',
|
|
4065
4044
|
messages: [
|
|
4066
4045
|
{
|
|
4067
4046
|
role: 'system',
|
|
4068
|
-
content: `你根据用户需求,从以下模板中选择一个匹配的模板,返回模板ID:\n\n${JSON.stringify(templates)}\n\n**约束**:只输出模板ID
|
|
4047
|
+
content: `你根据用户需求,从以下模板中选择一个匹配的模板,返回模板ID:\n\n${JSON.stringify(templates)}\n\n**约束**:只输出模板ID,不需要其他解释,如果没有匹配的模版,输出"无匹配模版"`,
|
|
4069
4048
|
},
|
|
4070
4049
|
{
|
|
4071
4050
|
role: 'user',
|
|
4072
|
-
content:
|
|
4051
|
+
content: user_request,
|
|
4073
4052
|
},
|
|
4074
4053
|
],
|
|
4075
4054
|
});
|
|
4076
4055
|
const templateId = completion.choices[0]?.message?.content.trim();
|
|
4077
|
-
if (!templateId) {
|
|
4056
|
+
if (!templateId || templateId === '无匹配模版') {
|
|
4078
4057
|
throw new Error('Failed to get template ID');
|
|
4079
4058
|
}
|
|
4080
4059
|
const workflowInfo = await ai.getCozeWorkflowInfo(templateId);
|
|
@@ -4102,6 +4081,7 @@ ${text_prompts}
|
|
|
4102
4081
|
|
|
4103
4082
|
## **materials**:
|
|
4104
4083
|
${JSON.stringify(materialUrls)}`;
|
|
4084
|
+
// console.log(prompt);
|
|
4105
4085
|
completion = await ai.getCompletions({
|
|
4106
4086
|
model: 'Doubao-Seed-1.6-flash',
|
|
4107
4087
|
messages: [
|
|
@@ -4123,7 +4103,20 @@ ${JSON.stringify(materialUrls)}`;
|
|
|
4123
4103
|
if (!parameters) {
|
|
4124
4104
|
throw new Error('Failed to get parameters');
|
|
4125
4105
|
}
|
|
4126
|
-
console.log(parameters);
|
|
4106
|
+
// console.log(parameters);
|
|
4107
|
+
// return {
|
|
4108
|
+
// content: [
|
|
4109
|
+
// {
|
|
4110
|
+
// type: 'text',
|
|
4111
|
+
// text: JSON.stringify({
|
|
4112
|
+
// success: true,
|
|
4113
|
+
// prompt,
|
|
4114
|
+
// templateId,
|
|
4115
|
+
// parameters,
|
|
4116
|
+
// }),
|
|
4117
|
+
// },
|
|
4118
|
+
// ],
|
|
4119
|
+
// };
|
|
4127
4120
|
const result = await ai.runCozeWorkflow(templateId, JSON.parse(parameters).parameters);
|
|
4128
4121
|
if (result.url) {
|
|
4129
4122
|
// 保存到项目材料目录
|