@webgal-tools/voice
Version:
WebGAL GPT-SoVITS语音合成应用
162 lines • 7.54 kB
JavaScript
import { logger } from '@webgal-tools/logger';
import path from 'path';
import { ModelScanner } from '../model-scanner.js';
/**
* 空白翻译类
* 当用户的配置的translate.check为false,或者角色的translate_to为空时使用
* 不进行翻译,直接返回原文
*/
export class NoTranslationService {
async translate(character, originalText, targetLanguage, config, characterConfig, context) {
logger.info(`🚫 [${character}] 跳过翻译,使用原文: "${originalText}"`);
return {
translatedText: originalText,
success: true,
isAutoMode: false
};
}
}
/**
* 静态翻译类
* 当用户translate.check为true,且角色的配置设置了auto为false或没有设置时使用
* 进行常规翻译,不进行情绪识别
*/
export class StaticTranslationService {
translateService; // 使用现有的TranslateService
constructor(translateService) {
this.translateService = translateService;
}
async translate(character, originalText, targetLanguage, config, characterConfig, context) {
try {
logger.info(`📝 [${character}] 开始静态翻译: "${originalText.substring(0, 20)}..."`);
const translatedText = await this.translateService.translate(character, originalText, targetLanguage, config, characterConfig, context);
logger.info(`✅ [${character}] 静态翻译完成: "${translatedText.substring(0, 20)}..."`);
return {
translatedText,
success: true,
isAutoMode: false
};
}
catch (error) {
logger.error(`❌ [${character}] 静态翻译失败:`, error);
return {
translatedText: originalText, // 失败时使用原文
success: false,
error: error instanceof Error ? error.message : String(error),
isAutoMode: false
};
}
}
}
/**
* 自动情绪识别翻译类
* 当用户translate.check为true,且角色的配置设置了auto为true时使用
* 进行翻译和情绪识别,自动选择最合适的模型文件
*/
export class AutoEmotionTranslationService {
translateService; // 使用现有的TranslateService
gptSovitsPath;
constructor(translateService, gptSovitsPath) {
this.translateService = translateService;
this.gptSovitsPath = gptSovitsPath;
}
async translate(character, originalText, targetLanguage, config, characterConfig, context) {
try {
logger.info(`🤖 [${character}] 开始自动情绪识别翻译: "${originalText.substring(0, 20)}..."`);
if (!characterConfig) {
throw new Error('自动模式需要角色配置');
}
// 构建文件夹路径
const gptDir = path.resolve(this.gptSovitsPath, characterConfig.gpt);
const sovitsDir = path.resolve(this.gptSovitsPath, characterConfig.sovits);
const refAudioDir = characterConfig.ref_audio;
// 扫描模型文件
const scannedFiles = ModelScanner.scanModelFiles(this.gptSovitsPath, gptDir, sovitsDir, refAudioDir);
// 检查是否有足够的文件
if (scannedFiles.gpt_files.length === 0) {
throw new Error(`未找到GPT模型文件在: ${gptDir}`);
}
if (scannedFiles.sovits_files.length === 0) {
throw new Error(`未找到SoVITS模型文件在: ${sovitsDir}`);
}
if (scannedFiles.ref_audio_files.length === 0) {
throw new Error(`未找到参考音频文件在: ${refAudioDir}`);
}
// 执行情绪识别和模型选择
const emotionResult = await this.translateService.selectModelAndTranslate(character, originalText, targetLanguage, scannedFiles, config, characterConfig, context);
logger.info(`✅ [${character}] 自动情绪识别翻译完成 - 情绪: ${emotionResult.emotion}, 翻译: "${emotionResult.translated_text.substring(0, 20)}..."`);
return {
translatedText: emotionResult.translated_text,
success: true,
isAutoMode: true,
emotionResult
};
}
catch (error) {
logger.error(`❌ [${character}] 自动情绪识别翻译失败:`, error);
return {
translatedText: originalText, // 失败时使用原文
success: false,
error: error instanceof Error ? error.message : String(error),
isAutoMode: true
};
}
}
}
/**
* 纯情绪识别翻译类
* 当用户禁用翻译(translate.check为false)但启用动态情绪选择(auto为true)时使用
* 不进行翻译,只进行情绪识别和模型文件选择
*/
export class EmotionOnlyTranslationService {
translateService; // 使用现有的TranslateService
gptSovitsPath;
constructor(translateService, gptSovitsPath) {
this.translateService = translateService;
this.gptSovitsPath = gptSovitsPath;
}
async translate(character, originalText, targetLanguage, config, characterConfig, context) {
try {
logger.info(`🎭 [${character}] 开始纯情绪识别(无翻译): "${originalText.substring(0, 20)}..."`);
if (!characterConfig) {
throw new Error('情绪识别模式需要角色配置');
}
// 构建文件夹路径
const gptDir = path.resolve(this.gptSovitsPath, characterConfig.gpt);
const sovitsDir = path.resolve(this.gptSovitsPath, characterConfig.sovits);
const refAudioDir = characterConfig.ref_audio;
// 扫描模型文件
const scannedFiles = ModelScanner.scanModelFiles(this.gptSovitsPath, gptDir, sovitsDir, refAudioDir);
// 检查是否有足够的文件
if (scannedFiles.gpt_files.length === 0) {
throw new Error(`未找到GPT模型文件在: ${gptDir}`);
}
if (scannedFiles.sovits_files.length === 0) {
throw new Error(`未找到SoVITS模型文件在: ${sovitsDir}`);
}
if (scannedFiles.ref_audio_files.length === 0) {
throw new Error(`未找到参考音频文件在: ${refAudioDir}`);
}
// 执行情绪识别和模型选择(不进行翻译)
const emotionResult = await this.translateService.selectModelAndTranslate(character, originalText, '中文', // 使用中文作为目标语言,因为不进行翻译
scannedFiles, config, characterConfig, context);
logger.info(`✅ [${character}] 纯情绪识别完成 - 情绪: ${emotionResult.emotion}, 使用原文: "${originalText.substring(0, 20)}..."`);
return {
translatedText: originalText, // 使用原文,不翻译
success: true,
isAutoMode: true,
emotionResult
};
}
catch (error) {
logger.error(`❌ [${character}] 纯情绪识别失败:`, error);
return {
translatedText: originalText, // 失败时使用原文
success: false,
error: error instanceof Error ? error.message : String(error),
isAutoMode: true
};
}
}
}
//# sourceMappingURL=implementations.js.map