この記事は OUCC Advent Calendar 2022 の 19 日目の記事です。昨日の記事は yuyu さんの「StackEditで非プログラマーと協同開発した話」でした。
はじめまして、ciffelia です。今日は私が開発している Discord 読み上げ Bot「Koe」と Koe で採用している技術をご紹介させていただきます。
https://github.com/ciffelia/koe
読み上げ Bot って何?
Discord のテキストチャンネルに送信されたメッセージをボイスチャンネルで読み上げてくれる Bot です。 聞き専の人たちが送信したメッセージを合成音声で代読し、会話に参加しやすくしてくれます。
特徴
- VOICEVOX を使用した高品質な音声合成 - ずんだもん、四国めたんを含む 10 人以上の音源から好みに合ったものを選択可能
- 特定の語句の読み方を設定する辞書機能
- 読み方が難しいユーザー名の人がいても安心
- ネタバレ(
||
で囲むやつ)は読み上げをスキップ
読み上げの仕組み
ボイスチャットに参加した Koe は概ね以下の手順でテキストを読み上げています。
- Discord API からメッセージを受信
- Redis から辞書データを取得
- 読み上げるテキストを生成
- Redis から声の設定(プリセット ID)を取得
- VOICEVOX Engine にテキストとプリセット ID を送信
- VOICEVOX Engine から合成音声の wav データを受信
- ffmpeg で音声データを変換
- 音声データを Opus にエンコードし、Discord に送信
使っている技術
プログラミング言語: Rust
Koe は Rust で書かれています。Rust は高速かつメモリ安全なプログラミング言語で、以下のような特徴があります。
- 機械語にコンパイルされる
- C や C++ と同じコンパイラ言語です。
- Python や JavaScript のようなインタプリタ言語と比較して非常に高速に動作します。
- ただしコンパイルは比較的遅いです。
- GC が存在しない
- 後述するように、変数の生存期間がコンパイル時に確定するためガベージコレクタが存在しません。
- GC がメモリ管理を行っている Go と比較して高速に動作します。
- Discord が Go から Rust に移行してパフォーマンスを改善した話が面白いです: Why Discord is switching from Go to Rust
- 型システムがメモリ安全性を保証してくれる
- 変数がコードのどの部分で使われているのかコンパイラがチェックします。
- メモリ安全であることが保証されないとコンパイルが通りません。
- Rust の学習が難しいと言われる所以はこのメモリ安全性チェックにあります。
- use-after-free をはじめとする C/C++ で起こりがちなバグを未然に防ぐことができます。
- 他の言語に類を見ない特徴的な機能です。
- 標準のパッケージマネージャがある
- Cargo と呼ばれるパッケージマネージャが同梱されています。
- Cargo ではパッケージのことを crate と呼び、crates.io で検索できます。
- Node.js の npm と同じような使い心地です。
- npm ほど酷くはありませんが、Depenency Hell に陥ることもあります。
- 高機能で書きやすい
- 開発が活発なため、便利な機能が他の言語から多数取り入れられています。
- 例えば、関数型言語のように、配列に
map
やfilter
を適用できます。 - JavaScript や C#のように、
async
/await
で非同期処理を行うこともできます。 - シンプルさを重視し限られた機能のみを実装する Go とは対照的です。どちらが良いか好みが分かれる部分かもしれません。
Discord API: serenity / songbird
Rust で Discord API を扱うための crate として最も有名なのが serenity です。基本的な API 呼び出し機能に加えてキャッシュ機構を備えており、Discord API の扱いにくい部分を隠蔽してくれます。 また、Discord のボイスチャットに関する API を扱うための crate が songbird です。ボイスチャンネルに Bot として接続し音声を流す機能を備えています。
音声合成: VOICEVOX Engine
読み上げソフトウェアとして有名な VOICEVOX から音声合成エンジンを切り出したものが VOICEVOX Engine です。 VOICEVOX Engine に対して HTTP リクエストでパラメータを送ると、合成された音声データを返してくれます。
データベース: Redis
Redis は key-value store として使えるデータベースです。いわゆる NoSQL データベースの一つです。 Koe では辞書やユーザーの声などの設定を保存するために使用しています。
コンテナ管理: Docker
Docker は言わずと知れたコンテナ管理ソフトウェアです。コンテナとは、超軽量な Linux の仮想マシンのようなものなのですが、簡潔かつ正確に語るのは難しいので詳細は割愛します。
Koe ではdocker-compose.yml
を配布しており、コマンド一つで簡単に Koe、Redis、VOICEVOX Engine のコンテナを起動・停止できるようにしています。
リリース自動化: GitHub Actions
GitHub Actions は、GitHub の管理する仮想マシン上で様々なイベントをトリガーとして任意の処理を実行できるサービスです。 Koe では以下のような処理を自動化しています。
- リポジトリにコードがプッシュされたとき
- コンパイルが通るかチェック
- コンテナをビルドして GitHub Container Registry にプッシュ
- 私がリリースボタンを押したとき
- 新しいバージョンをリリースするコミットを作成
- バージョンに対応する Git のタグを作成
- バージョンに対応する Docker コンテナのタグを作成
- リリースノートを作成
依存しているソフトウェアのアップデート自動化: Renovate
Koe は様々なソフトウェアに依存しています。先述した serenity, songbird, Redis に加えて、設定ファイルのデシリアライザとして Serde、HTTP クライアントとして reqwest などを利用しています。 それらの新しいバージョンがリリースされるたびに手動で更新を行うのは面倒なので、アップデートを自動化する Renovate を導入しました。Renovate は指定した時間に自動で Pull Request を作成し、ビルドが通るとマージしてくれます。
おわりに
Koe を使ってみたくなった方はドキュメントを読めば簡単に導入できます。ソースコードが公開されているため改造も容易です。ぜひお試しください。 また、今回ご紹介した技術の多くは Discord Bot の開発以外にも活用できるものです。これらの技術を活用し、効率的なソフトウェア開発に役立てていただければ幸いです。