cerevox 2.43.0 → 3.0.0-alpha.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.
Files changed (39) hide show
  1. package/dist/core/ai.d.ts +26 -3
  2. package/dist/core/ai.d.ts.map +1 -1
  3. package/dist/core/ai.js +15 -8
  4. package/dist/core/ai.js.map +1 -1
  5. package/dist/mcp/servers/prompts/actions/storyboard_optimization.md +5 -5
  6. package/dist/{utils/videoproject-schema.json → mcp/servers/prompts/draft_content-schema.json} +3 -3
  7. package/dist/mcp/servers/prompts/rules/creative-ad.md +6 -6
  8. package/dist/mcp/servers/prompts/rules/expert.md +25 -25
  9. package/dist/mcp/servers/prompts/rules/freeform.md +2 -3
  10. package/dist/mcp/servers/prompts/rules/general-video.md +10 -10
  11. package/dist/mcp/servers/prompts/rules/material-creation.md +2 -2
  12. package/dist/mcp/servers/prompts/rules/music-video.md +3 -3
  13. package/dist/mcp/servers/prompts/rules/stage-play.md +4 -4
  14. package/dist/mcp/servers/prompts/rules/story-telling.md +8 -8
  15. package/dist/mcp/servers/prompts/skills/storyboard/storyboard-optimization-skill.md +5 -5
  16. package/dist/mcp/servers/prompts/skills/video/continuity-techniques.md +1 -1
  17. package/dist/mcp/servers/prompts/skills/workflows/general-video.md +10 -10
  18. package/dist/mcp/servers/prompts/skills/workflows/music-video.md +3 -3
  19. package/dist/mcp/servers/prompts/zerocut-core.md +26 -27
  20. package/dist/mcp/servers/zerocut.d.ts.map +1 -1
  21. package/dist/mcp/servers/zerocut.js +383 -427
  22. package/dist/mcp/servers/zerocut.js.map +1 -1
  23. package/dist/utils/coze.d.ts +1 -0
  24. package/dist/utils/coze.d.ts.map +1 -1
  25. package/dist/utils/coze.js +19 -0
  26. package/dist/utils/coze.js.map +1 -1
  27. package/package.json +2 -2
  28. package/dist/timeline-editor/index.d.ts +0 -42
  29. package/dist/timeline-editor/index.d.ts.map +0 -1
  30. package/dist/timeline-editor/index.js +0 -82
  31. package/dist/timeline-editor/index.js.map +0 -1
  32. package/dist/timeline-editor/public/app.js +0 -2086
  33. package/dist/timeline-editor/public/index.html +0 -141
  34. package/dist/timeline-editor/public/style.css +0 -695
  35. package/dist/timeline-editor/server.d.ts +0 -137
  36. package/dist/timeline-editor/server.d.ts.map +0 -1
  37. package/dist/timeline-editor/server.js +0 -418
  38. package/dist/timeline-editor/server.js.map +0 -1
  39. /package/dist/{utils → mcp/servers/prompts}/storyboard-schema.json +0 -0
@@ -211,7 +211,7 @@ async function initProject(session) {
211
211
  // 创建素材目录和成品目录 materials、output
212
212
  await (await terminal.run('mkdir materials output')).end();
213
213
  // 文件包括(大部分不需要此时创建)
214
- // story_board.json 故事版
214
+ // storyboard.json 故事版
215
215
  // draft_content.json 草稿内容,Agent在创作过程中,会根据项目规范,自动生成和修改该文件
216
216
  return workDir;
217
217
  }
@@ -1158,7 +1158,7 @@ server.registerTool('generate-image', {
1158
1158
  type: zod_1.z.enum(['banana', 'seedream']).optional().default('seedream'),
1159
1159
  prompt: zod_1.z
1160
1160
  .string()
1161
- .describe('The prompt to generate. 一般要严格对应 story_board 中当前场景的 start_frame 或 end_frame 中的字段描述'),
1161
+ .describe('The prompt to generate. 一般要严格对应 storyboard 中当前场景的 start_frame 或 end_frame 中的字段描述'),
1162
1162
  sceneIndex: zod_1.z
1163
1163
  .number()
1164
1164
  .min(1)
@@ -1167,7 +1167,7 @@ server.registerTool('generate-image', {
1167
1167
  storyBoardFile: zod_1.z
1168
1168
  .string()
1169
1169
  .optional()
1170
- .default('story_board.json')
1170
+ .default('storyboard.json')
1171
1171
  .describe('故事板文件路径'),
1172
1172
  skipConsistencyCheck: zod_1.z
1173
1173
  .boolean()
@@ -1252,7 +1252,7 @@ server.registerTool('generate-image', {
1252
1252
  \`\`\`
1253
1253
  `),
1254
1254
  },
1255
- }, async ({ type = 'seedream', prompt, sceneIndex, storyBoardFile = 'story_board.json', skipConsistencyCheck = false, size = '720x1280', saveToFileName, watermark, referenceImages, optimizePrompt, }) => {
1255
+ }, async ({ type = 'seedream', prompt, sceneIndex, storyBoardFile = 'storyboard.json', skipConsistencyCheck = false, size = '720x1280', saveToFileName, watermark, referenceImages, optimizePrompt, }) => {
1256
1256
  try {
1257
1257
  // 验证session状态
1258
1258
  const currentSession = await validateSession('generate-image');
@@ -1260,10 +1260,10 @@ server.registerTool('generate-image', {
1260
1260
  // 检查 storyboard 标志
1261
1261
  if (!checkStoryboardFlag && (0, node_fs_1.existsSync)(storyBoardPath)) {
1262
1262
  checkStoryboardFlag = true;
1263
- return createErrorResponse('必须先审查生成的 story_board.json 内容,确保每个场景中的stage_atmosphere内容按照规则被正确融合到start_frame和video_prompt中,不得遗漏,检查完成后先汇报,如果有问题,应当先修改 story_board.json 内容,然后再调用 generate-image 生成图片。注意修改 story_board 内容时,仅修改相应字段的字符串值,不要破坏JSON格式!', 'generate-image');
1263
+ return createErrorResponse('必须先审查生成的 storyboard.json 内容,确保每个场景中的stage_atmosphere内容按照规则被正确融合到start_frame和video_prompt中,不得遗漏,检查完成后先汇报,如果有问题,应当先修改 storyboard.json 内容,然后再调用 generate-image 生成图片。注意修改 storyboard 内容时,仅修改相应字段的字符串值,不要破坏JSON格式!', 'generate-image');
1264
1264
  }
1265
1265
  const validatedFileName = validateFileName(saveToFileName);
1266
- // 校验 prompt 与 story_board.json 中场景设定的一致性
1266
+ // 校验 prompt 与 storyboard.json 中场景设定的一致性
1267
1267
  if (sceneIndex && !skipConsistencyCheck) {
1268
1268
  try {
1269
1269
  if ((0, node_fs_1.existsSync)(storyBoardPath)) {
@@ -1283,9 +1283,9 @@ server.registerTool('generate-image', {
1283
1283
  const endFrame = scene.end_frame;
1284
1284
  // 检查 prompt 是否严格等于 start_frame 或 end_frame
1285
1285
  if (prompt !== startFrame && prompt !== endFrame) {
1286
- return createErrorResponse('图片提示词必须严格遵照story_board的设定,如果用户明确指出不需要遵守,请将skipConsistencyCheck设置为true后再次调用', 'generate-image');
1286
+ return createErrorResponse('图片提示词必须严格遵照storyboard的设定,如果用户明确指出不需要遵守,请将skipConsistencyCheck设置为true后再次调用', 'generate-image');
1287
1287
  }
1288
- // 校验 size 参数与 story_board 的 orientation 属性一致性
1288
+ // 校验 size 参数与 storyboard 的 orientation 属性一致性
1289
1289
  if (size && storyBoard.orientation) {
1290
1290
  const isLandscapeSize = [
1291
1291
  '1152x864',
@@ -1330,7 +1330,7 @@ server.registerTool('generate-image', {
1330
1330
  }
1331
1331
  }
1332
1332
  else {
1333
- console.warn(`Scene index ${sceneIndex} not found in story_board.json`);
1333
+ console.warn(`Scene index ${sceneIndex} not found in storyboard.json`);
1334
1334
  }
1335
1335
  }
1336
1336
  }
@@ -1340,7 +1340,7 @@ server.registerTool('generate-image', {
1340
1340
  }
1341
1341
  catch (error) {
1342
1342
  console.error('Failed to validate prompt with story board:', error);
1343
- // 如果读取或解析 story_board.json 失败,继续执行但记录警告
1343
+ // 如果读取或解析 storyboard.json 失败,继续执行但记录警告
1344
1344
  }
1345
1345
  }
1346
1346
  // 检查并替换英文单引号包裹的中文内容为中文双引号
@@ -1647,7 +1647,7 @@ server.registerTool('generate-video', {
1647
1647
  inputSchema: {
1648
1648
  prompt: zod_1.z
1649
1649
  .string()
1650
- .describe('The prompt to generate. 一般要严格对应 story_board 中当前场景的 video_prompt 字段描述'),
1650
+ .describe('The prompt to generate. 一般要严格对应 storyboard 中当前场景的 video_prompt 字段描述'),
1651
1651
  sceneIndex: zod_1.z
1652
1652
  .number()
1653
1653
  .min(1)
@@ -1656,7 +1656,7 @@ server.registerTool('generate-video', {
1656
1656
  storyBoardFile: zod_1.z
1657
1657
  .string()
1658
1658
  .optional()
1659
- .default('story_board.json')
1659
+ .default('storyboard.json')
1660
1660
  .describe('故事板文件路径'),
1661
1661
  skipConsistencyCheck: zod_1.z
1662
1662
  .boolean()
@@ -1691,7 +1691,7 @@ server.registerTool('generate-video', {
1691
1691
  .describe('The image file name of the start frame.'),
1692
1692
  duration: zod_1.z
1693
1693
  .number()
1694
- .min(2)
1694
+ .min(1)
1695
1695
  .max(23)
1696
1696
  .describe('The duration of the video. 一般与 tts 配音音频时长向上取整秒(ceil)一致,或者与 timeline_analysis 中确定的歌曲片段时长一致'),
1697
1697
  end_frame: zod_1.z
@@ -1718,7 +1718,7 @@ server.registerTool('generate-video', {
1718
1718
  .default(false)
1719
1719
  .describe('Whether to optimize the prompt.'),
1720
1720
  },
1721
- }, async ({ prompt, sceneIndex, storyBoardFile = 'story_board.json', skipConsistencyCheck = false, saveToFileName, start_frame, end_frame, duration, watermark, resolution, type, optimizePrompt, saveLastFrameAs, }, context) => {
1721
+ }, async ({ prompt, sceneIndex, storyBoardFile = 'storyboard.json', skipConsistencyCheck = false, saveToFileName, start_frame, end_frame, duration, watermark, resolution, type, optimizePrompt, saveLastFrameAs, }, context) => {
1722
1722
  try {
1723
1723
  // 验证session状态
1724
1724
  const currentSession = await validateSession('generate-video');
@@ -1739,7 +1739,7 @@ server.registerTool('generate-video', {
1739
1739
  console.warn(`zero 模型的视频仅支持 1080p 分辨率,用户指定的分辨率为 %s,已自动将 ${resolution} 转换为 1080p`, resolution);
1740
1740
  resolution = '1080p';
1741
1741
  }
1742
- // 校验 prompt 与 story_board.json 中场景设定的一致性以及视频时长与 timeline_analysis.json 中 proposed_video_scenes 的匹配
1742
+ // 校验 prompt 与 storyboard.json 中场景设定的一致性以及视频时长与 timeline_analysis.json 中 proposed_video_scenes 的匹配
1743
1743
  if (sceneIndex && !skipConsistencyCheck) {
1744
1744
  try {
1745
1745
  const storyBoardPath = (0, node_path_1.resolve)(process.env.ZEROCUT_PROJECT_CWD || process.cwd(), projectLocalDir, storyBoardFile);
@@ -1758,7 +1758,7 @@ server.registerTool('generate-video', {
1758
1758
  if (scene) {
1759
1759
  const videoPrompt = scene.video_prompt;
1760
1760
  if (videoPrompt && prompt !== videoPrompt) {
1761
- return createErrorResponse('视频提示词必须严格遵照story_board的设定,如果用户明确指出不需要遵守,请将skipConsistencyCheck设置为true后再次调用', 'generate-video');
1761
+ return createErrorResponse('视频提示词必须严格遵照storyboard的设定,如果用户明确指出不需要遵守,请将skipConsistencyCheck设置为true后再次调用', 'generate-video');
1762
1762
  }
1763
1763
  if (scene.is_continuous && !end_frame) {
1764
1764
  return createErrorResponse('连续场景必须指定end_frame参数,如果用户明确指出不需要遵守,请将skipConsistencyCheck设置为true后再次调用', 'generate-video');
@@ -1771,7 +1771,7 @@ server.registerTool('generate-video', {
1771
1771
  }
1772
1772
  }
1773
1773
  else {
1774
- console.warn(`Scene index ${sceneIndex} not found in story_board.json`);
1774
+ console.warn(`Scene index ${sceneIndex} not found in storyboard.json`);
1775
1775
  }
1776
1776
  }
1777
1777
  }
@@ -1781,7 +1781,7 @@ server.registerTool('generate-video', {
1781
1781
  }
1782
1782
  catch (error) {
1783
1783
  console.error('Failed to validate prompt with story board:', error);
1784
- // 如果读取或解析 story_board.json 失败,继续执行但记录警告
1784
+ // 如果读取或解析 storyboard.json 失败,继续执行但记录警告
1785
1785
  }
1786
1786
  // 校验视频时长与 timeline_analysis.json 中 proposed_video_scenes 的匹配
1787
1787
  try {
@@ -1818,10 +1818,10 @@ server.registerTool('generate-video', {
1818
1818
  if (!checkAudioVideoDurationFlag) {
1819
1819
  checkAudioVideoDurationFlag = true;
1820
1820
  if (scene.audio_mode === 'vo_sync') {
1821
- return createErrorResponse('请先自我检查 media_logs 中的音频时长,确保 story_board 中视频时长为音频时长向上取整 即 ceil(音频时长),然后再按照正确的视频时长创建视频', 'generate-video');
1821
+ return createErrorResponse('请先自我检查 media_logs 中的音频时长,确保 storyboard 中视频时长为音频时长向上取整 即 ceil(音频时长),然后再按照正确的视频时长创建视频', 'generate-video');
1822
1822
  }
1823
1823
  else if (scene.audio_mode === 'dialogue') {
1824
- return createErrorResponse('请先自我检查 media_logs 中的音频时长,确保 story_board 中视频时长**不小于**音频时长向上取整 即 ceil(音频时长),然后再按照正确的视频时长创建视频', 'generate-video');
1824
+ return createErrorResponse('请先自我检查 media_logs 中的音频时长,确保 storyboard 中视频时长**不小于**音频时长向上取整 即 ceil(音频时长),然后再按照正确的视频时长创建视频', 'generate-video');
1825
1825
  }
1826
1826
  }
1827
1827
  }
@@ -1946,10 +1946,10 @@ server.registerTool('generate-video', {
1946
1946
  type: 'string',
1947
1947
  description: 'kenburns 视频 宽x高',
1948
1948
  },
1949
- },
1950
- duration: {
1951
- type: 'number',
1952
- description: 'kenburns 视频 时长',
1949
+ duration: {
1950
+ type: 'number',
1951
+ description: 'kenburns 视频 时长',
1952
+ },
1953
1953
  },
1954
1954
  required: ['camera_motion', 'size', 'duration'],
1955
1955
  },
@@ -2423,7 +2423,7 @@ server.registerTool('generate-scene-tts', {
2423
2423
  storyBoardFile: zod_1.z
2424
2424
  .string()
2425
2425
  .optional()
2426
- .default('story_board.json')
2426
+ .default('storyboard.json')
2427
2427
  .describe('故事板文件路径'),
2428
2428
  skipConsistencyCheck: zod_1.z
2429
2429
  .boolean()
@@ -2489,7 +2489,7 @@ server.registerTool('generate-scene-tts', {
2489
2489
  const finalSpeed = speed ?? 1;
2490
2490
  volume = volume ?? 1;
2491
2491
  let scene = null;
2492
- // 校验 text 与 story_board.json 中场景设定的一致性
2492
+ // 校验 text 与 storyboard.json 中场景设定的一致性
2493
2493
  if (sceneIndex && !skipConsistencyCheck) {
2494
2494
  try {
2495
2495
  const storyBoardPath = (0, node_path_1.resolve)(process.env.ZEROCUT_PROJECT_CWD || process.cwd(), projectLocalDir, storyBoardFile);
@@ -2524,11 +2524,11 @@ server.registerTool('generate-scene-tts', {
2524
2524
  }
2525
2525
  }
2526
2526
  if (!isValidText) {
2527
- return createErrorResponse('配音文本必须严格遵照story_board的设定,如果用户明确指出不需要遵守,请将skipConsistencyCheck设置为true后再次调用', 'generate-scene-tts');
2527
+ return createErrorResponse('配音文本必须严格遵照storyboard的设定,如果用户明确指出不需要遵守,请将skipConsistencyCheck设置为true后再次调用', 'generate-scene-tts');
2528
2528
  }
2529
2529
  }
2530
2530
  else {
2531
- console.warn(`Scene index ${sceneIndex} not found in story_board.json`);
2531
+ console.warn(`Scene index ${sceneIndex} not found in storyboard.json`);
2532
2532
  }
2533
2533
  }
2534
2534
  }
@@ -2538,7 +2538,7 @@ server.registerTool('generate-scene-tts', {
2538
2538
  }
2539
2539
  catch (error) {
2540
2540
  console.error('Failed to validate text with story board:', error);
2541
- // 如果读取或解析 story_board.json 失败,继续执行但记录警告
2541
+ // 如果读取或解析 storyboard.json 失败,继续执行但记录警告
2542
2542
  }
2543
2543
  }
2544
2544
  console.log(`Generating TTS with voice: ${voiceID}, speed: ${finalSpeed}, text: ${text.substring(0, 100)}...`);
@@ -2592,7 +2592,7 @@ server.registerTool('generate-scene-tts', {
2592
2592
  console.log('TTS generated successfully, saving to materials...');
2593
2593
  const { url, duration, ...opts } = res;
2594
2594
  if (!skipConsistencyCheck && duration > 16) {
2595
- return createErrorResponse('TTS duration exceeds 16 seconds, 建议调整文本长度、提升语速或拆分场景...,⚠️如简化文本内容或拆分文本,需要立即更新 story_board 以保持内容同步!如仍要生成,可设置 skipConsistencyCheck 为 true,跳过一致性检查。', 'generate-scene-tts');
2595
+ return createErrorResponse('TTS duration exceeds 16 seconds, 建议调整文本长度、提升语速或拆分场景...,⚠️如简化文本内容或拆分文本,需要立即更新 storyboard 以保持内容同步!如仍要生成,可设置 skipConsistencyCheck 为 true,跳过一致性检查。', 'generate-scene-tts');
2596
2596
  }
2597
2597
  if (!duration) {
2598
2598
  return createErrorResponse('TTS duration not returned from AI service', 'generate-scene-tts');
@@ -2678,8 +2678,8 @@ server.registerTool('compile-and-run', {
2678
2678
  checkStoryboardSubtitlesFlag = true;
2679
2679
  return createErrorResponse(`请先对 draft_content 进行以下一致性检查:
2680
2680
 
2681
- 1. 检查字幕文字内容是否与 story_board 中各个场景的 script 或 dialog 内容完全一致(⚠️ 允许字幕分段展示,只要最终文本保持一致就行)
2682
- 2. 检查视频 resolution 设定是否与 story_board 的 orientation 设置一致,默认 720p 情况下视频尺寸应为横屏 1280x720,竖屏 720x1280,若视频为 1080p 则尺寸应分别为横屏 1920x1080 和竖屏 1080x1920,切勿设反
2681
+ 1. 检查字幕文字内容是否与 storyboard 中各个场景的 script 或 dialog 内容完全一致(⚠️ 允许字幕分段展示,只要最终文本保持一致就行)
2682
+ 2. 检查视频 resolution 设定是否与 storyboard 的 orientation 设置一致,默认 720p 情况下视频尺寸应为横屏 1280x720,竖屏 720x1280,若视频为 1080p 则尺寸应分别为横屏 1920x1080 和竖屏 1080x1920,切勿设反
2683
2683
  3. 除非用户明确表示不要背景音乐,否则应检查是否有生成并配置了 BGM,若无,则生成 BGM 并将其加入素材和轨道配置
2684
2684
 
2685
2685
  以上检查任何一项有问题,先修复 draft_content 使其符合要求后再进行合成`, 'compile-and-run');
@@ -2837,47 +2837,26 @@ server.registerTool('compile-and-run', {
2837
2837
  return createErrorResponse(error, 'compile-and-run');
2838
2838
  }
2839
2839
  });
2840
- server.registerTool('get-video-project-schema', {
2841
- title: 'Get VideoProject Schema',
2842
- description: 'Get the complete VideoProject JSON Schema definition. Should use this schema to validate draft_content JSON files.',
2843
- inputSchema: {},
2844
- }, async () => {
2840
+ server.registerTool('get-schema', {
2841
+ title: 'Get Storyboard Schema or Draft Content Schema',
2842
+ description: 'Get the complete Storyboard or Draft Content JSON Schema definition. Use this schema to validate storyboard.json or draft_content.json files.',
2843
+ inputSchema: {
2844
+ type: zod_1.z.enum(['storyboard', 'draft_content']),
2845
+ },
2846
+ }, async ({ type }) => {
2845
2847
  try {
2846
- const schemaPath = (0, node_path_1.resolve)(__dirname, '../../utils/videoproject-schema.json');
2848
+ const schemaPath = (0, node_path_1.resolve)(__dirname, `./prompts/${type}-schema.json`);
2847
2849
  const schemaContent = await (0, promises_1.readFile)(schemaPath, 'utf-8');
2848
2850
  const schema = JSON.parse(schemaContent);
2849
- return {
2850
- content: [
2851
- {
2852
- type: 'text',
2853
- text: JSON.stringify({
2854
- success: true,
2855
- schema,
2856
- important_guidelines: `⚠️ 生成文件时请严格遵守输出规范,字幕文本内容必须与 story_board.json 中的 script(或dialog) 字段的文本内容完全一致。
2851
+ let important_guidelines = '';
2852
+ if (type === 'draft_content') {
2853
+ important_guidelines = `⚠️ 生成文件时请严格遵守输出规范,字幕文本内容必须与 storyboard.json 中的 script(或dialog) 字段的文本内容完全一致。
2857
2854
 
2858
2855
  ** 字幕优化 **
2859
- * 在保证字幕文本内容与 story_board.json 中的 script(或dialog) 字段的文本内容完全一致的前提下,可根据 tts 返回的 \`captions.utterances\` 字段对字幕的显示进行优化,将过长的字幕分段显示,在 draft_content.json 中使用分段字幕,captions 的内容在 media_logs.json 中可查询到。
2856
+ * 在保证字幕文本内容与 storyboard.json 中的 script(或dialog) 字段的文本内容完全一致的前提下,可根据 tts 返回的 \`captions.utterances\` 字段对字幕的显示进行优化,将过长的字幕分段显示,在 draft_content.json 中使用分段字幕,captions 的内容在 media_logs.json 中可查询到。
2860
2857
  * 如用户未特殊指定,字幕样式(字体及大小)务必遵守输出规范
2861
- `,
2862
- timestamp: new Date().toISOString(),
2863
- }),
2864
- },
2865
- ],
2866
- };
2867
- }
2868
- catch (error) {
2869
- return createErrorResponse(error, 'get-video-project-schema');
2870
- }
2871
- });
2872
- server.registerTool('get-storyboard-schema', {
2873
- title: 'Get Storyboard Schema',
2874
- description: 'Get the complete Storyboard JSON Schema definition.',
2875
- inputSchema: {},
2876
- }, async () => {
2877
- try {
2878
- const schemaPath = (0, node_path_1.resolve)(__dirname, '../../utils/storyboard-schema.json');
2879
- const schemaContent = await (0, promises_1.readFile)(schemaPath, 'utf-8');
2880
- const schema = JSON.parse(schemaContent);
2858
+ `;
2859
+ }
2881
2860
  return {
2882
2861
  content: [
2883
2862
  {
@@ -2885,6 +2864,7 @@ server.registerTool('get-storyboard-schema', {
2885
2864
  text: JSON.stringify({
2886
2865
  success: true,
2887
2866
  schema,
2867
+ important_guidelines,
2888
2868
  timestamp: new Date().toISOString(),
2889
2869
  }),
2890
2870
  },
@@ -2892,7 +2872,7 @@ server.registerTool('get-storyboard-schema', {
2892
2872
  };
2893
2873
  }
2894
2874
  catch (error) {
2895
- return createErrorResponse(error, 'get-storyboard-schema');
2875
+ return createErrorResponse(error, 'get-schema');
2896
2876
  }
2897
2877
  });
2898
2878
  server.registerTool('do-storyboard-optimization', {
@@ -2912,7 +2892,7 @@ server.registerTool('do-storyboard-optimization', {
2912
2892
  text: JSON.stringify({
2913
2893
  content: {
2914
2894
  guideline: storyboardOptimizationGuidelines,
2915
- action: '你应当根据guideline优化story_board.json',
2895
+ action: '你应当根据guideline优化storyboard.json',
2916
2896
  },
2917
2897
  }),
2918
2898
  },
@@ -3296,180 +3276,206 @@ server.registerTool('media-analyzer', {
3296
3276
  return createErrorResponse(error, 'media-analyzer');
3297
3277
  }
3298
3278
  });
3299
- server.registerTool('image-aligner', {
3300
- title: 'Image Aligner',
3301
- description: 'Analyze image quality and alignment with prompt using AI Image Quality Inspector.',
3302
- inputSchema: {
3303
- imageFileName: zod_1.z
3304
- .string()
3305
- .describe('The image file name in materials directory to analyze.'),
3306
- sceneIndex: zod_1.z.number().min(1).describe('场景索引,从1开始的下标'),
3307
- storyBoardFile: zod_1.z
3308
- .string()
3309
- .optional()
3310
- .default('story_board.json')
3311
- .describe('故事板文件路径'),
3312
- imagePrompt: zod_1.z
3313
- .string()
3314
- .optional()
3315
- .describe('可选的图片提示词,如果提供则覆盖story_board中的提示词'),
3316
- customPrompt: zod_1.z
3317
- .string()
3318
- .optional()
3319
- .describe('可选的额外用户要求,用于补充图片质量评估的特定需求'),
3320
- },
3321
- }, async ({ imageFileName, sceneIndex, storyBoardFile = 'story_board.json', imagePrompt, customPrompt, }) => {
3322
- try {
3323
- const currentSession = await validateSession('image-aligner');
3324
- // 验证图片文件
3325
- validateImageFile(imageFileName);
3326
- // 获取图片 URL
3327
- const imageUrl = getMaterialUri(currentSession, imageFileName);
3328
- // 确定要使用的提示词
3329
- let finalPrompt = imagePrompt;
3330
- // 如果没有提供imagePrompt,则从story_board中获取
3331
- if (!imagePrompt) {
3332
- try {
3333
- const storyBoardPath = (0, node_path_1.resolve)(process.env.ZEROCUT_PROJECT_CWD || process.cwd(), projectLocalDir, storyBoardFile);
3334
- if ((0, node_fs_1.existsSync)(storyBoardPath)) {
3335
- const storyBoardContent = await (0, promises_1.readFile)(storyBoardPath, 'utf8');
3336
- const storyBoard = JSON.parse(storyBoardContent);
3337
- if (storyBoard.scenes && Array.isArray(storyBoard.scenes)) {
3338
- const scene = storyBoard.scenes[sceneIndex - 1]; // sceneIndex 从1开始,数组从0开始
3339
- if (scene) {
3340
- // 根据文件名判断优先级:若end_frame存在且imageFileName包含"_end"则优先取end_frame,否则取start_frame
3341
- if (scene.end_frame && imageFileName.includes('_end')) {
3342
- finalPrompt = scene.end_frame;
3343
- }
3344
- else {
3345
- finalPrompt = scene.start_frame || scene.end_frame;
3346
- }
3347
- if (!finalPrompt) {
3348
- return createErrorResponse(`场景 ${sceneIndex} 中未找到 start_frame 或 end_frame 提示词`, 'image-aligner');
3349
- }
3350
- }
3351
- else {
3352
- return createErrorResponse(`在 ${storyBoardFile} 中未找到场景索引 ${sceneIndex}`, 'image-aligner');
3353
- }
3354
- }
3355
- else {
3356
- return createErrorResponse(`${storyBoardFile} 文件格式不正确,缺少 scenes 数组`, 'image-aligner');
3357
- }
3358
- }
3359
- else {
3360
- return createErrorResponse(`故事板文件不存在: ${storyBoardPath}`, 'image-aligner');
3361
- }
3362
- }
3363
- catch (error) {
3364
- return createErrorResponse(`读取或解析故事板文件失败: ${error}`, 'image-aligner');
3365
- }
3366
- }
3367
- // 如果仍然没有提示词,返回错误
3368
- if (!finalPrompt) {
3369
- return createErrorResponse('未提供 imagePrompt 且无法从故事板中获取提示词', 'image-aligner');
3370
- }
3371
- // 读取图片质量检查指南
3372
- const alignerGuidelinePath = (0, node_path_1.resolve)(__dirname, './prompts/reasonings/image_aligner.md');
3373
- let alignerGuideline = '';
3374
- try {
3375
- alignerGuideline = await (0, promises_1.readFile)(alignerGuidelinePath, 'utf8');
3376
- }
3377
- catch (error) {
3378
- console.warn('无法读取图片质量检查指南:', error);
3379
- alignerGuideline =
3380
- '请对图片质量进行评估,包括构图、色彩、清晰度等方面。';
3381
- }
3382
- // 构建系统提示
3383
- const systemPrompt = `你是一个专业的AI图片质量检查员。请根据以下指南对图片进行评估:
3384
-
3385
- ${alignerGuideline}
3386
-
3387
- 请严格按照指南中的JSON格式返回评估结果。`;
3388
- // 构建用户提示
3389
- const userPrompt = `请对这张图片进行质量评估。
3390
-
3391
- 原始提示词:${finalPrompt}${customPrompt
3392
- ? `
3393
-
3394
- 额外要求:${customPrompt}`
3395
- : ''}
3396
-
3397
- 请按照指南要求,返回包含评分、问题列表和优化建议的JSON格式结果。`;
3398
- // 调用AI模型进行图片质量评估
3399
- const ai = currentSession.ai;
3400
- const completion = await ai.getCompletions({
3401
- model: 'Doubao-Seed-1.6',
3402
- messages: [
3403
- {
3404
- role: 'system',
3405
- content: systemPrompt,
3406
- },
3407
- {
3408
- role: 'user',
3409
- content: [
3410
- {
3411
- type: 'image_url',
3412
- image_url: {
3413
- url: imageUrl,
3414
- },
3415
- },
3416
- {
3417
- type: 'text',
3418
- text: userPrompt,
3419
- },
3420
- ],
3421
- },
3422
- ],
3423
- });
3424
- const result = completion.choices[0]?.message?.content;
3425
- if (!result) {
3426
- throw new Error('No response from AI model');
3427
- }
3428
- // 解析AI响应
3429
- let alignmentResult;
3430
- try {
3431
- // 尝试从响应中提取JSON
3432
- const jsonMatch = result.match(/```json\s*([\s\S]*?)\s*```/) ||
3433
- result.match(/\{[\s\S]*\}/);
3434
- if (jsonMatch) {
3435
- alignmentResult = JSON.parse(jsonMatch[1] || jsonMatch[0]);
3436
- }
3437
- else {
3438
- // 如果没有找到JSON格式,尝试直接解析整个响应
3439
- alignmentResult = JSON.parse(result);
3440
- }
3441
- }
3442
- catch (error) {
3443
- // 如果解析失败,返回原始响应
3444
- alignmentResult = {
3445
- error: 'JSON解析失败',
3446
- raw_response: result,
3447
- };
3448
- }
3449
- return {
3450
- content: [
3451
- {
3452
- type: 'text',
3453
- text: JSON.stringify({
3454
- success: true,
3455
- imageFileName,
3456
- sceneIndex,
3457
- storyBoardFile,
3458
- imagePrompt: finalPrompt,
3459
- customPrompt,
3460
- promptSource: imagePrompt ? 'manual_override' : 'story_board',
3461
- analysis: alignmentResult,
3462
- imageUrl,
3463
- nextActionSuggest: '可根据分析结果调整提示词,修改story_board后,重新生成图片。',
3464
- }),
3465
- },
3466
- ],
3467
- };
3468
- }
3469
- catch (error) {
3470
- return createErrorResponse(error, 'image-aligner');
3471
- }
3472
- });
3279
+ // server.registerTool(
3280
+ // 'image-aligner',
3281
+ // {
3282
+ // title: 'Image Aligner',
3283
+ // description:
3284
+ // 'Analyze image quality and alignment with prompt using AI Image Quality Inspector.',
3285
+ // inputSchema: {
3286
+ // imageFileName: z
3287
+ // .string()
3288
+ // .describe('The image file name in materials directory to analyze.'),
3289
+ // sceneIndex: z.number().min(1).describe('场景索引,从1开始的下标'),
3290
+ // storyBoardFile: z
3291
+ // .string()
3292
+ // .optional()
3293
+ // .default('storyboard.json')
3294
+ // .describe('故事板文件路径'),
3295
+ // imagePrompt: z
3296
+ // .string()
3297
+ // .optional()
3298
+ // .describe('可选的图片提示词,如果提供则覆盖storyboard中的提示词'),
3299
+ // customPrompt: z
3300
+ // .string()
3301
+ // .optional()
3302
+ // .describe('可选的额外用户要求,用于补充图片质量评估的特定需求'),
3303
+ // },
3304
+ // },
3305
+ // async ({
3306
+ // imageFileName,
3307
+ // sceneIndex,
3308
+ // storyBoardFile = 'storyboard.json',
3309
+ // imagePrompt,
3310
+ // customPrompt,
3311
+ // }) => {
3312
+ // try {
3313
+ // const currentSession = await validateSession('image-aligner');
3314
+ // // 验证图片文件
3315
+ // validateImageFile(imageFileName);
3316
+ // // 获取图片 URL
3317
+ // const imageUrl = getMaterialUri(currentSession, imageFileName);
3318
+ // // 确定要使用的提示词
3319
+ // let finalPrompt = imagePrompt;
3320
+ // // 如果没有提供imagePrompt,则从storyboard中获取
3321
+ // if (!imagePrompt) {
3322
+ // try {
3323
+ // const storyBoardPath = resolve(
3324
+ // process.env.ZEROCUT_PROJECT_CWD || process.cwd(),
3325
+ // projectLocalDir,
3326
+ // storyBoardFile
3327
+ // );
3328
+ // if (existsSync(storyBoardPath)) {
3329
+ // const storyBoardContent = await readFile(storyBoardPath, 'utf8');
3330
+ // const storyBoard = JSON.parse(storyBoardContent);
3331
+ // if (storyBoard.scenes && Array.isArray(storyBoard.scenes)) {
3332
+ // const scene = storyBoard.scenes[sceneIndex - 1]; // sceneIndex 从1开始,数组从0开始
3333
+ // if (scene) {
3334
+ // // 根据文件名判断优先级:若end_frame存在且imageFileName包含"_end"则优先取end_frame,否则取start_frame
3335
+ // if (scene.end_frame && imageFileName.includes('_end')) {
3336
+ // finalPrompt = scene.end_frame;
3337
+ // } else {
3338
+ // finalPrompt = scene.start_frame || scene.end_frame;
3339
+ // }
3340
+ // if (!finalPrompt) {
3341
+ // return createErrorResponse(
3342
+ // `场景 ${sceneIndex} 中未找到 start_frame 或 end_frame 提示词`,
3343
+ // 'image-aligner'
3344
+ // );
3345
+ // }
3346
+ // } else {
3347
+ // return createErrorResponse(
3348
+ // `在 ${storyBoardFile} 中未找到场景索引 ${sceneIndex}`,
3349
+ // 'image-aligner'
3350
+ // );
3351
+ // }
3352
+ // } else {
3353
+ // return createErrorResponse(
3354
+ // `${storyBoardFile} 文件格式不正确,缺少 scenes 数组`,
3355
+ // 'image-aligner'
3356
+ // );
3357
+ // }
3358
+ // } else {
3359
+ // return createErrorResponse(
3360
+ // `故事板文件不存在: ${storyBoardPath}`,
3361
+ // 'image-aligner'
3362
+ // );
3363
+ // }
3364
+ // } catch (error) {
3365
+ // return createErrorResponse(
3366
+ // `读取或解析故事板文件失败: ${error}`,
3367
+ // 'image-aligner'
3368
+ // );
3369
+ // }
3370
+ // }
3371
+ // // 如果仍然没有提示词,返回错误
3372
+ // if (!finalPrompt) {
3373
+ // return createErrorResponse(
3374
+ // '未提供 imagePrompt 且无法从故事板中获取提示词',
3375
+ // 'image-aligner'
3376
+ // );
3377
+ // }
3378
+ // // 读取图片质量检查指南
3379
+ // const alignerGuidelinePath = resolve(
3380
+ // __dirname,
3381
+ // './prompts/reasonings/image_aligner.md'
3382
+ // );
3383
+ // let alignerGuideline = '';
3384
+ // try {
3385
+ // alignerGuideline = await readFile(alignerGuidelinePath, 'utf8');
3386
+ // } catch (error) {
3387
+ // console.warn('无法读取图片质量检查指南:', error);
3388
+ // alignerGuideline =
3389
+ // '请对图片质量进行评估,包括构图、色彩、清晰度等方面。';
3390
+ // }
3391
+ // // 构建系统提示
3392
+ // const systemPrompt = `你是一个专业的AI图片质量检查员。请根据以下指南对图片进行评估:
3393
+ // ${alignerGuideline}
3394
+ // 请严格按照指南中的JSON格式返回评估结果。`;
3395
+ // // 构建用户提示
3396
+ // const userPrompt = `请对这张图片进行质量评估。
3397
+ // 原始提示词:${finalPrompt}${
3398
+ // customPrompt
3399
+ // ? `
3400
+ // 额外要求:${customPrompt}`
3401
+ // : ''
3402
+ // }
3403
+ // 请按照指南要求,返回包含评分、问题列表和优化建议的JSON格式结果。`;
3404
+ // // 调用AI模型进行图片质量评估
3405
+ // const ai = currentSession.ai;
3406
+ // const completion = await ai.getCompletions({
3407
+ // model: 'Doubao-Seed-1.6',
3408
+ // messages: [
3409
+ // {
3410
+ // role: 'system',
3411
+ // content: systemPrompt,
3412
+ // },
3413
+ // {
3414
+ // role: 'user',
3415
+ // content: [
3416
+ // {
3417
+ // type: 'image_url',
3418
+ // image_url: {
3419
+ // url: imageUrl,
3420
+ // },
3421
+ // },
3422
+ // {
3423
+ // type: 'text',
3424
+ // text: userPrompt,
3425
+ // },
3426
+ // ],
3427
+ // },
3428
+ // ],
3429
+ // });
3430
+ // const result = completion.choices[0]?.message?.content;
3431
+ // if (!result) {
3432
+ // throw new Error('No response from AI model');
3433
+ // }
3434
+ // // 解析AI响应
3435
+ // let alignmentResult;
3436
+ // try {
3437
+ // // 尝试从响应中提取JSON
3438
+ // const jsonMatch =
3439
+ // result.match(/```json\s*([\s\S]*?)\s*```/) ||
3440
+ // result.match(/\{[\s\S]*\}/);
3441
+ // if (jsonMatch) {
3442
+ // alignmentResult = JSON.parse(jsonMatch[1] || jsonMatch[0]);
3443
+ // } else {
3444
+ // // 如果没有找到JSON格式,尝试直接解析整个响应
3445
+ // alignmentResult = JSON.parse(result);
3446
+ // }
3447
+ // } catch (error) {
3448
+ // // 如果解析失败,返回原始响应
3449
+ // alignmentResult = {
3450
+ // error: 'JSON解析失败',
3451
+ // raw_response: result,
3452
+ // };
3453
+ // }
3454
+ // return {
3455
+ // content: [
3456
+ // {
3457
+ // type: 'text',
3458
+ // text: JSON.stringify({
3459
+ // success: true,
3460
+ // imageFileName,
3461
+ // sceneIndex,
3462
+ // storyBoardFile,
3463
+ // imagePrompt: finalPrompt,
3464
+ // customPrompt,
3465
+ // promptSource: imagePrompt ? 'manual_override' : 'storyboard',
3466
+ // analysis: alignmentResult,
3467
+ // imageUrl,
3468
+ // nextActionSuggest:
3469
+ // '可根据分析结果调整提示词,修改storyboard后,重新生成图片。',
3470
+ // }),
3471
+ // },
3472
+ // ],
3473
+ // };
3474
+ // } catch (error) {
3475
+ // return createErrorResponse(error, 'image-aligner');
3476
+ // }
3477
+ // }
3478
+ // );
3473
3479
  server.registerTool('audio-video-sync', {
3474
3480
  title: 'Audio Video Sync',
3475
3481
  description: 'Generate audio-video-synced video by matching video with audio. 还可以对口型。',
@@ -3640,7 +3646,7 @@ server.registerTool('generate-video-by-ref', {
3640
3646
  .describe('Array of reference image objects with name, url and type. Can be empty for text-only generation.'),
3641
3647
  duration: zod_1.z
3642
3648
  .number()
3643
- .min(2)
3649
+ .min(1)
3644
3650
  .max(16)
3645
3651
  .optional()
3646
3652
  .default(5)
@@ -3671,7 +3677,7 @@ server.registerTool('generate-video-by-ref', {
3671
3677
  storyBoardFile: zod_1.z
3672
3678
  .string()
3673
3679
  .optional()
3674
- .default('story_board.json')
3680
+ .default('storyboard.json')
3675
3681
  .describe('故事板文件路径'),
3676
3682
  skipConsistencyCheck: zod_1.z
3677
3683
  .boolean()
@@ -3696,17 +3702,17 @@ server.registerTool('generate-video-by-ref', {
3696
3702
  // 检查 storyboard 标志
3697
3703
  if (!checkStoryboardFlag && (0, node_fs_1.existsSync)(storyBoardPath)) {
3698
3704
  checkStoryboardFlag = true;
3699
- return createErrorResponse(`必须先审查生成的 story_board.json 内容,按照如下步骤:
3705
+ return createErrorResponse(`必须先审查生成的 storyboard.json 内容,按照如下步骤:
3700
3706
 
3701
3707
  1. 确保每个场景中的stage_atmosphere内容按照规则被正确融合到video_prompt中,不得遗漏
3702
3708
  2. 如有main_characters设定且包含了reference_image,或有reference_objects,需确保video_prompt描述已包含该场景相关main_characters和所有reference_objects中的物品或背景,并确保参考图具体内容已经在video_prompt中有明确描述,如果没有,可忽略。
3703
3709
  3. 如有配音,先自我检查 media_logs 中的查音频时长,确保以匹配音频时长来生成视频
3704
3710
 
3705
- 检查完上述问题后先汇报,如果有需要,应当先修改 story_board.json 内容,然后再调用 generate-video-by-ref 生成视频。注意修改 story_board 内容时,仅修改相应字段的字符串值,不要破坏JSON格式!
3711
+ 检查完上述问题后先汇报,如果有需要,应当先修改 storyboard.json 内容,然后再调用 generate-video-by-ref 生成视频。注意修改 storyboard 内容时,仅修改相应字段的字符串值,不要破坏JSON格式!
3706
3712
 
3707
3713
  再次调用 generate-video-by-ref 时,如需要参考图,要确保referenceImages使用正确(main_characters中的reference_image作为参考人物,reference_objects中的image作为参考物品或参考背景)`, 'generate-image');
3708
3714
  }
3709
- // 校验 prompt 与 story_board.json 中场景设定的一致性(如果提供了 sceneIndex)
3715
+ // 校验 prompt 与 storyboard.json 中场景设定的一致性(如果提供了 sceneIndex)
3710
3716
  if (!skipConsistencyCheck && sceneIndex) {
3711
3717
  try {
3712
3718
  if ((0, node_fs_1.existsSync)(storyBoardPath)) {
@@ -3724,7 +3730,7 @@ server.registerTool('generate-video-by-ref', {
3724
3730
  if (scene) {
3725
3731
  const videoPrompt = scene.video_prompt;
3726
3732
  if (videoPrompt && prompt !== videoPrompt) {
3727
- return createErrorResponse('视频提示词必须严格遵照story_board的设定,如果用户明确指出不需要遵守,请将skipConsistencyCheck设置为true后再次调用', 'generate-video-by-ref');
3733
+ return createErrorResponse('视频提示词必须严格遵照storyboard的设定,如果用户明确指出不需要遵守,请将skipConsistencyCheck设置为true后再次调用', 'generate-video-by-ref');
3728
3734
  }
3729
3735
  // 检查 scene.is_continuous 是否为 true
3730
3736
  if (scene.is_continuous === true) {
@@ -3791,7 +3797,7 @@ server.registerTool('generate-video-by-ref', {
3791
3797
  }
3792
3798
  }
3793
3799
  else {
3794
- console.warn(`Scene index ${sceneIndex} not found in story_board.json`);
3800
+ console.warn(`Scene index ${sceneIndex} not found in storyboard.json`);
3795
3801
  }
3796
3802
  }
3797
3803
  }
@@ -3801,7 +3807,7 @@ server.registerTool('generate-video-by-ref', {
3801
3807
  }
3802
3808
  catch (error) {
3803
3809
  console.error('Failed to validate prompt with story board:', error);
3804
- // 如果读取或解析 story_board.json 失败,继续执行但记录警告
3810
+ // 如果读取或解析 storyboard.json 失败,继续执行但记录警告
3805
3811
  }
3806
3812
  }
3807
3813
  const validatedFileName = validateFileName(saveToFileName);
@@ -4026,6 +4032,132 @@ server.registerTool('extend-video-duration', {
4026
4032
  return createErrorResponse(error, 'extend-video');
4027
4033
  }
4028
4034
  });
4035
+ server.registerTool('generate-video-by-template', {
4036
+ title: 'Generate Video by Template',
4037
+ description: 'Generate a video based on a template. The template must be a valid JSON string.',
4038
+ inputSchema: {
4039
+ purpose: zod_1.z
4040
+ .string()
4041
+ .describe('The prompt to generate the video. 自动根据意图匹配模板'),
4042
+ text_prompts: zod_1.z
4043
+ .array(zod_1.z.string().describe('Text prompt for the template to build video.'))
4044
+ .optional()
4045
+ .describe('Optional text prompts to use in the template.'),
4046
+ materials: zod_1.z
4047
+ .array(zod_1.z.string().describe('Material file name in materials directory.'))
4048
+ .optional()
4049
+ .describe('Optional materials to use in the template.'),
4050
+ saveToFileName: zod_1.z
4051
+ .string()
4052
+ .describe('The filename to save the generated video.'),
4053
+ },
4054
+ }, async ({ purpose, text_prompts, saveToFileName, materials }) => {
4055
+ try {
4056
+ const templates = {
4057
+ '7569583728302817331': '宠物唱歌',
4058
+ '7569605825011367976': '万圣节宠物弹吉他',
4059
+ };
4060
+ const currentSession = await validateSession('generate-video-by-template');
4061
+ const validatedFileName = validateFileName(saveToFileName);
4062
+ const ai = currentSession.ai;
4063
+ let completion = await ai.getCompletions({
4064
+ model: 'Doubao-Seed-1.6-flash',
4065
+ messages: [
4066
+ {
4067
+ role: 'system',
4068
+ content: `你根据用户需求,从以下模板中选择一个匹配的模板,返回模板ID:\n\n${JSON.stringify(templates)}\n\n**约束**:只输出模板ID,不需要其他解释。`,
4069
+ },
4070
+ {
4071
+ role: 'user',
4072
+ content: `用户意图:${purpose}`,
4073
+ },
4074
+ ],
4075
+ });
4076
+ const templateId = completion.choices[0]?.message?.content.trim();
4077
+ if (!templateId) {
4078
+ throw new Error('Failed to get template ID');
4079
+ }
4080
+ const workflowInfo = await ai.getCozeWorkflowInfo(templateId);
4081
+ const materialUrls = materials?.map(material => getMaterialUri(currentSession, material));
4082
+ const schema = {
4083
+ name: 'workflow_parameters',
4084
+ schema: {
4085
+ type: 'object',
4086
+ properties: {
4087
+ parameters: {
4088
+ type: 'object',
4089
+ description: 'The parameters for the workflow.',
4090
+ },
4091
+ },
4092
+ required: ['parameters'],
4093
+ },
4094
+ };
4095
+ const prompt = `你根据模板工作流输入 schema 和 prompt、materials 生成一个 JSON 字符串,作为模板工作流的参数。
4096
+
4097
+ ## **工作流输入 schema**:
4098
+ ${JSON.stringify(workflowInfo.data.workflow_detail.description)}
4099
+
4100
+ ## **prompt**:
4101
+ ${text_prompts}
4102
+
4103
+ ## **materials**:
4104
+ ${JSON.stringify(materialUrls)}`;
4105
+ completion = await ai.getCompletions({
4106
+ model: 'Doubao-Seed-1.6-flash',
4107
+ messages: [
4108
+ {
4109
+ role: 'system',
4110
+ content: prompt,
4111
+ },
4112
+ {
4113
+ role: 'user',
4114
+ content: `生成模板调用的正确parameters参数`,
4115
+ },
4116
+ ],
4117
+ response_format: {
4118
+ type: 'json_schema',
4119
+ json_schema: schema,
4120
+ },
4121
+ });
4122
+ const parameters = completion.choices[0]?.message?.content.trim();
4123
+ if (!parameters) {
4124
+ throw new Error('Failed to get parameters');
4125
+ }
4126
+ console.log(parameters);
4127
+ const result = await ai.runCozeWorkflow(templateId, JSON.parse(parameters).parameters);
4128
+ if (result.url) {
4129
+ // 保存到项目材料目录
4130
+ const uri = await saveMaterial(currentSession, result.url, validatedFileName);
4131
+ return {
4132
+ content: [
4133
+ {
4134
+ type: 'text',
4135
+ text: JSON.stringify({
4136
+ success: true,
4137
+ parameters,
4138
+ uri,
4139
+ }),
4140
+ },
4141
+ ],
4142
+ };
4143
+ }
4144
+ return {
4145
+ content: [
4146
+ {
4147
+ type: 'text',
4148
+ text: JSON.stringify({
4149
+ success: false,
4150
+ result,
4151
+ parameters,
4152
+ }),
4153
+ },
4154
+ ],
4155
+ };
4156
+ }
4157
+ catch (error) {
4158
+ return createErrorResponse(error, 'generate-video-by-template');
4159
+ }
4160
+ });
4029
4161
  server.registerTool('run-ffmpeg-command', {
4030
4162
  title: 'Run FFmpeg Command',
4031
4163
  description: 'Run ffmpeg or ffprobe commands in the sandbox environment. Only ffmpeg and ffprobe commands are allowed. The default working directory is the materials directory.',
@@ -4269,182 +4401,6 @@ server.registerTool('build-capcat-draft', {
4269
4401
  return createErrorResponse(error, 'build-capcat-draft');
4270
4402
  }
4271
4403
  });
4272
- // server.registerTool(
4273
- // 'custom-edit-draft',
4274
- // {
4275
- // title: 'Custom Edit Draft',
4276
- // description:
4277
- // 'Launch timeline editor server for custom draft editing. Starts a local server at specified port with draft file configuration.',
4278
- // inputSchema: {
4279
- // draftContentFileName: z
4280
- // .string()
4281
- // .optional()
4282
- // .default('draft_content.json')
4283
- // .describe('Draft content filename (default: draft_content.json)'),
4284
- // port: z
4285
- // .number()
4286
- // .optional()
4287
- // .default(6789)
4288
- // .describe('Server port (default: 6789)'),
4289
- // },
4290
- // },
4291
- // async ({ draftContentFileName = 'draft_content.json', port = 6789 }) => {
4292
- // try {
4293
- // // 使用项目本地目录
4294
- // const workDir = resolve(
4295
- // process.env.ZEROCUT_PROJECT_CWD || process.cwd(),
4296
- // projectLocalDir
4297
- // );
4298
- // // 检查 draft_content.json 文件是否存在
4299
- // const draftFilePath = resolve(workDir, draftContentFileName);
4300
- // if (!existsSync(draftFilePath)) {
4301
- // return createErrorResponse(
4302
- // new Error(
4303
- // `Draft content file not found: ${draftContentFileName}. Please generate draft content first using the generate-draft-content tool.`
4304
- // ),
4305
- // 'custom-edit-draft'
4306
- // );
4307
- // }
4308
- // // 备份原始的 draft_content.json 文件
4309
- // const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
4310
- // const backupFileName = `${draftContentFileName}.backup.${timestamp}`;
4311
- // const backupFilePath = resolve(workDir, backupFileName);
4312
- // try {
4313
- // const { copyFileSync } = await import('fs');
4314
- // copyFileSync(draftFilePath, backupFilePath);
4315
- // console.log(`Draft file backed up to: ${backupFileName}`);
4316
- // } catch (backupError) {
4317
- // console.warn(`Failed to backup draft file: ${backupError}`);
4318
- // // 继续执行,不因备份失败而中断
4319
- // }
4320
- // // 构建启动命令参数
4321
- // const timelineEditorPath = resolve(
4322
- // __dirname,
4323
- // '../../../dist/timeline-editor/index.js'
4324
- // );
4325
- // console.log(`Starting timeline editor server...`);
4326
- // console.log(`Working directory: ${workDir}`);
4327
- // console.log(`Draft file: ${draftContentFileName}`);
4328
- // console.log(`Server port: ${port}`);
4329
- // console.log(`Timeline editor path: ${timelineEditorPath}`);
4330
- // // 检查端口是否被占用,如果被占用则停止占用的进程
4331
- // if (await isPortInUse(port)) {
4332
- // console.log(`Port ${port} is in use, killing existing processes...`);
4333
- // await killPortProcess(port);
4334
- // }
4335
- // // 直接启动服务器进程
4336
- // const platform = os.platform();
4337
- // const nodeCommand = platform === 'win32' ? 'node.exe' : 'node';
4338
- // const serverProcess = spawn(
4339
- // nodeCommand,
4340
- // [
4341
- // timelineEditorPath,
4342
- // '--draft-file',
4343
- // draftContentFileName,
4344
- // '--project-dir',
4345
- // workDir,
4346
- // '--port',
4347
- // port.toString(),
4348
- // ],
4349
- // {
4350
- // cwd: workDir,
4351
- // stdio: 'pipe',
4352
- // shell: platform === 'win32', // 在 Windows 下使用 shell
4353
- // }
4354
- // );
4355
- // const serverUrl = `http://localhost:${port}`;
4356
- // // 等待服务器启动 - 使用健康检查 API 轮询
4357
- // await new Promise((resolve, reject) => {
4358
- // const timeout = setTimeout(() => {
4359
- // reject(new Error('Server startup timeout'));
4360
- // }, 30000); // 增加超时时间到30秒
4361
- // const checkHealth = async () => {
4362
- // try {
4363
- // const healthUrl = `${serverUrl}/health`;
4364
- // const req = http.get(healthUrl, (res: any) => {
4365
- // let data = '';
4366
- // res.on('data', (chunk: any) => {
4367
- // data += chunk;
4368
- // });
4369
- // res.on('end', () => {
4370
- // try {
4371
- // const healthData = JSON.parse(data);
4372
- // if (healthData.status === 'ok') {
4373
- // clearTimeout(timeout);
4374
- // console.log('Server health check passed');
4375
- // resolve(void 0);
4376
- // } else {
4377
- // // 继续轮询
4378
- // setTimeout(checkHealth, 1000);
4379
- // }
4380
- // } catch (parseError) {
4381
- // // 继续轮询
4382
- // setTimeout(checkHealth, 1000);
4383
- // }
4384
- // });
4385
- // });
4386
- // req.on('error', () => {
4387
- // // 服务器还未启动,继续轮询
4388
- // setTimeout(checkHealth, 1000);
4389
- // });
4390
- // req.setTimeout(2000, () => {
4391
- // req.destroy();
4392
- // // 继续轮询
4393
- // setTimeout(checkHealth, 1000);
4394
- // });
4395
- // } catch (error) {
4396
- // // 继续轮询
4397
- // setTimeout(checkHealth, 1000);
4398
- // }
4399
- // };
4400
- // serverProcess.stdout?.on('data', (data: any) => {
4401
- // console.log('Server output:', data.toString());
4402
- // });
4403
- // serverProcess.stderr?.on('data', (data: any) => {
4404
- // console.error('Server error:', data.toString());
4405
- // });
4406
- // serverProcess.on('error', (error: any) => {
4407
- // clearTimeout(timeout);
4408
- // reject(error);
4409
- // });
4410
- // // 开始健康检查轮询
4411
- // setTimeout(checkHealth, 2000); // 2秒后开始第一次检查
4412
- // });
4413
- // return {
4414
- // content: [
4415
- // {
4416
- // type: 'text',
4417
- // text: JSON.stringify(
4418
- // {
4419
- // success: true,
4420
- // message: 'Timeline editor server started successfully',
4421
- // serverUrl: serverUrl,
4422
- // draftFile: draftContentFileName,
4423
- // backupFile: backupFileName,
4424
- // projectDirectory: workDir,
4425
- // port: port,
4426
- // pid: serverProcess.pid,
4427
- // instructions: [
4428
- // `Timeline editor is now running at: ${serverUrl}`,
4429
- // 'Open the URL in your browser to edit the draft',
4430
- // 'The server will automatically save changes to the draft file',
4431
- // `Original draft file has been backed up as: ${backupFileName}`,
4432
- // `Server process ID: ${serverProcess.pid}`,
4433
- // 'The server will continue running in the background',
4434
- // ],
4435
- // },
4436
- // null,
4437
- // 2
4438
- // ),
4439
- // },
4440
- // ],
4441
- // };
4442
- // } catch (error) {
4443
- // console.error('Error starting timeline editor:', error);
4444
- // return createErrorResponse(error, 'custom-edit-draft');
4445
- // }
4446
- // }
4447
- // );
4448
4404
  async function run() {
4449
4405
  // Start receiving messages on stdin and sending messages on stdout
4450
4406
  const transport = new stdio_js_1.StdioServerTransport();