cerevox 2.38.0 → 2.38.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.
@@ -53,7 +53,6 @@ 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_http_1 = __importDefault(require("node:http"));
57
56
  const node_child_process_1 = require("node:child_process");
58
57
  const node_util_1 = require("node:util");
59
58
  const os = __importStar(require("node:os"));
@@ -451,7 +450,7 @@ server.registerTool('retrieve-rules-context', {
451
450
  'stage-play',
452
451
  'story-telling',
453
452
  'creative-ad',
454
- 'professional',
453
+ 'expert',
455
454
  'material-creation',
456
455
  'freeform',
457
456
  'custom',
@@ -464,9 +463,9 @@ server.registerTool('retrieve-rules-context', {
464
463
  - stage-play 创建舞台播放视频
465
464
  - story-telling 创建故事讲述视频
466
465
  - creative-ad 创建创意广告视频
467
- - professional 创建专业视频
468
- - material-creation 素材创作模式
469
- - freeform 自由创作模式
466
+ - expert 以专家模式创建视频,必须用户主动要求才触发
467
+ - material-creation 素材创作模式,必须用户主动要求才触发
468
+ - freeform 自由创作模式,必须用户主动要求才触发
470
469
  - custom 自定义模式`),
471
470
  },
472
471
  }, async ({ purpose }) => {
@@ -492,7 +491,7 @@ server.registerTool('retrieve-rules-context', {
492
491
  purpose !== 'stage-play' &&
493
492
  purpose !== 'story-telling' &&
494
493
  purpose !== 'creative-ad' &&
495
- purpose !== 'professional' &&
494
+ purpose !== 'expert' &&
496
495
  purpose !== 'material-creation' &&
497
496
  purpose !== 'freeform') {
498
497
  return createErrorResponse(`Project rules file not found: ${projectRulesFile}`, 'retrieve-rules-context');
@@ -2183,6 +2182,21 @@ server.registerTool('generate-video', {
2183
2182
  ],
2184
2183
  };
2185
2184
  }
2185
+ else if (res.execute_id) {
2186
+ return {
2187
+ content: [
2188
+ {
2189
+ type: 'text',
2190
+ text: JSON.stringify({
2191
+ success: true,
2192
+ message: '该视频生成任务已提交,它是异步任务,且执行时间较长,你应立即调用工具 wait-for-workflow-finish 来等待任务结束,如该工具调用超时,你应立即再次重新调用直到任务结束。',
2193
+ execute_id: res.execute_id,
2194
+ workflow_id: res.workflow_id,
2195
+ }),
2196
+ },
2197
+ ],
2198
+ };
2199
+ }
2186
2200
  else {
2187
2201
  console.warn('Video generation completed but no URL returned');
2188
2202
  return {
@@ -2205,6 +2219,73 @@ server.registerTool('generate-video', {
2205
2219
  return createErrorResponse(error, 'generate-video');
2206
2220
  }
2207
2221
  });
2222
+ server.registerTool('wait-for-workflow-finish', {
2223
+ title: 'Wait Workflow Done',
2224
+ description: 'Wait for a workflow to complete.',
2225
+ inputSchema: {
2226
+ workflowID: zod_1.z
2227
+ .string()
2228
+ .describe('The workflow_id of the workflow to wait for.'),
2229
+ executeID: zod_1.z
2230
+ .string()
2231
+ .describe('The execute_id of the workflow to wait for.'),
2232
+ saveToFileName: zod_1.z
2233
+ .string()
2234
+ .describe('The file name to save the video to.'),
2235
+ },
2236
+ }, async ({ workflowID, executeID, saveToFileName }, context) => {
2237
+ try {
2238
+ const currentSession = await validateSession('wait-for-workflow-finish');
2239
+ const ai = currentSession.ai;
2240
+ let progress = 0;
2241
+ const res = await ai.waitForWorkflowFinish({
2242
+ workflowId: workflowID,
2243
+ executeId: executeID,
2244
+ onProgress: async (metaData) => {
2245
+ try {
2246
+ await sendProgress(context, ++progress, undefined, JSON.stringify(metaData));
2247
+ }
2248
+ catch (progressError) {
2249
+ console.warn('Failed to send progress update:', progressError);
2250
+ }
2251
+ },
2252
+ });
2253
+ if (res.url) {
2254
+ const uri = await saveMaterial(currentSession, res.url, saveToFileName);
2255
+ // Update media_logs.json
2256
+ try {
2257
+ await updateMediaLogs(currentSession, saveToFileName, res, 'audio');
2258
+ }
2259
+ catch (error) {
2260
+ console.warn(`Failed to update media_logs.json for ${saveToFileName}:`, error);
2261
+ }
2262
+ return {
2263
+ content: [
2264
+ {
2265
+ type: 'text',
2266
+ text: JSON.stringify({
2267
+ success: true,
2268
+ uri,
2269
+ source: res.url,
2270
+ duration: res.duration,
2271
+ }),
2272
+ },
2273
+ ],
2274
+ };
2275
+ }
2276
+ return {
2277
+ content: [
2278
+ {
2279
+ type: 'text',
2280
+ text: JSON.stringify(res),
2281
+ },
2282
+ ],
2283
+ };
2284
+ }
2285
+ catch (error) {
2286
+ return createErrorResponse(error, 'wait-for-workflow-finish');
2287
+ }
2288
+ });
2208
2289
  server.registerTool('generate-sound-effect', {
2209
2290
  title: 'Generate Sound Effect',
2210
2291
  description: 'Generate sound effect with text prompt.',
@@ -4213,163 +4294,182 @@ server.registerTool('run-ffmpeg-command', {
4213
4294
  return createErrorResponse(error, 'run-ffmpeg-command');
4214
4295
  }
4215
4296
  });
4216
- server.registerTool('custom-edit-draft', {
4217
- title: 'Custom Edit Draft',
4218
- description: 'Launch timeline editor server for custom draft editing. Starts a local server at specified port with draft file configuration.',
4219
- inputSchema: {
4220
- draftContentFileName: zod_1.z
4221
- .string()
4222
- .optional()
4223
- .default('draft_content.json')
4224
- .describe('Draft content filename (default: draft_content.json)'),
4225
- port: zod_1.z
4226
- .number()
4227
- .optional()
4228
- .default(6789)
4229
- .describe('Server port (default: 6789)'),
4230
- },
4231
- }, async ({ draftContentFileName = 'draft_content.json', port = 6789 }) => {
4232
- try {
4233
- // 使用项目本地目录
4234
- const workDir = (0, node_path_1.resolve)(process.env.ZEROCUT_PROJECT_CWD || process.cwd(), projectLocalDir);
4235
- // 检查 draft_content.json 文件是否存在
4236
- const draftFilePath = (0, node_path_1.resolve)(workDir, draftContentFileName);
4237
- if (!(0, node_fs_1.existsSync)(draftFilePath)) {
4238
- return createErrorResponse(new Error(`Draft content file not found: ${draftContentFileName}. Please generate draft content first using the generate-draft-content tool.`), 'custom-edit-draft');
4239
- }
4240
- // 备份原始的 draft_content.json 文件
4241
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
4242
- const backupFileName = `${draftContentFileName}.backup.${timestamp}`;
4243
- const backupFilePath = (0, node_path_1.resolve)(workDir, backupFileName);
4244
- try {
4245
- const { copyFileSync } = await Promise.resolve().then(() => __importStar(require('fs')));
4246
- copyFileSync(draftFilePath, backupFilePath);
4247
- console.log(`Draft file backed up to: ${backupFileName}`);
4248
- }
4249
- catch (backupError) {
4250
- console.warn(`Failed to backup draft file: ${backupError}`);
4251
- // 继续执行,不因备份失败而中断
4252
- }
4253
- // 构建启动命令参数
4254
- const timelineEditorPath = (0, node_path_1.resolve)(__dirname, '../../../dist/timeline-editor/index.js');
4255
- console.log(`Starting timeline editor server...`);
4256
- console.log(`Working directory: ${workDir}`);
4257
- console.log(`Draft file: ${draftContentFileName}`);
4258
- console.log(`Server port: ${port}`);
4259
- console.log(`Timeline editor path: ${timelineEditorPath}`);
4260
- // 检查端口是否被占用,如果被占用则停止占用的进程
4261
- if (await isPortInUse(port)) {
4262
- console.log(`Port ${port} is in use, killing existing processes...`);
4263
- await killPortProcess(port);
4264
- }
4265
- // 直接启动服务器进程
4266
- const platform = os.platform();
4267
- const nodeCommand = platform === 'win32' ? 'node.exe' : 'node';
4268
- const serverProcess = (0, node_child_process_1.spawn)(nodeCommand, [
4269
- timelineEditorPath,
4270
- '--draft-file',
4271
- draftContentFileName,
4272
- '--project-dir',
4273
- workDir,
4274
- '--port',
4275
- port.toString(),
4276
- ], {
4277
- cwd: workDir,
4278
- stdio: 'pipe',
4279
- shell: platform === 'win32', // 在 Windows 下使用 shell
4280
- });
4281
- const serverUrl = `http://localhost:${port}`;
4282
- // 等待服务器启动 - 使用健康检查 API 轮询
4283
- await new Promise((resolve, reject) => {
4284
- const timeout = setTimeout(() => {
4285
- reject(new Error('Server startup timeout'));
4286
- }, 30000); // 增加超时时间到30秒
4287
- const checkHealth = async () => {
4288
- try {
4289
- const healthUrl = `${serverUrl}/health`;
4290
- const req = node_http_1.default.get(healthUrl, (res) => {
4291
- let data = '';
4292
- res.on('data', (chunk) => {
4293
- data += chunk;
4294
- });
4295
- res.on('end', () => {
4296
- try {
4297
- const healthData = JSON.parse(data);
4298
- if (healthData.status === 'ok') {
4299
- clearTimeout(timeout);
4300
- console.log('Server health check passed');
4301
- resolve(void 0);
4302
- }
4303
- else {
4304
- // 继续轮询
4305
- setTimeout(checkHealth, 1000);
4306
- }
4307
- }
4308
- catch (parseError) {
4309
- // 继续轮询
4310
- setTimeout(checkHealth, 1000);
4311
- }
4312
- });
4313
- });
4314
- req.on('error', () => {
4315
- // 服务器还未启动,继续轮询
4316
- setTimeout(checkHealth, 1000);
4317
- });
4318
- req.setTimeout(2000, () => {
4319
- req.destroy();
4320
- // 继续轮询
4321
- setTimeout(checkHealth, 1000);
4322
- });
4323
- }
4324
- catch (error) {
4325
- // 继续轮询
4326
- setTimeout(checkHealth, 1000);
4327
- }
4328
- };
4329
- serverProcess.stdout?.on('data', (data) => {
4330
- console.log('Server output:', data.toString());
4331
- });
4332
- serverProcess.stderr?.on('data', (data) => {
4333
- console.error('Server error:', data.toString());
4334
- });
4335
- serverProcess.on('error', (error) => {
4336
- clearTimeout(timeout);
4337
- reject(error);
4338
- });
4339
- // 开始健康检查轮询
4340
- setTimeout(checkHealth, 2000); // 2秒后开始第一次检查
4341
- });
4342
- return {
4343
- content: [
4344
- {
4345
- type: 'text',
4346
- text: JSON.stringify({
4347
- success: true,
4348
- message: 'Timeline editor server started successfully',
4349
- serverUrl: serverUrl,
4350
- draftFile: draftContentFileName,
4351
- backupFile: backupFileName,
4352
- projectDirectory: workDir,
4353
- port: port,
4354
- pid: serverProcess.pid,
4355
- instructions: [
4356
- `Timeline editor is now running at: ${serverUrl}`,
4357
- 'Open the URL in your browser to edit the draft',
4358
- 'The server will automatically save changes to the draft file',
4359
- `Original draft file has been backed up as: ${backupFileName}`,
4360
- `Server process ID: ${serverProcess.pid}`,
4361
- 'The server will continue running in the background',
4362
- ],
4363
- }, null, 2),
4364
- },
4365
- ],
4366
- };
4367
- }
4368
- catch (error) {
4369
- console.error('Error starting timeline editor:', error);
4370
- return createErrorResponse(error, 'custom-edit-draft');
4371
- }
4372
- });
4297
+ // server.registerTool(
4298
+ // 'custom-edit-draft',
4299
+ // {
4300
+ // title: 'Custom Edit Draft',
4301
+ // description:
4302
+ // 'Launch timeline editor server for custom draft editing. Starts a local server at specified port with draft file configuration.',
4303
+ // inputSchema: {
4304
+ // draftContentFileName: z
4305
+ // .string()
4306
+ // .optional()
4307
+ // .default('draft_content.json')
4308
+ // .describe('Draft content filename (default: draft_content.json)'),
4309
+ // port: z
4310
+ // .number()
4311
+ // .optional()
4312
+ // .default(6789)
4313
+ // .describe('Server port (default: 6789)'),
4314
+ // },
4315
+ // },
4316
+ // async ({ draftContentFileName = 'draft_content.json', port = 6789 }) => {
4317
+ // try {
4318
+ // // 使用项目本地目录
4319
+ // const workDir = resolve(
4320
+ // process.env.ZEROCUT_PROJECT_CWD || process.cwd(),
4321
+ // projectLocalDir
4322
+ // );
4323
+ // // 检查 draft_content.json 文件是否存在
4324
+ // const draftFilePath = resolve(workDir, draftContentFileName);
4325
+ // if (!existsSync(draftFilePath)) {
4326
+ // return createErrorResponse(
4327
+ // new Error(
4328
+ // `Draft content file not found: ${draftContentFileName}. Please generate draft content first using the generate-draft-content tool.`
4329
+ // ),
4330
+ // 'custom-edit-draft'
4331
+ // );
4332
+ // }
4333
+ // // 备份原始的 draft_content.json 文件
4334
+ // const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
4335
+ // const backupFileName = `${draftContentFileName}.backup.${timestamp}`;
4336
+ // const backupFilePath = resolve(workDir, backupFileName);
4337
+ // try {
4338
+ // const { copyFileSync } = await import('fs');
4339
+ // copyFileSync(draftFilePath, backupFilePath);
4340
+ // console.log(`Draft file backed up to: ${backupFileName}`);
4341
+ // } catch (backupError) {
4342
+ // console.warn(`Failed to backup draft file: ${backupError}`);
4343
+ // // 继续执行,不因备份失败而中断
4344
+ // }
4345
+ // // 构建启动命令参数
4346
+ // const timelineEditorPath = resolve(
4347
+ // __dirname,
4348
+ // '../../../dist/timeline-editor/index.js'
4349
+ // );
4350
+ // console.log(`Starting timeline editor server...`);
4351
+ // console.log(`Working directory: ${workDir}`);
4352
+ // console.log(`Draft file: ${draftContentFileName}`);
4353
+ // console.log(`Server port: ${port}`);
4354
+ // console.log(`Timeline editor path: ${timelineEditorPath}`);
4355
+ // // 检查端口是否被占用,如果被占用则停止占用的进程
4356
+ // if (await isPortInUse(port)) {
4357
+ // console.log(`Port ${port} is in use, killing existing processes...`);
4358
+ // await killPortProcess(port);
4359
+ // }
4360
+ // // 直接启动服务器进程
4361
+ // const platform = os.platform();
4362
+ // const nodeCommand = platform === 'win32' ? 'node.exe' : 'node';
4363
+ // const serverProcess = spawn(
4364
+ // nodeCommand,
4365
+ // [
4366
+ // timelineEditorPath,
4367
+ // '--draft-file',
4368
+ // draftContentFileName,
4369
+ // '--project-dir',
4370
+ // workDir,
4371
+ // '--port',
4372
+ // port.toString(),
4373
+ // ],
4374
+ // {
4375
+ // cwd: workDir,
4376
+ // stdio: 'pipe',
4377
+ // shell: platform === 'win32', // 在 Windows 下使用 shell
4378
+ // }
4379
+ // );
4380
+ // const serverUrl = `http://localhost:${port}`;
4381
+ // // 等待服务器启动 - 使用健康检查 API 轮询
4382
+ // await new Promise((resolve, reject) => {
4383
+ // const timeout = setTimeout(() => {
4384
+ // reject(new Error('Server startup timeout'));
4385
+ // }, 30000); // 增加超时时间到30秒
4386
+ // const checkHealth = async () => {
4387
+ // try {
4388
+ // const healthUrl = `${serverUrl}/health`;
4389
+ // const req = http.get(healthUrl, (res: any) => {
4390
+ // let data = '';
4391
+ // res.on('data', (chunk: any) => {
4392
+ // data += chunk;
4393
+ // });
4394
+ // res.on('end', () => {
4395
+ // try {
4396
+ // const healthData = JSON.parse(data);
4397
+ // if (healthData.status === 'ok') {
4398
+ // clearTimeout(timeout);
4399
+ // console.log('Server health check passed');
4400
+ // resolve(void 0);
4401
+ // } else {
4402
+ // // 继续轮询
4403
+ // setTimeout(checkHealth, 1000);
4404
+ // }
4405
+ // } catch (parseError) {
4406
+ // // 继续轮询
4407
+ // setTimeout(checkHealth, 1000);
4408
+ // }
4409
+ // });
4410
+ // });
4411
+ // req.on('error', () => {
4412
+ // // 服务器还未启动,继续轮询
4413
+ // setTimeout(checkHealth, 1000);
4414
+ // });
4415
+ // req.setTimeout(2000, () => {
4416
+ // req.destroy();
4417
+ // // 继续轮询
4418
+ // setTimeout(checkHealth, 1000);
4419
+ // });
4420
+ // } catch (error) {
4421
+ // // 继续轮询
4422
+ // setTimeout(checkHealth, 1000);
4423
+ // }
4424
+ // };
4425
+ // serverProcess.stdout?.on('data', (data: any) => {
4426
+ // console.log('Server output:', data.toString());
4427
+ // });
4428
+ // serverProcess.stderr?.on('data', (data: any) => {
4429
+ // console.error('Server error:', data.toString());
4430
+ // });
4431
+ // serverProcess.on('error', (error: any) => {
4432
+ // clearTimeout(timeout);
4433
+ // reject(error);
4434
+ // });
4435
+ // // 开始健康检查轮询
4436
+ // setTimeout(checkHealth, 2000); // 2秒后开始第一次检查
4437
+ // });
4438
+ // return {
4439
+ // content: [
4440
+ // {
4441
+ // type: 'text',
4442
+ // text: JSON.stringify(
4443
+ // {
4444
+ // success: true,
4445
+ // message: 'Timeline editor server started successfully',
4446
+ // serverUrl: serverUrl,
4447
+ // draftFile: draftContentFileName,
4448
+ // backupFile: backupFileName,
4449
+ // projectDirectory: workDir,
4450
+ // port: port,
4451
+ // pid: serverProcess.pid,
4452
+ // instructions: [
4453
+ // `Timeline editor is now running at: ${serverUrl}`,
4454
+ // 'Open the URL in your browser to edit the draft',
4455
+ // 'The server will automatically save changes to the draft file',
4456
+ // `Original draft file has been backed up as: ${backupFileName}`,
4457
+ // `Server process ID: ${serverProcess.pid}`,
4458
+ // 'The server will continue running in the background',
4459
+ // ],
4460
+ // },
4461
+ // null,
4462
+ // 2
4463
+ // ),
4464
+ // },
4465
+ // ],
4466
+ // };
4467
+ // } catch (error) {
4468
+ // console.error('Error starting timeline editor:', error);
4469
+ // return createErrorResponse(error, 'custom-edit-draft');
4470
+ // }
4471
+ // }
4472
+ // );
4373
4473
  async function run() {
4374
4474
  // Start receiving messages on stdin and sending messages on stdout
4375
4475
  const transport = new stdio_js_1.StdioServerTransport();