@kajidog/mcp-tts-voicevox 0.0.6 → 0.0.8

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.
Files changed (54) hide show
  1. package/README.md +29 -47
  2. package/dist/index.d.ts +4 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +3 -2
  5. package/dist/test.d.ts +2 -0
  6. package/dist/test.d.ts.map +1 -0
  7. package/dist/voicevox/api.d.ts +28 -0
  8. package/dist/voicevox/api.d.ts.map +1 -0
  9. package/dist/voicevox/api.js +3 -3
  10. package/dist/voicevox/error.d.ts +73 -0
  11. package/dist/voicevox/error.d.ts.map +1 -0
  12. package/dist/voicevox/error.js +89 -0
  13. package/dist/voicevox/index.d.ts +60 -8
  14. package/dist/voicevox/index.d.ts.map +1 -1
  15. package/dist/voicevox/index.js +79 -9
  16. package/dist/voicevox/player.d.ts +70 -3
  17. package/dist/voicevox/player.d.ts.map +1 -1
  18. package/dist/voicevox/player.js +55 -141
  19. package/dist/voicevox/queue/__tests__/manager.test.d.ts +2 -0
  20. package/dist/voicevox/queue/__tests__/manager.test.d.ts.map +1 -0
  21. package/dist/voicevox/queue/__tests__/manager.test.js +122 -91
  22. package/dist/voicevox/queue/audio-generator.d.ts +33 -0
  23. package/dist/voicevox/queue/audio-generator.d.ts.map +1 -0
  24. package/dist/voicevox/queue/audio-generator.js +11 -6
  25. package/dist/voicevox/queue/audio-player.d.ts +18 -0
  26. package/dist/voicevox/queue/audio-player.d.ts.map +1 -0
  27. package/dist/voicevox/queue/audio-player.js +2 -3
  28. package/dist/voicevox/queue/event-manager.d.ts +28 -0
  29. package/dist/voicevox/queue/event-manager.d.ts.map +1 -0
  30. package/dist/voicevox/queue/file-manager.d.ts +30 -0
  31. package/dist/voicevox/queue/file-manager.d.ts.map +1 -0
  32. package/dist/voicevox/queue/file-manager.js +35 -0
  33. package/dist/voicevox/queue/index.d.ts +7 -0
  34. package/dist/voicevox/queue/index.d.ts.map +1 -0
  35. package/dist/voicevox/queue/manager.d.ts +111 -0
  36. package/dist/voicevox/queue/manager.d.ts.map +1 -0
  37. package/dist/voicevox/queue/manager.js +104 -70
  38. package/dist/voicevox/queue/types.d.ts +96 -0
  39. package/dist/voicevox/queue/types.d.ts.map +1 -0
  40. package/dist/voicevox/queue/types.js +1 -0
  41. package/dist/voicevox/types.d.ts +145 -0
  42. package/dist/voicevox/types.d.ts.map +1 -0
  43. package/dist/voicevox/utils.d.ts +13 -0
  44. package/dist/voicevox/utils.d.ts.map +1 -0
  45. package/dist/voicevox/utils.js +8 -0
  46. package/package.json +2 -1
  47. package/dist/index.js.map +0 -1
  48. package/dist/voicevox/client.js +0 -391
  49. package/dist/voicevox/generator.d.ts +0 -6
  50. package/dist/voicevox/generator.d.ts.map +0 -1
  51. package/dist/voicevox/generator.js +0 -37
  52. package/dist/voicevox/generator.js.map +0 -1
  53. package/dist/voicevox/index.js.map +0 -1
  54. package/dist/voicevox/player.js.map +0 -1
package/README.md CHANGED
@@ -2,81 +2,63 @@
2
2
 
3
3
  VOICEVOXを使用した音声合成MCPサーバー
4
4
 
5
+ ## 特徴
6
+
7
+ - **キュー管理機能** - 複数の音声合成リクエストを効率的に処理
8
+ - **プリフェッチ** - 次の音声を事前に生成し、再生をスムーズに
9
+
5
10
  ## 必要条件
6
11
 
7
12
  - Node.js
8
13
  - [VOICEVOXエンジン](https://voicevox.hiroshiba.jp/)
9
14
 
10
- ## 機能概要
11
-
12
- - テキストから音声を合成して再生
13
- - テキストから音声合成用クエリを生成
14
- - 音声合成用クエリから音声ファイルを生成
15
- - テキストまたはクエリを音声生成キューに追加
16
-
17
- ## 使い方
18
-
19
- ### インストール
15
+ ## インストール
20
16
 
21
17
  ```bash
22
18
  npm install -g @kajidog/mcp-tts-voicevox
23
19
  ```
24
20
 
25
- ### 実行
21
+ ## 使い方
22
+
23
+ ### MCPサーバーとして
26
24
 
27
25
  1. VOICEVOXエンジンを起動
28
- 2. 以下のコマンドを実行
26
+ 2. MCPサーバーを起動
29
27
 
30
28
  ```bash
31
29
  npx @kajidog/mcp-tts-voicevox
32
30
  ```
33
31
 
34
- ### MCPツールとして使用
32
+ ### ライブラリとして
35
33
 
36
- #### 1. テキストを音声に変換して再生
34
+ プロジェクトに直接インポートして使用することも可能です:
37
35
 
38
- ```typescript
39
- await mcp.invoke("speak", {
40
- text: "こんにちは!", // 読み上げるテキスト
41
- speaker: 1 // 話者ID(オプション)
42
- });
36
+ ```bash
37
+ npm install @kajidog/mcp-tts-voicevox
43
38
  ```
44
39
 
45
- #### 2. テキストから音声合成用クエリを生成
40
+ ```javascript
41
+ import { VoicevoxClient } from "@kajidog/mcp-tts-voicevox";
46
42
 
47
- ```typescript
48
- const queryResult = await mcp.invoke("generate_query", {
49
- text: "こんにちは!", // 音声合成するテキスト
50
- speaker: 1 // 話者ID(オプション)
43
+ // クライアントを初期化
44
+ const client = new VoicevoxClient({
45
+ url: "http://localhost:50021", // VOICEVOXエンジンのURL
46
+ defaultSpeaker: 1, // デフォルト話者ID(オプション)
47
+ defaultSpeedScale: 1.0 // デフォルト速度(オプション)
51
48
  });
52
49
 
53
- // 返されたテキストをJSONにパース
54
- const query = JSON.parse(queryResult.content[0].text);
55
- ```
56
-
57
- #### 3. 音声合成用クエリから音声ファイルを生成
50
+ // テキストを音声に変換して再生
51
+ await client.speak("こんにちは");
58
52
 
59
- ```typescript
60
- const fileResult = await mcp.invoke("synthesize_file", {
61
- query: query, // 音声合成用クエリ
62
- output: "/path/to/output.wav", // 出力ファイルパス
63
- speaker: 1 // 話者ID(オプション)
64
- });
65
-
66
- // 生成された音声ファイルのパス
67
- const filePath = fileResult.content[0].text;
53
+ // テキストから音声ファイルを生成
54
+ const filePath = await client.generateAudioFile("こんにちは", "./output.wav");
68
55
  ```
69
56
 
70
- ## 活用例
71
-
72
- 1. **テキストを直接音声に変換**
73
- - `speak` - 短いテキストをすぐに読み上げたいとき
74
-
75
- 2. **細かい音声設定をカスタマイズ**
76
- - `generate_query` → クエリ編集 → `synthesize_file` の流れで高度な調整が可能
57
+ ## 主な機能
77
58
 
78
- 3. **バッチ処理で大量の音声ファイルを作成**
79
- - テキストをクエリに変換してから一括で音声ファイルを生成
59
+ - **テキスト読み上げ** (`speak`) - テキストを音声に変換して再生
60
+ - **クエリ生成** (`generate_query`) - 音声合成用クエリの作成
61
+ - **ファイル生成** (`synthesize_file`) - クエリから音声ファイルを生成
80
62
 
81
63
  ## 環境変数
82
64
 
package/dist/index.d.ts CHANGED
@@ -1,2 +1,5 @@
1
- export {};
1
+ #!/usr/bin/env node
2
+ import { VoicevoxClient } from "./voicevox";
3
+ import { AudioQuery, VoicevoxConfig, VoicevoxError, Score, Note, FrameAudioQuery } from "./voicevox/types";
4
+ export { AudioQuery, VoicevoxConfig, VoicevoxClient, VoicevoxError, Score, Note, FrameAudioQuery, };
2
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACL,UAAU,EACV,cAAc,EACd,aAAa,EACb,KAAK,EACL,IAAI,EACJ,eAAe,EAChB,MAAM,kBAAkB,CAAC;AA4K1B,OAAO,EACL,UAAU,EACV,cAAc,EACd,cAAc,EACd,aAAa,EACb,KAAK,EACL,IAAI,EACJ,eAAe,GAChB,CAAC"}
package/dist/index.js CHANGED
@@ -1,16 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.VoicevoxError = void 0;
4
+ exports.VoicevoxError = exports.VoicevoxClient = void 0;
5
5
  const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
6
6
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
7
7
  const zod_1 = require("zod");
8
8
  const voicevox_1 = require("./voicevox");
9
+ Object.defineProperty(exports, "VoicevoxClient", { enumerable: true, get: function () { return voicevox_1.VoicevoxClient; } });
9
10
  const types_1 = require("./voicevox/types");
10
11
  Object.defineProperty(exports, "VoicevoxError", { enumerable: true, get: function () { return types_1.VoicevoxError; } });
11
12
  const server = new mcp_js_1.McpServer({
12
13
  name: "MCP TTS Voicevox",
13
- version: "0.0.6",
14
+ version: "0.0.8",
14
15
  description: "A Voicevox server that converts text to speech for playback and saving.",
15
16
  });
16
17
  // VoicevoxClientを一度だけインスタンス化
package/dist/test.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../src/test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,28 @@
1
+ import { AudioQuery } from "./types";
2
+ export declare class VoicevoxApi {
3
+ private readonly baseUrl;
4
+ constructor(baseUrl: string);
5
+ /**
6
+ * テキストから音声合成用クエリを生成
7
+ */
8
+ generateQuery(text: string, speaker?: number): Promise<AudioQuery>;
9
+ /**
10
+ * 音声合成用クエリから音声ファイルを生成
11
+ */
12
+ synthesize(query: AudioQuery, speaker?: number): Promise<ArrayBuffer>;
13
+ /**
14
+ * プリセットを使用してテキストから音声合成用クエリを生成
15
+ */
16
+ generateQueryFromPreset(text: string, presetId: number, coreVersion?: string): Promise<AudioQuery>;
17
+ /**
18
+ * APIリクエストを実行
19
+ * @private
20
+ */
21
+ private makeRequest;
22
+ /**
23
+ * URLの正規化
24
+ * @private
25
+ */
26
+ private normalizeUrl;
27
+ }
28
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/voicevox/api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAiB,MAAM,SAAS,CAAC;AAGpD,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,EAAE,MAAM;IAI3B;;OAEG;IACU,aAAa,CACxB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,MAAU,GAClB,OAAO,CAAC,UAAU,CAAC;IAetB;;OAEG;IACU,UAAU,CACrB,KAAK,EAAE,UAAU,EACjB,OAAO,GAAE,MAAU,GAClB,OAAO,CAAC,WAAW,CAAC;IAiBvB;;OAEG;IACU,uBAAuB,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,UAAU,CAAC;IAuBtB;;;OAGG;YACW,WAAW;IAuCzB;;;OAGG;IACH,OAAO,CAAC,YAAY;CAGrB"}
@@ -16,7 +16,7 @@ class VoicevoxApi {
16
16
  */
17
17
  async generateQuery(text, speaker = 1) {
18
18
  try {
19
- const endpoint = `/audio_query?text=${encodeURIComponent(text)}&speaker=${speaker}`;
19
+ const endpoint = `/audio_query?text=${encodeURIComponent(text)}&speaker=${encodeURIComponent(speaker.toString())}`;
20
20
  const query = await this.makeRequest("post", endpoint, null, {
21
21
  "Content-Type": "application/json",
22
22
  });
@@ -31,7 +31,7 @@ class VoicevoxApi {
31
31
  */
32
32
  async synthesize(query, speaker = 1) {
33
33
  try {
34
- return await this.makeRequest("post", `/synthesis?speaker=${speaker}`, query, {
34
+ return await this.makeRequest("post", `/synthesis?speaker=${encodeURIComponent(speaker.toString())}`, query, {
35
35
  "Content-Type": "application/json",
36
36
  Accept: "audio/wav",
37
37
  }, "arraybuffer");
@@ -45,7 +45,7 @@ class VoicevoxApi {
45
45
  */
46
46
  async generateQueryFromPreset(text, presetId, coreVersion) {
47
47
  try {
48
- let endpoint = `/audio_query_from_preset?text=${encodeURIComponent(text)}&preset_id=${presetId}`;
48
+ let endpoint = `/audio_query_from_preset?text=${encodeURIComponent(text)}&preset_id=${encodeURIComponent(presetId.toString())}`;
49
49
  if (coreVersion) {
50
50
  endpoint += `&core_version=${encodeURIComponent(coreVersion)}`;
51
51
  }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * エラーハンドリングを行い、適切なエラーメッセージとともに例外をスローします
3
+ * @param message エラーメッセージのプレフィックス
4
+ * @param error 発生したエラー
5
+ * @returns never(常に例外をスロー)
6
+ */
7
+ export declare function handleError(message: string, error: unknown): never;
8
+ /**
9
+ * エラーハンドリングを行い、エラーメッセージを返します (例外をスローしない)
10
+ * @param message エラーメッセージのプレフィックス
11
+ * @param error 発生したエラー
12
+ * @returns エラーメッセージ
13
+ */
14
+ export declare function formatError(message: string, error: unknown): string;
15
+ /**
16
+ * VOICEVOX関連のエラーコード
17
+ */
18
+ export declare enum VoicevoxErrorCode {
19
+ API_CONNECTION_ERROR = "api_connection_error",
20
+ QUERY_GENERATION_ERROR = "query_generation_error",
21
+ SYNTHESIS_ERROR = "synthesis_error",
22
+ FILE_OPERATION_ERROR = "file_operation_error",
23
+ PLAYBACK_ERROR = "playback_error",
24
+ QUEUE_OPERATION_ERROR = "queue_operation_error",
25
+ UNKNOWN_ERROR = "unknown_error"
26
+ }
27
+ /**
28
+ * VOICEVOXエラークラス
29
+ */
30
+ export declare class VoicevoxError extends Error {
31
+ code: VoicevoxErrorCode;
32
+ originalError?: unknown;
33
+ constructor(message: string, code?: VoicevoxErrorCode, originalError?: unknown);
34
+ /**
35
+ * エラー発生箇所とスタックトレースを含むエラーの詳細情報を取得
36
+ */
37
+ getDetailedMessage(): string;
38
+ }
39
+ /**
40
+ * エラーハンドリングユーティリティクラス
41
+ * アプリケーション全体で統一されたエラーハンドリングを提供
42
+ */
43
+ export declare class ErrorHandler {
44
+ /**
45
+ * エラーをVoicevoxError形式に変換して例外をスロー
46
+ */
47
+ static throw(message: string, code?: VoicevoxErrorCode, originalError?: unknown): never;
48
+ /**
49
+ * APIエラーを処理
50
+ */
51
+ static handleApiError(message: string, error: unknown): never;
52
+ /**
53
+ * クエリ生成エラーを処理
54
+ */
55
+ static handleQueryGenerationError(message: string, error: unknown): never;
56
+ /**
57
+ * 音声合成エラーを処理
58
+ */
59
+ static handleSynthesisError(message: string, error: unknown): never;
60
+ /**
61
+ * ファイル操作エラーを処理
62
+ */
63
+ static handleFileError(message: string, error: unknown): never;
64
+ /**
65
+ * 再生エラーを処理
66
+ */
67
+ static handlePlaybackError(message: string, error: unknown): never;
68
+ /**
69
+ * キュー操作エラーを処理
70
+ */
71
+ static handleQueueError(message: string, error: unknown): never;
72
+ }
73
+ //# sourceMappingURL=error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/voicevox/error.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,KAAK,CAIlE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAInE;AAED;;GAEG;AACH,oBAAY,iBAAiB;IAC3B,oBAAoB,yBAAyB;IAC7C,sBAAsB,2BAA2B;IACjD,eAAe,oBAAoB;IACnC,oBAAoB,yBAAyB;IAC7C,cAAc,mBAAmB;IACjC,qBAAqB,0BAA0B;IAC/C,aAAa,kBAAkB;CAChC;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,IAAI,EAAE,iBAAiB,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;gBAGtB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,iBAAmD,EACzD,aAAa,CAAC,EAAE,OAAO;IAQzB;;OAEG;IACH,kBAAkB,IAAI,MAAM;CAY7B;AAED;;;GAGG;AACH,qBAAa,YAAY;IACvB;;OAEG;IACH,MAAM,CAAC,KAAK,CACV,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,iBAAmD,EACzD,aAAa,CAAC,EAAE,OAAO,GACtB,KAAK;IAKR;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,KAAK;IAI7D;;OAEG;IACH,MAAM,CAAC,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,KAAK;IAIzE;;OAEG;IACH,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,KAAK;IAInE;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,KAAK;IAI9D;;OAEG;IACH,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,KAAK;IAIlE;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,KAAK;CAGhE"}
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ErrorHandler = exports.VoicevoxError = exports.VoicevoxErrorCode = void 0;
3
4
  exports.handleError = handleError;
4
5
  exports.formatError = formatError;
5
6
  /**
@@ -24,3 +25,91 @@ function formatError(message, error) {
24
25
  console.error(`${message}: ${errorMsg}`, error);
25
26
  return `${message}: ${errorMsg}`;
26
27
  }
28
+ /**
29
+ * VOICEVOX関連のエラーコード
30
+ */
31
+ var VoicevoxErrorCode;
32
+ (function (VoicevoxErrorCode) {
33
+ VoicevoxErrorCode["API_CONNECTION_ERROR"] = "api_connection_error";
34
+ VoicevoxErrorCode["QUERY_GENERATION_ERROR"] = "query_generation_error";
35
+ VoicevoxErrorCode["SYNTHESIS_ERROR"] = "synthesis_error";
36
+ VoicevoxErrorCode["FILE_OPERATION_ERROR"] = "file_operation_error";
37
+ VoicevoxErrorCode["PLAYBACK_ERROR"] = "playback_error";
38
+ VoicevoxErrorCode["QUEUE_OPERATION_ERROR"] = "queue_operation_error";
39
+ VoicevoxErrorCode["UNKNOWN_ERROR"] = "unknown_error";
40
+ })(VoicevoxErrorCode || (exports.VoicevoxErrorCode = VoicevoxErrorCode = {}));
41
+ /**
42
+ * VOICEVOXエラークラス
43
+ */
44
+ class VoicevoxError extends Error {
45
+ constructor(message, code = VoicevoxErrorCode.UNKNOWN_ERROR, originalError) {
46
+ super(message);
47
+ this.name = "VoicevoxError";
48
+ this.code = code;
49
+ this.originalError = originalError;
50
+ }
51
+ /**
52
+ * エラー発生箇所とスタックトレースを含むエラーの詳細情報を取得
53
+ */
54
+ getDetailedMessage() {
55
+ let details = `${this.message} [${this.code}]`;
56
+ if (this.originalError instanceof Error) {
57
+ details += `\nOriginal Error: ${this.originalError.message}`;
58
+ if (this.originalError.stack) {
59
+ details += `\nStack: ${this.originalError.stack}`;
60
+ }
61
+ }
62
+ return details;
63
+ }
64
+ }
65
+ exports.VoicevoxError = VoicevoxError;
66
+ /**
67
+ * エラーハンドリングユーティリティクラス
68
+ * アプリケーション全体で統一されたエラーハンドリングを提供
69
+ */
70
+ class ErrorHandler {
71
+ /**
72
+ * エラーをVoicevoxError形式に変換して例外をスロー
73
+ */
74
+ static throw(message, code = VoicevoxErrorCode.UNKNOWN_ERROR, originalError) {
75
+ console.error(`[${code}] ${message}`, originalError);
76
+ throw new VoicevoxError(message, code, originalError);
77
+ }
78
+ /**
79
+ * APIエラーを処理
80
+ */
81
+ static handleApiError(message, error) {
82
+ return this.throw(message, VoicevoxErrorCode.API_CONNECTION_ERROR, error);
83
+ }
84
+ /**
85
+ * クエリ生成エラーを処理
86
+ */
87
+ static handleQueryGenerationError(message, error) {
88
+ return this.throw(message, VoicevoxErrorCode.QUERY_GENERATION_ERROR, error);
89
+ }
90
+ /**
91
+ * 音声合成エラーを処理
92
+ */
93
+ static handleSynthesisError(message, error) {
94
+ return this.throw(message, VoicevoxErrorCode.SYNTHESIS_ERROR, error);
95
+ }
96
+ /**
97
+ * ファイル操作エラーを処理
98
+ */
99
+ static handleFileError(message, error) {
100
+ return this.throw(message, VoicevoxErrorCode.FILE_OPERATION_ERROR, error);
101
+ }
102
+ /**
103
+ * 再生エラーを処理
104
+ */
105
+ static handlePlaybackError(message, error) {
106
+ return this.throw(message, VoicevoxErrorCode.PLAYBACK_ERROR, error);
107
+ }
108
+ /**
109
+ * キュー操作エラーを処理
110
+ */
111
+ static handleQueueError(message, error) {
112
+ return this.throw(message, VoicevoxErrorCode.QUEUE_OPERATION_ERROR, error);
113
+ }
114
+ }
115
+ exports.ErrorHandler = ErrorHandler;
@@ -1,11 +1,63 @@
1
+ import { AudioQuery, VoicevoxConfig } from "./types";
1
2
  export declare class VoicevoxClient {
2
- private audioGenerationQueue;
3
- private audioPlaybackQueue;
4
- private generator;
5
- private player;
6
- constructor(voicevoxUrl?: string);
7
- private processAudioQueue;
8
- private startQueueProcessing;
9
- speak(text: string, speaker?: number): Promise<string>;
3
+ private readonly player;
4
+ private readonly api;
5
+ private readonly defaultSpeaker;
6
+ private readonly defaultSpeedScale;
7
+ private readonly maxSegmentLength;
8
+ constructor(config: VoicevoxConfig);
9
+ /**
10
+ * テキストを音声に変換して再生します
11
+ * @param text 変換するテキスト
12
+ * @param speaker 話者ID(オプション)
13
+ * @param speedScale 再生速度(オプション)
14
+ * @returns 処理結果のメッセージ
15
+ */
16
+ speak(text: string, speaker?: number, speedScale?: number): Promise<string>;
17
+ /**
18
+ * テキストから音声合成用クエリを生成します
19
+ * @param text 変換するテキスト
20
+ * @param speaker 話者ID(オプション)
21
+ * @param speedScale 再生速度(オプション)
22
+ * @returns 音声合成用クエリ
23
+ */
24
+ generateQuery(text: string, speaker?: number, speedScale?: number): Promise<AudioQuery>;
25
+ /**
26
+ * テキストから直接音声ファイルを生成します
27
+ * @param textOrQuery テキストまたは音声合成用クエリ
28
+ * @param outputPath 出力ファイルパス(オプション、省略時は一時ファイル)
29
+ * @param speaker 話者ID(オプション)
30
+ * @param speedScale 再生速度(オプション)
31
+ * @returns 生成した音声ファイルのパス
32
+ */
33
+ generateAudioFile(textOrQuery: string | AudioQuery, outputPath?: string, speaker?: number, speedScale?: number): Promise<string>;
34
+ /**
35
+ * テキストを音声ファイル生成キューに追加します
36
+ * @param text テキスト
37
+ * @param speaker 話者ID(オプション)
38
+ * @param speedScale 再生速度(オプション)
39
+ * @returns 処理結果のメッセージ
40
+ */
41
+ enqueueAudioGeneration(text: string, speaker?: number, speedScale?: number): Promise<string>;
42
+ /**
43
+ * 音声合成用クエリを音声ファイル生成キューに追加します
44
+ * @param query 音声合成用クエリ
45
+ * @param speaker 話者ID(オプション)
46
+ * @param speedScale 再生速度(オプション)
47
+ * @returns 処理結果のメッセージ
48
+ */
49
+ enqueueAudioGeneration(query: AudioQuery, speaker?: number, speedScale?: number): Promise<string>;
50
+ /**
51
+ * 話者IDを取得(指定がない場合はデフォルト値を使用)
52
+ * @private
53
+ */
54
+ private getSpeakerId;
55
+ /**
56
+ * 再生速度を取得(指定がない場合はデフォルト値を使用)
57
+ * @private
58
+ */
59
+ private getSpeedScale;
60
+ private validateConfig;
10
61
  }
62
+ export * from "./types";
11
63
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/voicevox/index.ts"],"names":[],"mappings":"AAGA,qBAAa,cAAc;IACzB,OAAO,CAAC,oBAAoB,CAA2C;IACvE,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,MAAM,CAAiB;gBAEnB,WAAW,GAAE,MAAiC;YAO5C,iBAAiB;IAkB/B,OAAO,CAAC,oBAAoB;IAKf,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,MAAU,GAAG,OAAO,CAAC,MAAM,CAAC;CAIvE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/voicevox/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAKrD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;IAClC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE9B,MAAM,EAAE,cAAc;IASlC;;;;;;OAMG;IACU,KAAK,CAChB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC;IAyClB;;;;;;OAMG;IACU,aAAa,CACxB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,UAAU,CAAC;IAYtB;;;;;;;OAOG;IACU,iBAAiB,CAC5B,WAAW,EAAE,MAAM,GAAG,UAAU,EAChC,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC;IA8ClB;;;;;;OAMG;IACU,sBAAsB,CACjC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC;IAElB;;;;;;OAMG;IACU,sBAAsB,CACjC,KAAK,EAAE,UAAU,EACjB,OAAO,CAAC,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC;IA4DlB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAIpB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,cAAc;CAUvB;AAGD,cAAc,SAAS,CAAC"}
@@ -18,12 +18,14 @@ exports.VoicevoxClient = void 0;
18
18
  const player_1 = require("./player");
19
19
  const utils_1 = require("./utils");
20
20
  const error_1 = require("./error");
21
+ const api_1 = require("./api");
21
22
  class VoicevoxClient {
22
23
  constructor(config) {
23
24
  this.validateConfig(config);
24
25
  this.defaultSpeaker = config.defaultSpeaker ?? 1;
25
26
  this.defaultSpeedScale = config.defaultSpeedScale ?? 1.0;
26
27
  this.maxSegmentLength = 150;
28
+ this.api = new api_1.VoicevoxApi(config.url);
27
29
  this.player = new player_1.VoicevoxPlayer(config.url);
28
30
  }
29
31
  /**
@@ -38,10 +40,30 @@ class VoicevoxClient {
38
40
  const speakerId = this.getSpeakerId(speaker);
39
41
  const speed = this.getSpeedScale(speedScale);
40
42
  const segments = (0, utils_1.splitText)(text, this.maxSegmentLength);
41
- for (const segment of segments) {
42
- const query = await this.player.generateQuery(segment, speakerId);
43
- query.speedScale = speed;
44
- await this.player.enqueueWithQuery(query, speakerId);
43
+ const queueManager = this.player.getQueueManager();
44
+ if (segments.length === 0) {
45
+ return "テキストが空です";
46
+ }
47
+ // 最初のセグメントを優先的に処理して再生を早く開始
48
+ if (segments.length > 0) {
49
+ const firstQuery = await this.generateQuery(segments[0], speakerId);
50
+ firstQuery.speedScale = speed;
51
+ await queueManager.enqueueQuery(firstQuery, speakerId);
52
+ }
53
+ // 残りのセグメントは非同期で処理
54
+ if (segments.length > 1) {
55
+ // 残りのセグメントを非同期で処理する関数
56
+ const processRemainingSegments = async () => {
57
+ for (let i = 1; i < segments.length; i++) {
58
+ const query = await this.generateQuery(segments[i], speakerId);
59
+ query.speedScale = speed;
60
+ await queueManager.enqueueQuery(query, speakerId);
61
+ }
62
+ };
63
+ // 非同期で開始するが結果を待たない
64
+ processRemainingSegments().catch((error) => {
65
+ console.error("残りのセグメント処理中にエラーが発生しました:", error);
66
+ });
45
67
  }
46
68
  return `音声生成キューに追加しました: ${text}`;
47
69
  }
@@ -59,7 +81,8 @@ class VoicevoxClient {
59
81
  async generateQuery(text, speaker, speedScale) {
60
82
  try {
61
83
  const speakerId = this.getSpeakerId(speaker);
62
- const query = await this.player.generateQuery(text, speakerId);
84
+ // 直接APIを使用してクエリを生成
85
+ const query = await this.api.generateQuery(text, speakerId);
63
86
  query.speedScale = this.getSpeedScale(speedScale);
64
87
  return query;
65
88
  }
@@ -79,14 +102,33 @@ class VoicevoxClient {
79
102
  try {
80
103
  const speakerId = this.getSpeakerId(speaker);
81
104
  const speed = this.getSpeedScale(speedScale);
105
+ // キューマネージャーにアクセス
106
+ const queueManager = this.player.getQueueManager();
82
107
  if (typeof textOrQuery === "string") {
108
+ // テキストからクエリを生成
83
109
  const query = await this.generateQuery(textOrQuery, speakerId);
84
110
  query.speedScale = speed;
85
- return await this.player.synthesizeToFile(query, outputPath, speakerId);
111
+ // 直接APIで音声合成
112
+ const audioData = await this.api.synthesize(query, speakerId);
113
+ // 一時ファイル保存またはパス指定の保存
114
+ if (!outputPath) {
115
+ return await queueManager.saveTempAudioFile(audioData);
116
+ }
117
+ else {
118
+ return await this.player.synthesizeToFile(query, outputPath, speakerId);
119
+ }
86
120
  }
87
121
  else {
122
+ // クエリを使って音声合成
88
123
  const query = { ...textOrQuery, speedScale: speed };
89
- return await this.player.synthesizeToFile(query, outputPath, speakerId);
124
+ const audioData = await this.api.synthesize(query, speakerId);
125
+ // 一時ファイル保存またはパス指定の保存
126
+ if (!outputPath) {
127
+ return await queueManager.saveTempAudioFile(audioData);
128
+ }
129
+ else {
130
+ return await this.player.synthesizeToFile(query, outputPath, speakerId);
131
+ }
90
132
  }
91
133
  }
92
134
  catch (error) {
@@ -98,12 +140,40 @@ class VoicevoxClient {
98
140
  try {
99
141
  const speakerId = this.getSpeakerId(speaker);
100
142
  const speed = this.getSpeedScale(speedScale);
143
+ const queueManager = this.player.getQueueManager();
101
144
  if (typeof textOrQuery === "string") {
102
- return await this.speak(textOrQuery, speakerId, speed);
145
+ // テキストの場合:分割して処理
146
+ const segments = (0, utils_1.splitText)(textOrQuery, this.maxSegmentLength);
147
+ if (segments.length === 0) {
148
+ return "テキストが空です";
149
+ }
150
+ // 最初のセグメントを優先処理
151
+ if (segments.length > 0) {
152
+ const firstQuery = await this.generateQuery(segments[0], speakerId);
153
+ firstQuery.speedScale = speed;
154
+ await queueManager.enqueueQuery(firstQuery, speakerId);
155
+ }
156
+ // 残りのセグメントは非同期で処理
157
+ if (segments.length > 1) {
158
+ // 非同期で処理する関数
159
+ const processRemainingSegments = async () => {
160
+ for (let i = 1; i < segments.length; i++) {
161
+ const query = await this.generateQuery(segments[i], speakerId);
162
+ query.speedScale = speed;
163
+ await queueManager.enqueueQuery(query, speakerId);
164
+ }
165
+ };
166
+ // 非同期で開始するが結果を待たない
167
+ processRemainingSegments().catch((error) => {
168
+ console.error("残りのセグメント処理中にエラーが発生しました:", error);
169
+ });
170
+ }
171
+ return `テキストをキューに追加しました: ${textOrQuery}`;
103
172
  }
104
173
  else {
174
+ // クエリをキューに追加
105
175
  const query = { ...textOrQuery, speedScale: speed };
106
- await this.player.enqueueWithQuery(query, speakerId);
176
+ await queueManager.enqueueQuery(query, speakerId);
107
177
  return "クエリをキューに追加しました";
108
178
  }
109
179
  }