今回作る Web アプリは、文字の含まれる画像をアップロードすると、それを認識して文字列にして表示してくれる OCR (文字認識) アプリです。
アプリには Python 3, Flask, Microsoft の AI サービスの Cognitive Services などを使用しています。
クラウド (Microsoft Azure) へのデプロイは git push トリガーの自動デプロイとなっています。
Thank you!
この OCR アプリは Microsoft 社のエンジニア Christopher Harrison さんによって作られた「 sign-reading 」という web アプリです。
これを題材にハンズオンをしていきましょう。
0. 必要なソフトウェアのインストール
- git https://git-scm.com/downloads
- Python3 https://www.python.org/downloads/
- Visual Studio Code (VSCode) https://code.visualstudio.com/download
1. 初めにクラウド側の設定
まずはデプロイ先の web アプリのデプロイや、Cognitive Services のインスタンス (リソース) 立てたりなど、
クラウド (Azure) 側の設定をしていきましょう。
Azure 無料アカウントの作成 (もしなければ)
もし Azure にアカウントをまだ持っていない場合 https://azure.com/ からアカウントを作成します。最初の30日間は無料で使えますので、このハンズオンにはお金はかかりません。
Azure ポータルから Cloud Shell
GUI 画面ポチポチでもできますが、今回は Azure CLI (コマンドライン インターフェース) を使っていきましょう。
まず、Web ブラウザで、Microsoft Azure のポータルページ portal.azure.com を開きます。
画面上部に「Cloud Shell」を開けるボタンがあるので、そこをクリックします。
Azure Cloud Shell とは、Azure リソースを管理するための、Web ブラウザ上で利用できるシェル環境です。
参考)Azure Cloud Shell の公式ドキュメント
→ https://docs.microsoft.com/ja-jp/azure/cloud-shell/overview
画面上部の「Cloud Shell」ボタンを押すと、
Web ブラウザの中の、画面下半分に shell ウィンドウが現れます。
Azure Cloud Shell 初めての人
Cloud Shell 立ち上げるのが初めての人は、
Cloud Shell 立ち上げる用の Storage Account (保存領域) を作ってねという画面になるので、画面の指示に従ってください
しばらく待つと、準備が出来て、このような画面になります。
Cloud Shell で az hack インストール
ここで、前述した az hack
エクステンション (拡張コマンド) を入れます。
今回のハンズオン用に、
素早くそれ用の Azure のリソースを作ってくれる便利コマンドです。
az extension add --name 入れたいエクステンションの名前
で、その指定のエクステンションを入れることができます。
az extension add [--name]
[--pip-extra-index-urls]
[--pip-proxy]
[--source]
[--yes]
参考)az hack コマンドの公式ドキュメント
→ https://docs.microsoft.com/ja-jp/cli/azure/ext/hack/hack
このハンズオンでは、このハンズオン用の az hack
コマンドを使いたいので、以下のコマンドを Azure Cloud Shell に打ちましょう。
az extension add --name hack
参考)az extension の公式ドキュメント
→ https://docs.microsoft.com/ja-jp/cli/azure/extension
入りました。(az hack コマンドはまだ preview 版のようですね。でもちゃんと動くので大丈夫です)
az hack create --name signdemo --runtime python --ai --location westus2 --output yaml
(リソースのデプロイ先の場所 --location
を、普段は japaneast
(東日本リージョン) や japanwest
(西日本リージョン) に指定しますが、今回は本社の作ったハンズオンに合わせて westus2
(米国西部 2) のままでいきます。)
もし westus2
で問題がある場合は westus
で試してみてください。
ちなみに Azure Location 一覧は az account list-locations -o table
で表示させることができます。詳細はブログで書いたので興味があったらどうぞ。
また、ここでは Python 製の Web アプリを作るので、オプションで --runtime python
を指定しました。
上記のコマンド (az hack create ~) を叩くと、画面が走り出します。私は5分くらい待ちました。
ちなみに。
上のコマンドでは、我々はアプリの名前を --name signdemo
と『signdemo』と指定しましたが、
ここはデプロイされた Web アプリの URL の一部となるので、世界で一意となるように、このハンズオン (のコマンド az hack を使った場合) では、新設設計で最後に勝手に短いランダムな文字列が付くようになっています。(ハンズオンだから皆同じの入れるからね)(私の場合「signdemo78a6e」になった)
デプロイ先の Web ページを見てみる
Cloud Shell の出力の最後にデプロイ先の Web サイトの URL が載っていますので、クリックしてみます。
私の場合の URL は「 https://signdemo78a6e.azurewebsites.net/ 」でした。(後で私はリソース消すかもしれないからもしリンク先が 404 になってたらすみません)
こんな感じの Web サイトが表示されていたらオーケーです。
Python 3.6.6 で動いているようですね。
出力情報の確認
さっきの出力された情報を見てみます。
↓ こんな感じの yaml の出力があったと思います。(上で叩いたコマンドで --output yaml
を指定してたので)
Settings and keys:
Note: All values are stored as environmental variables on website
Values:
COGSVCS_CLIENTURL: https://westus2.api.cognitive.microsoft.com/
COGSVCS_KEY: 00000000000000000000000000000000
DATABASE_HOST: signdemo78a6e.mysql.database.azure.com
DATABASE_NAME: signdemo78a6e
DATABASE_PASSWORD: 00000000-0000-00000-00000-0000000000000
DATABASE_PORT: '3306'
DATABASE_USER: database_admin@signdemo78a6e
Website url: https://signdemo78a6e.azurewebsites.net
読んでみましょう。
この上の方の
COGSVCS_CLIENTURL: https://westus2.api.cognitive.microsoft.com/
COGSVCS_KEY: 00000000000000000000000000000000
の部分が Azure Cognitive Services の情報で、
その下↓がデータベースの情報となっています。
DATABASE_HOST: signdemo78a6e.mysql.database.azure.com
DATABASE_NAME: signdemo78a6e
DATABASE_PASSWORD: 00000000-0000-00000-00000-0000000000000
DATABASE_PORT: '3306'
DATABASE_USER: database_admin@signdemo78a6e
これらは
Note: All values are stored as environmental variables on website
とある通り、デプロイした Web app の環境変数としてストアされています。(つまりアプリにハードコードしなくて良いということ)
何がデプロイされたか見てみる
では、画面上で何がデプロイされたか見てみましょう。
ポータルの「リソースグループ」を見てみます。
「リソースグループ」をクリックすると、さっきコマンド叩いて作ったリソースグループ (私の場合「signdemo78a6e」) が生えているのが分かります。↓
これをクリックして、このリソースグループの中にどんなリソースが作られているかを確認します。
私の場合、無料の App Service Plan (アプリの動くサーバー) を既に持っていたのでそちらが使われましたが、
人によってはそれも含めて新規で作られるので、人によって 4 つ入っていると思います↓。
上から、
| |サービス名|説明
----|----|----|----
1| |App Service Plan|Web アプリの乗るサーバのようなもの
2|| Cognitive Services|Microsoft の AI 系サービス
3| |Azure Database for MySQL|Azure のマネージドな MySQL
4||App Service|Webアプリ、Web API、モバイルバックエンドをホストするためサービス。App Service Plan の上に乗って動く
App Service を見てみる
アプリケーション設定 - 環境変数
では、このリソース一覧の中の App Service をクリックして、中を見てみましょう。
左側のメニューの「設定 (Settings)」の「構成 (Configuration)」から
「アプリケーション設定 (Application Settings)」を見ることができます。
データベースの情報や、Cognitive Services の API キー設定など、先ほどの Cloud Shell での出力で見た内容ですね!(セキュリティ上、データの実際の中身は非表示になっていますが、確認したいときはそれぞれの値の目のマークをクリックしたら見れます。)
これらの値は環境変数として、Python のプログラムからアクセスすることができます。
デプロイセンター - Git push トリガーの自動デプロイ
左側のメニューの「デプロイメント (Deployment)」の「デプロイセンター (Deployment Center)」をクリックします。
「デプロイセンター (Deployment Center)」とは、Azure App Service のデプロイに関する設定をするところで、2018年冬に正式リリースされたサービスです。Web アプリの自動デプロイとかの設定が簡単にできます。
その中の「展開の資格情報 (Deployment Credentials)」をクリックします。
ここに書いてある「ユーザ名 (私の場合 "$signdemo78a6e")」と「パスワード」は後で使うことになります。
2. 次はアプリをローカルで動かしてみる
一度 Azure ポータルから離れて、
ローカルでの作業が始まります。
Git Clone
今回動かす Web アプリのコードはこちらに上がっています
https://github.com/geektrainer/sign-reading
これを clone します。
Terminal や PowerShell、コマンドプロンプトなど (ちなみに私は Windows Terminal で PowerShell Core を使っています) を開いて、
お好きなディレクトリに git clone しましょう。
$ git clone https://github.com/geektrainer/sign-reading
sign-reading ディレクトリに移動します。
$ cd sign-reading
このディレクトリを Visual Studio Code で開きます。
$ code .
そうすると、このディレクトリを Visual Studio Code で開くことができます。
もし、ここで開いた Visual Studio Code に、まだ Python の環境が入っていなかったら「Python のエクステンション入れる?」とダイアログが出て来るので、Install をクリックして入れておきましょう。
app.py を開く
まず、アプリの本体となる app.py
を開きます。
すると、いくつかのところに波線(エラー)が出ていることが分かります。
これは、例えば
「僕は flask なんて知らないよ」(定義が見つからない)
などと言っています。
なので、これらの依存しているパッケージのインストールをしていきましょう。
依存するパッケージのインストール
まずは何が必要なのか確認するために requirements.txt
を開きます。
# web framework
flask
# System variables
python-dotenv
# Azure SDK components
azure-cognitiveservices-vision-computervision
これら 3 つが必要なようですね。
まず環境を作っておきます。
ターミナル (私は Visual Studio Code のターミナルウィンドウを使っています) で
$ python -m venv venv
そしてインストールするコマンド叩きます
$ pip install -r requirements.txt
どんどんインストールが走ります。ちなみにもしmacを使っていてpython2もインストールされている場合 python
でなく python3
、pip
の代わりに pip3
を叩く必要があるかも知れません。
インストールが終わると、あの app.py
のエラー波線が消えましたね!
API キーの設定ファイル追加
では、Sign-reading フォルダの中に .env
ファイルを生やしましょう。
「新しいファイル作成」アイコンをクリックします
そして .env
と名付けます。
空っぽのファイルができました。
ここに、あの Azure で先ほど作っておいた Cognitive Services のキーなどをコピペしてきます。
(もし Cloud Shell の出力がセッション切れで消えてしまったという場合は、Azure ポータル 画面ポチポチの「アプリケーション設定」から取ってくることができます)
COGSVCS_CLIENTURL=https://westus2.api.cognitive.microsoft.com/
COGSVCS_KEY=コピペしてきた値
これで、アプリ本体の app.py
から、今定義した API キーを読み込むことができます
Flask
ここで app.py
の中身を見てみましょう。
# app.py
import os, base64, json, requests
from flask import Flask, render_template, request
Flask をインポートしていますね。
Flask とは、Python の軽量な Web アプリフレームワークです。
Python の Web アプリ開発用のフレームワークはたくさんありますが、
他のはとてもリッチというか、たくさんのことが出来過ぎるので
今回は、軽量で学習コストも低めの Flask を使っています。
app.py:Cognitive Services 接続部
vision クライアントを定義して、
.env ファイルに書いておいた API キーを使って
Cognitive Services に接続しています
# Create vision_client
from msrest.authentication import CognitiveServicesCredentials
from azure.cognitiveservices.vision.computervision import ComputerVisionClient
from azure.cognitiveservices.vision.computervision.models import ComputerVisionErrorException
vision_credentials = CognitiveServicesCredentials(key)
vision_client = ComputerVisionClient(endpoint, vision_credentials)
日本語対応
ちなみに、今のデフォルトのままではこれは英語対応となっていますので、
日本語対応したい場合、少し追記する必要があります。
client.recognize_printed_text_in_stream
メソッドの引数に language="ja"
を追記します。
現在
# 今こうなってる
def extract_text_from_image(image, client):
result = client.recognize_printed_text_in_stream(image=image)
↓
# こうしてください
def extract_text_from_image(image, client):
result = client.recognize_printed_text_in_stream(image=image, language="ja")
app.py:出力部
Cognitive Services から返ってきた、解析結果のテキストをひとつひとつ読み取って出力しているところです。
def extract_text_from_image(image, client):
result = client.recognize_printed_text_in_stream(image=image)
lines=[]
if len(result.regions) == 0:
lines.append("Photo contains no text")
else:
for region in result.regions:
for line in result.regions[0].lines:
text = " ".join([word.text for word in line.words])
lines.append(text)
return lines
アプリをローカルで動かす
いよいよアプリをローカルで動かしてみましょう。
$ flask run
すると一瞬で web サーバが立ち上がりました!
下の方に
Running on http://127.0.0.1:5000
と書いてあるので、そこをクリックして、飛んでみます。
おお!ローカルで動いてる!
それで、試しにサンプルの写真を食わせてみます。
「Upload Photo」をクリック
すごい!認識した!動いてる!
では、次はクラウドへのデプロイですね!
今はまだローカルで動いてるだけだから私しか見れないからね
3. Azure へのデプロイ
まず、ローカルで動いている Web サーバを止めます。( 実行したターミナルに戻り Ctrl + C
で止まります)
それで、今回は git 連携をしているので、
git push トリガーで自動デプロイすることが可能です。(かっこいい!!!!!!!!!!!)
$ git remote add azure https://gitのユーザ名@signdemo自分の番号.scm.azurewebsites.net/signdemo自分の番号.git
↑「自分の番号」のところは app service の自分のインスタンスの名前を入れてください。 (私の場合は 78a6e
)
↑「gitのユーザ名」のところは 自分の git のユーザ名を入れてください。 (私の場合は chomado
)
git push でデプロイ!
$ git push azure
をターミナルで打ちます。
すると、git の資格情報を訊ねるダイアログが出てきます。
Azure ポータル の「デプロイセンター」の
「展開 (デプロイ) の資格情報」の中の
ユーザ名とパスワードをそれぞれ入れてください。
それでOKを押すと、どんどん git push azure
が進んでいきます。
(ローカル Git から Azure へのデプロイが初めての人で、git push がうまくいかなかった方は、
こちらのドキュメントを参考に、デプロイユーザを構成する必要があります → Azure App Service へのローカル Git デプロイ)
終わったら、実際にデプロイ先の web サイトを確認してみましょう。
Azure ポータル から web サイトの URL を確認します。
クリックすると、更新されたページを見ることができます!