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


なんでやったの?

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

画像から文字列抽出はどうやったの?

OCR という技術を利用しました。OCRって何?という人は下記。

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

OCRが可能なライブラリとかAPIとか

今回は開発自体を担当する方が PythonTypeScript は開発経験があるが、それ以外はないというメンバーだったので、Python 寄りになってます

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

システム構成図、CI/CDなど

せっかくなので、下記と同じ手段で構成図作ってみた。その後に こいつがリリースされて泣きそうになったけど

PlantUMLでAWSのシステム構成図がなるべく管理される世界観を考えてみた - Qiita

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

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

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

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

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

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

ハマったのは 「サービス アカウント キー」がなんと、JSONファイルなんですねー なんでやねん


※引用:クイックスタート: クライアント ライブラリの使用  |  Cloud Vision API  |  Google Cloud

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

{
  "type": "service_account",
  "project_id": "XXXXX-XXXXXX",
  "private_key_id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "private_key": "-----BEGIN PRIVATE KEY-----\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n-----END PRIVATE KEY-----\n",
  "client_email": "[email protected]",
  "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 な値だと思い楽勝だろ と思っていたんですが、上記では環境変数の key に対して、
value がファイルのパスを指定するという仕組みなんですねー・・・

ここから現在のCI/CD環境に合わせて、環境変数の受け渡しをどうするか 想定外の問題が勃発

ファイル化するならdocker image内にファイル入れないとなー・・・でもクレデンシャル情報だからGitでソース管理するわけにいかんし・・・
なんか簡単にいかないかなーって色々と模索したのが下記

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

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

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