💬

Linux × Node.js × voicevoxで音声読み上げ

2022/06/29に公開

タイトルの通りvoicevoxとnode.jsを使って音声読み上げをさせます。

コード

最初に結論のコードを載せます。どーん

index.mjs
import fetch from "node-fetch";
import fs from "fs"

const text = "おはようございます"
const res = await fetch(`http://localhost:50021/audio_query?text=${text}&speaker=0`, {
    method: "POST",
    headers: {
        'Content-Type': 'application/json'
    }

})

const query = await res.json()

const sound_row = await fetch(`http://localhost:50021/synthesis?speaker=0&enable_interrogative_upspeak=true`, {
  method: "POST",
  headers: { 
    'Content-Type': 'application/json',
    'accept': 'audio/wav',
    'responseType': "stream"
   },
   body: JSON.stringify(query)
})

const dest = fs.createWriteStream("stream.wav");
sound_row.body.pipe(dest)

ただまぁVoicevoxのengineとかを動かさなきゃいけないんでその辺をこれから解説します

始める前に1点だけ。
Zenn自体初めてなのでなんか不手際があればそっと教えてください。

環境

  • voicevox engine cpu-ubuntu20.04-latest
  • docker
  • node.js ver 16.15.1
  • CentOS 9

CentOS 9を使ってますが、同じ方法でubuntu 20.04での動作も確認しております。

まずはvoicevox engineのサーバーを立てる

voicevox engineを起動させる方法は公式のGitHubに書かれてるようにいろいろありますが、今回はすぐに作れるdockerを使っていきます。

そもそもdockerが入ってない人は下のサイトを参考にして入れてみてください。3分で入れられます。
https://knowledge.sakura.ad.jp/13795/

公式GitHubにある通り、CPUの場合は

$ docker pull voicevox/voicevox_engine:cpu-ubuntu20.04-latest
$ docker run --rm -it -p '127.0.0.1:50021:50021' voicevox/voicevox_engine:cpu-ubuntu20.04-latest

でok
GPUの場合は

$ docker pull voicevox/voicevox_engine:nvidia-ubuntu20.04-latest
$ docker run --rm --gpus all -p '127.0.0.1:50021:50021' voicevox/voicevox_engine:nvidia-ubuntu20.04-latest

としてください。
http://localhost:50021/docshttp://localhost:50021/redoc でドキュメントが見ることができればおーけー

voicevoxでしゃべってもらう

engineがスタートできたらもうほとんど終わりです。
ドキュメントの通りPOSTすればok

具体的には最初のコードの通り。コードをもう一度貼っておきます
node-fetchを使ってますがaxiosなり好きなやつを使ってください。

ES6のmoduleです。

index.mjs
import fetch from "node-fetch";
import fs from "fs"

const text = "おはようございます"
const res = await fetch(`http://localhost:50021/audio_query?text=${text}&speaker=0`, {
    method: "POST",
    headers: {
        'Content-Type': 'application/json'
    }

})

const query = await res.json()

const sound_row = await fetch(`http://localhost:50021/synthesis?speaker=0&enable_interrogative_upspeak=true`, {
  method: "POST",
  headers: { 
    'Content-Type': 'application/json',
    'accept': 'audio/wav',
    'responseType': "stream"
   },
   body: JSON.stringify(query)
})

const dest = fs.createWriteStream("stream.wav");
sound_row.body.pipe(dest)

まずaudio_queryにpostすると音声合成するためのクエリが返ってきます。
それをsynthesisにbodyとしてPOSTすると音声データが返ってくる仕組みです。

それをfs.createWriteStreamでwavにしてます

ちなみに、個人的にはstremのほうが個人的に使いやすいのでstreamにしてますが、arraybufferを使った方法もあります。

arraybufferを使って保存する場合は以下の通り。const sound_row以前は前のコードと同じです

index.mjs
const sound_row = await fetch(`http://localhost:50021/synthesis?speaker=0&enable_interrogative_upspeak=true`, {
  method: "POST",
  headers: { 
    'Content-Type': 'application/json',
    'accept': 'audio/wav'
   },
   body: JSON.stringify(query)
})

const buffer = Buffer.from(await sound_row.arrayBuffer())
fs.writeFileSync("arraybuffer.wav", buffer)

お好きなほうをどうぞ。
体感そこまで差があるわけでもなかったのでマジで好きなほうで大丈夫です。

速度としてはおはようございますを出力するのに3秒ほどかかりました。
おそらくgpuを使えばもっと早く出力できます。

あとspeakerを変えるとしゃべるキャラ?声?が変わるのでそれも好きなやつ使ってみてください。

ほかにもいろいろな機能があるので、ぜひhttp://localhost:50021/docs を見てみてください。結構便利です

注意点

  • めちゃくちゃ長い音声を読み上げさせようとするとクラッシュします。
    • 分割して読み上げさせることもできるのでそれを活用してください
  • 特殊な文字を読み上げさせようとするとエラーが出ることがあります
  • 仕様が変わったらこれができないかもしれないです。

以上です!
なんかあったらTwitterの

  • @ice_hisa
  • @ice_hisame

のどちらかまでお願いします!

Discussion