MkItYs

MkItYs > AI・交渉・物語の自動生成 > 

images

音声合成のサーバ/クライアントを作る:Python (aiohttp), JavaScript, VOICEVOX

images

音声合成のサーバ〜クライアントを作ってみます。

関連


サーバ証明書を取得〜更新する(ワイルドカード証明書、ネームサーバ経由):Let's Encrypt

検証


クラウド:GCP
コンテナ:Docker
ゲストOS:Ubuntu 22.04
ウェブブラウザ:Chrome
画像生成アプリ:ComfyUI

概要


背景

いまは音声合成のモデルを、ローカル環境で動かすことができます。

対応

ここでは、音声合成のサーバ〜クライアントの、かんたんな実装を試みます。

構成

VOICEVOX は、音声合成のエンジンだけを独立して取得できますーーこれを核に、音声合成のサーバ〜クライアントを実装します:[※1]

https://github.com/VOICEVOX/voicevox_core

※1
いまローカル環境では、VITS を使う音声合成に活気がありますよね(Bert-VITS2, GPT-SoVITS, ... )。短い時間で、それなりに自然な感情表現をともなう音声合成を学習できるからですがーーただエンジンとサーバが別ではないので、ここではエンジンを単独で動かせる VOICEVOX を利用します。

設置


リモートのサーバで、コンテナ向けのフォルダ群を作ります:

$ cd ${HOME}/system
$ mkdir vir106
$ mkdir vol106

音声合成のコアを設置するための、スクリプトを取得します:

$ cd ${HOME}/system/vol106/prj
$ curl -sSfL https://github.com/VOICEVOX/voicevox_core/releases/download/0.14.4/download-linux-x64 -o download
$ chmod 755 download

コンテナを作成し、いったん起動します。コンテナの変更は、適宜イメージに反映させます:

$ docker build --no-cache -t ubuntu:vir106 ${HOME}/system/vir106
$ docker commit cnt106 ubuntu:vir106

$ docker run -it --rm --gpus all -v ${HOME}/system:/system --name cnt106 ubuntu:vir106

コンテナ上で、ライブラリ群を設置します:

$ cd /system/vol106/prj
$ ./download --device cuda
$ pip install https://github.com/VOICEVOX/voicevox_core/releases/download/0.14.4/voicevox_core-0.14.4+cuda-cp38-abi3-linux_x86_64.whl

# ウェブサーバ/クライアント向けライブラリ群(非同期)
$ pip install aiohttp

実装



バックエンド:サーバ
apptts/bin/ttssrv.py
import ssl
from pathlib import Path
from aiohttp import web
from voicevox_core import VoicevoxCore

async def res001(datreq):
  global spkold
  dicreq = await datreq.json()
  txtreq = dicreq["txtreq"]
  numspk = dicreq["numspk"]
  if spkold != numspk:
    objvox.load_model(numspk)
    spkold = numspk
  datwav = objvox.tts(txtreq, numspk) 
  datres = web.StreamResponse(
    status=200,
    reason='OK',
    headers={
      'Content-Type': 'audio/wav',
      'Content-Disposition': 'attachment; filename="output.wav"',
      'Access-Control-Allow-Origin': '*',
    }
  )
  await datres.prepare(datreq)
  await datres.write(datwav)
  await datres.write_eof()
  return datres

async def opt001(datreq):
  return web.Response(
    headers={
      'Access-Control-Allow-Methods': 'POST, OPTIONS',
      'Access-Control-Allow-Headers': 'Content-Type',
      'Access-Control-Allow-Origin': '*',
    }
  )

prttgt = 8080
adr001 = '/'
pthcrt = '/system/vol105/etc_nginx/letsencrypt/<server_remote>/fullchain.pem'
pthkey = '/system/vol105/etc_nginx/letsencrypt/<server_remote>/privkey.pem'
pthdct = "open_jtalk_dic_utf_8-1.11"

spkold = 0
objvox = VoicevoxCore(open_jtalk_dict_dir=Path(pthdct))
appweb = web.Application()
appweb.add_routes([web.post(adr001, res001)])
appweb.add_routes([web.options(adr001, opt001)])
sslcon = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
sslcon.load_cert_chain(pthcrt, pthkey)
web.run_app(appweb, port=prttgt, ssl_context=sslcon)

フロントエンド:クライアント
apptts/web/ttsclt.htm
<html lang="ja">
<head>
  <meta charset="UTF-8">
</head>
<body>
  <textarea id="txtreq" style="width: 32em; height: 8em;"></textarea><br/>
  <input id="numspk" style="width: 32em"></input><br/>
  <button onclick="req001()">ttsclt</button>
  <script>
    const adr001 = 'https://<server_remote>:8081/';

    const req001 = async () => {
      const txtreq = document.getElementById('txtreq').value;
      const numspk = parseInt(document.getElementById('numspk').value);
      const dicreq = {txtreq: txtreq, numspk: numspk};
      const stsres = await fetch(adr001, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(dicreq)
      });
      if (stsres.ok) {
        const blbado = await stsres.blob();
        const adrado = URL.createObjectURL(blbado);
        const objado = new Audio(adrado);
        objado.play();
      } else {
        alert('err: ' + stsres.statusText);
      }
    }
  </script>
</body>
</html>

利用


コンテナを起動します:

$ docker run -it --rm \
-p 8081:8080 \
-v ${HOME}/system:/system \
-v /exp001:/exp001 \
--name cnt106 ubuntu:vir106

コンテナ上で、サーバを起動します:

$ cd /system/vol106/prj/voicevox_core ; python ttssrv.py &

ローカルのウェブブラウザで、クライアントを実行します:

> apptts/web/ttsclt.htm