推しのラジオのダッシュボードを作ったら「そのサイト月2万かかるで」と脅されて怯えた話

この記事は[BrainPad Advent Calender 2023](https://qiita.com/advent-calendar/2023/brainpad) 3日目の記事です。
いわゆる「作ってみた」系の内容で、私が推しているラジオのダッシュボードを業務外で作成した経験をまとめます。
技術的にハードな内容や深堀りした解説ではありませんので「ダッシュボードって意外と簡単に作れるんだな」「こんな推し活のやり方もあるんだな」くらいの軽い気持ちで読んで頂ければ幸いです。

# TL;DR

- [とあるVTuber](https://twitter.com/Rukako_Oura)のラジオにどハマりしている時期があった。当時、過去放送の内容がまとまったサイトが欲しいと思った。
- [Streamlit](https://streamlit.io/)でダッシュボードを作成・公開した。レイアウトやデザインのカスタマイズ性が弱かった。公開は[Streamlit Community Cloud](https://streamlit.io/cloud)で簡単に出来た。
- [Dash](https://dash.plotly.com/)でダッシュボードを作成した。カスタマイズ性が高いぶんコード量が多くなり大変だった。公開は[Google App Engine](https://cloud.google.com/appengine)を使用した。
- 作成したてのサイトの予想支払い額が月2万円を超えた。慌ててGAEの設定を見直し、ほぼ無料で運用できた。

# ダッシュボード作成の動機

VTuber事務所ななしいんく所属の「[大浦るかこ](https://twitter.com/Rukako_Oura)」というVTuberがいる。
文学芸能サブカルなどへの幅広くかつ深い造詣、知的（≒屁理屈がち）な会話、低く落ち着く声、愛すべきポンコツさなどといった特徴がある、私の「推し」であるVTuberだ。

特に私が好きなコンテンツとして、毎週金曜深夜にYouTubeで配信するラジオ「**裏ラジオウルナイト（裏ラジ）**」がある。

https://x.com/Rukako_Oura/status/1639476776211734529?s=20

このラジオは放送時間が伸びがちであるとリスナーの間で有名である。
例えば、初回は１時間放送だったのに、回を重ねるにつれ話の脱線の量が増え、放送時間２時間が当たり前になっていたりする。
また、雑談や脱線が多いため「この話題ってどこかの放送で言ってたっけ？どの放送だっけ？」と本人やリスナー含めて分からなくなることが多くあるという話を聞いた。

そこで、以下のような機能を揃えたダッシュボードがあれば便利なのではないかと思った。
- 過去放送時間などの**放送に関する情報の可視化**
- Whisperによる**ラジオ音声書き起こしテキストの可視化・検索**

ダッシュボード作成・公開ツールをいくつか調べてみて、まずはStreamlitでダッシュボードを実装することにした。

# Streamlitでのダッシュボード作成

## 制作物

[裏ラジアーカイブス](https://uraradi-archives.streamlit.app/)というサイトを作成・公開した。

### 機能

機能は以下のようなものを揃えている。
- 放送時間の分布・推移の可視化
- Whisperによる書き起こしテキストの表示
- 書き起こしテキストの検索
- WordCloudによる放送回の要約

![裏ラジアーカイブス機能](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1839273/f56d4722-8f3e-b818-f9cc-6b34807c2174.png)

### データフロー

YouTubeラジオからサイトに公開するまでには以下のようなデータフローとなっている。

![データフロー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1839273/b23d6e44-521a-6765-9de8-66f8a409e3e5.png)

ここでは、**Streamlit**と**Streamlit Comminity Cloud**について簡単に紹介する。

## Streamlit

[Streamlit](https://streamlit.io/)とは、Pythonでwebアプリを作成するためのオープンソースライブラリ。
以下のようなコードを作成し、`streamlit run app.py`とコマンドを実行することで、ローカル環境でwebアプリが動く。

```app.py
import streamlit as st
import numpy as np
import pandas as pd

df = pd.DataFrame(np.random.randn(10, 3), columns=["a", "b", "c"])

st.title("タイトル")
st.header("ヘッダー")
st.markdown("*markdown*のデモ")
st.button("ボタン")
st.dataframe(df.head())
st.line_chart(df)
```

![app.pyの実行結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1839273/b9da05f0-3292-af74-d003-54ee1e2868ff.png)

使ってみての感想は以下の通り。

**利点**
- テキスト・ボタン・表・グラフなどの表示が簡単。可能なコマンドは[こちら](https://docs.streamlit.io/library/api-reference)を参照。
- フォルダの配置を変えるだけでマルチページを作成できる。詳細は[こちら](https://docs.streamlit.io/library/get-started/multipage-apps)
- 背景色・テキスト色・テーマカラーの変更が簡単。詳細は[こちら](https://docs.streamlit.io/library/advanced-features/theming)

**欠点**
- 細かいレイアウトの調整ができない部分がある。
  - テーブル内に画像を表示
  - 画面上ナビゲーションバーの作成
  - 表示コンテンツごとの配色変更
  - テーブルの幅・高さを細かく調整
  - など……。
- ボタンなどの入力を実行した際にページ全体が再読み込みされる。重いデータ処理がある場合にも都度処理が実行されるためページ自体の動作が重くなる。

## Streamlit Community Cloud

[Streamlit Community Cloud](https://streamlit.io/cloud)とは、Streamlit公式のクラウドサービス。
Streamlitで作成したコードをGitHubにアップロードし、Streamlit Community Cloudで設定を行うことでサイトが公開される。
手順は[公式サイトのデモ動画](https://streamlit.io/cloud)を見てもらうのがわかりやすい。

このような設定画面になる。

![Streamlit Community Cloudの設定画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1839273/652fa403-fedd-fe31-95ed-d9ee84694ca1.png)

## ダッシュボード公開後の話

作成したダッシュボードサイトを公開したところ、ラジオのパーソナリティ本人である大浦るかこさんからも反応を頂いた。
他のリスナーの方々も「裏ラジで話していた〇〇についてGoogleで調べても分からなかったけど、裏ラジアーカイブスで調べたらわかった」という声があり、制作者として嬉しい限りだった。

https://x.com/Rukako_Oura/status/1603952892305891328?s=20

一方で、Streamlitのダッシュボードを作成するなかで「より細かいレイアウトを調整したい」「処理の重さが気になる」という想いが出てきたため、自身の学習の意味も込めてDashを使用したダッシュボードを作成することにした。

# Dash + GAEでのダッシュボード作成

## 制作物

Dashを使用したダッシュボードを公開した。
公開した段階では一部機能のみ実装済みであり、随時機能を追加する予定だった。なお最終的には開発を中断することとなり、公開したサイトはクローズした。

### 機能

機能は以下のようなものを揃えている。
- 放送時間の分布・推移の可視化
- Whisperによる書き起こしテキストの表示
- 書き起こしテキストの検索

![Dash版ダッシュボード](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1839273/3363587e-c42a-a854-c3fc-d497a3c0ba68.png)

### データフロー

YouTubeラジオからサイトに公開するまでには以下のようなデータフローとなっている。

![Dash版ダッシュボードのデータフロー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1839273/da54e3d7-e11f-0e87-2eaf-1db3b026e2a3.png)

ここでは、DashとGoogle App Engineについて簡単に紹介する。

## Dash

[Dash](https://dash.plotly.com/)とは、Plotly社が公開したwebアプリ用のライブラリ。
以下のようなコードを作成し、`python app.py`とコマンドを実行することで、ローカルでwebアプリが動く。

```app.py
import dash
import plotly.express as px
import numpy as np
import pandas as pd

df = pd.DataFrame(np.random.randn(10, 3), columns=["a", "b", "c"])

app = dash.Dash(__name__)
app.title = "タイトル"

app.layout = dash.html.Div([
    dash.html.H1("ヘッダー"),
    dash.dcc.Markdown("*マークダウン*のデモ"),
    dash.html.Button("ボタン"),
    dash.dash_table.DataTable(df.head().to_dict("records")),
    dash.dcc.Graph(figure=px.line(df))
])

if __name__ == "__main__":
    app.run_server()
```

![Dashデモ実行結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1839273/ce2a265c-91d8-b021-5646-af517d951b48.png)

使ってみての感想は以下の通り。

**利点**
- htmlのように自由にレイアウト・配色・カスタマイズが可能。CSSやJavascriptによるカスタマイズもサポートしている。
- ボタン等で入力を行った際の挙動をcallback関数で指定することができる。必要な処理のみが実行されるのでサイトの動作が軽い。
- [Dash Bootstrap Components](https://dash-bootstrap-components.opensource.faculty.ai/)などの有志が開発しているライブラリがあり、これらを活用するとモダンなwebコンポーネントが簡単に実装できる。

**欠点**
- Streamlitに比べてコード量が多くなるため、開発期間がかかる。
  - htmlやcssについてほとんど知識がなかったため、それらを勉強するための時間もかかった。
- [dash Enterprise](https://plotly.com/dash/)という、アプリをデプロイするためのサービスがあるが、有料なため個人開発ユーザーには向いていない。

## Google App Engine

上述したとおり、dashで作成したアプリを公開するためのサービスは有料であり自分の用途には一致しなかったため、Google App Engineを利用してサイトを公開することにした。

サイトを公開するために最低限必要なファイルは以下の３つである。
- ローカル環境で実行するためのファイル群（pyファイル、csv、css、etc...）
- requirement.txt
- app.yaml

このうちのapp.yamlにはGoogle Cloud上で実行する際のマシンの設定を記載する。最新の情報は[公式サイト](https://cloud.google.com/appengine/docs/standard/go/config/appref?hl=ja)を参考にするとよいが、おおまかに以下のような内容を記載していた。

```app.yaml

service: default    # 作成するサービス名
runtime: python39   # ランタイム環境の指定。python3.9を指定

env: standard       # GAEの環境設定。standardを選択
instance_class: F1  # インスタンス（仮想サーバー）の種類を設定

automatic_scaling:        # アクセスに応じて起動するインスタンス数を変えるための設定
    min_instances: 0      # 最小インスタンス数
    max_instances: 2      # 最大インスタンス数
    min_idle_instances: 0 # アイドル（待機）状態の最小インスタンス数
    max_idle_instances: 1 # アイドル（待機）状態の最大インスタンス数

entrypoint: python app.py # アプリの起動コマンド
```

GAEでサイトを公開してみての感想
- GCP周りの用語・仕組みについてほぼ知識がなかったため公開に時間がかかってしまった。
- app.yamlファイルの設定を確認するのは大事！

## ダッシュボード公開後の話

一部機能を実装した状態でダッシュボードを公開したのが2023年3月末のことだったが、4月1日に急激なアクセス数があることがわかった。

![リクエスト数の増加](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1839273/70d3f147-77e3-2070-8c53-7a8966187ba4.png)

一体何事だと調べてみた結果、自分が作成したサイトが裏ラジで紹介されていたことを知った。
黄色の投稿者コメントで自分が作成したサイトのURLが流れている。

![裏ラジでの紹介](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1839273/6e090841-1657-c9ca-948e-51070a09d8e8.png)

この4月1日の急激なアクセス数の結果、1日のサイト運用費用が200円を超えていた。

![4月1日のサイト運用費用](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1839273/33bee5e6-26b1-6d4a-8296-8470e63bc2cb.png)

このとき、Google Cloud Platform上で表示される**4月の月間予想支払額が2万円を超えており**、震えあがってしまった。
（なお、本当にビビりまくっていたため証拠となるスクショは撮れていない。）

単純計算でも200円/月×30日=6000円程度のはずが、なぜ2万円と予想されたのか？については、3月末と4月のアクセス数の傾向を踏まえたうえで４月の予想支払い額が計算されていたからということらしい。
つまり、3月末は全然アクセスがなかったのに4月に入って急に人気になったサイトだと判断されたようで、今後もアクセス数が増えると見込まれたため、予想支払い額が2万円になったのだと思う。

とはいえ月6000円の運用費用も馬鹿にならないので慌ててGAEのマシン設定についていろいろ調べ、app.yamlファイルの見直しを行った。
アクセス数が落ち着いたこともあり、その結果1日の運用費用が最大でも5円程度となり、個人運用でも問題ないレベルになった。

　

その後、Dash版の開発に充てる時間がとれなくなったことや、Streamlit版のダッシュボードでも問題なく機能が使えているなどといった理由から、Dash版への移行の中断を決定し、現在はStreamlit版のダッシュボードのみを公開している。

# 結論

- 推し活（ダッシュボード作成）が楽しかった。
- デザインに凝らず、データ量が少ないならStreamlitでダッシュボードを作るのが楽だった。
- 凝ったものを作りたいなら、Dash＋クラウドサービスを使うのがよいかもしれない。
- クラウドサービスを使うときは、マシンの設定をしっかりしておいたほうがよい。

　

　

　

# 後日談

ここまでの話を、主にダッシュボード作成ツールの比較という観点から、社内勉強会で発表することにした。
発表後の余談として「**私が推してる大浦るかこの裏ラジオウルナイト、皆さんも聞いてみてくださいね！**」と布教しておいた。
この発表を行ったのが**2023年5月26日**のことだった。

その翌日だった。

https://x.com/Rukako_Oura/status/1662373455193595905?s=20

https://x.com/774inc_official/status/1662398246508179457?s=20

# 本当の結論

**推しは推せるときに推せ！！！！！**