PythonでgTTSを使ってみる(音声合成、Node-RED)
はじめに
今回はPythonでgTTS(Google Text-to-Speech)を使ってみました。
以前VoiceVoxも使ったことがあるのですが、英語も話すことができて、ローカル環境での音声の生成が早いものを探していました。簡単に使える上に生成も早かったので、今後使っていきたいなと思っています。
▼以前の記事はこちら
関連情報
▼GitHubのリポジトリはこちら
https://github.com/pndurette/gTTS
▼Examplesのページがありました。
https://gtts.readthedocs.io/en/latest/module.html#examples
▼PyPIのページはこちら。
Pythonで実行してみる
Pythonの仮想環境を作成し、gTTSをインストールしました。環境はWindows 11、Python 3.10で実行しています。
▼環境を構築するためのコマンドはこちら
python -m venv pyenv
cd pyenv
.\Scripts\activate
pip install gTTS
▼Pythonの仮想環境の作成について、詳細は以下の記事をご覧ください。Pythonのバージョンを指定して作成することもできます。
gTTSのExamplesのページにあった、サンプルプログラムを試してみました。
▼以下のコードを実行しました。言語も選択できるようですね。
from gtts import gTTS
tts = gTTS('hello', lang='en')
tts.save('hello.mp3')
▼以下の音声ファイルが生成されました。
▼後で利用するgtts-cli.exeという実行ファイルが、Scriptsフォルダに追加されています。
python-venvノードで実行してみる
Node-REDでPythonの仮想環境を作成して、その環境でPythonを実行することができるpython-venvノードを利用して、gTTSを使ってみました。
▼Node-RED Advent Calendarにノードの開発の変遷について紹介しています。
https://qiita.com/background/items/d2e05e8d85427761a609
▼ノードの開発については以下の記事でも紹介しています。
今年の10月に新たに追加したvenv-execノードで仮想環境に追加された実行ファイルを実行することができます。gTTSを使ったサンプルフローがGitHubのリポジトリにも入っています。
▼まずは以下のフローを試してみました。
[{"id":"3eaf61a6234b295e","type":"pip","z":"22eb2b8f4786695c","venvconfig":"36c2cf6f351fdc6e","name":"","arg":"gTTS","action":"install","tail":false,"x":630,"y":3900,"wires":[["adc2bd3e14623eac"]]},{"id":"0329d8a408d93a42","type":"inject","z":"22eb2b8f4786695c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":480,"y":3900,"wires":[["3eaf61a6234b295e"]]},{"id":"adc2bd3e14623eac","type":"debug","z":"22eb2b8f4786695c","name":"debug 150","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":790,"y":3900,"wires":[]},{"id":"ad3e228c832881fd","type":"venv-exec","z":"22eb2b8f4786695c","name":"","venvconfig":"36c2cf6f351fdc6e","mode":"execute","executable":"gtts-cli.exe","arguments":"'hello' --output hello.mp3","x":630,"y":3960,"wires":[["d2b90b2d03a26252"]]},{"id":"faf05570b1bc51af","type":"inject","z":"22eb2b8f4786695c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":480,"y":3960,"wires":[["ad3e228c832881fd"]]},{"id":"d2b90b2d03a26252","type":"debug","z":"22eb2b8f4786695c","name":"debug 155","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":790,"y":3960,"wires":[]},{"id":"36c2cf6f351fdc6e","type":"venv-config","venvname":"AI","version":"3.8"}]
pipノードでgTTSをインストール後、venv-execノードでインストールされた実行ファイルを実行できるようになります。
▼venv-execノードではgtts-cli.exeを実行しています。
▼実際に生成された音声ファイルはこちら。
venv-execノードはArgument(引数)の欄が空白の場合、msg.payloadの値を受け取って実行します。templateノードを使って、引数を変数にしてみます。
injectノードとvenv-execノードの間にtemplateノードを入れるだけでは、以下のようなエラーが起きていました。
▼Hello, World!のように文字列にスペースが含まれていると、スペースで区切られているかのようなエラーが出ていました。
▼debugノードで確認すると、文字列がダブルクォーテーションで囲まれています。
changeノードでダブルクォーテーションを取り除くようにしました。最終的に以下のフローを作成して実行できるようになりました。
▼全体のフローはこちら
[{"id":"5def8c7caba7d4da","type":"venv-exec","z":"22eb2b8f4786695c","name":"gTTS","venvconfig":"36c2cf6f351fdc6e","mode":"execute","executable":"gtts-cli.exe","arguments":"","x":860,"y":4160,"wires":[["2211e3a3be80c988"]]},{"id":"44c0cb2499027b61","type":"inject","z":"22eb2b8f4786695c","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"Hello, World!","payloadType":"str","x":450,"y":4100,"wires":[["68c9da00af3ff5d4"]]},{"id":"2211e3a3be80c988","type":"debug","z":"22eb2b8f4786695c","name":"debug 324","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1020,"y":4160,"wires":[]},{"id":"68c9da00af3ff5d4","type":"template","z":"22eb2b8f4786695c","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"'{{payload}}' --output voice.mp3","output":"str","x":600,"y":4100,"wires":[["e63d63cb8887f452","1b16618e69c8cb72"]]},{"id":"ed0419f2c389e0c2","type":"inject","z":"22eb2b8f4786695c","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"Nice to meet you.","payloadType":"str","x":460,"y":4180,"wires":[["68c9da00af3ff5d4"]]},{"id":"89f3ba3345fa9899","type":"template","z":"22eb2b8f4786695c","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"'{{payload}}' --output voice_ja.mp3 --lang ja","output":"str","x":620,"y":4220,"wires":[["5def8c7caba7d4da"]]},{"id":"12d9b5c47a80a876","type":"inject","z":"22eb2b8f4786695c","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"こんにちは","payloadType":"str","x":440,"y":4220,"wires":[["89f3ba3345fa9899"]]},{"id":"7be349c8c215c65b","type":"inject","z":"22eb2b8f4786695c","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"はじめまして","payloadType":"str","x":450,"y":4260,"wires":[["89f3ba3345fa9899"]]},{"id":"e63d63cb8887f452","type":"debug","z":"22eb2b8f4786695c","name":"debug 325","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":770,"y":4060,"wires":[]},{"id":"1b16618e69c8cb72","type":"change","z":"22eb2b8f4786695c","name":"","rules":[{"t":"change","p":"payload","pt":"msg","from":"\"","fromt":"str","to":"","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":800,"y":4100,"wires":[["5def8c7caba7d4da"]]},{"id":"36c2cf6f351fdc6e","type":"venv-config","venvname":"AI","version":"3.8"}]
▼templateノードでテキストだけ受け取って、必要な引数を指定しています。
▼日本語の場合、引数で日本語を指定しています。
▼changeノードでダブルクォーテーションを取り除いています。
実際に実行してみました。
▼動画の速度くらいで生成されます。テキストが短いというのもありますが、1秒かからないくらいですね。
▼生成された音声ファイルはこちら
最後に
日本語はゆっくり話しているような印象です。この後、venvノードでPythonのコードを実行し、生成した音声ファイルを再生したり、再生速度を変更したりすることもできました。
templateノードでテキストだけ受け取るようになっているので、他のノードと組み合わせて使うことができます。例えばdashboardノードと組み合わせて、入力したテキストの音声ファイルを生成するという使い方ができそうです。