素人でも短時間で作れるWebアプリ入門[画像内英文を和訳するWebアプリ]

# はじめに
以前作成したpythonスクリプトをWebアプリにして公開してみました。
URL:~~http://ysuzuki.pythonanywhere.com/~~←現在停止中

プログラム自体は気軽に作れるのですが、それをWebアプリにするのは少しハードルが高かったです。同じような人が多くいると思い、公開するまでの過程を記しました。
「こんなPythonスクリプト作ったよ！Webアプリにしたい！」という方は、よかったら参考にしてみてください。

# Webアプリにするプログラム
[画像内の英文を和訳するPythonスクリプトを作りました](https://qiita.com/ysuzuki19/items/6b254448ebdfe197c757)
に掲載したプログラムをWebアプリにする。

# 使用したもの
- macbook pro
- python3 (cv2, PIL, pyocr, googletrans)
- flask
- pythonanywhere

# Flaskをはじめる
```sh:
~$ pip3 install Flask
~$ mkdir flask-ws
~$ cd flask-ws
```

[こちら](https://a2c.bitbucket.io/flask/quickstart.html#id2)に最小規模のソースコードが載っている。以下、引用。

```py:~/flask-ws/simple.py
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return "Hello World!"

if __name__ == '__main__':
    app.run()
```

このプログラムを実行すると、

```sh:run_simple.py
~/flask-ws $ python3 simple.py 
 * Serving Flask app "simple" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
```
と、ローカルサーバが完成する。最下行にURL(`http://127.0.0.1:5000/`)が記載されており、ここにアクセスすることでWebアプリにアクセス（？）することができる。ターミナルはこのままにして、好みのブラウザのURL入力欄に`http://127.0.0.1:5000/`と入力すると、

<img width="539" alt="スクリーンショット 2019-07-22 2.07.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282145/dd60fdc3-d9a3-5a5b-11ae-8486c9805a9c.png">

アクセスできた。この時、先ほどのターミナルを見てみると、

```sh:acces_simple.py
~/flask-ws $ python3 simple.py 
 * Serving Flask app "simple" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [22/Jul/2019 02:07:00] "GET / HTTP/1.1" 200 -
```
と一番下にGETが追加された。
ここまでで、Flaskそのものの動作確認ができた。

# 自分のプログラムをFlaskアプリにする
画像取得は[こちら](https://qiita.com/redshoga/items/60db7285a573a5e87eb6)が非常に勉強になった。この方のソースコードに上乗せする形で作成することになった。

### 主な変更部分
- 変換部分を削除
- image_process.pyは使わずに`app.py`に直書き
- 保存したプログラムをpyocrのtoolから開く
- 読み取った後はファイルを削除する
- return でリダイレクトではなくてプレーンテキストを返す(ダサいけど)
- `template/index.html`に`<h1>title</h1>, <h3>message</h3>`で文字を追加(ダサいけど)

完成したpythonスクリプトは以下。

```py:app.py
# coding: utf-8
from flask import Flask, render_template, request, redirect, url_for, send_from_directory
import numpy as np
import cv2
from image_process import canny
from datetime import datetime
import os
import string
import random
from PIL import Image
import pyocr
import pyocr.builders
from googletrans import Translator

SAVE_DIR = "./images"
if not os.path.isdir(SAVE_DIR):
    os.mkdir(SAVE_DIR)

app = Flask(__name__, static_url_path="")

def random_str(n):
    return ''.join([random.choice(string.ascii_letters + string.digits) for i in range(n)])

@app.route('/')
def index():
	title = "画像内の英文を和訳するページです"
    message = "英文の入った画像をアップロードしてください"
    return render_template('index.html', title=title, message=message)

@app.route('/images/<path:path>')
def send_js(path):
    return send_from_directory(SAVE_DIR, path)

@app.route('/upload', methods=['POST'])
def upload():
    if request.files['image']:
        stream = request.files['image'].stream
        img_array = np.asarray(bytearray(stream.read()), dtype=np.uint8)
        img = cv2.imdecode(img_array, 1)

        dt_now = datetime.now().strftime("%Y_%m_%d%_H_%M_%S_") + random_str(5)
        save_path = os.path.join(SAVE_DIR, dt_now + ".png")
        cv2.imwrite(save_path, img)

        tools = pyocr.get_available_tools()
        if len(tools) == 0:
            sys.exit(1)
        tool = tools[0]

        langs = tool.get_available_languages()
        lang = langs[0]

        txt = tool.image_to_string(
            Image.open(save_path),
            lang=lang,
            builder=pyocr.builders.TextBuilder()
        )
        translator = Translator()
        translated = translator.translate(txt, src='en', dest='ja')

        os.system('rm ' + save_path.replace(' ', '\ '))

        return '<h1>和訳ができました！</h1><h2>英文</h2>' + txt + '<h2>和訳</h2>' + translated.text

if __name__ == '__main__':
    app.debug = True
    app.run(host='0.0.0.0', port=8888)
```
完成した`index.html`は以下。

```html:template/index.html
{% extends "layout.html" %}
{% block content %}

<h1>画像内の英文を和訳するページです</h1>
<h3>英文の入った画像をアップロードしてください</h3>
<form action="/upload" method="post" enctype="multipart/form-data">
  <input type="file" name="image" accept="image/png, image/jpeg">
  <button type="submit">submit</button>
</form>

{% if images %}
  {% for path in images %}
    <div>
      <img src="images/{{ path }}" style="margin-top: 10px; vertical-align: bottom; width: 200px;">
      {{ path }}
    </div>
  {% endfor %}
{% endif %}

{% endblock %}
```

以上の結果、画像を受け取って、画像内の英文を抽出して和訳するWebアプリが完成した。完成したWebアプリについては下の方で紹介する。
ここまでは先ほどの`http://127.0.0.1:5000/`のローカルサーバで確認しながら作業を進めた。

# pythonanywhereに自分のWebアプリを移す
これまでの作業のプログラムをGithubリモートリポジトリにプッシュしておいた。ここでの作業は基本的に[こちら](https://techium.hatenablog.com/entry/2018/02/01/214332)のページを参考にした。なので、ここでは概要だけを記載する。実際に作業する方はリンク先を参考にしてほしい。

- pythonanywhereに登録→[こちら](https://www.pythonanywhere.com/)
- bashコンソールを開く
- 'git clone https://github.com/<user name>/<repository name>`でクローン
- bash上で動作確認(しなくてよい)
    - `pip install`は`pip install user`にしないとエラーが発生する
- dush board上でWeb apps内のの「Open Web Tab」をクリック
- 「Code」という見出しの`/var/www/<user name>_pythonanywhere_com_wsgi.py`を調整
    - `project_home`変数を自分のプロジェクトホームに変更
    - `from app ...`行の先頭の`app`のみを自分のプログラム名に変更
- Web appページの上の方の「Reload <user name>.pythonanywhere.com」をクリック

ブラウザから`http://<user name>.pythonanywhere.com`へアクセスすると、自分で作成したWebアプリを使用することができた。

# 完成したWebアプリ
ここまで来て、ついに自分のWebアプリが完成した。是非試してみてほしい。
URL:http://ysuzuki.pythonanywhere.com/

上記URLへアクセスすると、

<img width="800" alt="スクリーンショット 2019-07-22 3.44.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282145/c54f22ff-3337-7cb5-049b-8735559b8332.png">
アップロードを促すページが表示された。
今回は、Wikipediaのホームのスクリーンショットである以下を和訳してみようと思う。
<img width="500" alt="スクリーンショット 2019-07-22 3.45.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282145/2d6394af-b3f3-6259-6143-0300c5697259.png">
「ファイルを選択」をクリックして上の画像を選択すると、
<img width="800" alt="スクリーンショット 2019-07-22 3.50.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282145/d1c5b625-acff-d3ad-11d9-02dc8d61fd4a.png">
「submit」をクリックして少し待つと、
<img width="800" alt="スクリーンショット 2019-07-22 3.47.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282145/61dffc0a-8f4a-4a42-a4e6-300724a3161b.png">
おお！英文と和訳が出力された！

# 困ったエラーの解消について
ひとつ困ったエラーがあり、応急処置した。これはどこにも載っておらず自分で考えたので邪道ではあるだろうが、一応記す。
「Reload <user name>.pythonanywhere.com」をクリックしてURLにアクセスしても
<img width="529" alt="スクリーンショット 2019-07-22 3.58.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282145/c1917e90-690f-72d7-30d7-89391a0d0625.png">
と出てきて、自分のWebアプリが表示されなかった。そこで、`<user name>.pythonanywhere.com.error.log`を開いたところ、

```sh:pythonanywhere_error_log
ModuleNotFoundError: No module named 'pyocr'
ModuleNotFoundError: No module named 'googletrans'
```
と、pythonでおなじみのエラーが吐かれていた。（実際のlogには他の出力もあったがエラー部分はこれ）
そこで、`bash console`でWebアプリを起動してみても、問題なく動作する。bash上でインストールした`pyocr,googletrans`たちはbashのユーザ(`--user`)にインストールされており、そのままでは使えないようだ・・・
そこで考えた応急処置が、
#### 「実行ディレクトリにmoduleを持ってくる」
だ。その流れは以下。

```sh:error_handling
$ find / -name pyocr
/home/<user name>/.local/lib/python3.7/site-packages/pyocr
$ cp -r path/to/pyocr path/to/project_directory
$ find / -name googletrans
/home/<user name>/.local/lib/python3.7/site-packages/googletrans
$ cp -r path/to/googletrans path/to/project_directory
```

この結果、なんとかWebアプリは動いたのだが、カレントディレクトリにライブラリが直接おいてあるというなんとも不恰好な環境になってしまった。本来は仮想環境でやるようである。

# おわりに
Webアプリについての知識が少なかったので、多くの人のページを参考にさせていただきました。
取り敢えず動くものをと開発したため、多くの粗があると思いますので、まるまる真似すると危険かもしれません！！
特に、無理矢理解決したpyocr,googletransのimportについてはなんとか改善したいと考えています。（仮想環境でできるのかな？）

# 参考
- [Flaskで簡単につくる、画像処理した結果を見るだけのWebサービス
](https://qiita.com/redshoga/items/60db7285a573a5e87eb6)
    - Flaskで画像を取得する部分
- [PythonAnywhere に Flask アプリをデプロイ](https://techium.hatenablog.com/entry/2018/02/01/214332)
    - PythonAnywhereでFlaskアプリを動作させる処理全般
- [Installing new modules](https://help.pythonanywhere.com/pages/InstallingNewModules/)
    - pythonanywhere上のターミナルにpythonモジュールをインストールする方法
- [Flaskへ ようこそ¶](https://a2c.bitbucket.io/flask/quickstart.html#id2)
    - flaskの基礎、最小規模のプログラム
- [Pythonで簡単なWebアプリ作りたいならFlaskがおすすめ](https://miyach.in/programming/python-flask-tutorial/)
    - Flaskアプリの基礎、文字をブラウザに返す方法
- [【初心者向け】HTMLの改行方法まとめ｜pタグとbrタグの使い方](https://webliker.info/22498/)
    - プレーンテキストに改行を追加
- [Flaskの簡単な使い方](https://qiita.com/zaburo/items/5091041a5afb2a7dffc8)
    - タイトルの追加(index.html)