Document AI と Python による光学式文字認識(OCR)

1. 概要

ラボの概要

Document AI とは何か

Document AI は非構造化データ(ドキュメント、メール、請求書、フォームなど)を取得し、データを理解、分析、利用しやすくするためのドキュメント理解ソリューションです。この API はコンテンツ分類、エンティティ抽出、検索オプションなどにより構造を提供します。

このラボでは、Document AI API と Python を使用して光学式文字認識を行う方法について学びます。

アメリカのパブリック ドメインに最近加わった AA Milne の古典小説「Winnie the Pooh」の PDF ファイルを使用します。このファイルは Google ブックスによってスキャンされ、デジタル化されています。

学習内容

  • Document AI API を有効にする方法
  • API リクエストを認証する方法
  • Python 用クライアント ライブラリのインストール方法
  • PDF ファイルのテキストを解析する方法
  • Google Cloud Storage を使用して非同期リクエストを行う方法

必要なもの

  • Google Cloud プロジェクト
  • ブラウザ(ChromeFirefox など)
  • Python の使用経験(3.7 以上)

アンケート

このチュートリアルをどのように使用されますか?

通読するのみ 通読し、演習を行う

Python のご利用経験

初心者 中級者 上級者

Google Cloud サービスのご利用についてどのように評価されますか?

初心者 中級者 上級者

2. 設定と要件

cae48e4b2e19921d.png

表示されるダイアログで、[同意して続行] ボタンをクリックして利用規約に同意します。

27D87930a0daf2f8.png

利用規約に同意すると、右下に次のようなパネルを含む [料金概略] ページにリダイレクトされます。

2076ea7aa9bf3f65.png

最後に、最初のプロジェクトを作成するときに、プロジェクトに請求先アカウントを割り当てるためのダイアログが表示されます。無料クレジットに関連付けられた請求先アカウントを選択し、作成ボタンをクリックします。

dd3b0e795843296.png

これで要約ができました。請求先アカウントとプロジェクトが作成され、この 2 つのエンティティがリンクされました。今日の Codelab で行った作業は、すべて無料のクレジットで賄われています**。**

セルフペース型の環境設定

  1. Cloud Console にログインし、新しいプロジェクトを作成するか、既存のプロジェクトを再利用します(Gmail または Google Workspace アカウントをまだお持ちでない場合は、アカウントを作成する必要があります)。

プロジェクトを選択

新しいプロジェクト

プロジェクト ID の取得

プロジェクト ID を覚えておいてください。プロジェクト ID は、すべての Google Cloud プロジェクトで一意の名前です。(上記のプロジェクト ID は取得済みのため機能しません)。この ID は後で PROJECT_ID として指定する必要があります。

  1. 次に、Google Cloud リソースを使用するには、Cloud Console で課金を有効にする必要があります。

必ず「クリーンアップ」セクションの手順を実施してください。このセクションでは、このチュートリアル以外で課金されないようにリソースをシャットダウンする方法について説明します。Google Cloud の新規ユーザーは $300 の無料トライアル プログラムをご利用いただけます。

Cloud Shell の起動

Google Cloud はノートパソコンから リモートで操作できますが、この Codelab では、Google Cloud Shell(Cloud 上で動作するコマンドライン環境)を使用します。

Cloud Shell をアクティブにする

  1. Cloud Console で、[Cloud Shell をアクティブにする ] Cloud Shell をアクティブにする をクリックします。

Cloud Shell をアクティブにする

Cloud Shell を初めて使用する場合は、それが何であるかを示す中間画面(スクロールしなければ見えない位置)が表示されます。その場合は、[続行] をクリックします(再表示されることはありません)。このワンタイム スクリーンは次のようになります。

Cloud Shell の概要

プロビジョニングと Cloud Shell への接続には数分かかります。 Cloud Shell さん

Cloud Shell を使用すると、クラウドにホストされている仮想マシンにターミナル アクセスできます。仮想マシンには、必要な開発ツールがすべて含まれています。5 GB の永続ホーム ディレクトリが用意されており、Google Cloud で稼働するため、ネットワーク パフォーマンスが充実しており認証もスムーズです。この Codelab の作業のほとんどは、ブラウザだけで行うことができます。

Cloud Shell に接続されると、認証が完了し、プロジェクトがプロジェクト ID にすでに設定されていることを確認できます。

  1. Cloud Shell で次のコマンドを実行して、認証されたことを確認します。
gcloud auth list

コマンド出力

 Credentialed Accounts
ACTIVE  ACCOUNT
*      <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
gcloud config list project

コマンド出力

[core]
project = <PROJECT_ID>

上記のようになっていない場合は、次のコマンドで設定できます。

gcloud config set project <PROJECT_ID>

コマンド出力

Updated property [core/project].

3. Document AI API を有効にする

Document AI の使用を開始する前に、API を有効にする必要があります。ブラウザで Cloud Console を開きます。

  1. コンソールの上部にある検索バーで「Document AI API」を検索し、[有効にする] をクリックして Google Cloud プロジェクトで API を使用します。

Search API

  1. また、次の gcloud コマンドを使用して API を有効にすることもできます。
gcloud services enable documentai.googleapis.com

次のように表示されます。

Operation "operations/..." finished successfully.

Document AI を使用できるようになりました。

4.プロセッサの作成とテスト

まず、抽出を実行する Document OCR プロセッサのインスタンスを作成する必要があります。これを行うには、Cloud Console または Processor Management API を使用します。

Cloud Console

  1. コンソールで [Document AI Platform Overview] に移動します。
  2. [プロセッサを作成] をクリックして、[Document OCR] を選択します。プロセッサ
  3. プロセッサ名を指定し、リストからリージョンを選択します。
  4. プロセッサを作成するには [作成] をクリックします
  5. プロセッサ ID をコピーします。これは、後でコードで使用する必要があります。 プロセッサ ID さん

ドキュメントをアップロードすることで、コンソールでプロセッサをテストできます。[Upload Test Document] をクリックして、解析するドキュメントを選択します。

以下の PDF ファイルをダウンロードできます。PDF ファイルには小説の最初の 3 ページが含まれています。

タイトル ページ

出力は次のようになります。Parsed Book

Python Client ライブラリ

Python クライアント ライブラリを使用して Document AI プロセッサを管理する方法については、以下の Codelab をご覧ください。

Python を使用した Document AI プロセッサの管理 - Codelab

5. API リクエストの認証

Document AI API にリクエストを行うには、サービス アカウントを使用する必要があります。サービス アカウントはプロジェクトに属するものであり、Python クライアント ライブラリで API リクエストを行うために使用されます。他のユーザー アカウントと同様に、サービス アカウントはメールアドレスで表されます。このセクションでは、Cloud SDK を使用してサービス アカウントを作成し、サービス アカウントとして認証するために必要な認証情報を作成します。

まず、この Codelab で使用する PROJECT_ID で環境変数を設定します。

export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value core/project)

次に、次のコマンドで Document AI API にアクセスするための新しいサービス アカウントを作成します。

gcloud iam service-accounts create my-docai-sa \
  --display-name "my-docai-service-account"

次に、Python コードで新しいサービス アカウントとしてログインする際に使用する認証情報を作成します。次のコマンドを使用して認証情報を作成し、JSON ファイル「~/key.json」として保存します。

gcloud iam service-accounts keys create ~/key.json \
  --iam-account  my-docai-sa@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com

最後に、GOOGLE_APPLICATION_CREDENTIALS 環境変数を設定します。この環境変数は、ライブラリが認証情報を見つけるために使用します。このフォーム認証の詳細については、ガイドをご覧ください。次のコマンドを使用して、作成した認証情報 JSON ファイルのフルパスを環境変数に設定します。

export GOOGLE_APPLICATION_CREDENTIALS="/path/to/key.json"

6. クライアント ライブラリをインストールする

クライアント ライブラリをインストールします。

pip3 install --upgrade google-cloud-documentai
pip3 install --upgrade google-cloud-storage

次のように表示されます。

...
Installing collected packages: google-cloud-documentai
Successfully installed google-cloud-documentai-1.2.0
.
.
Installing collected packages: google-cloud-storage
Successfully installed google-cloud-storage-1.43.0

これで、Document AI API を使用する準備ができました。

インタラクティブ Python の起動

このチュートリアルでは、IPython というインタラクティブな Python インタープリタを使用します。Cloud Shell で ipython を実行してセッションを開始します。このコマンドは、インタラクティブ セッションで Python インタープリタを実行します。

ipython

次のように表示されます。

Python 3.7.3 (default, Jul 25 2020, 13:03:44)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.30.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]:

7. サンプル PDF をダウンロード

小説の最初の 3 ページが含まれているサンプル ドキュメントがあります。

次のリンクから PDF をダウンロードできます。cloudshell インスタンスにアップロードします。

gsutil を使用して一般公開の Google Cloud Storage バケットからダウンロードすることもできます。

gsutil cp gs://cloud-samples-data/documentai/codelabs/ocr/Winnie_the_Pooh_3_Pages.pdf .

8. 同期プロセスのドキュメント リクエストを行う

このステップでは、同期エンドポイントを使用して小説の最初の 3 ページを処理します。この方法は、ローカルに保存される小さなドキュメントに最適です。プロセッサ タイプごとの最大ページ数とファイルサイズについては、プロセッサの詳細リストをご覧ください。

次のコードを iPython セッションにコピーします。

from google.cloud import documentai_v1 as documentai

def process_document(project_id: str, location: str,
                     processor_id: str, file_path: str,
                     mime_type: str) -> documentai.Document:
    """
    Processes a document using the Document AI API.
    """

    # Instantiates a client
    documentai_client = documentai.DocumentProcessorServiceClient()

    # The full resource name of the processor, e.g.:
    # projects/project-id/locations/location/processor/processor-id
    # You must create new processors in the Cloud Console first
    resource_name = documentai_client.processor_path(
        project_id, location, processor_id)

    # Read the file into memory
    with open(file_path, "rb") as image:
        image_content = image.read()

        # Load Binary Data into Document AI RawDocument Object
        raw_document = documentai.RawDocument(
            content=image_content, mime_type=mime_type)

        # Configure the process request
        request = documentai.ProcessRequest(
            name=resource_name, raw_document=raw_document)

        # Use the Document AI client to process the sample form
        result = documentai_client.process_document(request=request)

        return result.document

def main():
    """
    Run the codelab.
    """
    project_id = 'YOUR_PROJECT_ID'
    location = 'YOUR_PROJECT_LOCATION'  # Format is 'us' or 'eu'
    processor_id = 'YOUR_PROCESSOR_ID'  # Create processor in Cloud Console

    file_path = 'Winnie_the_Pooh_3_Pages.pdf'  # The local file in your current working directory
    # Refer to https://cloud.google.com/document-ai/docs/processors-list for the supported file types
    mime_type = 'application/pdf'

    document = process_document(project_id=project_id, location=location,
                                processor_id=processor_id, file_path=file_path,
                                mime_type=mime_type)

    print("Document processing complete.")
    print(f"Text: {document.text}")

main 関数を呼び出すと、抽出して出力したテキストがコンソールに表示されます。

main()

サンプル ドキュメントを使用すると、次の出力が表示されます。

Document processing complete.
Text: CHAPTER I
IN WHICH We Are Introduced to
Winnie-the-Pooh and Some
Bees, and the Stories Begin
Here is Edward Bear, coming
downstairs now, bump, bump, bump, on the back
of his head, behind Christopher Robin. It is, as far
as he knows, the only way of coming downstairs,
but sometimes he feels that there really is another
way, if only he could stop bumping for a moment
and think of it. And then he feels that perhaps there
isn't. Anyhow, here he is at the bottom, and ready
to be introduced to you. Winnie-the-Pooh.
When I first heard his name, I said, just as you
are going to say, "But I thought he was a boy?"
"So did I," said Christopher Robin.
"Then you can't call him Winnie?"
"I don't."
"But you said "

...

Digitized by
Google

9. 非同期プロセスのドキュメント リクエストを行う

ここで、小説全体からテキストを読みたいとします。

  • process_documents() メソッドには、送信できるページ数とファイルサイズに制限があり、1 回の API 呼び出しで 1 つのドキュメント ファイルしか使用できません。
  • batch_process_documents() メソッドを使用すると、サイズの大きいファイルを非同期で処理し、複数のファイルをバッチ処理できます。

このステップでは、Document AI の非同期 API を使用して小型の「Winnie the Pooh」全体を処理し、そのテキストを Google Cloud Storage バケットに出力します。

PDF を Cloud Storage にアップロードする

現在、batch_process_documents() メソッドは Google Cloud Storage のファイルを受け入れます。オブジェクト構造について詳しくは、documentai_v1.types.BatchProcessRequest をご覧ください。

この例では、サンプル データバケットからファイルをコピーできます。

gsutil cp gs://cloud-samples-data/documentai/codelabs/ocr/Winnie_the_Pooh.pdf gs://YOUR_BUCKET_NAME/

または、下のリンクから小説のサンプル ファイルをダウンロードして、ご自身のバケットにアップロードすることもできます。

API の出力を保存する GCS バケットも必要です。

batch_process_documents() メソッドの使用

次のコードを iPython セッションにコピーします。

import re

from google.api_core.operation import Operation
from google.cloud import documentai_v1 as documentai
from google.cloud import storage

def batch_process_documents(
    project_id: str,
    location: str,
    processor_id: str,
    gcs_input_uri: str,
    input_mime_type: str,
    gcs_output_uri: str,
) -> Operation:
    """
    Constructs a request to process a document using the Document AI
    Asynchronous API.
    """
    # You must set the api_endpoint if you use a location other than 'us', e.g.:
    opts = {}
    if location == "eu":
        opts = {"api_endpoint": "eu-documentai.googleapis.com"}

    # Instantiates a client
    documentai_client = documentai.DocumentProcessorServiceClient(client_options=opts)

    # The full resource name of the processor, e.g.:
    # projects/project-id/locations/location/processor/processor-id
    # You must create new processors in the Cloud Console first
    resource_name = documentai_client.processor_path(project_id, location, processor_id)

    # Cloud Storage URI for the Input Document
    input_document = documentai.GcsDocument(
        gcs_uri=gcs_input_uri, mime_type=input_mime_type
    )

    # Load GCS Input URI into a List of document files
    input_config = documentai.BatchDocumentsInputConfig(
        gcs_documents=documentai.GcsDocuments(documents=[input_document])
    )

    # Cloud Storage URI for Output directory
    gcs_output_config = documentai.DocumentOutputConfig.GcsOutputConfig(
        gcs_uri=gcs_output_uri
    )

    # Load GCS Output URI into OutputConfig object
    output_config = documentai.DocumentOutputConfig(gcs_output_config=gcs_output_config)

    # Configure Process Request
    request = documentai.BatchProcessRequest(
        name=resource_name,
        input_documents=input_config,
        document_output_config=output_config,
    )

    # Future for long-running operations returned from Google Cloud APIs.
    operation = documentai_client.batch_process_documents(request)

    return operation

def get_documents_from_gcs(
    gcs_output_uri: str, operation_name: str
) -> [documentai.Document]:
    """
    Download the document output from GCS.
    """

    # The GCS API requires the bucket name and URI prefix separately
    match = re.match(r"gs://([^/]+)/(.+)", gcs_output_uri)
    output_bucket = match.group(1)
    prefix = match.group(2)

    # The output files will be in a new subdirectory with the Operation ID as the name
    operation_id = re.search("operations\/(\d+)", operation_name, re.IGNORECASE).group(1)

    output_directory = f"{prefix}/{operation_id}"

    storage_client = storage.Client()

    # List of all of the files in the directory `gs://gcs_output_uri/operation_id`
    blob_list = list(storage_client.list_blobs(output_bucket, prefix=output_directory))

    output_documents = []

    for blob in blob_list:
        # Document AI should only output JSON files to GCS
        if ".json" in blob.name:
            document = documentai.types.Document.from_json(blob.download_as_bytes())
            output_documents.append(document)
        else:
            print(f"Skipping non-supported file type {blob.name}")

    return output_documents

def main():
    """
    Run the codelab.
    """

    project_id = 'YOUR_PROJECT_ID'
    location = 'YOUR_PROJECT_LOCATION'  # Format is 'us' or 'eu'
    processor_id = 'YOUR_PROCESSOR_ID'  # Create processor in Cloud Console

    # Format 'gs://input_bucket/directory/file.pdf'
    gcs_input_uri = "INPUT_BUCKET_URI"
    input_mime_type = "application/pdf"

    # Format 'gs://output_bucket/directory'
    gcs_output_uri = "YOUR_OUTPUT_BUCKET_URI"

    # Batch Process returns a Long Running Operation (LRO)
    operation = batch_process_documents(
        project_id=project_id,
        location=location,
        processor_id=processor_id,
        gcs_input_uri=gcs_input_uri,
        input_mime_type=input_mime_type,
        gcs_output_uri=gcs_output_uri,
    )

    # Format: projects/PROJECT_NUMBER/locations/LOCATION/operations/OPERATION_ID
    operation_name = operation.operation.name

    # Continually polls the operation until it is complete.
    # This could take some time for larger files
    print(f"Waiting for operation {operation_name} to complete...")
    result = operation.result(timeout=300)

    # NOTE: Can also use callbacks for asynchronous processing
    #
    # def my_callback(future):
    #   result = future.result()
    #
    # operation.add_done_callback(my_callback)

    print("Document processing complete.")

    # Get the Document Objects from the Output Bucket
    document_list = get_documents_from_gcs(
        gcs_output_uri=gcs_output_uri, operation_name=operation_name
    )

    for document in document_list:
        print(document.text)

main 関数を呼び出すと、抽出した完全なテキストがコンソールに出力されます。

main()

ファイルが前の例よりもはるかに大きいため、完了までに時間がかかることがあります。...

ただし、非同期 API ではオペレーション ID が返されます。この ID を使用して、タスクの完了後に GCS から出力を取得できます。

This is a reproduction of a library book that was digitized
by Google as part of an ongoing effort to preserve the
information in books and make it universally accessible.
TM
Google books
https://books.google.com

.....

He nodded and went
out ... and in a moment
I heard Winnie-the-Pooh
-bump, bump, bump-go-ing up the stairs behind
him.
Digitized by
Google

10. 完了

Document AI を使用して、同期 API と非同期 API を使用して小説からテキストを抽出することができました。

他のドキュメントを試したり、プラットフォームで使用できる他のプロセッサを試したりすることをおすすめします。

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにする手順は次のとおりです。

  • Cloud Console で [リソースの管理] ページに移動します。
  • プロジェクト リストでプロジェクトを選択し、[削除] をクリックします。
  • ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。

詳細

ライセンス

この作業はクリエイティブ・コモンズの表示 2.0 汎用ライセンスにより使用許諾されています。