概要
音声対話システムを作るためのステップとして、voicevoxをインストールし、pythonで音声合成しましたので、作業内容をメモします。
すでに多くのノウハウが世に公開されていると思いますが、環境依存のところもあると思いますので、自分の環境ではこうやった、というのを情報として残します。
環境
- VoiceVoxサーバ
- ubuntu 24.04、RTX4060Ti
- docker, docker composeはインストール済みとします。
- dockerからnvidiaのgpuを使う設定も済とします。
- 音声合成用クライアント
- macOS M1
- python 3.11.2
VoiceVoxのインストール
GUIは不要なのでvoicevox engineのみ使います。
dockerを用いた利用方法がを使用して公式にあります。
再利用性を考えて、docker-compose.yamlを作成します。
mkdir -p ~/app/voicevox
cd ~/app/voicevox
nano docker-compose.yml
version: "3.8"
services:
voicevox_engine:
image: voicevox/voicevox_engine:nvidia-ubuntu20.04-latest
ports:
- "50021:50021"
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
environment:
NVIDIA_VISIBLE_DEVICES: "all"
NVIDIA_DRIVER_CAPABILITIES: "compute,utility"
runtime: nvidia
作成したら保存し、docker composeで起動します。
docker compose up -d
voicevox engineが起動したら、クライアントPCから音声合成できるか試してみます。
クライアントPCで以下のファイルを作成します。
echo -n "こんにちは、音声合成の世界へようこそ" >text.txt
curl -s \
-X POST \
"{UBUNTUのIPアドレス}:50021/audio_query?speaker=1"\
--get --data-urlencode text@text.txt \
> query.json
curl -s \
-H "Content-Type: application/json" \
-X POST \
-d @query.json \
"{UBUNTUのIPアドレス}:50021/synthesis?speaker=1" \
> audio.wav
作成したら実行します。
sh synthesis.sh
成功したらaudio.wavというファイルが同じフォルダに作成されているはずですので、再生して、synthesis.shで指定した文章が再生されるか確認してください。
afplay audio.wav
systemdへの登録(オプション)
必須ではありませんが、サーバPCの起動時にvoicevox engineを自動起動できるように、systemdにコマンドを登録します。
まずすでにvoicevox engineを起動済みであればstopします。
cd ~/app/voicevox/
docker compose down
サーバPC(ubuntu)で以下のファイルを作成します。
sudo nano /etc/systemd/system/voicevox.service
[Unit]
Description=VoiceVox Engine via Docker Compose
After=network.target docker.service
Requires=docker.service
[Service]
WorkingDirectory=/home/USER/app/voicevox
ExecStart=/usr/bin/docker compose up
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
Restart=always
[Install]
WantedBy=multi-user.target
USER
あるいはWorkingDirecotryの値は環境に合わせて書き換えてください。
ExecStartのコマンドはdocker compose up
にしており、バックグラウンド実行用の引数である-d
は除いています。systemd自体がバックグラウンドで実行されるためです。
ファイル作成後、サービスを有効化します。これによりPC起動時にvoicevox engineのサービスも起動されるようになります。
sudo systemctl enable voicevox
サービスの起動してstatusを確認します。
sudo systemctl start voicevox
systemctl status voicevox
active (running)
みたいな文字列が出力されていればOKです。
終了したい場合は以下のコマンドを使います。
sudo systemctl stop voicevox
PC起動時に自動実行したくない場合は以下で無効化できます。
sudo systemctl disable voicevox
pythonクライアントの作成
pythonのシステムと連携させたいので、pythonから音声合成できるようにします。
pipでinstall可能なvoicevox-clientというライブラリがあります。asyncが使われているので非同期処理に抵抗がなければこれを使っても良いと思います。
今回はasyncを使いたくないので、自前で実装します。
import wave
import requests
import json
import simpleaudio
import io
class VoiceVoxClient:
def __init__(self, host="localhost", port=50021):
self.host = host
self.port = port
def get_content(self, text, speaker=0):
params = (
('text', text),
('speaker', speaker),
)
response1 = requests.post(
f'http://{self.host}:{self.port}/audio_query',
params=params
)
headers = {'Content-Type': 'application/json',}
response2 = requests.post(
f'http://{self.host}:{self.port}/synthesis',
headers=headers,
params=params,
data=json.dumps(response1.json())
)
return response2.content
# VOICEVOXで音声合成
def generate_wav(self, text, speaker=0, filepath=None) -> tuple[io.BytesIO, float]:
content = self.get_content(text, speaker)
if filepath:
with open(filepath, "wb") as f:
f.write(content)
wav_io = io.BytesIO(content)
with wave.open(wav_io, 'rb') as wf:
frame_rate = wf.getframerate()
duration = wf.getnframes() / float(frame_rate)
return content, duration
def play_voice(self, text, speaker=8, *, wait=False) -> tuple[simpleaudio.PlayObject, float]:
content = self.get_content(text, speaker)
# WAVデータをメモリ上で読み込み
wav_io = io.BytesIO(content)
with wave.open(wav_io, 'rb') as wf:
audio_data = wf.readframes(wf.getnframes())
play_obj = simpleaudio.play_buffer(audio_data, wf.getnchannels(), wf.getsampwidth(), wf.getframerate())
# 再生が終了するまで待機
if wait:
play_obj.wait_done()
duration = wf.getnframes() / float(wf.getframerate())
return play_obj, duration
if __name__ == "__main__":
VOICEVOX_IP = "サーバのIP"
voicevox_PORT = "サーバのポート"
voicevox_client = VoiceVoxClient(VOICEVOX_IP, VOICEVOX_PORT)
voicevox_client.play_voice("こんにちはー、今日は来てくれてありがとうね", 8)
上記プログラムを実行して、音声が再生されたら成功です。
処理としては、get_contentで音声合成結果のバイトを受けとり、generate_wavかplay_voiceに渡しています。
generate_wavとplay_voiceは用途に応じて使い分けます。
generate_wavはfilepathが指定されていればwavに保存します。また、wavを別スレッドで再生するときなどに待機できるように再生時間(duration)を音声のバイト列と合わせて返します。play_voiceは実行PCのデフォルトスピーカで直接再生します。