Herokuでpython+mecab+ffmpegを使う

## はじめに
最近、ちまちまとdiscord上で動くchatbotを作っているのですが、やっぱり公開サーバーで動かさないと日常的に使えないのでHerokuにデプロイすることにしました。
ただ、無料枠のHerokuで動かそうとするといろいろと解決しないといけない課題が多くてひたすら逃げていたのですが、ようやく重い腰を上げてデプロイしたので、手順をメモがてら残してみたいと思います。

## 必要な要件

+ python (3.5以上)
+ mecab+mecab-ipadic
+ FFmpeg
+ open-jtalk

を使っているのでこれらが動かせる環境が必要。

Herokuでpython+mecabの環境づくりは下記の記事を参考にしました。
[herokuでpython+django+scikit-learn+mecab(1)](https://qiita.com/kenchin110100/items/6f1c84ac8858525fffc5)
ffmpegの環境づくりはこちらを参考にしました。
[DiscordBotでyoutubeの音声をボイスチャットに流す](https://note.mu/akaness_note/n/nc466d2a00ead)

## いざ、構築
condaとherokuの複数のビルドパックを使うので[heroku-buildpack-multi](https://github.com/heroku/heroku-buildpack-multi)でアプリを作成する必要があります。気になるのはこのリポジトリがメンテナンスを終了していることでしょうか。
> **This buildpack is no longer actively maintained.** The associated functionality exists natively on the Heroku platform. Please refer to https://devcenter.heroku.com/articles/buildpacks and https://devcenter.heroku.com/articles/using-multiple-buildpacks-for-an-app for documentation.

まず、ローカルでリポジトリを作ります。

```bash
$ git init
$ heroku create --buildpack https://github.com/heroku/heroku-buildpack-multi
```
使用するビルドパックは以下の通りです。

```bash:.buildpacks
https://github.com/Sashimimochi/conda-buildpack.git
https://github.com/sunny4381/heroku-buildpack-linuxbrew.git
https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest.git
https://github.com/Crazycatz00/heroku-buildpack-libopus.git
```

`scikit-learn`などのCコンパイラを必要とするライブラリも使いたいのでcondaのビルドパックがいるのですが、pythonのバージョンを固定したいので以下のリポジトリをforkして自前で用意することにしました。
https://elements.heroku.com/buildpacks/teamupstart/conda-buildpack
minicondaのバージョン一覧はこちらから見れます。
https://repo.continuum.io/miniconda/

ちなみに、ものによっては、以下のような最近のpipでは廃止されたオプションが付いていてビルドエラーを起こすので注意。

```bash
pip install -r requirements.txt  --exists-action=w --allow-all-external | indent
```

- https://github.com/heroku-python/conda-buildpack/issues/36
- https://stackoverflow.com/questions/57546079/no-such-option-allow-all-external-when-deploying-a-django-app-to-heroku-wit

上記の`.buildpacks`で`heroku-buildpack-linuxbrew`を入れたので`brew`が使えるようになっています。`brew`で入れたいパッケージを`.cellar`で指定します。

```bash:.cellar
mecab
mecab-ipadic
open-jtalk
```
`conda`および`pip`でインストールするライブラリは`conda-requirements.txt`や`requirements.txt`に書いておきます。

Herokuに[mecab-python](https://pypi.org/project/mecab-python/)をインストールしようとすると案の定、エラーが出ました。
[herokuでpython+django+scikit-learn+mecab(1)](https://qiita.com/kenchin110100/items/6f1c84ac8858525fffc5)では手動でインストールしていましたが、今回は、python3系を使うわけですし、[mecab-python3](https://pypi.org/project/mecab-python3/)ならはいったので、代わりにこちらを入れます。
[Heroku mecabインストール時にエラー](https://ja.stackoverflow.com/questions/48649/heroku-mecab%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E6%99%82%E3%81%AB%E3%82%A8%E3%83%A9%E3%83%BC)

あとはパスを指定してデプロイします。

```bash
$ heroku config:add LD_LIBRARY_PATH=/app/.linuxbrew/lib
$ heroku config:set MECAB_PATH=/app/.linuxbrew/lib/libmecab.so
$ git add .
$ git commit -m 'initial'
$ git push heroku master
```

滞りなく、一連のデプロイが進んで無事うまくいったように思えたのですが、最後のメッセージであえなく撃沈。

```bash
-----> Compressing...
 !     Compiled slug size: 3009.8M is too large (max is 500M).
 !     See: http://devcenter.heroku.com/articles/slug-size
 !     Push failed
```

https://devcenter.heroku.com/articles/slug-compiler#slug-size
上記のメッセージにもある通り、Herokuの無料枠のストレージサイズが500MBなのでデプロイ時にこの範囲内に収める必要があります。

容量を食っているのが、機械学習モデルだったので、Herokuでこれを動かすにはモデルのサイズを圧縮しておく必要がありました。
中でも一番のファイルサイズが大きいのがWord2Vecだったので、こちらのライブラリを使ってモデルサイズを圧縮しました。
50,000語程度にまで絞れば約60MBまで圧縮できます。
https://github.com/yagays/minify_w2v
重要語は以下から選択しました。
[日本語を読むための語彙データベース Ver. 1.1](http://tatsuma2010.web.fc2.com/)
その他にもcacheを削除するなどいろいろ工夫の余地はありそうです。

- https://masutaka.net/chalow/2018-12-21-1.html
- https://github.com/heroku/heroku-repo#purge_cache

これでリポジトリの容量をかなり圧縮できました。

大量のライブラリを使ってしまったせいで、これでもデプロイ時に`pip install`までしてしまうと上限の500MBを超えてしまったので、起動時に`pip install`が走るようにしておきました。

```shell:Procfile
bot: bash run.sh
```

```shell:run.sh
pip install -r requirements.txt
python app.py
```

以上で、なんとか無事に動きました。

## トラブルシューティング
### Herokuリポジトリにログイン
Herokuにログインしてマニュアル操作するときは以下のようにすればログインして`bash`コマンドが使えます。

```bash
heroku run bash
```

### ログの確認
デプロイ後にアプリケーションのログが見たければ以下のコマンドで確認できます。

```bash
$ heroku logs
```
[Herokuアプリケーションのログについて](http://info-i.net/heroku-log)