curlコマンドでPOSTをするのではなく、WebアプリっぽくHTMLテンプレートから画像データを送信するようにしてみました。
少しづつぽい雰囲気が出てきたね〜
Pytorchのflaskでの画像分類アプリを改造しています。前回に引き続き、よりWebアプリっぽくしていきたいと思います。今回は、HTMLのテンプレートから画像をアプリに渡すように改造をしていきます。今まではWebAPIのようにPOSTリクエストに対してjsonを返すような仕様なので、ユーザーがブラウザから操作できるようにテンプレートHTMLから画像を選択して送信できるようにしたいと思います。
前回、前々回の流れの続きとなります。
こんな人の役に立つかも
・flaskでWebアプリのテンプレートを実装したい人
・Pytorchのflask画像分類アプリチュートリアルを発展させたい人
・Pythonのflaskチュートリアルが物足りない人
テンプレートでUIを作成
view関数を改良
まずはview関数のPytorchでdensenetモデルで画像分類処理を行う部分を改良していきます。
そのために、view関数のpredictがGETメソッドで画像選択フォームを表示するようにします。
#①「GET」メソッドでテンプレートを表示するように変更しました。
@bp.route('/predict', methods=['GET','POST'])
def predict():
if request.method == 'POST':
file = request.files['file']
if file is not None:
input_tensor = transform_image(file)
prediction_idx = get_prediction(input_tensor)
class_id, class_name = render_prediction(prediction_idx)
return jsonify({'class_id': class_id, 'class_name': class_name})
#②テンプレート「prediction.html」を追加します。
return render_template('prediction.html')
変更した箇所は2点です。
①view関数がGETメソッドにも反応するように変更しました。
②GETメソッドの時はprediction.htmlをレンダリングするようにrender_templateをreturnします。
テンプレートを追加
templatesフォルダを追加して、「prediction.html」というテンプレートを作成しました。
「prediction.html」は次のようにシンプルな形にしておきました。
<h1>Prediction</h1>
<form method="post" enctype="multipart/form-data">
<input type="file" name="file">
<button type="submit">送信</button>
</form>
動作検証
ここまでで一度動作を見てみます。Flaskのデバッグ用Webサーバーを立ち上げて確認してみます。
mac
(venv)$ export FLASK_APP=densenet
(venv)$ export FLASK_ENV=development
(venv)$ flask run
windows
(venv)> set FLASK_APP=densenet
(venv)> set FLASK_ENV=development
(venv)> flask run
ブラウザで「localhost:5000/predict」を見ると、次のようにフォームが表示されます。猫の画像「kitten.jpg」を選択して送信してみました。
json形式の応答があったので、firefoxでは次のように表示されました。
これで、ユーザーの入力が視覚的にできるようになりました。
結果表示のテンプレート
次に、結果をテンプレートHTMLに表示するように変更していきます。
view関数の変更
まずはview関数を変更します。
predictの中のPOSTリクエストのreturnで「result.html」というテンプレートを返すようにしました。変数として「class_id」と「class_name」を渡すようにしています。
@bp.route('/predict', methods=['GET','POST'])
def predict():
if request.method == 'POST':
file = request.files['file']
if file is not None:
get_model()
get_label()
input_tensor = transform_image(file)
prediction_idx = get_prediction(input_tensor)
class_id, class_name = render_prediction(prediction_idx)
#return jsonify({'class_id': class_id, 'class_name': class_name})
#●POSTリクエストのretuenでテンプレート「result.html」を返すように変更しました。
return render_template('result.html', class_id = class_id, class_name = class_name)
テンプレートの作成
「templates」フォルダに「result.html」を作成しました。シンプルなものにしてあります。
<h1>Result</h1>
<div>{{ class_id }}</div>
<div>{{ class_name }}</div>
シンプルすぎますね・・・
ということで、今度は、しっかりHTMLで結果が表示できるようになりました。
改善の方向性
画像ファイル形式のチェックなどをしていないので、セキュリティのことも考えて、POSTされた画像の拡張子やファイル名が大丈夫か確認するような仕組みを取り入れたいです。flaskのファイルアップロードのチュートリアルでそのサンプルが記載されていましたので、参考に実装してみたいと思います。