3 minutes
streamlit で画像処理アプリを作る。
最近流行のstreamlit
を使って簡単な画像処理アプリを作ったので備忘録
パッケージ管理にはpipenv
を使用。
顔検出モデル
opencv/data/haarcascades at master · opencv/opencv
かなり昔に書いたのコードを流用した。
streamlit どうやって Heroku にデプロイするの?
Procfile
に以下のように記載。
web: streamlit run --server.enableCORS false --server.port $PORT app.py
Hosting streamlit on Heroku - Questions - Streamlit
より詳細は以下記事参照。
Python ファイル分割しないの?
streamlit の面白いところは以下のようにclone
とかなしに直接ローカル環境で試すことができる点だと思う。
$ streamlit run https://github.com/tomowarkar/stapp/blob/master/app.py
これをするにあたってできるだけシングルページにまとめた方がいいかな(分けるにしてもそのあたりを考えつつ)という意図。
Heroku で OpenCV が使えない
何も知らずに Heroku で OpenCV をつかおうとすると以下のエラーが…
...
import cv2
from .cv2 import *
...
ImportError: libSM.so.6: cannot open shared object file: No such file or directory
Heroku のビルドパックに heroku-buildpack-apt を追加
$ heroku buildpacks:add --index 1 https://github.com/heroku/heroku-buildpack-apt
Aptfile を追加し、OpenCV の依存関係を入れる
Aptfile
を作成し、 libsm6
, libxrender1
, libfontconfig1
, libice6
の 4 つのライブラリを 1 行毎に記載
libsm6
libxrender1
libfontconfig1
libice6
python - How to use OpenCV with Heroku - Stack Overflow
heroku で OpenCV を利用する [Python3] - Qiita
Heroku の無料枠を最大限使いたい
Free Dyno Hours | Heroku Dev Center
Heroku のアプリはアクセスや内部実行がなければ 30 分間でスリープ状態に入り、スリープからの起動には少し時間がかかる。
無料枠を超えない範囲でアプリをスリープさせないようにトラフィックを送ってやればいい。
定期実行できればなんでもいいが、コードと一緒に管理できるGitHub Actions
が個人的に扱いやすいのでこれで行う。
GitHub Actions について - GitHub ヘルプ
GitHub Actions で 20 分毎にアプリにトラフィックを送る
Procfile
と 同階層に.github/workflows/heroku.yml
を作成する。
heroku.yml
に以下のように記載。
name: Heroku Alarm Clock
on:
schedule:
- cron: "*/20 * * * *"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Alarm
run: curl YOUR_HEROKU_APP_URL
cron を 20 分おきに実行し、curl でアプリにアクセスするというだけの内容だ。これだとデフォルトの無料枠は超えてしまうので好きに変更されたし。
ちなみに Heroku の個人アカウントにはデフォルトで毎月 550 時間の無料枠が割り当てられていて(アカウントに紐づく全てのアプリの総起動時間と思われる。)、超過すると月の残りは強制スリープになるので注意。
できなかったこと
クライアント側のパラメータに応じてその場で動画を生成し、表示すること。
/tmp
にfilename
を作成しそれを元にst.video(video)
で表示する。
fourcc = cv2.VideoWriter_fourcc(*"avc1")
video = cv2.VideoWriter(filename, fourcc, fps, (width, height))
steps = fps * 10
for i in range(steps):
img = np.random.randint(0, 256, (width, height, 3), np.uint8)
video.write(img)
video.release()
ローカルでは動作したけど、heroku
上でうまく/tmp
ディレクトリにファイルを作れず動作しなかった。