2022NHKハッカソン 防災編に出て、災害を学べるコンテンツを返すアプリを作った

10月にNHKハッカソン 防災編に参加しました。

ハッカソン自体への参加がはじめてでした（多分）。イベント自体は、いろいろな方が参加されており、アイデアを聞いているだけでも楽しめました。

一応手も動かしたいということで、チームで作った「災害の学習に役立つNHKコンテンツのCSVファイル」を使って、それをランダムに返すアプリを作成しました。

イベントは様々な方と作業ができて、凄い楽しかったです。この記事は、参加記録兼作ったもののメモです（遅いけどw。

## 概観

``` 
--- 開発環境 ---
WSL2
python 3.8.10
dash 2.6.2
flask 2.2.2
    --------
```

アプリの構造的には[Flask](https://flask.palletsprojects.com/en/2.2.x/)でランダムにニュースのURLを返すAPIを作って、それを[Dash](https://dash.plotly.com/)で描画します。

DashはPythonのReactラッパーみたいな存在で、お手軽に使えるので、使いました。

アプリはヘロクの無料枠で動いており、11月28日に動かなくなる見込みです。
https://nhk-hackathon-front.herokuapp.com/

<a href="https://gyazo.com/fda1d01e27553d161d7a2909ffb1b075"><img src="https://i.gyazo.com/fda1d01e27553d161d7a2909ffb1b075.gif" alt="Image from Gyazo" width="1600"/></a>

## API

APIはFlaskを使って作りました。普段はデータ分析ばかりしているので、あまりAPIとか作りませんが、Flaskはちょっと触ったことがあったので、簡単に作成できました。

コードとデータはリンク先のリポジトリに置いてあります。今見たらvenvディレクトリが入りっぱなし。修正しておきます。
https://github.com/mazarimono/nhk-hackathon

ここでは、[dataディレクトリ](https://github.com/mazarimono/nhk-hackathon/tree/main/data)にnhk-news.csvを置いています。

そのファイルをpandasを使って読み込み、データフレームの列数を数えたあと、ランダムな数値を生成し、ニュースのタイトルとURLを返します。

```python3
from flask import Flask
import pandas as pd
import random

@app.route('/api/v0/news/random_news')
def return_randomnews():
    df = pd.read_csv('data/nhk-news.csv')
    random_int = random.randrange(0, len(df))
    rand_df = df.iloc[random_int, :]
    news_title = rand_df.loc['タイトル']
    news_url = rand_df.loc['URL']
    return {
        'news_title': news_title,
        'news_url': news_url
    }
```

## フロント

フロントでは、Dashのコールバックで先ほど作成したAPIを叩いてニュースのリンクを呼び出して描画しています。

工夫した点はボタンのn_clicks属性の初期値を1にしたうえで、コールバックがn_clicks>0で動作するようにした点です。これによりアプリの立ち上がりでもAPIを叩いて、ニュースのリンクが表示されます。

コールバックでは、ボタンが押されるとAPIを叩き、記事のリンクとURLを返します。

再度ボタンが押されると、次のニュースが呼び出されます。
https://github.com/mazarimono/nhk-randomnews

```python3
from dash import Dash, html, Input, Output
import dash_bootstrap_components as dbc
import requests


app = Dash(
    "__name__",
    external_stylesheets=[dbc.themes.BOOTSTRAP],
    meta_tags=[
        {"name": "viewport", "content": "width=device-width, initial-scale=1"},
    ],
)
server = app.server


app.layout = html.Div(
    [
        html.Div(
            [
                html.H1("おススメNHK防災コンテンツ", style={"padding": 10}),
                html.H3(id="selected_title"),
                html.A(id="selected_link"),
            ]
        ),
        html.Div(
            [dbc.Button(id="update_button", children="ニュース更新ボタン", n_clicks=1)],
            style={"padding": 30},
        ),
        html.Div(
            [
                dbc.Accordion(
                    [
                        dbc.AccordionItem(
                            [html.P("このサイトは防災について学べるおススメ記事のリンクを、ランダムにおススメします")],
                            title="サイトの説明",
                        )
                    ],
                    start_collapsed=True,
                    style={"width": "80%", "margin": "auto"},
                ),
            ]
        ),
    ],
    style={"textAlign": "center", "padding": 10},
)


@app.callback(
    Output("selected_title", "children"),
    Output("selected_link", "href"),
    Output("selected_link", "children"),
    Input("update_button", "n_clicks"),
)
def update_news(n_clicks):
    if n_clicks > 0:
        r = requests.get("https://nhk-hackathon.herokuapp.com/api/v0/news/random_news")
        news_title = r.json()["news_title"]
        news_url = r.json()["news_url"]
        return news_title, news_url, news_url
    else:
        pass


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

## まとめ

以上のようなアプリを作って、NHKさんの防災に役立つ記事が読めるアプリを作成してみました。NHKさんにはたくさんのアセットがあるそうなので、APIとか作られると色々楽しそうですね！

私はこのアプリを使って、CSVファイルにある記事をたまに読んで、防災学習をしています。

最後に、ハッカソンの開催ありがとうございました！

```
csvをランダムに吐き出すのはDashのみでもできるのですが、チームのアプリでこのような機能を使いたかったのでAPIを作成しました。このアプリでもそのAPIを使ったらええやんと思い、こんかいのようなかたちとなっております。

```