Google Cloud Text-to-Speech を利用し SSML (またはその他形式)の脚本を読み上げるプログラムです。
- Google Cloud Consoleにプロジェクトを作成します
- Cloud プロジェクトに対して課金が有効になっていることを確認します(毎月最初の400万文字が無料)
- Cloud Text-to-Speech API を有効にします
- アカウント キー(JSONファイル)をダウンロードします
- 環境変数
GOOGLE_APPLICATION_CREDENTIALS="/FULL/PATH/TO/ACCOUNT_KET.json"
になるようにセットします
詳しくは こちら をご覧ください。
モジュールとして
npm i google-tts-narrator
Cliアプリとして
npx google-tts-narrator --from my_scenario.ssml.pug --to my_scenario_sounds/
Google Cloud Text-to-SpeechのAPIは一回のCallに <speak></speak>
要素一つしか対応しておりません。
このライブラリーはお手元のSSMLファイルを分析し、各 <speak></speak>
要素にそれぞれ異なるConfigでText-to-Speech APIにアクセスします。
但し、それぞれの <speak></speak>
要素に audioConfig
と voice
のプロパティーを設置しなければなりません。設置の仕方は下記のサンプルをご覧ください。また こちらのページ や こちらのページ では、使用可能な条件を紹介しており、テストができます。
<speak audioConfig='{"audioEncoding": "MP3", "pitch": 0, "speakingRate": 1}'
voice='{"languageCode": "en-US", "name": "en-US-Wavenet-G"}'>
The <say-as interpret-as="characters">SSML</say-as>standard
<break time="1s"/>is defined by the
<sub alias="World Wide Web Consortium">W3C</sub>.
</speak>
<speak audioConfig='{"audioEncoding": "MP3", "pitch": 0, "speakingRate": 1}'
voice='{"languageCode": "en-ES", "name": "es-ES-Standard-C", "ssmlGender": "MALE"}'>
¡Hola<break time="200ms"/>mundo!
</speak>
上記シナリオは以下の2本MP3に変換されています。
[demo_1.mp3](./assets/demo_1.mp3)[demo_2.mp3](./assets/demo_2.mp3)
PugはインデントスタイルでHTMLを書けるDSL(Domain-Specific Language)です。 HTMLだけでなく、XMLの作成も用いられます。
前述したSSMLファイルは以下のように書き直せます。
speak(
audioconfig='{"audioEncoding": "MP3", "pitch": 0, "speakingRate": 1}'
voice='{"languageCode": "en-US", "name": "en-US-Wavenet-G"}')
| The #[say-as(interpret-as='characters') SSML] standard #[break(time='1s')/]
| is defined by the #[sub(alias='World Wide Web Consortium') W3C].
speak(
audioconfig='{"audioEncoding": "MP3", "pitch": 0, "speakingRate": 1}'
voice='{"languageCode": "en-ES", "name": "es-ES-Standard-C", "ssmlGender": "MALE"}')
| ¡Hola#[break(time='200ms')/] mundo!
その上、語り手の設定を独立したファイルに分割して、会話の見通しをよくすることができます。 [警告] モジュールとして利用する場合、分割したpugファイルは読み込めません。
//- _speaker.pug
mixin enSpeaker(audioConfig = {}, voice = {})
-
audioConfig = Object.assign({
speakingRate: 1.12, audioEncoding: 'MP3',
}, audioConfig)
voice = Object.assign({
languageCode: 'en-US', ssmlGender: 'MALE',
}, voice)
speak(audioConfig=audioConfig voice=voice)
block
mixin jaSpeaker(audioConfig = {}, voice = {})
-
audioConfig = Object.assign({
pitch: 1.6, speakingRate: 1.12,
audioEncoding: 'MP3',
}, audioConfig)
voice = Object.assign({
languageCode: 'ja-JP', name: 'ja-JP-Wavenet-A',
}, voice)
speak(audioConfig=audioConfig voice=voice)
block
//- include_demo.pug
include _speaker.pug
+enSpeaker Hello!
+jaSpeaker こんにちは!
+enSpeaker Goodbye!
+jaSpeaker さようなら!
またJSONやYAMLファイルにて、Text-to-Speech API用の変数を配列にして一括処理できます。
YAML
- &staff # Setup staff
audioConfig:
audioEncoding: MP3
pitch: 1.6
speakingRate: 1.07
voice:
languageCode: ja-JP
name: ja-JP-Wavenet-A
input:
text: いらっしゃいませ。
- &customer # Setup customer
audioConfig:
audioEncoding: MP3
pitch: 1.6
speakingRate: 1.07
voice:
languageCode: ja-JP
name: ja-JP-Wavenet-D
input:
text: チーズバーガーをください。
-
<<: *staff
input:
ssml: |-
<speak>
かしこまりました。お召し上がりですか?<break time="300ms"/>お持ち帰りですか?
</speak>
-
<<: *customer
input:
text: 持ち帰ります。
JSON
[
{
"voice": {
"languageCode": "en-US",
"ssmlGender": "NEUTRAL"
},
"audioConfig": {
"audioEncoding": "MP3"
},
"input": {
"text": "Hello, world!"
}
},
{
"voice": {
"languageCode": "en-ES",
"name": "es-ES-Standard-C"
},
"audioConfig": {
"audioEncoding": "MP3"
},
"input": {
"text": "¡Hola, mundo!"
}
}
]
環境変数 GOOGLE_APPLICATION_CREDENTIALS
を設定してから実行してください。
下記のコマンドで合成音声が生成されます。
npx google-tts-narrator -s PATH/TO/FILE
シナリオファイルPath以外、何も設定していない場合、システムは拡張子よりタイプを算出し処理を行い、出力フォルダも自動で作成します。
Options:
-s, --from Your Scenario File Path [required]
-d, --to Target Directory Path
-t, --type Scenario File Type, One of [pug|xml|yaml|json]
-h, --help Show help [boolean]
-v, --version Show version number [boolean]
環境変数 GOOGLE_APPLICATION_CREDENTIALS
を設定するか、下記のように手動で認証ファイルを設置します。
const Narrator = require('google-tts-narrator');
const options = { credentials: require('/PATH/TO/credentials.json') }
const scenario = fs.readFileSync('PATH/TO/scenario.pug', 'utf-8');
const gen = Narrator.yieldSpeeches(scenario, 'pug', options);
...
また、APIとして利用する場合、single fileのみ対応します。
ジェネレーターを使って音声を1ステップずつ合成できます、途中でやめられるので、時間や経費の節約につながります。
const fs = require('fs');
const Narrator = require('google-tts-narrator');
const scenario = fs.readFileSync('PATH/TO/scenario.pug', 'utf-8');
const gen = Narrator.yieldSpeeches(scenario, 'pug');
(async () => {
for await (let speach of gen) {
const { step } = speach.narratorInfo;
fs.writeFileSync(`PATH/TO/DIR/${step}.mp3`, speach.audioContent, 'binary');
}
})();
async/await スタイルのAPIを使って、シナリオを一括変換することもできます。
const fs = require('fs');
const Narrator = require('google-tts-narrator');
const scenario = fs.readFileSync('PATH/TO/scenario.pug', 'utf-8');
(async () => {
const speaches = await Narrator.fetchSpeeches();
speaches.forEach((speach, i) => {
fs.writeFileSync(`PATH/TO/DIR/${i}.mp3`, speach.audioContent, 'binary');
})
})();
本プロジェクトのサンプルに使う日本語対話サンプルは Rose Ladies School の 石川理江先生 のご厚意より寄贈されております。
該当部分の著作権はRose Ladies Schoolの石川理江先生に帰属します。
MIT(日本語対話サンプルを除く)