AWSでGoogle Cloud Vision APIを使うWEBアプリ作ってみたらちょっとハマった話

# なんでやったの？
- 業務でCloud Vision APIを利用して、画像から文字列を抽出して、コンテンツにNGな文字列が入っていないかをチェックするシステムの開発があった
- 自分の開発リソースがない中で、いくつものライブラリなりを検証してコストをかけずに実装を進める余裕がなかった :sweat_drops: 


# 画像から文字列抽出はどうやったの？
**OCR** という技術を利用しました。OCRって何？という人は下記。

>OCR（Optical Character Recognition/Reader、オーシーアール、光学的文字認識）とは、手書きや印刷された文字を、イメージスキャナやデジタルカメラによって読みとり、コンピュータが利用できるデジタルの文字コードに変換する技術です。
※引用：[OCR | OCRとは | メディアドライブ](https://mediadrive.jp/technology/ocr.html)

## OCRが可能なライブラリとかAPIとか
今回は開発自体を担当する方が **Python**  と **TypeScript** は開発経験があるが、それ以外はないというメンバーだったので、**Python** 寄りになってます :bow: 

- [tesseract-ocr/tesseract: Tesseract Open Source OCR Engine (main repository)](https://github.com/tesseract-ocr/tesseract)
    - Googleがオープンソースで開発しているOCRエンジン
- [Amazon Textract（ドキュメントからテキストやデータを簡単に自動抽出）| AWS](https://aws.amazon.com/jp/textract/)
    - AWS上で利用できるフルマネージド型の機械学習サービス
- [画像内のテキストを検出する  |  Cloud Vision API  |  Google Cloud](https://cloud.google.com/vision/docs/ocr/?hl=JA)
    - Google Cloud VisionはGoogleが提供している画像の分析サービスで、顔の検出とかもできる

**tesseract-ocr** もGoogleで開発してるようなので、最初はそっちを利用して開発を進めました。 :coffee: 

# システム構成図、CI/CDなど
せっかくなので、下記と同じ手段で構成図作ってみた。その後に **[こいつ](https://aws.amazon.com/jp/solutions/implementations/aws-perspective/)**がリリースされて泣きそうになったけど :sweat: 

[PlantUMLでAWSのシステム構成図がなるべく管理される世界観を考えてみた - Qiita](https://qiita.com/takarake/items/ff906a19f96cdfa5ec6a)

![574c4a62e357d6f3f78d89ecac451992a3bd5fc9-1- (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14268/36043e65-aec3-8954-92c2-62629b688f8d.png)

CI/CDについてはソース管理をGithubでやったので、CircleCIなり他のCIも考えました :thinking: が、ちょうどリリースされたばかりで使ってみたかったので、 
[Github Actions](https://github.co.jp/features/actions) を使って、Fargate環境へ自動ビルド、自動デプロイされるようにしました。

### 開発環境も揃い、しばらくは大きな問題もなく、開発を進めましたが、、、、 :timer: テスト運用時に問題発生 :cry: :cry: :cry: :cry: 

### 業務の中でアップロードされる画像からの文字列抽出の精度が良くない :sweat_smile: :sweat_smile: :sweat_smile: :sweat_smile: 

多少は画像をゴニョゴニョしてみたり、OCRへかける際のパラメータをいじってみたりとしましたが、大きくは変わらずといった感じでした。

結果、Amazon Textractも日本語対応はまだしていない（※参考資料は下記）ということで、ここ最近でも精度が高いと評判の **Google Cloud Vision** を利用することにしました。

- [Amazon Rekognition イメージ内のテキスト は日本語に対応していない - Qiita](https://qiita.com/atmaru/items/341c6b06b9df860974b2)
- [【Google Colab】Vision APIで『レシートOCR』 - Qiita](https://qiita.com/ayuma/items/bf5645894803769edc72)

### 使うモジュールを変更した結果は精度はとても良くなったのですが、、、

### ハマったのは 「サービス アカウント キー」がなんと、JSONファイルなんですねー :bomb: :fire: なんでやねん :sweat_smile: 
![クイックスタート-クライアント-ライブラリの使用-Cloud-Vision-API-Google-Cloud.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14268/b91f15cd-74b8-0abb-a85f-41e36c3f1d6f.png)
※引用：[クイックスタート: クライアント ライブラリの使用  |  Cloud Vision API  |  Google Cloud](https://cloud.google.com/vision/docs/quickstart-client-libraries?hl=JA)

実際のサービスアカウントキーのファイルの中身はこんな感じです :point_down: 

```vim
{
  "type": "service_account",
  "project_id": "XXXXX-XXXXXX",
  "private_key_id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "private_key": "-----BEGIN PRIVATE KEY-----\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n-----END PRIVATE KEY-----\n",
  "client_email": "XXXXXXXXXXXX@XXXXXXXXXXXXXXX.iam.gserviceaccount.com",
  "client_id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.iam.gserviceaccount.com"
}
```

皆さんも開発時に各種APIのキーやDBのユーザID、パスワードなどのクレデンシャル情報は環境変数化されて利用するかと思いますが、
環境変数というくらいなので、基本的には **key=value** な値だと思い楽勝だろ :muscle: と思っていたんですが、上記では環境変数の **key** に対して、
**value** がファイルのパスを指定するという仕組みなんですねー・・・ :sweat_smile: 


### ここから現在のCI/CD環境に合わせて、環境変数の受け渡しをどうするか :thinking: 想定外の問題が勃発 :bamboo: :bamboo: :bamboo: 
ファイル化するならdocker image内にファイル入れないとなー・・・でもクレデンシャル情報だからGitでソース管理するわけにいかんし・・・ :sweat: 
なんか簡単にいかないかなーって色々と模索したのが下記 :point_down: 

1.  GithubのSecretsで作成する環境変数にJSONコンテンツまるごと保存して、 `docker image` 内に `echo` なりで吐く  :arrow_right: 失敗 :x:
1. `echo` でファイル化したらバックスラッシュも出力されてしまったのでそれを置換するコマンド追加 :arrow_right: 失敗 :x: 
1. `echo` のオプションでバックスラッシュ出力されないように頑張る  :arrow_right: 失敗 :x: 
1. `echo` じゃなく、`printf` 使ってみる  :arrow_right: 失敗 :x: 
1. `sed` コマンドで置換頑張る  :arrow_right: 失敗 :x:
1. とりあえず泣く :cry: 

ここで、一度立ち止まってどうするか考えました :thinking: 
そういえば、、、、Fargateって Secrets Managerとかからも環境変数取れたよなー :thinking: となって、もう数ヶ月前なのでどの記事を参考にしたか正直覚えていませんが、たぶんこの辺 :point_down: :point_down: :point_down: 

- [AWS Fargate で AWS Secrets Managerを使用して認証情報を保護する | Amazon Web Services ブログ](https://aws.amazon.com/jp/blogs/news/securing-credentials-using-aws-secrets-manager-with-aws-fargate/)
- [環境変数地獄にはAWS Secrets Managerで立ち向かえ！ 〜ECS開発・運用のつらみ〜 - Qiita](https://qiita.com/jumpyoshim/items/08f216a95509a24c58ec)

### ということで、AWS Secrets ManagerにてJSONのコンテンツまるごと保存して、ECSのタスク定義にてコンテンツを引っ張り、 `printf` でコンテナ内部のファイル化し、めでたく環境変数化ができましたとさ :white_check_mark: めでたし、めでたし :older_woman: :older_woman: :older_woman: