cerevox 3.0.0-beta.3 → 3.0.0-beta.30
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 +23 -16
- package/dist/core/ai.d.ts.map +1 -1
- package/dist/core/ai.js +397 -108
- package/dist/core/ai.js.map +1 -1
- package/dist/mcp/servers/helper/doubao_voices_full.js +1 -1
- package/dist/mcp/servers/prompts/image-prompt-optimizer bak.md +68 -0
- package/dist/mcp/servers/prompts/image-prompt-optimizer.md +14 -34
- package/dist/mcp/servers/prompts/rules/creative-ad.md +2 -2
- package/dist/mcp/servers/prompts/rules/expert.md +1 -1
- package/dist/mcp/servers/prompts/rules/freeform.md +2 -2
- package/dist/mcp/servers/prompts/rules/general-video.md +10 -5
- package/dist/mcp/servers/prompts/rules/story-telling.md +3 -3
- package/dist/mcp/servers/prompts/skills/workflows/general-video.md +2 -2
- package/dist/mcp/servers/prompts/skills/workflows/music-video.md +1 -1
- package/dist/mcp/servers/prompts/zerocut-core.md +0 -5
- package/dist/mcp/servers/zerocut.d.ts.map +1 -1
- package/dist/mcp/servers/zerocut.js +475 -585
- package/dist/mcp/servers/zerocut.js.map +1 -1
- package/dist/utils/coze.d.ts.map +1 -1
- package/dist/utils/coze.js +4 -1
- package/dist/utils/coze.js.map +1 -1
- package/package.json +1 -1
package/dist/core/ai.js
CHANGED
|
@@ -108,80 +108,91 @@ let AI = class AI extends base_1.BaseClass {
|
|
|
108
108
|
const data = await res.json();
|
|
109
109
|
return data;
|
|
110
110
|
}
|
|
111
|
-
async generateImageSeries(options
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
`;
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
111
|
+
// async generateImageSeries(options: {
|
|
112
|
+
// prompts: string | string[];
|
|
113
|
+
// refPrefix?: string; // 参考图前缀,默认 ''
|
|
114
|
+
// size?: string;
|
|
115
|
+
// watermark?: boolean;
|
|
116
|
+
// image?: string[]; // 参考图(可多张)
|
|
117
|
+
// max_count?: number; // 最大生成数量,默认 15
|
|
118
|
+
// onProgress?: (metaData: any) => void;
|
|
119
|
+
// }) {
|
|
120
|
+
// try {
|
|
121
|
+
// if (Array.isArray(options.prompts)) {
|
|
122
|
+
// const count = options.prompts.length;
|
|
123
|
+
// options.prompts = options.prompts
|
|
124
|
+
// .map((p, i) => `图片${i + 1}: ${p.trim()}`)
|
|
125
|
+
// .join('\n');
|
|
126
|
+
// options.prompts = `生成${count}张图片\n${options.prompts.trim()}`;
|
|
127
|
+
// }
|
|
128
|
+
// if (options.refPrefix) {
|
|
129
|
+
// options.prompts = `${options.refPrefix}
|
|
130
|
+
// 参考以上图片,执行以下各场景绘图:
|
|
131
|
+
// ${options.prompts};
|
|
132
|
+
// `;
|
|
133
|
+
// }
|
|
134
|
+
// const max_count = options.max_count ?? 15;
|
|
135
|
+
// const payload = {
|
|
136
|
+
// prompt: options.prompts,
|
|
137
|
+
// size: options.size ?? '1280x720',
|
|
138
|
+
// watermark: options.watermark ?? false,
|
|
139
|
+
// image: options.image,
|
|
140
|
+
// max_images: max_count,
|
|
141
|
+
// };
|
|
142
|
+
// // 启动心跳机制
|
|
143
|
+
// let heartbeatInterval: NodeJS.Timeout | null = null;
|
|
144
|
+
// if (options.onProgress) {
|
|
145
|
+
// heartbeatInterval = setInterval(() => {
|
|
146
|
+
// options.onProgress?.({});
|
|
147
|
+
// }, 60000); // 每60秒调用一次
|
|
148
|
+
// }
|
|
149
|
+
// try {
|
|
150
|
+
// const res = await this.session.sandbox.request(
|
|
151
|
+
// '/ai/image/sequential_generate',
|
|
152
|
+
// {
|
|
153
|
+
// method: 'POST',
|
|
154
|
+
// headers: {
|
|
155
|
+
// 'Content-Type': 'application/json',
|
|
156
|
+
// },
|
|
157
|
+
// body: JSON.stringify(payload),
|
|
158
|
+
// }
|
|
159
|
+
// );
|
|
160
|
+
// const data = await res.json();
|
|
161
|
+
// // 清除心跳定时器
|
|
162
|
+
// if (heartbeatInterval) {
|
|
163
|
+
// clearInterval(heartbeatInterval);
|
|
164
|
+
// }
|
|
165
|
+
// if (data.data) {
|
|
166
|
+
// const urls = data.data
|
|
167
|
+
// .map((item: any) => item.url)
|
|
168
|
+
// .filter((url: any) => url?.trim());
|
|
169
|
+
// for (const url of urls) {
|
|
170
|
+
// this.session.track('Image Generated', { url });
|
|
171
|
+
// }
|
|
172
|
+
// return {
|
|
173
|
+
// prompt: options.prompts,
|
|
174
|
+
// data,
|
|
175
|
+
// urls,
|
|
176
|
+
// };
|
|
177
|
+
// }
|
|
178
|
+
// return data;
|
|
179
|
+
// } catch (error) {
|
|
180
|
+
// // 确保在出错时也清除心跳定时器
|
|
181
|
+
// if (heartbeatInterval) {
|
|
182
|
+
// clearInterval(heartbeatInterval);
|
|
183
|
+
// }
|
|
184
|
+
// throw error;
|
|
185
|
+
// }
|
|
186
|
+
// } catch (error) {
|
|
187
|
+
// this.logger.error('generateImage error', error);
|
|
188
|
+
// return { error: `generateImage error: ${error}` };
|
|
189
|
+
// }
|
|
190
|
+
// }
|
|
184
191
|
async generateImage(options) {
|
|
192
|
+
if (options.type === 'line-sketch') {
|
|
193
|
+
options.prompt = `请根据以下描述绘制一张线稿:\n\n${options.prompt}\n\n画面除了主体和提到的物品之外,不要画其他任何东西,留白`;
|
|
194
|
+
options.type = 'banana';
|
|
195
|
+
}
|
|
185
196
|
try {
|
|
186
197
|
const res = await this.session.sandbox.request(`/ai/image/generate`, {
|
|
187
198
|
method: 'POST',
|
|
@@ -191,18 +202,20 @@ ${options.prompts};
|
|
|
191
202
|
body: JSON.stringify(options),
|
|
192
203
|
});
|
|
193
204
|
const data = await res.json();
|
|
194
|
-
if (data.data
|
|
195
|
-
|
|
205
|
+
if (data.data) {
|
|
206
|
+
const urls = data.data
|
|
207
|
+
.map((item) => item.url)
|
|
208
|
+
.filter((url) => url?.trim());
|
|
209
|
+
for (const url of urls) {
|
|
210
|
+
this.session.track('Image Generated', { url });
|
|
211
|
+
}
|
|
196
212
|
return {
|
|
197
|
-
|
|
213
|
+
prompt: options.prompt,
|
|
214
|
+
// data,
|
|
215
|
+
urls,
|
|
198
216
|
};
|
|
199
217
|
}
|
|
200
|
-
|
|
201
|
-
// banana
|
|
202
|
-
this.session.track('Image Generated', data);
|
|
203
|
-
return data;
|
|
204
|
-
}
|
|
205
|
-
throw new Error(`generateImage error: ${JSON.stringify(data)}`);
|
|
218
|
+
return data;
|
|
206
219
|
}
|
|
207
220
|
catch (error) {
|
|
208
221
|
this.logger.error('generateImage error', error);
|
|
@@ -210,28 +223,6 @@ ${options.prompts};
|
|
|
210
223
|
throw error;
|
|
211
224
|
}
|
|
212
225
|
}
|
|
213
|
-
async generateLineSketch(options) {
|
|
214
|
-
try {
|
|
215
|
-
const res = await this.session.sandbox.request(`/ai/image/line_sketch`, {
|
|
216
|
-
method: 'POST',
|
|
217
|
-
headers: {
|
|
218
|
-
'Content-Type': 'application/json',
|
|
219
|
-
},
|
|
220
|
-
body: JSON.stringify(options),
|
|
221
|
-
});
|
|
222
|
-
const data = await res.json();
|
|
223
|
-
if (data.url) {
|
|
224
|
-
this.session.track('Line Sketch Generated', data);
|
|
225
|
-
return data;
|
|
226
|
-
}
|
|
227
|
-
throw new Error(`generateLineSketch error: ${JSON.stringify(data)}`);
|
|
228
|
-
}
|
|
229
|
-
catch (error) {
|
|
230
|
-
this.logger.error('generateLineSketch error', error);
|
|
231
|
-
this.session.track('Line Sketch Generated', { error: error.message });
|
|
232
|
-
throw error;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
226
|
async extendVideo(options) {
|
|
236
227
|
try {
|
|
237
228
|
const waitForFinish = options.waitForFinish ?? true;
|
|
@@ -299,6 +290,27 @@ ${options.prompts};
|
|
|
299
290
|
return { error: error.message };
|
|
300
291
|
}
|
|
301
292
|
}
|
|
293
|
+
async generateZeroCutMusicVideo(options) {
|
|
294
|
+
try {
|
|
295
|
+
const waitForFinish = options.waitForFinish ?? true;
|
|
296
|
+
const workflowId = '7574088452263591988';
|
|
297
|
+
const parameters = {
|
|
298
|
+
prompt: options.prompt,
|
|
299
|
+
singer_apperance: options.singerPhoto,
|
|
300
|
+
orientation: options.orientation,
|
|
301
|
+
resolution: options.resolution,
|
|
302
|
+
music_duration: options.duration,
|
|
303
|
+
origin_song: options.originalSong,
|
|
304
|
+
gen_subtitles: options.genSubtitles,
|
|
305
|
+
};
|
|
306
|
+
const result = await this.runCozeWorkflow(workflowId, parameters, options.onProgress, 1500, waitForFinish);
|
|
307
|
+
return result;
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
this.logger.error('Generate ZeroCut Video error', error);
|
|
311
|
+
return { error: error.message, content: null };
|
|
312
|
+
}
|
|
313
|
+
}
|
|
302
314
|
// 用自己的模型生成 video
|
|
303
315
|
async generateZeroCutVideo(options) {
|
|
304
316
|
try {
|
|
@@ -738,7 +750,6 @@ ${timbre ? `timbre: ${timbre}` : ''}`;
|
|
|
738
750
|
async textToSpeechVolc(options) {
|
|
739
751
|
const speech_rate = options.speed ?? 0; // -50 ~ 100
|
|
740
752
|
const loudness_rate = options.volume ?? 0; // -50 ~ 100
|
|
741
|
-
const emotion = options.emotion ?? 'storytelling';
|
|
742
753
|
const explicit_language = options.explicit_language ?? 'zh';
|
|
743
754
|
// 随机停顿 300 ~ 500 ms 模拟人对话
|
|
744
755
|
const silence_duration = options.silence_duration ?? Math.floor(Math.random() * 200 + 300);
|
|
@@ -753,10 +764,10 @@ ${timbre ? `timbre: ${timbre}` : ''}`;
|
|
|
753
764
|
text: options.text,
|
|
754
765
|
speech_rate,
|
|
755
766
|
loudness_rate,
|
|
756
|
-
emotion,
|
|
757
767
|
silence_duration,
|
|
758
768
|
explicit_language,
|
|
759
769
|
context_texts: options.context_texts,
|
|
770
|
+
version: options.version,
|
|
760
771
|
}),
|
|
761
772
|
});
|
|
762
773
|
const data = await res.json();
|
|
@@ -1279,6 +1290,25 @@ ${timbre ? `timbre: ${timbre}` : ''}`;
|
|
|
1279
1290
|
return { error: error.message };
|
|
1280
1291
|
}
|
|
1281
1292
|
}
|
|
1293
|
+
async splitVideoAndAudio(options) {
|
|
1294
|
+
try {
|
|
1295
|
+
const res = await this.session.sandbox.request(`/ai/video/split`, {
|
|
1296
|
+
method: 'POST',
|
|
1297
|
+
headers: {
|
|
1298
|
+
'Content-Type': 'application/json',
|
|
1299
|
+
},
|
|
1300
|
+
body: JSON.stringify({
|
|
1301
|
+
url: options.videoUrl,
|
|
1302
|
+
}),
|
|
1303
|
+
});
|
|
1304
|
+
const data = await res.json();
|
|
1305
|
+
return data;
|
|
1306
|
+
}
|
|
1307
|
+
catch (error) {
|
|
1308
|
+
this.logger.error('splitVideoAndAudio error', error);
|
|
1309
|
+
return { error: error.message };
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1282
1312
|
async getCozeWorkflowInfo(workflowId) {
|
|
1283
1313
|
return (0, coze_1.getWorkflowInfo)(workflowId, this.session.sandbox.token);
|
|
1284
1314
|
}
|
|
@@ -1317,7 +1347,7 @@ ${timbre ? `timbre: ${timbre}` : ''}`;
|
|
|
1317
1347
|
}
|
|
1318
1348
|
async waitForWorkflowFinish(options) {
|
|
1319
1349
|
try {
|
|
1320
|
-
const { taskUrl, onProgress, interval = 1500, timeout =
|
|
1350
|
+
const { taskUrl, onProgress, interval = 1500, timeout = 1800000, } = options;
|
|
1321
1351
|
const result = await Promise.race([
|
|
1322
1352
|
waitForWorkflowFinish(taskUrl, this.session.sandbox.token, this.logger, onProgress, interval),
|
|
1323
1353
|
new Promise(resolve => {
|
|
@@ -1325,6 +1355,7 @@ ${timbre ? `timbre: ${timbre}` : ''}`;
|
|
|
1325
1355
|
resolve({
|
|
1326
1356
|
status: 'running',
|
|
1327
1357
|
reason: `wait timeout ${timeout}ms`,
|
|
1358
|
+
nextAction: '可继续等待',
|
|
1328
1359
|
taskUrl,
|
|
1329
1360
|
});
|
|
1330
1361
|
}, timeout);
|
|
@@ -1359,7 +1390,7 @@ ${timbre ? `timbre: ${timbre}` : ''}`;
|
|
|
1359
1390
|
}
|
|
1360
1391
|
async waitForVideoTaskComplete(options) {
|
|
1361
1392
|
try {
|
|
1362
|
-
const { taskUrl, onProgress, interval = 1500, traceWorkflow = true, timeout =
|
|
1393
|
+
const { taskUrl, onProgress, interval = 1500, traceWorkflow = true, timeout = 1800000, } = options;
|
|
1363
1394
|
if (taskUrl.startsWith('https://api.coze.cn/v1/workflows/')) {
|
|
1364
1395
|
return this.waitForWorkflowFinish(options);
|
|
1365
1396
|
}
|
|
@@ -1378,6 +1409,7 @@ ${timbre ? `timbre: ${timbre}` : ''}`;
|
|
|
1378
1409
|
resolve({
|
|
1379
1410
|
status: 'running',
|
|
1380
1411
|
reason: `wait timeout ${timeout}ms`,
|
|
1412
|
+
nextAction: '可继续等待',
|
|
1381
1413
|
taskUrl,
|
|
1382
1414
|
});
|
|
1383
1415
|
}, timeout);
|
|
@@ -1482,6 +1514,263 @@ ${timbre ? `timbre: ${timbre}` : ''}`;
|
|
|
1482
1514
|
async listContextRules() {
|
|
1483
1515
|
return (await this.session.sandbox.request('/ai/personas')).json();
|
|
1484
1516
|
}
|
|
1517
|
+
async listVoices() {
|
|
1518
|
+
const volcano_tts_2_voices = [
|
|
1519
|
+
{
|
|
1520
|
+
id: 'zh_female_vv_uranus_bigtts',
|
|
1521
|
+
description: ['语调平稳、咬字柔和、自带治愈安抚力的女声音色'],
|
|
1522
|
+
gender: 'female',
|
|
1523
|
+
languages: ['zh', 'en'],
|
|
1524
|
+
type: 'volcano_tts_2',
|
|
1525
|
+
},
|
|
1526
|
+
{
|
|
1527
|
+
id: 'zh_female_xiaohe_uranus_bigtts',
|
|
1528
|
+
description: ['声线甜美有活力的妹妹,活泼开朗,笑容明媚。'],
|
|
1529
|
+
gender: 'female',
|
|
1530
|
+
languages: ['zh', 'en'],
|
|
1531
|
+
type: 'volcano_tts_2',
|
|
1532
|
+
},
|
|
1533
|
+
{
|
|
1534
|
+
id: 'zh_male_m191_uranus_bigtts',
|
|
1535
|
+
description: ['声音磁性的男生,成熟理性,做事有条理,让人信赖。'],
|
|
1536
|
+
gender: 'male',
|
|
1537
|
+
languages: ['zh', 'en'],
|
|
1538
|
+
type: 'volcano_tts_2',
|
|
1539
|
+
},
|
|
1540
|
+
{
|
|
1541
|
+
id: 'zh_male_taocheng_uranus_bigtts',
|
|
1542
|
+
description: ['眉目清朗男大,清澈温润有朝气,开朗真诚。'],
|
|
1543
|
+
gender: 'male',
|
|
1544
|
+
languages: ['zh', 'en'],
|
|
1545
|
+
type: 'volcano_tts_2',
|
|
1546
|
+
},
|
|
1547
|
+
{
|
|
1548
|
+
id: 'zh_female_xueayi_saturn_bigtts',
|
|
1549
|
+
description: ['温柔又有力量的音色,陪孩子在故事里勇敢探索!'],
|
|
1550
|
+
gender: 'female',
|
|
1551
|
+
languages: ['zh', 'en'],
|
|
1552
|
+
type: 'volcano_tts_2',
|
|
1553
|
+
},
|
|
1554
|
+
{
|
|
1555
|
+
id: 'zh_male_dayi_saturn_bigtts',
|
|
1556
|
+
description: ['语气沉稳有力、咬字清晰厚重、自带可靠安全感的男声音色'],
|
|
1557
|
+
gender: 'male',
|
|
1558
|
+
languages: ['zh', 'en'],
|
|
1559
|
+
type: 'volcano_tts_2',
|
|
1560
|
+
},
|
|
1561
|
+
{
|
|
1562
|
+
id: 'zh_female_mizai_saturn_bigtts',
|
|
1563
|
+
description: ['语调沉稳、咬字扎实、自带踏实和包容感的女声音色'],
|
|
1564
|
+
gender: 'female',
|
|
1565
|
+
languages: ['zh', 'en'],
|
|
1566
|
+
type: 'volcano_tts_2',
|
|
1567
|
+
},
|
|
1568
|
+
{
|
|
1569
|
+
id: 'zh_female_jitangnv_saturn_bigtts',
|
|
1570
|
+
description: [
|
|
1571
|
+
'鸡汤女:语气轻软、尾音轻落、带有自然呼吸感且十分亲切的女声音色',
|
|
1572
|
+
],
|
|
1573
|
+
gender: 'female',
|
|
1574
|
+
languages: ['zh', 'en'],
|
|
1575
|
+
type: 'volcano_tts_2',
|
|
1576
|
+
},
|
|
1577
|
+
{
|
|
1578
|
+
id: 'zh_female_meilinvyou_saturn_bigtts',
|
|
1579
|
+
description: ['魅力女友:嗲软轻飘的轻熟美人,妩媚有耐心,温柔勾人。'],
|
|
1580
|
+
gender: 'female',
|
|
1581
|
+
languages: ['zh', 'en'],
|
|
1582
|
+
type: 'volcano_tts_2',
|
|
1583
|
+
},
|
|
1584
|
+
{
|
|
1585
|
+
id: 'zh_female_santongyongns_saturn_bigtts',
|
|
1586
|
+
description: [
|
|
1587
|
+
'流畅女声:语调顺滑自然、咬字利落不拖沓、适配多种场景的百搭女声音色',
|
|
1588
|
+
],
|
|
1589
|
+
gender: 'female',
|
|
1590
|
+
languages: ['zh', 'en'],
|
|
1591
|
+
type: 'volcano_tts_2',
|
|
1592
|
+
},
|
|
1593
|
+
{
|
|
1594
|
+
id: 'zh_male_ruyayichen_saturn_bigtts',
|
|
1595
|
+
description: [
|
|
1596
|
+
'儒雅逸辰:语气温润有礼、咬字文雅舒缓、自带书卷气的儒雅男声音色',
|
|
1597
|
+
],
|
|
1598
|
+
gender: 'male',
|
|
1599
|
+
languages: ['zh', 'en'],
|
|
1600
|
+
type: 'volcano_tts_2',
|
|
1601
|
+
},
|
|
1602
|
+
{
|
|
1603
|
+
id: 'saturn_zh_female_keainvsheng_tob',
|
|
1604
|
+
description: ['可爱女生:可爱的妹妹,性格活泼,举动讨喜。'],
|
|
1605
|
+
gender: 'female',
|
|
1606
|
+
languages: ['zh', 'en'],
|
|
1607
|
+
type: 'volcano_tts_2',
|
|
1608
|
+
},
|
|
1609
|
+
{
|
|
1610
|
+
id: 'saturn_zh_female_tiaopigongzhu_tob',
|
|
1611
|
+
description: [
|
|
1612
|
+
'调皮公主:语调灵动跳脱、尾音带娇俏、古灵精怪爱撒娇的少女音色',
|
|
1613
|
+
],
|
|
1614
|
+
gender: 'female',
|
|
1615
|
+
languages: ['zh', 'en'],
|
|
1616
|
+
type: 'volcano_tts_2',
|
|
1617
|
+
},
|
|
1618
|
+
{
|
|
1619
|
+
id: 'saturn_zh_male_shuanglangshaonian_tob',
|
|
1620
|
+
description: [
|
|
1621
|
+
'爽朗少年:语气洪亮开阔、咬字干脆爽朗、阳光率真不扭捏的少年音色',
|
|
1622
|
+
],
|
|
1623
|
+
gender: 'male',
|
|
1624
|
+
languages: ['zh', 'en'],
|
|
1625
|
+
type: 'volcano_tts_2',
|
|
1626
|
+
},
|
|
1627
|
+
{
|
|
1628
|
+
id: 'saturn_zh_male_tiancaitongzhuo_tob',
|
|
1629
|
+
description: [
|
|
1630
|
+
'天才同桌:语气明快利落、咬字清晰带活力、聪明机敏又毒舌的少年音色',
|
|
1631
|
+
],
|
|
1632
|
+
gender: 'male',
|
|
1633
|
+
languages: ['zh', 'en'],
|
|
1634
|
+
type: 'volcano_tts_2',
|
|
1635
|
+
},
|
|
1636
|
+
{
|
|
1637
|
+
id: 'saturn_zh_female_cancan_tob',
|
|
1638
|
+
description: [
|
|
1639
|
+
'知性灿灿:语气温柔平缓、带有些许软绵感却又善解人意的少女音色',
|
|
1640
|
+
],
|
|
1641
|
+
gender: 'female',
|
|
1642
|
+
languages: ['zh', 'en'],
|
|
1643
|
+
type: 'volcano_tts_2',
|
|
1644
|
+
},
|
|
1645
|
+
];
|
|
1646
|
+
const list = await (await this.session.sandbox.request('/ai/voices/minimax')).json();
|
|
1647
|
+
const minimax_voices = list
|
|
1648
|
+
.filter((v) => v.description.length > 0)
|
|
1649
|
+
.map((v) => {
|
|
1650
|
+
const description = v.description[0];
|
|
1651
|
+
let gender;
|
|
1652
|
+
let languages = ['zh'];
|
|
1653
|
+
if (description.includes('男') ||
|
|
1654
|
+
description.includes('哥') ||
|
|
1655
|
+
description.includes('弟')) {
|
|
1656
|
+
gender = 'male';
|
|
1657
|
+
}
|
|
1658
|
+
else if (description.includes('女') ||
|
|
1659
|
+
description.includes('姐') ||
|
|
1660
|
+
description.includes('妹')) {
|
|
1661
|
+
gender = 'female';
|
|
1662
|
+
}
|
|
1663
|
+
if (description.includes('英语') || v.voice_id.startsWith('English')) {
|
|
1664
|
+
languages = ['en'];
|
|
1665
|
+
}
|
|
1666
|
+
else if (description.includes('日语')) {
|
|
1667
|
+
languages = ['ja'];
|
|
1668
|
+
}
|
|
1669
|
+
else if (description.includes('韩语')) {
|
|
1670
|
+
languages = ['ko'];
|
|
1671
|
+
}
|
|
1672
|
+
else if (description.includes('西班牙语')) {
|
|
1673
|
+
languages = ['es'];
|
|
1674
|
+
}
|
|
1675
|
+
else if (description.includes('葡萄牙语')) {
|
|
1676
|
+
languages = ['pt'];
|
|
1677
|
+
}
|
|
1678
|
+
else if (description.includes('荷兰语')) {
|
|
1679
|
+
languages = ['nl'];
|
|
1680
|
+
}
|
|
1681
|
+
else if (description.includes('越南语')) {
|
|
1682
|
+
languages = ['vi'];
|
|
1683
|
+
}
|
|
1684
|
+
else if (description.includes('俄语')) {
|
|
1685
|
+
languages = ['ru'];
|
|
1686
|
+
}
|
|
1687
|
+
else if (description.includes('印度尼西亚语')) {
|
|
1688
|
+
languages = ['id'];
|
|
1689
|
+
}
|
|
1690
|
+
else if (description.includes('德语')) {
|
|
1691
|
+
languages = ['de'];
|
|
1692
|
+
}
|
|
1693
|
+
else if (description.includes('法语')) {
|
|
1694
|
+
languages = ['fr'];
|
|
1695
|
+
}
|
|
1696
|
+
else if (description.includes('意大利语')) {
|
|
1697
|
+
languages = ['it'];
|
|
1698
|
+
}
|
|
1699
|
+
else if (description.includes('阿拉伯语')) {
|
|
1700
|
+
languages = ['ar'];
|
|
1701
|
+
}
|
|
1702
|
+
else if (description.includes('土耳其语')) {
|
|
1703
|
+
languages = ['tr'];
|
|
1704
|
+
}
|
|
1705
|
+
else if (description.includes('乌克兰语')) {
|
|
1706
|
+
languages = ['uk'];
|
|
1707
|
+
}
|
|
1708
|
+
return {
|
|
1709
|
+
id: v.voice_id,
|
|
1710
|
+
gender,
|
|
1711
|
+
languages,
|
|
1712
|
+
description: v.description[0],
|
|
1713
|
+
};
|
|
1714
|
+
});
|
|
1715
|
+
return [...volcano_tts_2_voices, ...minimax_voices];
|
|
1716
|
+
}
|
|
1717
|
+
async pickVoice(options) {
|
|
1718
|
+
const voices = await this.listVoices();
|
|
1719
|
+
const prompt = `根据用户输入的语音上下文内容,从音色库数据中选择最合适的语音音色,将该音色ID和选择该音色的理由返回。
|
|
1720
|
+
|
|
1721
|
+
## 重要原则
|
|
1722
|
+
在合适的情况下,尽量优先采用 volcano_tts_2 类型的语音
|
|
1723
|
+
|
|
1724
|
+
## 音色库数据
|
|
1725
|
+
${JSON.stringify(voices)}
|
|
1726
|
+
|
|
1727
|
+
## 输出格式
|
|
1728
|
+
{
|
|
1729
|
+
"voice_id": "音色ID",
|
|
1730
|
+
"reason": "选择该音色理由"
|
|
1731
|
+
}
|
|
1732
|
+
`;
|
|
1733
|
+
const schema = {
|
|
1734
|
+
name: 'emotion_schema',
|
|
1735
|
+
schema: {
|
|
1736
|
+
type: 'object',
|
|
1737
|
+
properties: {
|
|
1738
|
+
voice_id: {
|
|
1739
|
+
type: 'string',
|
|
1740
|
+
description: '从语音列表中选出的语音ID',
|
|
1741
|
+
},
|
|
1742
|
+
reason: {
|
|
1743
|
+
type: 'string',
|
|
1744
|
+
description: '选择的理由',
|
|
1745
|
+
},
|
|
1746
|
+
},
|
|
1747
|
+
required: ['voice_id', 'reason'],
|
|
1748
|
+
},
|
|
1749
|
+
};
|
|
1750
|
+
const payload = {
|
|
1751
|
+
model: 'Doubao-Seed-1.6',
|
|
1752
|
+
messages: [
|
|
1753
|
+
{
|
|
1754
|
+
role: 'system',
|
|
1755
|
+
content: prompt,
|
|
1756
|
+
},
|
|
1757
|
+
{
|
|
1758
|
+
role: 'user',
|
|
1759
|
+
content: `## 语音上下文
|
|
1760
|
+
|
|
1761
|
+
${options.prompt}
|
|
1762
|
+
`,
|
|
1763
|
+
},
|
|
1764
|
+
],
|
|
1765
|
+
response_format: {
|
|
1766
|
+
type: 'json_schema',
|
|
1767
|
+
json_schema: schema,
|
|
1768
|
+
},
|
|
1769
|
+
};
|
|
1770
|
+
const completion = await this.getCompletions(payload);
|
|
1771
|
+
const voiceObj = JSON.parse(completion.choices[0]?.message?.content ?? '{}');
|
|
1772
|
+
return voiceObj;
|
|
1773
|
+
}
|
|
1485
1774
|
};
|
|
1486
1775
|
exports.AI = AI;
|
|
1487
1776
|
exports.AI = AI = __decorate([
|