@kajidog/mcp-tts-voicevox 0.0.3 → 0.0.5

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/index.js CHANGED
@@ -1,82 +1,131 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.VoicevoxError = void 0;
5
+ exports.initVoicevox = initVoicevox;
4
6
  const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
5
7
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
8
  const zod_1 = require("zod");
7
- const index_js_1 = require("./voicevox/index.js");
9
+ const voicevox_1 = require("./voicevox");
10
+ const types_1 = require("./voicevox/types");
11
+ Object.defineProperty(exports, "VoicevoxError", { enumerable: true, get: function () { return types_1.VoicevoxError; } });
12
+ /**
13
+ * VOICEVOX音声合成クライアントを初期化します
14
+ * @param config 設定オブジェクト
15
+ * @returns VoicevoxClientのインスタンス
16
+ */
17
+ function initVoicevox(config) {
18
+ return new voicevox_1.VoicevoxClient(config);
19
+ }
20
+ // デフォルトのVOICEVOXクライアント
21
+ const voicevoxClient = initVoicevox({
22
+ url: process.env.VOICEVOX_URL || "http://localhost:50021",
23
+ defaultSpeaker: Number(process.env.VOICEVOX_DEFAULT_SPEAKER || "1"),
24
+ defaultSpeedScale: Number(process.env.VOICEVOX_DEFAULT_SPEED_SCALE || "1.0"),
25
+ });
8
26
  const server = new mcp_js_1.McpServer({
9
27
  name: "MCP TTS Voicevox",
10
- version: "0.0.3",
11
- description: "Voicevoxで音声を生成します。",
12
- });
13
- // VoicevoxClientを一度だけインスタンス化
14
- const voicevoxClient = new index_js_1.VoicevoxClient({
15
- url: process.env.VOICEVOX_URL ?? "http://localhost:50021",
16
- defaultSpeaker: 1,
17
- });
18
- // 共通のエラーハンドリング関数
19
- const handleError = (error) => {
20
- const errorMessage = error instanceof Error ? error.message : String(error);
21
- console.error("エラーが発生しました:", error);
22
- return {
23
- content: [{ type: "text", text: `エラー: ${errorMessage}` }],
24
- };
25
- };
26
- // テキストを音声に変換して再生
27
- server.tool("speak", {
28
- text: zod_1.z.string().describe("読み上げるテキスト"),
29
- speaker: zod_1.z.number().optional().describe("話者ID"),
30
- }, async ({ text, speaker }) => {
31
- try {
32
- const result = await voicevoxClient.enqueueAudioGeneration(text, speaker);
33
- return {
34
- content: [{ type: "text", text: result }],
35
- };
36
- }
37
- catch (error) {
38
- return handleError(error);
39
- }
40
- });
41
- // クエリ生成ツール
42
- server.tool("generate_query", {
43
- text: zod_1.z.string().describe("音声合成するテキスト"),
44
- speaker: zod_1.z.number().optional().describe("話者ID"),
45
- }, async ({ text, speaker }) => {
46
- try {
47
- const query = await voicevoxClient.generateQuery(text, speaker);
48
- return {
49
- content: [{ type: "text", text: JSON.stringify(query) }],
50
- };
51
- }
52
- catch (error) {
53
- return handleError(error);
54
- }
55
- });
56
- // 音声ファイル生成ツール - クエリまたはテキストを受け付ける
57
- server.tool("synthesize_file", {
58
- text: zod_1.z
59
- .string()
60
- .optional()
61
- .describe("音声合成するテキスト(queryパラメータと同時に指定する場合はqueryが優先されます)"),
62
- query: zod_1.z.any().optional().describe("音声合成用クエリ"),
63
- output: zod_1.z.string().describe("音声ファイルの保存先パス"),
64
- speaker: zod_1.z.number().optional().describe("話者ID"),
65
- }, async ({ text, query, output, speaker }) => {
66
- try {
67
- if (!query && !text) {
68
- throw new Error("queryパラメータとtextパラメータのどちらかを指定してください");
69
- }
70
- const filePath = await voicevoxClient.generateAudioFile(query ?? text, output, speaker);
71
- return {
72
- content: [{ type: "text", text: filePath }],
73
- };
74
- }
75
- catch (error) {
76
- return handleError(error);
77
- }
28
+ version: "0.0.5",
29
+ description: "A Voicevox server that converts text to speech for playback and saving.",
30
+ functions: {
31
+ // 既存の関数
32
+ speak: {
33
+ parameters: zod_1.z.object({
34
+ text: zod_1.z
35
+ .string()
36
+ .describe("Text to be spoken (if both query and text are provided, query takes precedence)"),
37
+ speaker: zod_1.z
38
+ .number()
39
+ .optional()
40
+ .describe("Speaker ID (optional, used if text is provided)"),
41
+ query: zod_1.z.string().optional().describe("Voice synthesis query"),
42
+ speedScale: zod_1.z
43
+ .number()
44
+ .optional()
45
+ .describe("Playback speed (optional, default is from environment variable)"),
46
+ }),
47
+ handler: async ({ text, speaker, query, speedScale, }) => {
48
+ try {
49
+ if (query) {
50
+ // クエリが提供されている場合はそれを使用
51
+ const audioQuery = JSON.parse(query);
52
+ if (speedScale !== undefined) {
53
+ audioQuery.speedScale = speedScale;
54
+ }
55
+ return await voicevoxClient.enqueueAudioGeneration(audioQuery, speaker);
56
+ }
57
+ else {
58
+ // テキストからの通常の発話
59
+ return await voicevoxClient.speak(text, speaker, speedScale);
60
+ }
61
+ }
62
+ catch (error) {
63
+ console.error("VOICEVOX speak error:", error);
64
+ return `Error: ${error instanceof Error ? error.message : String(error)}`;
65
+ }
66
+ },
67
+ },
68
+ generate_query: {
69
+ parameters: zod_1.z.object({
70
+ text: zod_1.z.string().describe("Text for voice synthesis"),
71
+ speaker: zod_1.z.number().optional().describe("Speaker ID (optional)"),
72
+ speedScale: zod_1.z
73
+ .number()
74
+ .optional()
75
+ .describe("Playback speed (optional, default is from environment variable)"),
76
+ }),
77
+ handler: async ({ text, speaker, speedScale, }) => {
78
+ try {
79
+ const query = await voicevoxClient.generateQuery(text, speaker, speedScale);
80
+ return JSON.stringify(query);
81
+ }
82
+ catch (error) {
83
+ console.error("VOICEVOX generate query error:", error);
84
+ return `Error: ${error instanceof Error ? error.message : String(error)}`;
85
+ }
86
+ },
87
+ },
88
+ synthesize_file: {
89
+ parameters: zod_1.z.object({
90
+ text: zod_1.z
91
+ .string()
92
+ .optional()
93
+ .describe("Text for voice synthesis (if both query and text are provided, query takes precedence)"),
94
+ query: zod_1.z.string().optional().describe("Voice synthesis query"),
95
+ speaker: zod_1.z.number().optional().describe("Speaker ID (optional)"),
96
+ output: zod_1.z.string().describe("Output path for the audio file"),
97
+ speedScale: zod_1.z
98
+ .number()
99
+ .optional()
100
+ .describe("Playback speed (optional, default is from environment variable)"),
101
+ }),
102
+ handler: async ({ text, query, speaker, output, speedScale, }) => {
103
+ try {
104
+ if (query) {
105
+ // クエリが提供されている場合はそれを使用
106
+ const audioQuery = JSON.parse(query);
107
+ if (speedScale !== undefined) {
108
+ audioQuery.speedScale = speedScale;
109
+ }
110
+ return await voicevoxClient.generateAudioFile(audioQuery, output, speaker);
111
+ }
112
+ else if (text) {
113
+ // テキストから音声ファイルを生成
114
+ return await voicevoxClient.generateAudioFile(text, output, speaker, speedScale);
115
+ }
116
+ else {
117
+ return "Error: Either text or query must be provided";
118
+ }
119
+ }
120
+ catch (error) {
121
+ console.error("VOICEVOX synthesize file error:", error);
122
+ return `Error: ${error instanceof Error ? error.message : String(error)}`;
123
+ }
124
+ },
125
+ },
126
+ },
78
127
  });
79
128
  server.connect(new stdio_js_1.StdioServerTransport()).catch((error) => {
80
- console.error(error);
129
+ console.error("Error connecting to MCP transport:", error);
81
130
  process.exit(1);
82
131
  });
package/dist/test.js CHANGED
@@ -37,159 +37,310 @@ const voicevox_1 = require("./voicevox");
37
37
  const path_1 = require("path");
38
38
  const os_1 = require("os");
39
39
  const fs = __importStar(require("fs/promises"));
40
- // クライアントテスト
40
+ const soundPlay = require("sound-play");
41
+ // ----- ユーティリティ関数 -----
42
+ /**
43
+ * 音声ファイルを再生するユーティリティ関数
44
+ * @param filePath 再生する音声ファイルのパス
45
+ * @param description 再生内容の説明
46
+ */
47
+ async function playAudioFile(filePath, description = "") {
48
+ try {
49
+ const displayText = description ? `${description} (${filePath})` : filePath;
50
+ console.log(`🔊 音声ファイル「${displayText}」の再生を開始します...`);
51
+ await soundPlay.play(filePath);
52
+ console.log(`✅ 音声ファイル「${displayText}」の再生が完了しました`);
53
+ }
54
+ catch (error) {
55
+ console.error(`❌ 音声再生中にエラーが発生しました: ${error}`);
56
+ throw error;
57
+ }
58
+ }
59
+ /**
60
+ * ヘッダーを出力する関数
61
+ * @param title セクションタイトル
62
+ */
63
+ function printHeader(title) {
64
+ console.log(`\n${"=".repeat(80)}`);
65
+ console.log(`📌 ${title}`);
66
+ console.log(`${"=".repeat(80)}`);
67
+ }
68
+ /**
69
+ * サブセクションのヘッダーを出力する関数
70
+ * @param title セクションタイトル
71
+ */
72
+ function printSubHeader(title) {
73
+ console.log(`\n${"- ".repeat(40)}`);
74
+ console.log(`🔹 ${title}`);
75
+ console.log(`${"- ".repeat(40)}`);
76
+ }
77
+ // ----- クライアントテスト関数 -----
78
+ /**
79
+ * VoicevoxClientの基本機能をテストする
80
+ */
81
+ async function testTextToSpeech(client, speaker) {
82
+ printSubHeader("テキストから音声再生のテスト");
83
+ const testText = "これはテストです。VOICEVOXの機能を検証します。";
84
+ // 1. speak テスト - テキストからの音声再生
85
+ console.log("➡️ テキストから直接音声再生");
86
+ const speakResult = await client.speak(testText, speaker);
87
+ console.log("✅ 結果:", speakResult);
88
+ // 2. generateQuery テスト - テキストから音声合成用クエリを生成
89
+ console.log("\n➡️ テキストから音声合成用クエリ生成");
90
+ const query = await client.generateQuery(testText, speaker);
91
+ console.log("✅ クエリ生成結果 (一部):", JSON.stringify(query).substring(0, 100) + "...");
92
+ return query;
93
+ }
94
+ /**
95
+ * 音声ファイル生成機能をテストする
96
+ */
97
+ async function testAudioFileGeneration(client, query, speaker) {
98
+ printSubHeader("音声ファイル生成のテスト");
99
+ // 1. クエリから音声ファイルを生成
100
+ console.log("➡️ クエリから音声ファイル生成");
101
+ const outputPath = (0, path_1.join)((0, os_1.tmpdir)(), `voicevox-${Date.now()}.wav`);
102
+ const filePath = await client.generateAudioFile(query, outputPath, speaker);
103
+ console.log(`✅ 音声ファイル生成: ${filePath}`);
104
+ // ファイルが存在するか確認
105
+ const fileExists = await fs
106
+ .stat(filePath)
107
+ .then(() => true)
108
+ .catch(() => false);
109
+ console.log(`📂 ファイルの存在確認: ${fileExists ? "✅ 存在します" : "❌ 存在しません"}`);
110
+ // 生成した音声ファイルを再生
111
+ if (fileExists) {
112
+ await playAudioFile(filePath, "クエリから生成した音声");
113
+ }
114
+ // 2. テキストから直接音声ファイルを生成
115
+ console.log("\n➡️ テキストから直接音声ファイル生成");
116
+ const directFilePath = await client.generateAudioFile("直接ファイルに変換するテスト。", undefined, speaker);
117
+ console.log(`✅ 直接音声ファイル生成: ${directFilePath}`);
118
+ await playAudioFile(directFilePath, "テキストから直接生成した音声");
119
+ }
120
+ /**
121
+ * 再生速度変更機能をテストする
122
+ */
123
+ async function testSpeedScale(client, speaker) {
124
+ printSubHeader("再生速度の変更テスト");
125
+ // 1. 速い再生速度のテスト
126
+ console.log("➡️ 再生速度を1.5倍に設定したテスト");
127
+ const speedTestFilePath = await client.generateAudioFile("これは再生速度を1.5倍に設定したテストです。", (0, path_1.join)((0, os_1.tmpdir)(), `voicevox-speed-${Date.now()}.wav`), speaker, 1.5 // 速度を1.5倍に設定
128
+ );
129
+ console.log(`✅ 再生速度1.5倍: ${speedTestFilePath}`);
130
+ await playAudioFile(speedTestFilePath, "速度を1.5倍に設定した音声");
131
+ // 遅い再生速度のテストはタイムアウトを起こしやすいため、条件付きでスキップ
132
+ const doSlowTest = process.env.TEST_SLOW_SPEED === "true";
133
+ if (doSlowTest) {
134
+ // 2. 遅い再生速度のテスト
135
+ console.log("\n➡️ 再生速度を0.8倍に設定したテスト");
136
+ try {
137
+ const slowSpeedTestFilePath = await client.generateAudioFile("これは再生速度を0.8倍に設定したテストです。ゆっくり話します。", (0, path_1.join)((0, os_1.tmpdir)(), `voicevox-slow-${Date.now()}.wav`), speaker, 0.8 // 速度を0.8倍に設定
138
+ );
139
+ console.log(`✅ 再生速度0.8倍: ${slowSpeedTestFilePath}`);
140
+ await playAudioFile(slowSpeedTestFilePath, "速度を0.8倍に設定した音声");
141
+ }
142
+ catch (error) {
143
+ console.warn(`⚠️ 遅い再生速度のテストはスキップされました: ${error}`);
144
+ }
145
+ }
146
+ else {
147
+ console.log("\n⏭️ 再生速度0.8倍のテストはスキップします (タイムアウト防止のため)");
148
+ }
149
+ }
150
+ /**
151
+ * 音声生成キュー機能をテストする
152
+ */
153
+ async function testAudioQueue(client, query, speaker) {
154
+ printSubHeader("音声生成キューテスト");
155
+ // クエリを使って音声生成キューに追加
156
+ console.log("➡️ クエリを使って音声生成キューへの追加");
157
+ const enqueueResult = await client.enqueueAudioGeneration(query, speaker);
158
+ console.log(`✅ キュー追加結果:`, enqueueResult);
159
+ }
160
+ /**
161
+ * VoicevoxClientの基本機能をテストする統合関数
162
+ */
41
163
  async function testClient() {
42
164
  try {
43
- console.log("=== VoicevoxClient直接テスト ===");
165
+ printHeader("VoicevoxClient直接テスト");
44
166
  const client = new voicevox_1.VoicevoxClient({
45
167
  url: "http://localhost:50021",
46
168
  defaultSpeaker: 1,
169
+ defaultSpeedScale: 1.0,
47
170
  });
48
- // テスト用のテキスト
49
- const testText = "これはテストです。VOICEVOXの機能を検証します。";
50
- const speaker = 1; // 四国めたん (ノーマル)
51
- // 1. speak テスト - テキストからの音声再生
52
- console.log("\n----- テキストから音声再生のテスト -----");
53
- const speakResult = await client.speak(testText, speaker);
54
- console.log(speakResult);
55
- // 2. generateQuery テスト - テキストから音声合成用クエリを生成
56
- console.log("\n----- テキストから音声合成用クエリ生成のテスト -----");
57
- const query = await client.generateQuery(testText, speaker);
58
- console.log("クエリ生成結果 (一部):", JSON.stringify(query).substring(0, 100) + "...");
59
- // 3. synthesizeToFile テスト - クエリから音声ファイルを生成
60
- console.log("\n----- クエリから音声ファイル生成のテスト -----");
61
- const outputPath = (0, path_1.join)((0, os_1.tmpdir)(), `voicevox-test-${Date.now()}.wav`);
62
- const filePath = await client.generateAudioFile(query, outputPath, speaker);
63
- console.log(`音声ファイル生成結果: ${filePath}`);
64
- // ファイルが存在するか確認
65
- const fileExists = await fs
66
- .stat(filePath)
67
- .then(() => true)
68
- .catch(() => false);
69
- console.log(`ファイルが存在するか: ${fileExists}`);
70
- // 4. generateAudioFile テスト - テキストから直接音声ファイルを生成
71
- console.log("\n----- テキストから直接音声ファイル生成のテスト -----");
72
- const directFilePath = await client.generateAudioFile("直接ファイルに変換するテスト。", (0, path_1.join)((0, os_1.tmpdir)(), `voicevox-direct-${Date.now()}.wav`), speaker);
73
- console.log(`直接音声ファイル生成結果: ${directFilePath}`);
74
- // 5. enqueueAudioGeneration テスト - クエリを使って音声生成キューに追加
75
- console.log("\n----- クエリを使って音声生成キューへの追加テスト -----");
76
- const enqueueResult = await client.enqueueAudioGeneration(query, speaker);
77
- console.log(enqueueResult);
78
- // 待機してキューの処理が完了するのを待つ
79
- console.log("\n音声再生を待機しています...");
80
- await new Promise((resolve) => setTimeout(resolve, 3000));
171
+ // テスト用の話者
172
+ const speaker = 5; // 四国めたん (ノーマル)
173
+ // 1. 基本的なテキスト読み上げとクエリ生成
174
+ const query = await testTextToSpeech(client, speaker);
175
+ // 2. 音声ファイル生成
176
+ await testAudioFileGeneration(client, query, speaker);
177
+ // 3. 再生速度変更
178
+ await testSpeedScale(client, speaker);
179
+ // 4. 音声生成キュー
180
+ await testAudioQueue(client, query, speaker);
81
181
  return query; // 後のテストで使用するためにクエリを返す
82
182
  }
83
183
  catch (error) {
84
- console.error("クライアントテスト中にエラーが発生しました:", error);
184
+ console.error("クライアントテスト中にエラーが発生しました:", error);
85
185
  throw error;
86
186
  }
87
187
  }
88
- // MCPツールテスト
188
+ // ----- MCPツール関数 -----
189
+ /**
190
+ * speak MCPツールをテストする
191
+ */
192
+ async function testSpeakTool(client) {
193
+ printSubHeader("speak ツールのテスト");
194
+ // speak ツールハンドラ
195
+ const speakHandler = async (args) => {
196
+ try {
197
+ const { text, speaker, speedScale } = args;
198
+ console.log(`➡️ テキスト「${text}」を話者${speaker}、速度${speedScale || 1.0}で発話`);
199
+ const result = await client.speak(text, speaker, speedScale);
200
+ console.log("✅ speak 結果:", result);
201
+ return {
202
+ content: [{ type: "text", text: result }],
203
+ };
204
+ }
205
+ catch (error) {
206
+ const errorMessage = error instanceof Error ? error.message : String(error);
207
+ console.error("❌ エラーが発生しました:", error);
208
+ return {
209
+ content: [{ type: "text", text: `エラー: ${errorMessage}` }],
210
+ };
211
+ }
212
+ };
213
+ // 通常のテスト
214
+ await speakHandler({ text: "MCPツールからのテスト発話です。", speaker: 1 });
215
+ // 速度を変更したテスト
216
+ await speakHandler({
217
+ text: "MCPツールから速度を1.3倍に設定したテスト発話です。",
218
+ speaker: 1,
219
+ speedScale: 1.3,
220
+ });
221
+ }
222
+ /**
223
+ * generate_query MCPツールをテストする
224
+ */
225
+ async function testGenerateQueryTool(client) {
226
+ printSubHeader("generate_query ツールのテスト");
227
+ // generate_query ツールハンドラ
228
+ const generateQueryHandler = async (args) => {
229
+ try {
230
+ const { text, speaker, speedScale } = args;
231
+ console.log(`➡️ テキスト「${text}」を話者${speaker}、速度${speedScale || 1.0}でクエリ生成`);
232
+ const generatedQuery = await client.generateQuery(text, speaker, speedScale);
233
+ const queryJson = JSON.stringify(generatedQuery);
234
+ console.log("✅ クエリ生成結果 (一部):", queryJson.substring(0, 100) + "...");
235
+ return {
236
+ content: [{ type: "text", text: queryJson }],
237
+ };
238
+ }
239
+ catch (error) {
240
+ const errorMessage = error instanceof Error ? error.message : String(error);
241
+ console.error("❌ エラーが発生しました:", error);
242
+ return {
243
+ content: [{ type: "text", text: `エラー: ${errorMessage}` }],
244
+ };
245
+ }
246
+ };
247
+ // 実行
248
+ const queryResponse = await generateQueryHandler({
249
+ text: "MCPツールからのクエリ生成テスト。",
250
+ speaker: 1,
251
+ speedScale: 1.2,
252
+ });
253
+ // テキストからJSONに変換
254
+ return JSON.parse(queryResponse.content[0].text);
255
+ }
256
+ /**
257
+ * synthesize_file MCPツールをテストする
258
+ */
259
+ async function testSynthesizeFileTool(client, query) {
260
+ printSubHeader("synthesize_file ツールのテスト");
261
+ // synthesize_file ツールハンドラ
262
+ const synthesizeFileHandler = async (args) => {
263
+ try {
264
+ const { query: testQuery, output, speaker, speedScale } = args;
265
+ console.log(`➡️ クエリから音声ファイルを生成: 出力パス=${output}`);
266
+ const filePath = await client.generateAudioFile(testQuery, output, speaker, speedScale);
267
+ console.log("✅ ファイル生成結果:", filePath);
268
+ return {
269
+ content: [{ type: "text", text: filePath }],
270
+ };
271
+ }
272
+ catch (error) {
273
+ const errorMessage = error instanceof Error ? error.message : String(error);
274
+ console.error("❌ エラーが発生しました:", error);
275
+ return {
276
+ content: [{ type: "text", text: `エラー: ${errorMessage}` }],
277
+ };
278
+ }
279
+ };
280
+ // 実行
281
+ const testOutputPath = "";
282
+ const fileResponse = await synthesizeFileHandler({
283
+ query: query,
284
+ output: testOutputPath,
285
+ speaker: 1,
286
+ speedScale: 0.9,
287
+ });
288
+ return fileResponse.content[0].text;
289
+ }
290
+ /**
291
+ * MCPツールをテストする統合関数
292
+ */
89
293
  async function testMcpTools(query) {
90
294
  try {
91
- console.log("\n=== MCPツールテスト ===");
92
- // VoicevoxClientを一度だけインスタンス化
93
- const voicevoxClient = new voicevox_1.VoicevoxClient({
295
+ printHeader("MCPツールテスト");
296
+ // VoicevoxClientを初期化
297
+ const client = new voicevox_1.VoicevoxClient({
94
298
  url: process.env.VOICEVOX_URL ?? "http://localhost:50021",
95
299
  defaultSpeaker: 1,
300
+ defaultSpeedScale: Number(process.env.VOICEVOX_DEFAULT_SPEED_SCALE || "1.0"),
96
301
  });
97
- // 1. speak ツールテスト
98
- console.log("\n----- speak ツールのテスト -----");
99
- const speakHandler = async (args) => {
100
- try {
101
- const { text, speaker } = args;
102
- const result = await voicevoxClient.enqueueAudioGeneration(text, speaker);
103
- console.log("speak 結果:", result);
104
- return {
105
- content: [{ type: "text", text: result }],
106
- };
107
- }
108
- catch (error) {
109
- const errorMessage = error instanceof Error ? error.message : String(error);
110
- console.error("エラーが発生しました:", error);
111
- return {
112
- content: [{ type: "text", text: `エラー: ${errorMessage}` }],
113
- };
114
- }
115
- };
116
- // 実行
117
- await speakHandler({ text: "MCPツールからのテスト発話です。", speaker: 1 });
118
- // 2. generate_query ツールテスト
119
- console.log("\n----- generate_query ツールのテスト -----");
120
- const generateQueryHandler = async (args) => {
121
- try {
122
- const { text, speaker } = args;
123
- const generatedQuery = await voicevoxClient.generateQuery(text, speaker);
124
- const queryJson = JSON.stringify(generatedQuery);
125
- console.log("generate_query 結果 (一部):", queryJson.substring(0, 100) + "...");
126
- return {
127
- content: [{ type: "text", text: queryJson }],
128
- };
129
- }
130
- catch (error) {
131
- const errorMessage = error instanceof Error ? error.message : String(error);
132
- console.error("エラーが発生しました:", error);
133
- return {
134
- content: [{ type: "text", text: `エラー: ${errorMessage}` }],
135
- };
136
- }
137
- };
138
- // 実行
139
- const queryResponse = await generateQueryHandler({
140
- text: "MCPツールからのクエリ生成テスト。",
141
- speaker: 1,
142
- });
143
- // テキストからJSONに変換
144
- const generatedQuery = JSON.parse(queryResponse.content[0].text);
145
- // 3. synthesize_file ツールテスト
146
- console.log("\n----- synthesize_file ツールのテスト -----");
147
- const synthesizeFileHandler = async (args) => {
148
- try {
149
- const { query: testQuery, output, speaker } = args;
150
- const filePath = await voicevoxClient.generateAudioFile(testQuery, output, speaker);
151
- console.log("synthesize_file 結果:", filePath);
152
- return {
153
- content: [{ type: "text", text: filePath }],
154
- };
155
- }
156
- catch (error) {
157
- const errorMessage = error instanceof Error ? error.message : String(error);
158
- console.error("エラーが発生しました:", error);
159
- return {
160
- content: [{ type: "text", text: `エラー: ${errorMessage}` }],
161
- };
162
- }
163
- };
164
- // 実行
165
- const testOutputPath = (0, path_1.join)((0, os_1.tmpdir)(), `voicevox-mcp-final-test-${Date.now()}.wav`);
166
- await synthesizeFileHandler({
167
- query: generatedQuery,
168
- output: testOutputPath,
169
- speaker: 1,
170
- });
302
+ // 1. speak ツールのテスト
303
+ await testSpeakTool(client);
304
+ // 2. generate_query ツールのテスト
305
+ const generatedQuery = await testGenerateQueryTool(client);
306
+ // 3. synthesize_file ツールのテスト
307
+ const filePath = await testSynthesizeFileTool(client, generatedQuery);
308
+ // 生成したファイルを再生
309
+ printSubHeader("生成したファイルの再生テスト");
310
+ console.log(`➡️ ファイル ${filePath} を再生します...`);
311
+ await playAudioFile(filePath, "MCPツールで生成した音声ファイル");
312
+ console.log("✅ ファイルの再生が完了しました");
171
313
  // 待機してキューの処理が完了するのを待つ
172
- console.log("\nMCP音声再生を待機しています...");
314
+ console.log("\n⏳ MCP音声再生を待機しています...");
173
315
  await new Promise((resolve) => setTimeout(resolve, 3000));
174
316
  }
175
317
  catch (error) {
176
- console.error("MCPツールテスト中にエラーが発生しました:", error);
318
+ console.error("MCPツールテスト中にエラーが発生しました:", error);
177
319
  throw error;
178
320
  }
179
321
  }
180
- // メイン実行関数
322
+ // ----- メイン実行関数 -----
323
+ /**
324
+ * メイン実行関数
325
+ */
181
326
  async function main() {
182
327
  try {
183
- console.log("VOICEVOXテストを開始します...");
328
+ console.log("🚀 VOICEVOXテストを開始します...");
184
329
  // クライアントテスト実行
185
330
  const query = await testClient();
186
331
  // MCPツールテスト実行
187
332
  await testMcpTools(query);
188
- console.log("\nすべてのテストが完了しました!");
333
+ console.log("\n🎉 すべてのテストが完了しました!");
189
334
  }
190
335
  catch (error) {
191
- console.error("テスト中にエラーが発生しました:", error);
336
+ console.error("テスト中にエラーが発生しました:", error);
192
337
  process.exit(1);
193
338
  }
339
+ finally {
340
+ // 強制的にプロセスを終了
341
+ console.log("👋 プロセスを終了します...");
342
+ setTimeout(() => process.exit(0), 1000);
343
+ }
194
344
  }
345
+ // プログラム実行
195
346
  main();