UNPKG

@kajidog/mcp-tts-voicevox

Version:

VOICEVOX integration for MCP - Text-to-Speech server using VOICEVOX engine

145 lines (144 loc) 5.14 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.VoicevoxPlayer = void 0; const queue_1 = require("./queue"); const error_1 = require("./error"); const api_1 = require("./api"); /** * エラーハンドラープロキシ * メソッドをエラーハンドリングで包む高階関数 */ function withErrorHandling(method, errorMessage) { return method().catch((error) => { throw (0, error_1.handleError)(errorMessage, error); }); } /** * VOICEVOX音声プレイヤークラス * キュー管理システムを使用して音声の合成と再生を行う */ class VoicevoxPlayer { /** * コンストラクタ * @param voicevoxUrl VOICEVOX Engine API URL * @param prefetchSize 事前生成するアイテム数 */ constructor(voicevoxUrl = "http://localhost:50021", prefetchSize = 2) { // APIインスタンスを作成 const api = new api_1.VoicevoxApi(voicevoxUrl); // キューマネージャーにAPIインスタンスを注入 this.queueManager = new queue_1.VoicevoxQueueManager(api, prefetchSize); // デフォルトで再生を開始 this.queueManager.startPlayback(); // エラーイベントのログ記録 this.queueManager.addEventListener(queue_1.QueueEventType.ERROR, (_, item) => { if (item) { console.error(`音声合成エラー: ${item.text} (${item.error?.message || "不明なエラー"})`); } }); } /** * テキストをキューに追加 * @param text 合成するテキスト * @param speaker 話者ID */ async enqueue(text, speaker = 1) { return withErrorHandling(async () => { await this.queueManager.enqueueText(text, speaker); }, "テキストのキュー追加中にエラーが発生しました"); } /** * クエリを使ってキューに追加 * @param query 音声合成用クエリ * @param speaker 話者ID */ async enqueueWithQuery(query, speaker = 1) { return withErrorHandling(async () => { await this.queueManager.enqueueQuery(query, speaker); }, "クエリのキュー追加中にエラーが発生しました"); } /** * テキストから音声合成用クエリを生成 * キューマネージャーの内部機能を使用 * @param text 合成するテキスト * @param speaker 話者ID */ async generateQuery(text, speaker = 1) { return withErrorHandling(async () => { // AudioGeneratorのgenerateQueryを直接呼び出す return await this.queueManager .getAudioGenerator() .generateQuery(text, speaker); }, "音声合成クエリの生成中にエラーが発生しました"); } /** * 音声合成用クエリから音声ファイルを生成 * 重複を避けるためにQueueManagerの機能に委譲 * * @param query 音声合成用クエリ * @param output 出力ファイルパスまたは出力ディレクトリ(省略時は一時ディレクトリに生成) * @param speaker 話者ID */ async synthesizeToFile(query, output, speaker = 1) { return withErrorHandling(async () => { // クエリから音声を合成 const api = this.queueManager.getApi(); const audioData = await api.synthesize(query, speaker); // ファイル保存処理をFileManagerに完全に委譲 const fileManager = this.queueManager.getFileManager(); // 出力パスが指定されていない場合は一時ファイル、指定されている場合は指定パスに保存 if (!output) { return await fileManager.saveTempAudioFile(audioData); } else { return await fileManager.saveAudioFile(audioData, output); } }, "音声ファイル生成中にエラーが発生しました"); } /** * 再生を開始 */ startPlayback() { this.queueManager.startPlayback(); } /** * 再生を一時停止 */ pausePlayback() { this.queueManager.pausePlayback(); } /** * 再生を再開 */ resumePlayback() { this.queueManager.resumePlayback(); } /** * キュー内のアイテム数を取得 */ getQueueLength() { return this.queueManager.getQueue().length; } /** * キューが空かどうかを確認 */ isQueueEmpty() { return this.queueManager.getQueue().length === 0; } /** * キューが再生中かどうかを確認 */ isPlaying() { return this.queueManager .getQueue() .some((item) => item.status === queue_1.QueueItemStatus.PLAYING); } /** * キューマネージャーインスタンスを取得 * 高度な操作のため公開 */ getQueueManager() { return this.queueManager; } } exports.VoicevoxPlayer = VoicevoxPlayer;