2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

VOICEVOX(Core)をAWSLambdaで動かす

Last updated at Posted at 2024-08-16

はじめに

VOICEVOXという「無料で使える中品質なテキスト読み上げ・歌声合成ソフトウェア」があります。これで「中品質かー」と思うくらいよくできていて、ちょっと自作アプリに組み込んだり、Web 上で喋らせたり、コマンドラインから起動できたら楽しそうです。
配布するのもライセンス的にかなり緩いので問題ないのですが、環境(CPU/OS)やファイルサイズ(合計 1GB くらいある)的に苦労するところがあります。ちょっと遊びに使いたいだけなんだけどなー、というときにはやはり Lambda みたいなところで WebAPI として使えると便利です。

そこでこの VOICEVOX(Core) を Lambda で動くようにした
https://github.com/mokemokechicken/lambda-vvcore
というのを作ったので共有します。

作ったもの

何ができるのか

Lambda としてデプロイすると、HTTP リクエストを受け取って VOICEVOX で音声を生成し、その Wav データを base64 エンコードして返す API ができます。
「テキスト」「speakerId」を指定すると、そのテキストを指定した話者の声で読み上げた音声データを返します。

使い方例 1: ブラウザの JavaScript から

synthesizeAndPlayVoice("今日は台風ですね", 0);
synthesizeAndPlayVoiceの中身
const LAMBDA_ENDPOINT = "https://YOUR-LAMBDA-URL.lambda-url.ap-northeast-1.on.aws/";
const LAMBDA_APIKEY = "YOUR-LAMBDA-APIKEY";

async function synthesizeAndPlayVoice(text, speakerId) {
  const requestBody = JSON.stringify({
    text: text,
    speaker_id: speakerId,
  });

  try {
    // Lambda関数を呼び出し
    const response = await fetch(LAMBDA_ENDPOINT, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${LAMBDA_APIKEY}`,
      },
      body: requestBody,
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data = await response.json();

    // Base64エンコードされたWAVデータをデコード
    const wavData = atob(data.wav);

    // WAVデータをUint8Arrayに変換
    const wavArray = new Uint8Array(wavData.length);
    for (let i = 0; i < wavData.length; i++) {
      wavArray[i] = wavData.charCodeAt(i);
    }

    // AudioContextを作成
    const audioContext = new (window.AudioContext || window.webkitAudioContext)();

    // WAVデータをデコード
    const audioBuffer = await audioContext.decodeAudioData(wavArray.buffer);

    // 音源を作成
    const source = audioContext.createBufferSource();
    source.buffer = audioBuffer;

    // 出力に接続
    source.connect(audioContext.destination);

    // 再生開始
    source.start();

    console.log("音声の再生を開始しました。");
  } catch (error) {
    console.error("エラーが発生しました:", error);
  }
}

使い方例 2: コマンドラインから

こういう感じで使えます。

export LAMBDA_ENDPOINT="https://YOUR-LAMBDA-URL.lambda-url.ap-northeast-1.on.aws/";
export LAMBDA_APIKEY="YOUR-LAMBDA-APIKEY";

TEXT="ボイスボックスへ、ようこそ!"
SPEAKER=0
JSON='{"text":"'$TEXT'","speaker_id":'$SPEAKER'}'
curl -s -XPOST "$LAMBDA_ENDPOINT" -H "Content-Type: application/json" -d "$JSON" -H "Authorization: Bearer $LAMBDA_APIKEY" | jq -r '.wav' | base64 -d > voice.wav
# play voice.wav

デプロイ方法

https://github.com/mokemokechicken/lambda-vvcore に書いてある通りですが、ざっくり以下の手順です。

  1. AWSCDKv2 が使える環境を用意します。AWS のアカウントや認証情報は設定済みであることを前提とします。
  2. このリポジトリを clone して、lambda-vvcore ディレクトリに移動します。
  3. lambda-vvcore ディレクトリで npm install します。
  4. 環境変数を設定して、npx cdk deploy します。
  5. デプロイが完了したら、出力された URL と API キーを使って API を呼び出します。

処理速度 や 料金 について

処理速度

  • 話者Model の Load: 約 3 秒
    • Lambda は再利用されるので、Speaker 毎の最初のリクエストのみ
      • でも、Lambda はリクエストがない場合数分で終了するので、再度リクエストが来たときには再度 Load が走る
  • 音声合成: 「ボイスボックスをエーダブリューエス ラムダで動かす」 で 約 2.2 秒

つまり およそ 初回5.2秒、2回目なら2.2秒 という感じ。

料金

この Lambda の場合、メモリサイズを 10240MB(最大) に設定しています。これが 1 秒動くと約 0.020 円(1 ドル 150 円換算)かかります。
※ 東京リージョン、Arm、10240MB の 1 ミリ秒あたりの料金: 0.0000001333USD (2024 年 8 月現在)
※ リクエスト料金は相当低いので無視します。

AWS Lambda は メモリサイズを上げると処理速度が上がるらしいです(ついでに料金も上がります)。
メモリサイズを落とすと、顕著に処理速度が遅くなります。
あまり細かく計測はしていませんが、同じくらいの価格になるような感じがあるので、処理速度が速くなる 10240MB に設定しています(が好みで変えてください)。

実際のメモリ消費量は 1 モデルだと 300MB ~ 600MB くらいです。

その他

中身の構成

  • Rust で vvcore というライブラリを経由して VOICEVOX(Core) を呼び出しています
  • Docker コンテナ内に VOICEVOX(Core) の 共有ライブラリや モデルデータ等を入れて、それを Lambda で動かしています
  • VOICEVOX CORE は 0.15.4 を使っています。0.14系だと「初期化にとても時間がかかる(load_all_models=false にしても全ModelをLoadしている?)」

メモリサイズとスレッド数

VVCore の方で Lambda の CPU 数を動的に取得できないようなので(まあそうか)、固定値で thread 数を設定しています。
10240MB では vCPU が 6 らしいので、6 スレッドにしています。
(よく見るとこの話では 8896MB から 6 スレッドらしいので、8896MB にしてもいいかもしれないな...)

さいごに

新しいおもちゃができて楽しいです。開発者の方々、ありがとうございます。
結局 1 リクエストで 0.05 ~ 0.1 円くらいかかるので、まあちょっとした用途に使う感じかなと思います。

英語などの読み上げは得意ではないので、gpt-4o-mini とかで 平仮名に変換してから読み上げるオプションを追加するとか、そういうのも面白いかもしれませんね。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?