gpt-sovits-sdk
Version:
Node.js SDK for GPT-SoVITS API
502 lines (501 loc) • 22.4 kB
JavaScript
;
/**
* GPT-SoVITS SDK 直接返回文件的接口测试脚本
*
* 这个脚本专注于测试直接返回二进制数据的API端点,如获取音频文件和直接TTS
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const index_1 = require("./index");
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));
// 创建输出目录
const outputDir = path.join(__dirname, '../test-output/direct');
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// 创建客户端实例
const client = (0, index_1.createClient)({
baseUrl: 'http://127.0.0.1:9880', // 默认API地址
timeout: 60000, // 设置超时时间为60秒
debug: true, // 启用调试输出
retries: 2 // 设置重试次数
});
/**
* 测试获取音频文件
*/
async function testGetAudio() {
console.log('=== 测试获取音频文件 ===');
try {
// 首先,我们需要获取一个可用的音频文件路径
// 可以通过先执行TTS来获取一个音频文件
console.log('执行TTS以获取音频文件...');
// 获取情感参考音频列表
const emotionResponse = await client.getEmotionReferenceAudios();
if (!emotionResponse || !emotionResponse.data || !emotionResponse.data.referenceAudios || emotionResponse.data.referenceAudios.length === 0) {
console.log('没有找到可用的情感参考音频,跳过测试');
return false;
}
// 选择第一个音频
const refAudio = emotionResponse.data.referenceAudios[0];
console.log(`选择参考音频: ${refAudio.name}`);
// 获取可用模型
const modelsResponse = await client.getModels();
if (!modelsResponse || !modelsResponse.data ||
!modelsResponse.data.gpt_models || !modelsResponse.data.sovits_models ||
modelsResponse.data.gpt_models.length === 0 || modelsResponse.data.sovits_models.length === 0) {
console.log('没有找到可用的模型,跳过测试');
return false;
}
// 选择模型
const gptModel = modelsResponse.data.gpt_models[0].path;
const sovitsModel = modelsResponse.data.sovits_models[0].path;
console.log(`选择GPT模型: ${gptModel}`);
console.log(`选择SoVITS模型: ${sovitsModel}`);
// 设置模型
await client.setGptModel(gptModel);
await client.setSovitsModel(sovitsModel);
// 执行TTS
const ttsResponse = await client.textToSpeech({
text: '这是一个测试获取音频文件的示例。',
textLang: index_1.TextLanguage.CHINESE,
refAudioPath: refAudio.id,
promptLang: index_1.TextLanguage.CHINESE,
mediaType: index_1.MediaType.WAV,
gptModel: gptModel,
sovitsModel: sovitsModel
});
if (!ttsResponse || !ttsResponse.audio_path) {
console.log('TTS未返回有效的音频路径,跳过测试');
return false;
}
const audioPath = ttsResponse.audio_path;
console.log(`生成的音频文件路径: ${audioPath}`);
// 测试获取音频文件(返回ArrayBuffer)
console.log('\n测试获取音频文件(返回ArrayBuffer)...');
const audioData = await client.getAudio(audioPath);
if (!audioData) {
console.log('❌ 获取音频文件失败');
return false;
}
if (audioData instanceof ArrayBuffer) {
console.log(`✅ 成功获取音频文件,大小: ${audioData.byteLength} 字节`);
}
else {
console.log(`✅ 成功获取音频文件,路径: ${audioData}`);
if (fs.existsSync(audioData)) {
const fileStats = fs.statSync(audioData);
console.log(`文件大小: ${fileStats.size} 字节`);
}
}
// 测试获取音频文件并保存到本地
console.log('\n测试获取音频文件并保存到本地...');
const outputPath = path.join(outputDir, `get_audio_${Date.now()}.wav`);
const savedPath = await client.getAudio(audioPath, outputPath);
if (!savedPath) {
console.log('❌ 保存音频文件失败');
return false;
}
if (typeof savedPath === 'string' && fs.existsSync(savedPath)) {
console.log(`✅ 成功保存音频文件到: ${savedPath}`);
const fileStats = fs.statSync(savedPath);
console.log(`文件大小: ${fileStats.size} 字节`);
}
else {
console.log('❌ 保存音频文件失败或返回的不是有效路径');
return false;
}
return true;
}
catch (error) {
console.error('❌ 获取音频文件测试失败:', error);
if (error instanceof Error) {
console.error('错误信息:', error.message);
console.error('错误堆栈:', error.stack);
}
return false;
}
}
/**
* 测试直接TTS
*/
async function testDirectTTS() {
console.log('\n=== 测试直接TTS ===');
try {
// 获取情感参考音频列表
const emotionResponse = await client.getEmotionReferenceAudios();
if (!emotionResponse || !emotionResponse.data || !emotionResponse.data.referenceAudios || emotionResponse.data.referenceAudios.length === 0) {
console.log('没有找到可用的情感参考音频,跳过测试');
return false;
}
// 选择第一个音频
const refAudio = emotionResponse.data.referenceAudios[0];
console.log(`选择参考音频: ${refAudio.name}`);
// 获取可用模型
const modelsResponse = await client.getModels();
if (!modelsResponse || !modelsResponse.data ||
!modelsResponse.data.gpt_models || !modelsResponse.data.sovits_models ||
modelsResponse.data.gpt_models.length === 0 || modelsResponse.data.sovits_models.length === 0) {
console.log('没有找到可用的模型,跳过测试');
return false;
}
// 选择模型
const gptModel = modelsResponse.data.gpt_models[0].path;
const sovitsModel = modelsResponse.data.sovits_models[0].path;
console.log(`选择GPT模型: ${gptModel}`);
console.log(`选择SoVITS模型: ${sovitsModel}`);
// 设置模型
await client.setGptModel(gptModel);
await client.setSovitsModel(sovitsModel);
// 测试直接TTS(返回ArrayBuffer)
console.log('\n测试直接TTS(返回ArrayBuffer)...');
const audioData = await client.textToSpeechDirect({
text: '这是一个测试直接TTS的示例,返回ArrayBuffer。',
textLang: index_1.TextLanguage.CHINESE,
refAudioPath: refAudio.id,
promptLang: index_1.TextLanguage.CHINESE,
mediaType: index_1.MediaType.WAV,
gptModel: gptModel,
sovitsModel: sovitsModel
});
if (!audioData) {
console.log('❌ 直接TTS失败');
return false;
}
if (audioData instanceof ArrayBuffer) {
console.log(`✅ 成功执行直接TTS,返回数据大小: ${audioData.byteLength} 字节`);
}
else {
console.log(`✅ 成功执行直接TTS,返回路径: ${audioData}`);
if (fs.existsSync(audioData)) {
const fileStats = fs.statSync(audioData);
console.log(`文件大小: ${fileStats.size} 字节`);
}
}
// 测试直接TTS并保存到本地
console.log('\n测试直接TTS并保存到本地...');
const outputPath = path.join(outputDir, `direct_tts_${Date.now()}.wav`);
const savedPath = await client.textToSpeechDirect({
text: '这是一个测试直接TTS的示例,保存到本地文件。',
textLang: index_1.TextLanguage.CHINESE,
refAudioPath: refAudio.id,
promptLang: index_1.TextLanguage.CHINESE,
mediaType: index_1.MediaType.WAV,
gptModel: gptModel,
sovitsModel: sovitsModel
}, outputPath);
if (!savedPath) {
console.log('❌ 保存直接TTS音频文件失败');
return false;
}
if (typeof savedPath === 'string' && fs.existsSync(savedPath)) {
console.log(`✅ 成功保存直接TTS音频文件到: ${savedPath}`);
const fileStats = fs.statSync(savedPath);
console.log(`文件大小: ${fileStats.size} 字节`);
}
else {
console.log('❌ 保存直接TTS音频文件失败或返回的不是有效路径');
return false;
}
return true;
}
catch (error) {
console.error('❌ 直接TTS测试失败:', error);
if (error instanceof Error) {
console.error('错误信息:', error.message);
console.error('错误堆栈:', error.stack);
}
return false;
}
}
/**
* 测试不同媒体类型
*/
async function testDifferentMediaTypes() {
console.log('\n=== 测试不同媒体类型 ===');
try {
// 获取情感参考音频列表
const emotionResponse = await client.getEmotionReferenceAudios();
if (!emotionResponse || !emotionResponse.data || !emotionResponse.data.referenceAudios || emotionResponse.data.referenceAudios.length === 0) {
console.log('没有找到可用的情感参考音频,跳过测试');
return false;
}
// 选择第一个音频
const refAudio = emotionResponse.data.referenceAudios[0];
console.log(`选择参考音频: ${refAudio.name}`);
// 获取可用模型
const modelsResponse = await client.getModels();
if (!modelsResponse || !modelsResponse.data ||
!modelsResponse.data.gpt_models || !modelsResponse.data.sovits_models ||
modelsResponse.data.gpt_models.length === 0 || modelsResponse.data.sovits_models.length === 0) {
console.log('没有找到可用的模型,跳过测试');
return false;
}
// 选择模型
const gptModel = modelsResponse.data.gpt_models[0].path;
const sovitsModel = modelsResponse.data.sovits_models[0].path;
// 设置模型
await client.setGptModel(gptModel);
await client.setSovitsModel(sovitsModel);
// 测试不同的媒体类型
const mediaTypes = [index_1.MediaType.WAV, index_1.MediaType.MP3, index_1.MediaType.OGG];
for (const mediaType of mediaTypes) {
console.log(`\n测试媒体类型: ${mediaType}...`);
try {
// 注意:OGG格式在非流式模式下不支持,预期会失败
if (mediaType === index_1.MediaType.OGG) {
console.log('⚠️ 注意: OGG格式在非流式模式下不支持,预期会失败');
}
const outputPath = path.join(outputDir, `media_type_${mediaType}_${Date.now()}.${mediaType}`);
const savedPath = await client.textToSpeechDirect({
text: `这是一个测试${mediaType}格式的示例。`,
textLang: index_1.TextLanguage.CHINESE,
refAudioPath: refAudio.id,
promptLang: index_1.TextLanguage.CHINESE,
mediaType: mediaType,
gptModel: gptModel,
sovitsModel: sovitsModel
}, outputPath);
if (!savedPath) {
console.log(`❌ ${mediaType}格式测试失败`);
continue;
}
if (typeof savedPath === 'string' && fs.existsSync(savedPath)) {
console.log(`✅ 成功生成${mediaType}格式音频: ${savedPath}`);
const fileStats = fs.statSync(savedPath);
console.log(`文件大小: ${fileStats.size} 字节`);
}
else {
console.log(`❌ ${mediaType}格式测试失败或返回的不是有效路径`);
}
}
catch (mediaError) {
if (mediaType === index_1.MediaType.OGG && mediaError instanceof Error &&
(mediaError.message.includes('OGG格式不支持非流式模式') || mediaError.message.includes('400'))) {
console.log(`ℹ️ OGG格式测试预期失败: OGG格式不支持非流式模式,这是预期的行为`);
}
else {
console.error(`❌ ${mediaType}格式测试失败:`, mediaError);
}
}
}
return true;
}
catch (error) {
console.error('❌ 媒体类型测试失败:', error);
if (error instanceof Error) {
console.error('错误信息:', error.message);
console.error('错误堆栈:', error.stack);
}
return false;
}
}
/**
* 测试日文语音生成
*/
async function testJapaneseVoice() {
console.log('\n=== 测试日文语音生成 ===');
try {
// 获取情感参考音频列表
const emotionResponse = await client.getEmotionReferenceAudios();
if (!emotionResponse || !emotionResponse.data || !emotionResponse.data.referenceAudios || emotionResponse.data.referenceAudios.length === 0) {
console.log('没有找到可用的情感参考音频,跳过测试');
return false;
}
// 选择一个合适的音频(优先选择日语音频,如果没有则使用第一个)
let refAudio = emotionResponse.data.referenceAudios[0];
// 尝试查找日语音频
const japaneseAudio = emotionResponse.data.referenceAudios.find(audio => audio.language === '日文' || audio.language === 'ja' || audio.language === 'japanese');
if (japaneseAudio) {
refAudio = japaneseAudio;
console.log('找到日语参考音频:', refAudio.name);
}
else {
console.log('未找到日语参考音频,使用默认音频:', refAudio.name);
}
// 获取可用模型
const modelsResponse = await client.getModels();
if (!modelsResponse || !modelsResponse.data ||
!modelsResponse.data.gpt_models || !modelsResponse.data.sovits_models ||
modelsResponse.data.gpt_models.length === 0 || modelsResponse.data.sovits_models.length === 0) {
console.log('没有找到可用的模型,跳过测试');
return false;
}
// 选择模型
const gptModel = modelsResponse.data.gpt_models[0].path;
const sovitsModel = modelsResponse.data.sovits_models[0].path;
console.log(`选择GPT模型: ${gptModel}`);
console.log(`选择SoVITS模型: ${sovitsModel}`);
// 设置模型
await client.setGptModel(gptModel);
await client.setSovitsModel(sovitsModel);
// 日文测试文本
const japaneseText = 'こんにちは、これは日本語の音声合成テストです。';
console.log(`日文测试文本: ${japaneseText}`);
// 测试日文TTS并保存到本地
console.log('\n测试日文TTS并保存到本地...');
const outputPath = path.join(outputDir, `japanese_tts_${Date.now()}.wav`);
const savedPath = await client.textToSpeechDirect({
text: japaneseText,
textLang: 'ja',
refAudioPath: refAudio.id,
promptLang: refAudio.language === '日文' ? 'ja' : (refAudio.language === '英文' ? 'en' : 'zh'),
mediaType: index_1.MediaType.WAV,
gptModel: gptModel,
sovitsModel: sovitsModel
}, outputPath);
if (!savedPath) {
console.log('❌ 保存日文TTS音频文件失败');
return false;
}
if (typeof savedPath === 'string' && fs.existsSync(savedPath)) {
console.log(`✅ 成功保存日文TTS音频文件到: ${savedPath}`);
const fileStats = fs.statSync(savedPath);
console.log(`文件大小: ${fileStats.size} 字节`);
}
else {
console.log('❌ 保存日文TTS音频文件失败或返回的不是有效路径');
return false;
}
return true;
}
catch (error) {
console.error('❌ 日文TTS测试失败:', error);
if (error instanceof Error) {
console.error('错误信息:', error.message);
console.error('错误堆栈:', error.stack);
}
return false;
}
}
/**
* 测试英文语音生成
*/
async function testEnglishVoice() {
console.log('\n=== 测试英文语音生成 ===');
try {
// 获取情感参考音频列表
const emotionResponse = await client.getEmotionReferenceAudios();
if (!emotionResponse || !emotionResponse.data || !emotionResponse.data.referenceAudios || emotionResponse.data.referenceAudios.length === 0) {
console.log('没有找到可用的情感参考音频,跳过测试');
return false;
}
// 选择一个合适的音频(优先选择英语音频,如果没有则使用第一个)
let refAudio = emotionResponse.data.referenceAudios[0];
// 尝试查找英语音频
const englishAudio = emotionResponse.data.referenceAudios.find(audio => audio.language === '英文' || audio.language === 'en' || audio.language === 'english');
if (englishAudio) {
refAudio = englishAudio;
console.log('找到英语参考音频:', refAudio.name);
}
else {
console.log('未找到英语参考音频,使用默认音频:', refAudio.name);
}
// 获取可用模型
const modelsResponse = await client.getModels();
if (!modelsResponse || !modelsResponse.data ||
!modelsResponse.data.gpt_models || !modelsResponse.data.sovits_models ||
modelsResponse.data.gpt_models.length === 0 || modelsResponse.data.sovits_models.length === 0) {
console.log('没有找到可用的模型,跳过测试');
return false;
}
// 选择模型
const gptModel = modelsResponse.data.gpt_models[0].path;
const sovitsModel = modelsResponse.data.sovits_models[0].path;
console.log(`选择GPT模型: ${gptModel}`);
console.log(`选择SoVITS模型: ${sovitsModel}`);
// 设置模型
await client.setGptModel(gptModel);
await client.setSovitsModel(sovitsModel);
// 英文测试文本
const englishText = 'Hello, this is a test for English voice synthesis. The quick brown fox jumps over the lazy dog.';
console.log(`英文测试文本: ${englishText}`);
// 测试英文TTS并保存到本地
console.log('\n测试英文TTS并保存到本地...');
const outputPath = path.join(outputDir, `english_tts_${Date.now()}.wav`);
const savedPath = await client.textToSpeechDirect({
text: englishText,
textLang: 'en',
refAudioPath: refAudio.id,
promptLang: refAudio.language === '英文' ? 'en' : (refAudio.language === '日文' ? 'ja' : 'zh'),
mediaType: index_1.MediaType.WAV,
gptModel: gptModel,
sovitsModel: sovitsModel
}, outputPath);
if (!savedPath) {
console.log('❌ 保存英文TTS音频文件失败');
return false;
}
if (typeof savedPath === 'string' && fs.existsSync(savedPath)) {
console.log(`✅ 成功保存英文TTS音频文件到: ${savedPath}`);
const fileStats = fs.statSync(savedPath);
console.log(`文件大小: ${fileStats.size} 字节`);
}
else {
console.log('❌ 保存英文TTS音频文件失败或返回的不是有效路径');
return false;
}
return true;
}
catch (error) {
console.error('❌ 英文TTS测试失败:', error);
if (error instanceof Error) {
console.error('错误信息:', error.message);
console.error('错误堆栈:', error.stack);
}
return false;
}
}
/**
* 运行测试
*/
async function runTests() {
console.log('开始测试 GPT-SoVITS SDK 直接返回文件的接口...\n');
// 测试获取音频文件
await testGetAudio();
// 测试直接TTS
await testDirectTTS();
// 测试不同媒体类型
await testDifferentMediaTypes();
// 测试日文语音生成
await testJapaneseVoice();
// 测试英文语音生成
await testEnglishVoice();
console.log('\n测试完成!');
}
// 执行测试
runTests().catch(error => {
console.error('测试过程中发生错误:', error);
});