UNPKG

@aituber-onair/voice

Version:

Voice synthesis library for AITuber OnAir

241 lines (240 loc) 10.4 kB
"use strict"; 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 }); exports.VoiceEngineAdapter = void 0; const screenplay_1 = require("../utils/screenplay"); const AudioPlayerFactory_1 = require("./audio/AudioPlayerFactory"); /** * Adapter implementation for using existing voice engines */ class VoiceEngineAdapter { /** * Constructor * @param options Voice service options */ constructor(options) { this.options = options; this.audioPlayer = AudioPlayerFactory_1.AudioPlayerFactory.createAudioPlayer(); // Set up completion callback this.audioPlayer.setOnComplete(() => { if (this.options.onComplete) { this.options.onComplete(); } }); } /** * Speak the screenplay as audio * @param screenplay Screenplay (text and emotion) * @param options Audio playback options */ async speak(screenplay, options) { try { if (this.audioPlayer.isPlaying()) { this.stop(); } // Import existing VoiceEngineFactory dynamically const { VoiceEngineFactory } = await Promise.resolve().then(() => __importStar(require('../engines/VoiceEngineFactory'))); // Map emotion to style used by existing engine const getStyleFromEmotion = (emotion) => { switch (emotion) { case 'angry': return 'angry'; case 'happy': return 'happy'; case 'sad': return 'sad'; case 'surprised': return 'surprised'; default: return 'neutral'; } }; // Convert to Talk type for VoiceEngine const talk = { style: getStyleFromEmotion(screenplay.emotion || 'neutral'), message: screenplay.text, }; const engine = VoiceEngineFactory.getEngine(this.options.engineType); // カスタムエンドポイントURLの設定 if (engine.setApiEndpoint) { // エンジンタイプに応じてカスタムエンドポイントURLを設定 switch (this.options.engineType) { case 'voicevox': if (this.options.voicevoxApiUrl) { engine.setApiEndpoint(this.options.voicevoxApiUrl); } break; case 'voicepeak': if (this.options.voicepeakApiUrl) { engine.setApiEndpoint(this.options.voicepeakApiUrl); } break; case 'aivisSpeech': if (this.options.aivisSpeechApiUrl) { engine.setApiEndpoint(this.options.aivisSpeechApiUrl); } break; } } // MiniMaxエンジンの場合、GroupIdを設定 if (this.options.engineType === 'minimax' && engine.setGroupId) { if (this.options.groupId) { engine.setGroupId(this.options.groupId); } else { console.warn('MiniMax engine requires GroupId, but it is not provided in options'); } // エンドポイントの設定もMinimaxEngineでサポートされている場合 if (this.options.endpoint && engine.setEndpoint) { engine.setEndpoint(this.options.endpoint); } } // Aivis Cloud エンジンの場合、各種パラメータを設定 if (this.options.engineType === 'aivisCloud') { const aivisEngine = engine; // Model UUID (required) if (this.options.aivisCloudModelUuid) { aivisEngine.setModelUuid(this.options.aivisCloudModelUuid); } // Speaker UUID (optional) if (this.options.aivisCloudSpeakerUuid) { aivisEngine.setSpeakerUuid(this.options.aivisCloudSpeakerUuid); } // Style settings (style ID or name, but not both) if (this.options.aivisCloudStyleId !== undefined) { aivisEngine.setStyleId(this.options.aivisCloudStyleId); } else if (this.options.aivisCloudStyleName) { aivisEngine.setStyleName(this.options.aivisCloudStyleName); } // SSML setting if (this.options.aivisCloudUseSSML !== undefined) { aivisEngine.setUseSSML(this.options.aivisCloudUseSSML); } // Voice parameters if (this.options.aivisCloudSpeakingRate !== undefined) { aivisEngine.setSpeakingRate(this.options.aivisCloudSpeakingRate); } if (this.options.aivisCloudEmotionalIntensity !== undefined) { aivisEngine.setEmotionalIntensity(this.options.aivisCloudEmotionalIntensity); } if (this.options.aivisCloudTempoDynamics !== undefined) { aivisEngine.setTempoDynamics(this.options.aivisCloudTempoDynamics); } if (this.options.aivisCloudPitch !== undefined) { aivisEngine.setPitch(this.options.aivisCloudPitch); } if (this.options.aivisCloudVolume !== undefined) { aivisEngine.setVolume(this.options.aivisCloudVolume); } // Silence settings if (this.options.aivisCloudLeadingSilence !== undefined || this.options.aivisCloudTrailingSilence !== undefined || this.options.aivisCloudLineBreakSilence !== undefined) { aivisEngine.setSilenceDurations(this.options.aivisCloudLeadingSilence ?? 0.1, this.options.aivisCloudTrailingSilence ?? 0.1, this.options.aivisCloudLineBreakSilence ?? 0.4); } // Output format settings if (this.options.aivisCloudOutputFormat) { aivisEngine.setOutputFormat(this.options.aivisCloudOutputFormat); } if (this.options.aivisCloudOutputBitrate !== undefined) { aivisEngine.setOutputBitrate(this.options.aivisCloudOutputBitrate); } if (this.options.aivisCloudOutputSamplingRate !== undefined) { aivisEngine.setOutputSamplingRate(this.options.aivisCloudOutputSamplingRate); } if (this.options.aivisCloudOutputChannels) { aivisEngine.setOutputChannels(this.options.aivisCloudOutputChannels); } // Billing logs setting if (this.options.aivisCloudEnableBillingLogs !== undefined) { aivisEngine.setEnableBillingLogs(this.options.aivisCloudEnableBillingLogs); } } // Get audio data const audioBuffer = await engine.fetchAudio(talk, // Use any for type compatibility this.options.speaker, this.options.apiKey); // If there is a custom playback process, use it if (this.options.onPlay) { await this.options.onPlay(audioBuffer, options); return; } // Default playback process await this.audioPlayer.play(audioBuffer, options?.audioElementId); } catch (error) { console.error('Error in speak:', error); throw error; } } /** * Speak text as audio * @param text Text (with emotion tags) to speak * @param options Audio playback options */ async speakText(text, options) { // Convert text to screenplay and play const screenplay = (0, screenplay_1.textToScreenplay)(text); return this.speak(screenplay, options); } /** * Get whether currently playing */ isPlaying() { return this.audioPlayer.isPlaying(); } /** * Stop playback */ stop() { this.audioPlayer.stop(); } /** * Update service settings * @param options New settings options */ updateOptions(options) { this.options = { ...this.options, ...options }; // Update audio player callback if onComplete changes if (options.onComplete !== undefined) { this.audioPlayer.setOnComplete(() => { if (this.options.onComplete) { this.options.onComplete(); } }); } } } exports.VoiceEngineAdapter = VoiceEngineAdapter;