# 郡道美玲版の棒読みちゃん的なサイトを作りました

導入

http://speech.gundou-mirei.love/ これを作った話を書きます。

<blockquote class="twitter-tweet" data-theme="dark"><p lang="ja" dir="ltr">誰かが助かると聞いたので <a href="https://t.co/ZqYWuRLP38">pic.twitter.com/ZqYWuRLP38</a></p>&mdash; 郡道美玲🐽 (@g9v9g_mirei) <a href="https://twitter.com/g9v9g_mirei/status/1234580166229159939?ref_src=twsrc%5Etfw">March 2, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

この動画を仕事帰りの電車で何となく見ていて、「こういうサイトがあったら面白い!」と閃いて実装を始めました。 その日のうちにコア部分の実装をしてデプロイまで行えたのですが、こういう勢いをいつまでも忘れないでおきたいですね。 郡道美玲ボタンと同じくスキマ時間に何となく遊んで何となくニコニコしています。

50 音 (+濁点、半濁点、拗音付きの音) の音声素材さえあれば 〇〇ボタンみたいな感じで誰をテーマにしても作れるので、みんなぜひ作ってみてほしいなーと思っています。 そしてあわよくば以下に流暢に喋らせるか参考にさせていただきたい…。

実装

言語的には Go, JavaScript です。

フロントは本当に簡素なものしか無いので 1 枚の HTML に雑に埋め込んでいます。 https://github.com/lambdasawa/mirei-tts/blob/dev/public/index.html リッチな UI を作りたくなったらそのときは恐らく一番慣れている TypeScript + Vue になると思います。

サーバで Go を採用している理由はこれも慣れです。多分やっていることてきには Python とかのほうが枯れたライブラリがあって良いんだろうなあ…とは思っています。 肝心のやっていることは大体以下の感じです。

  • Web のフォームから来たリクエストから読み上げたいテキストを取得する
  • テキストを解析して漢字などが含まれないカタカナでの読みを取得する
  • カタカナ 1 文字ごとに 1 音声 (例: あ.wav) を割り当てて、それを連結する
  • 連結した音声のバイナリをレスポンスで返す

テキストを解析して〜の部分では読みが取れれば何でも良いのですが、その手段として自分が知っている限り形態素解析のライブラリを使うのが一番簡単だったので、 Go で日本語の形態素解析を行える https://github.com/ikawaha/kagome を利用させていただきました。 十分にシンプルな API が提供されていたため比較的簡単にこの部分の実装が出来ました。

ただし、デフォルトの辞書では「月ノ美兎」の読みが「ツキノヨシウサギ」などに解釈されてしまい、界隈の固有名詞の読みが上手く取れませんでした。 これに関しては別の辞書として https://github.com/neologd/mecab-ipadic-neologd を使わせていただいて解決することが出来ました。 こちらの辞書については https://engineering.linecorp.com/ja/blog/mecab-ipadic-neologd-new-words-and-expressions/ にて作者の方が詳しく説明してくれています。 kagome から NEologd を使う方法は https://ikawaha.hateblo.jp/entry/2016/04/20/145940 にて kagome の作者の方が記事を書いてくれています。 どちらもこのようにドキュメント類がよく用意されていてスムーズに作業が進みました。

音声の連結には https://github.com/faiface/beep を利用させていただきました。 個人的には SoX の利用にもある程度慣れているため、 外部コマンドとして SoX などを使う手段もあったのですが、デプロイを単純にしたいという意図があって Go のライブラリを利用するという判断をしました。 Go の標準ライブラリには画像処理のパッケージがありますが、 音声処理のパッケージが無いのは何か理由があるのでしょうか…。

連結元の音声の切り抜きは YAML で切り抜く箇所を指定してその通りに切り抜くツールを Go で実装しました。 こちらで使用しているライブラリも beep です。 切り抜く箇所は https://twitter.com/yoshi_yukky/status/1236671509629816834 のデータを参考にさせていただきました。ありがとうございます。

Web の部分は Echo を使っています。 これは慣れ + handler 部分で error を返り値に設定できるフレームワークが好きという理由で選択しました。 自分にはエラー処理で sendError(); return; みたいに毎回複数行のエラーハンドリングをすると正常系の処理が追いにくいという感覚があります。

デプロイは雑に AWS の Elastic Beanstalk を使っています。 大規模なサービスではないのでデプロイの部分であんまり頑張りたくないという思想です。 そのうち Lambda などに移行するかもしれないです。この規模だとそのほうが安いので…。 ただし、辞書を最初に読み込むあたりである程度時間がかかる (~10s くらい) ので、そういうアプリと Lambda の相性ってどうなんだ?という懸念はあります。

おまけ: ツイート生成

最近 https://markov.cordx.net/ によるツイート生成が流行ってる気がします。 しゅうまい君 (https://twitter.com/shuumai) も子豚の界隈では流行ってる (本人が無限にリツイートするため) と思います。 個人的にこういう機械に生成されたシュールな文章が大好きなので、こんな感じで郡道美玲っぽい文章が生成できないか試してみました。

この分野には詳しく無いのですが、どちらもマルコフ連鎖という技術を使っているようなので、 同じ方針で作業を進めました。 マルコフ連鎖の概念的な部分は https://note.com/coropon_no_neta/n/n51c9d8bb69b3 が分かりやすいと感じました。 Go のライブラリとしてググったらすぐに https://github.com/mb-14/gomarkov が見つかったのでこちらを採用しました。

そもそもの元データとしては本人の Twitter のデータを参照していただきました。 ここに関しては特筆することは特に無いです。強いて言えばちゃんと RT は弾こうねということくらいでしょうか…。 お金さえ潤沢にあれば AWS Transcribe で全配信の文字起こしをしてみたいなーとは思っていますが、そこまではやれていないです。

結果、しゅうまい君っぽい雰囲気が漂うものの郡道美玲っぽいツイートが生成できるようになったため、文章生成ボタンをサイトに配置することにしました。 これは別サイトとかでやってもよかった気がしますが、読み上げさせる文章を脳死で作れるようになったのでこれはこれでアリだと思ってます。

終わり

まだ長音を読み上げられなかったり、たまに文章生成に失敗したり buggy な部分がありますが、そのうち治ると思います。 問題はやっぱり大分カタコトなので流暢に喋らせたいのですが、そこに関するアイデアがない状態です…。これに関しては知見がある人がいたらリプとかしてもらえると本当に嬉しいです。 あとは UI に関しても現状が簡素すぎるので何か良いデザインをしたいなーという気持ちがあります。

最後に https://twitter.com/g9v9g_mirei/status/1234880357696077825 にてこのサイトの開発を許していただいた郡道美玲さん本人に感謝を述べたいです。 開発を快諾してくださりありがとうございます。これからも推していこうと思います。