cerevox 2.29.0 → 2.30.0

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.
@@ -2303,135 +2303,45 @@ server.registerTool('generate-sound-effect', {
2303
2303
  return createErrorResponse(error, 'generate-sound-effect');
2304
2304
  }
2305
2305
  });
2306
- server.registerTool('generate-song', {
2307
- title: 'Generate Song',
2308
- description: 'Generate a song with vocals and customizable parameters.',
2306
+ server.registerTool('generate-music', {
2307
+ title: 'Generate Music',
2308
+ description: 'Generate the music. Include background music or song.',
2309
2309
  inputSchema: {
2310
+ prompt: zod_1.z.string().describe('The prompt to generate.'),
2310
2311
  type: zod_1.z
2312
+ .enum(['bgm', 'song'])
2313
+ .describe('The type of music. Defaults to background music.')
2314
+ .default('bgm'),
2315
+ model: zod_1.z
2311
2316
  .enum(['doubao', 'minimax'])
2312
- .default('doubao')
2313
- .describe('The model type of AI to use.'),
2314
- lyrics: zod_1.z.string().describe(`The lyrics to generate the song.
2315
-
2316
- - 完整歌词通常包括以下桥段:
2317
- - 前奏: intro,歌曲开始的音乐部分,主要用于引导歌曲的整体氛围。
2318
- - 主歌: verse,通常在前奏之后,歌曲中叙述歌曲故事或主题的部分。
2319
- - 副歌: chorus,一般在主歌之后,旋律有记忆点和感染力,是整首歌的高潮,进一步强化歌曲的主题和情感。
2320
- - 间奏: inst,歌曲中的纯音乐段落,用于连接不同的演唱部分。
2321
- - 尾奏: outro,歌曲结束后的音乐段落,用于营造歌曲结束的氛围。
2322
- - 桥段: bridge,通常出现在歌曲中段或接近结尾处,是一个过渡部分,用于连接不同的歌曲段落。
2323
-
2324
- ### 歌词示例 lyrics.txt
2325
-
2326
- \`\`\`txt
2327
- [intro]
2328
- [verse]
2329
- 记得那一天 那一天我们相恋
2330
- 说好彼此都不说再见
2331
- 遵守诺言 用心去相恋
2332
- 我为你撑伞 你为我取暖
2333
- [inst]
2334
- [chorus]
2335
- 当我把心交给你的那一天
2336
- 你却消失在我的眼前
2337
- 事到如今已经过了好多年
2338
- 是否你还像从前
2339
- [outro]
2340
- \`\`\`
2341
- `),
2317
+ .optional()
2318
+ .describe('The model to use. Defaults to doubao.')
2319
+ .default('doubao'),
2342
2320
  duration: zod_1.z
2343
2321
  .number()
2344
2322
  .min(30)
2345
2323
  .max(240)
2346
- .describe('The duration of the song in seconds (30-240).'),
2347
- genre: zod_1.z
2348
- .enum([
2349
- 'Folk',
2350
- 'Pop',
2351
- 'Rock',
2352
- 'Chinese Style',
2353
- 'Hip Hop/Rap',
2354
- 'R&B/Soul',
2355
- 'Punk',
2356
- 'Electronic',
2357
- 'Jazz',
2358
- 'Reggae',
2359
- 'DJ',
2360
- 'Pop Punk',
2361
- 'Disco',
2362
- 'Future Bass',
2363
- 'Pop Rap',
2364
- 'Trap Rap',
2365
- 'R&B Rap',
2366
- 'Chinoiserie Electronic',
2367
- 'GuFeng Music',
2368
- 'Pop Rock',
2369
- 'Jazz Pop',
2370
- 'Bossa Nova',
2371
- 'Contemporary R&B',
2372
- ])
2373
- .optional()
2374
- .describe('The genre of the song.'),
2375
- mood: zod_1.z
2376
- .enum([
2377
- 'Happy',
2378
- 'Dynamic/Energetic',
2379
- 'Sentimental/Melancholic/Lonely',
2380
- 'Inspirational/Hopeful',
2381
- 'Nostalgic/Memory',
2382
- 'Excited',
2383
- 'Sorrow/Sad',
2384
- 'Chill',
2385
- 'Relaxing',
2386
- 'Romantic',
2387
- 'Miss',
2388
- 'Groovy/Funky',
2389
- 'Dreamy/Ethereal',
2390
- 'Calm/Relaxing',
2391
- ])
2392
- .optional()
2393
- .describe('The mood of the song.'),
2394
- gender: zod_1.z
2395
- .enum(['Female', 'Male'])
2396
- .optional()
2397
- .describe('The gender of the vocalist.'),
2398
- timbre: zod_1.z
2399
- .enum([
2400
- 'Warm',
2401
- 'Bright',
2402
- 'Husky',
2403
- 'Electrified voice',
2404
- 'Sweet_AUDIO_TIMBRE',
2405
- 'Cute_AUDIO_TIMBRE',
2406
- 'Loud and sonorous',
2407
- 'Powerful',
2408
- 'Sexy/Lazy',
2409
- ])
2410
- .optional()
2411
- .describe('The timbre/voice quality of the vocalist.'),
2324
+ .describe('The duration of the bgm or music.'),
2412
2325
  skipCopyCheck: zod_1.z
2413
2326
  .boolean()
2414
- .optional()
2415
2327
  .default(false)
2416
2328
  .describe('Whether to skip copyright check.'),
2417
2329
  saveToFileName: zod_1.z.string().describe('The filename to save.'),
2418
2330
  },
2419
- }, async ({ type = 'doubao', lyrics, duration, genre, mood, gender, timbre, skipCopyCheck, saveToFileName, }, context) => {
2331
+ }, async ({ prompt, type, model, duration, skipCopyCheck, saveToFileName }, context) => {
2420
2332
  try {
2421
2333
  // 验证session状态
2422
- const currentSession = await validateSession('generate-song');
2334
+ const currentSession = await validateSession('generate-music');
2423
2335
  const validatedFileName = validateFileName(saveToFileName);
2424
- console.log(`Generating Song with lyrics: ${lyrics.substring(0, 100)}... (${duration}s, genre: ${genre || 'auto'}, mood: ${mood || 'auto'})`);
2336
+ console.log(`Generating Music with prompt: ${prompt.substring(0, 100)}... (${duration}s)`);
2425
2337
  const ai = currentSession.ai;
2426
2338
  let progress = 0;
2427
- const res = await ai.generateSong({
2428
- type,
2429
- lyrics: lyrics.trim(),
2430
- duration,
2431
- genre,
2432
- mood,
2433
- gender,
2434
- timbre,
2339
+ if (type === 'bgm' && duration > 120) {
2340
+ throw new Error('BGM duration must be at most 120 seconds.');
2341
+ }
2342
+ const finalPrompt = `${prompt.trim()} ${type === 'bgm' ? `纯音乐无歌词,时长${duration}秒` : `时长${duration}秒,使用${model}模型`}`;
2343
+ const res = await ai.generateMusic({
2344
+ prompt: finalPrompt,
2435
2345
  skipCopyCheck,
2436
2346
  onProgress: async (metaData) => {
2437
2347
  try {
@@ -2443,18 +2353,12 @@ server.registerTool('generate-song', {
2443
2353
  },
2444
2354
  });
2445
2355
  if (!res) {
2446
- throw new Error('Failed to generate Song: no response from AI service');
2356
+ throw new Error('Failed to generate BGM: no response from AI service');
2447
2357
  }
2448
2358
  if (res.url) {
2449
- console.log('Song generated successfully, saving to materials...');
2359
+ console.log('BGM generated successfully, saving to materials...');
2450
2360
  const uri = await saveMaterial(currentSession, res.url, validatedFileName);
2451
- if (!res.captions) {
2452
- // 歌词获取失败,获取字幕
2453
- res.captions = await ai.voiceToCaptions({
2454
- url: res.url,
2455
- });
2456
- }
2457
- const { url, duration: songDuration, captions, ...opts } = res;
2361
+ const { url, duration: bgmDuration, captions, ...opts } = res;
2458
2362
  // 保存captions到本地
2459
2363
  if (captions) {
2460
2364
  const captionsText = JSON.stringify(captions, null, 2);
@@ -2463,103 +2367,13 @@ server.registerTool('generate-song', {
2463
2367
  // 保存到本地
2464
2368
  await (0, promises_1.writeFile)(localPath, captionsText);
2465
2369
  }
2466
- const result = {
2467
- success: true,
2468
- // source: url,
2469
- uri,
2470
- durationMs: Math.floor((songDuration || duration) * 1000),
2471
- lyrics,
2472
- requestedDuration: duration,
2473
- genre,
2474
- mood,
2475
- gender,
2476
- timbre,
2477
- captions,
2478
- timestamp: new Date().toISOString(),
2479
- ...opts,
2480
- };
2481
- // Update media_logs.json
2482
- try {
2483
- await updateMediaLogs(currentSession, validatedFileName, result, 'audio');
2484
- }
2485
- catch (error) {
2486
- console.warn(`Failed to update media_logs.json for ${validatedFileName}:`, error);
2487
- }
2488
- return {
2489
- content: [
2490
- {
2491
- type: 'text',
2492
- text: JSON.stringify(result),
2493
- },
2494
- ],
2495
- };
2496
- }
2497
- else {
2498
- console.warn('Song generation completed but no URL returned');
2499
- return {
2500
- content: [
2501
- {
2502
- type: 'text',
2503
- text: JSON.stringify({
2504
- success: false,
2505
- error: 'No Song URL returned from AI service',
2506
- response: res,
2507
- timestamp: new Date().toISOString(),
2508
- }),
2509
- },
2510
- ],
2511
- };
2512
- }
2513
- }
2514
- catch (error) {
2515
- return createErrorResponse(error, 'generate-song');
2516
- }
2517
- });
2518
- server.registerTool('generate-bgm', {
2519
- title: 'Generate BGM',
2520
- description: 'Generate the bgm.',
2521
- inputSchema: {
2522
- prompt: zod_1.z.string().describe('The prompt to generate.'),
2523
- duration: zod_1.z
2524
- .number()
2525
- .min(30)
2526
- .max(120)
2527
- .describe('The duration of the bgm.'),
2528
- saveToFileName: zod_1.z.string().describe('The filename to save.'),
2529
- },
2530
- }, async ({ prompt, duration, saveToFileName }, context) => {
2531
- try {
2532
- // 验证session状态
2533
- const currentSession = await validateSession('generate-bgm');
2534
- const validatedFileName = validateFileName(saveToFileName);
2535
- console.log(`Generating BGM with prompt: ${prompt.substring(0, 100)}... (${duration}s)`);
2536
- const ai = currentSession.ai;
2537
- let progress = 0;
2538
- const res = await ai.generateBGM({
2539
- prompt: prompt.trim(),
2540
- duration,
2541
- onProgress: async (metaData) => {
2542
- try {
2543
- await sendProgress(context, metaData.Result?.Progress ?? ++progress, metaData.Result?.Progress ? 100 : undefined, JSON.stringify(metaData));
2544
- }
2545
- catch (progressError) {
2546
- console.warn('Failed to send progress update:', progressError);
2547
- }
2548
- },
2549
- });
2550
- if (!res) {
2551
- throw new Error('Failed to generate BGM: no response from AI service');
2552
- }
2553
- if (res.url) {
2554
- console.log('BGM generated successfully, saving to materials...');
2555
- const uri = await saveMaterial(currentSession, res.url, validatedFileName);
2556
- const { url, duration: bgmDuration, ...opts } = res;
2557
2370
  const result = {
2558
2371
  success: true,
2559
2372
  // source: url,
2560
2373
  uri,
2561
2374
  durationMs: Math.floor((bgmDuration || duration) * 1000),
2562
2375
  prompt,
2376
+ captions,
2563
2377
  requestedDuration: duration,
2564
2378
  timestamp: new Date().toISOString(),
2565
2379
  ...opts,