@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.
- package/README.md +29 -47
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/test.d.ts +2 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/voicevox/api.d.ts +28 -0
- package/dist/voicevox/api.d.ts.map +1 -0
- package/dist/voicevox/api.js +3 -3
- package/dist/voicevox/error.d.ts +73 -0
- package/dist/voicevox/error.d.ts.map +1 -0
- package/dist/voicevox/error.js +89 -0
- package/dist/voicevox/index.d.ts +60 -8
- package/dist/voicevox/index.d.ts.map +1 -1
- package/dist/voicevox/index.js +79 -9
- package/dist/voicevox/player.d.ts +70 -3
- package/dist/voicevox/player.d.ts.map +1 -1
- package/dist/voicevox/player.js +55 -141
- package/dist/voicevox/queue/__tests__/manager.test.d.ts +2 -0
- package/dist/voicevox/queue/__tests__/manager.test.d.ts.map +1 -0
- package/dist/voicevox/queue/__tests__/manager.test.js +122 -91
- package/dist/voicevox/queue/audio-generator.d.ts +33 -0
- package/dist/voicevox/queue/audio-generator.d.ts.map +1 -0
- package/dist/voicevox/queue/audio-generator.js +11 -6
- package/dist/voicevox/queue/audio-player.d.ts +18 -0
- package/dist/voicevox/queue/audio-player.d.ts.map +1 -0
- package/dist/voicevox/queue/audio-player.js +2 -3
- package/dist/voicevox/queue/event-manager.d.ts +28 -0
- package/dist/voicevox/queue/event-manager.d.ts.map +1 -0
- package/dist/voicevox/queue/file-manager.d.ts +30 -0
- package/dist/voicevox/queue/file-manager.d.ts.map +1 -0
- package/dist/voicevox/queue/file-manager.js +35 -0
- package/dist/voicevox/queue/index.d.ts +7 -0
- package/dist/voicevox/queue/index.d.ts.map +1 -0
- package/dist/voicevox/queue/manager.d.ts +111 -0
- package/dist/voicevox/queue/manager.d.ts.map +1 -0
- package/dist/voicevox/queue/manager.js +104 -70
- package/dist/voicevox/queue/types.d.ts +96 -0
- package/dist/voicevox/queue/types.d.ts.map +1 -0
- package/dist/voicevox/queue/types.js +1 -0
- package/dist/voicevox/types.d.ts +145 -0
- package/dist/voicevox/types.d.ts.map +1 -0
- package/dist/voicevox/utils.d.ts +13 -0
- package/dist/voicevox/utils.d.ts.map +1 -0
- package/dist/voicevox/utils.js +8 -0
- package/package.json +2 -1
- package/dist/index.js.map +0 -1
- package/dist/voicevox/client.js +0 -391
- package/dist/voicevox/generator.d.ts +0 -6
- package/dist/voicevox/generator.d.ts.map +0 -1
- package/dist/voicevox/generator.js +0 -37
- package/dist/voicevox/generator.js.map +0 -1
- package/dist/voicevox/index.js.map +0 -1
- 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
|
-
###
|
|
32
|
+
### ライブラリとして
|
|
35
33
|
|
|
36
|
-
|
|
34
|
+
プロジェクトに直接インポートして使用することも可能です:
|
|
37
35
|
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
text: "こんにちは!", // 読み上げるテキスト
|
|
41
|
-
speaker: 1 // 話者ID(オプション)
|
|
42
|
-
});
|
|
36
|
+
```bash
|
|
37
|
+
npm install @kajidog/mcp-tts-voicevox
|
|
43
38
|
```
|
|
44
39
|
|
|
45
|
-
|
|
40
|
+
```javascript
|
|
41
|
+
import { VoicevoxClient } from "@kajidog/mcp-tts-voicevox";
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
//
|
|
54
|
-
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
#### 3. 音声合成用クエリから音声ファイルを生成
|
|
50
|
+
// テキストを音声に変換して再生
|
|
51
|
+
await client.speak("こんにちは");
|
|
58
52
|
|
|
59
|
-
|
|
60
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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.
|
|
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 @@
|
|
|
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"}
|
package/dist/voicevox/api.js
CHANGED
|
@@ -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"}
|
package/dist/voicevox/error.js
CHANGED
|
@@ -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;
|
package/dist/voicevox/index.d.ts
CHANGED
|
@@ -1,11 +1,63 @@
|
|
|
1
|
+
import { AudioQuery, VoicevoxConfig } from "./types";
|
|
1
2
|
export declare class VoicevoxClient {
|
|
2
|
-
private
|
|
3
|
-
private
|
|
4
|
-
private
|
|
5
|
-
private
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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":"
|
|
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"}
|
package/dist/voicevox/index.js
CHANGED
|
@@ -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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
176
|
+
await queueManager.enqueueQuery(query, speakerId);
|
|
107
177
|
return "クエリをキューに追加しました";
|
|
108
178
|
}
|
|
109
179
|
}
|