透過 Document AI 聰明處理手寫表單 (Node.js)

1. 總覽

什麼是 Document AI?

Document AI API 是文件解讀解決方案,可擷取文件和電子郵件等非結構化資料,方便您解讀、分析及使用。Document AI API 會透過內容分類、實體擷取、進階搜尋等功能,將文件轉換成結構化資料。

在本教學課程中,您會著重於使用 Node.js 搭配 Document AI API。本教學課程會示範如何剖析簡易病患資料登記表。

課程內容

  • 如何啟用 Document AI API
  • 如何驗證 API 要求
  • 如何安裝 Node.js 適用的用戶端程式庫
  • 如何剖析掃描表單中的資料

軟硬體需求

  • Google Cloud 專案
  • ChromeFirefox 瀏覽器
  • Node.js 知識

問卷調查

您會如何使用本教學課程?

僅閱讀 閱讀並完成練習

您對 Node.js 的體驗滿意嗎?

新手 中級 熟練

您對使用 Google Cloud 服務的體驗滿意嗎?

新手 中級 熟練

2. 設定和需求

自修實驗室環境設定

  1. 登入 Cloud 控制台,建立新專案或重複使用現有專案。(如果沒有 Gmail 或 G Suite 帳戶,請先建立帳戶)。

記住專案 ID,這是所有 Google Cloud 專案中不重複的名稱。(很抱歉,上述名稱已遭占用,無法使用!)。您稍後必須提供此 ID 做為 PROJECT_ID

  1. 接著,您必須在 Cloud 控制台中啟用帳單,才能使用 Google Cloud 資源。

完成活動後,請務必按照「清除」部分的指示操作,當中會說明如何停用資源,避免在本教學課程結束後繼續產生帳單費用。Google Cloud 新使用者可參加價值$300 美元的免費試用計畫。

啟動 Cloud Shell

您可以在 Google Cloud 中透過筆電遠端操作 Google Cloud,但本程式碼研究室會使用 Google Cloud Shell,這是可在雲端執行的指令列環境。

啟用 Cloud Shell

  1. 在 Cloud 控制台,點選「啟用 Cloud Shell」 圖示 H7JlbhKGHITmsxhQIcLwoe5HXZMhDlYue4K-SPszMxUxDjIeWfOHBfxDHYpmLQTzUmQ7Xx8o6OJUlANnQF0iBuUyfp1RzVad_4nCa0Zz5LtwBlUZFXFCWFrmrWZLqg1MkZz2LdgUDQ

zlNW0HehB_AFW1qZ4AyebSQUdWm95n7TbnOr7UVm3j9dFcg6oWApJRlC0jnU1Mvb-IQp-trP1Px8xKNwt6o3pP6fyih947sEhOFI4IRF0W7WZk6hFqZDUGXQQXrw21GuMm2ecHrbzQ

如果您是首次啟動 Cloud Shell,系統會顯示中繼畫面 (位於摺疊式選單下方),說明這個指令列環境。點選「繼續」後,這則訊息日後就不會再出現。以下是這個初次畫面的樣子:

kEPbNAo_w5C_pi9QvhFwWwky1cX8hr_xEMGWySNIoMCdi-Djx9AQRqWn-__DmEpC7vKgUtl-feTcv-wBxJ8NwzzAp7mY65-fi2LJo4twUoewT1SUjd6Y3h81RG3rKIkqhoVlFR-G7w

佈建並連至 Cloud Shell 預計只需要幾分鐘。

pTv5mEKzWMWp5VBrg2eGcuRPv9dLInPToS-mohlrqDASyYGWnZ_SwE-MzOWHe76ZdCSmw0kgWogSJv27lrQE8pvA5OD6P1I47nz8vrAdK7yR1NseZKJvcxAZrPb8wRxoqyTpD-gbhA

Cloud Shell 可讓您透過終端機存取雲端的虛擬機器。這部虛擬機器含有您需要的所有開發工具,並提供永久的 5GB 主目錄,而且可在 Google Cloud 運作,大幅提升網路效能並強化驗證功能。本程式碼研究室幾乎所有工作都可在瀏覽器或 Chromebook 上完成。

連線至 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. 啟用 Cloud Document AI API

您必須先啟用 API,才能使用 Document AI。在瀏覽器中開啟 Cloud Console

  1. 依序點選「導覽選單」圖示 ☰ >「API 和服務」>「程式庫」Search API
  2. 搜尋「Document AI API」,然後點按「啟用」,即可在 Google Cloud 專案中使用這個 API

4. 建立及測試處理器

在本實驗室,您必須先建立表單剖析器的處理器執行個體,才能用於 Document AI 平台。

  1. 前往控制台的「Document AI Platform Overview」
  2. 按一下「建立處理器」,然後選取「表單剖析器」處理器
  3. 指定處理器名稱,然後從清單中選取區域。
  4. 點按「建立」即可建立處理器
  5. 複製處理器 ID。您稍後必須在程式碼中使用此 ID。

(選用) 上傳文件即可在控制台測試處理器。按一下「上傳文件」,然後選取要剖析的表單。如果沒有可用的表單,可以下載並使用這份範本。

健康表單

輸出內容應如下所示:剖析後的表單

5. 驗證 API 要求

如要向 Document AI API 提出要求,必須使用「服務帳戶」「服務帳戶」屬於您的專案,Google Client Node.js 程式庫會使用此帳戶提出 API 要求。服務帳戶與其他使用者帳戶一樣,都是以電子郵件地址表示。在本節中,您將使用「Cloud SDK」建立服務帳戶,然後建立以服務帳戶身分進行驗證所需的憑證。

請先使用 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"

接著,建立 Node.js 程式碼使用的憑證,用以登入新的服務帳戶。輸入下列指令,建立憑證並儲存為 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. 下載範本表單

我們在公開的 Google Cloud Storage 範例 bucket 中儲存了範例表單。使用下列指令將其下載至工作目錄。

gsutil cp gs://cloud-samples-data/documentai/form.pdf .

使用下列指令,確認檔案已下載至 Cloud Shell:

ls -ltr form.pdf

7. 安裝用戶端程式庫

接著在工作目錄中設定程式碼。

初始化新的 Node.js 套件:

npm init

安裝 Document AI 用戶端程式庫

npm install @google-cloud/documentai

8. 發出同步處理文件要求

在這個步驟中,您將使用同步端點發出處理文件要求。如要一次處理大量文件,也可使用非同步 API。如要進一步瞭解如何使用表單剖析器 API,請參閱這份指南

建立 index.js 檔案並貼上以下程式碼。請填入適用變數的處理器資訊。

const { DocumentProcessorServiceClient } = require('@google-cloud/documentai').v1;
const fs = require('fs');

/**
 * Runs the sample document through Document AI to get key/value pairs and
 * confidence scores.
 */
async function processDocument(projectId, location, processorId, filePath, mimeType) {
    // Instantiates a client
    const documentaiClient = new 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
    const resourceName = documentaiClient.processorPath(projectId, location, processorId);

    // Read the file into memory.
    const imageFile = fs.readFileSync(filePath);

    // Convert the image data to a Buffer and base64 encode it.
    const encodedImage = Buffer.from(imageFile).toString('base64');

    // Load Binary Data into Document AI RawDocument Object
    const rawDocument = {
        content: encodedImage,
        mimeType: mimeType,
    };

    // Configure ProcessRequest Object
    const request = {
        name: resourceName,
        rawDocument: rawDocument
    };

    // Use the Document AI client to process the sample form
    const [result] = await documentaiClient.processDocument(request);

    return result.document;
}

/**
 * Run the codelab.
 */
async function main() {
    const projectId = 'YOUR_PROJECT_ID';
    const location = 'YOUR_PROJECT_LOCATION'; // Format is 'us' or 'eu'
    const processorId = 'YOUR_PROCESSOR_ID'; // Should be a Hexadecimal string

    // Supported File Types
    // https://cloud.google.com/document-ai/docs/processors-list#processor_form-parser
    filePath = 'form.pdf'; // The local file in your current working directory
    mimeType = 'application/pdf';

    const document = await processDocument(projectId, location, processorId, filePath, mimeType);
    console.log("Document Processing Complete");

    // Print the document text as one big string
    console.log(`Text: ${document.text}`);
}

main(...process.argv.slice(2)).catch(err => {
    console.error(err);
    process.exitCode = 1;
});

現在執行程式碼,控制台應會顯示下列文字。

Text: FakeDoc M.D.
HEALTH INTAKE FORM
Please fill out the questionnaire carefully. The information you provide will be used to complete
your health profile and will be kept confidential.
Name:
Date:
Sally
Walker
DOB: 09/04/1986
Address: 24 Barney Lane City: Towalo State: NJ Zip: 07082
Email: Sally, waller@cmail.com Phone #: (906) 917-3486
Gender:
Marital Status: Single Occupation: Software Engineer
Referred By: None
Emergency Contact: Eva Walker Emergency Contact Phone: (906) 334-8926
Describe your medical concerns (symptoms, diagnoses, etc):
Runny nose, mucas in throat, weakness,
aches, chills, tired
Are you currently taking any medication? (If yes, please describe):
Vyvanse (25mg) daily for attention

在後續步驟中,您會擷取結構化資料,這類資料更容易儲存在資料庫中,或用於其他應用程式。

9. 擷取表單鍵/值組合

您現在可以從表單中擷取鍵/值組合,以及對應的可信度分數。Document 回應物件包含輸入文件的頁面清單。每個 page 物件都包含表單欄位清單,以及這些欄位在文字中的位置。

下列程式碼會逐一查看每個頁面,並擷取每個鍵、值和可信度分數。

在程式碼中加入下列函式。

/**
 * Extract form data and confidence from processed document.
 */
function extractFormData(document) {
    // Extract shards from the text field
    function getText(textAnchor, document) {
        if (!textAnchor.textSegments || textAnchor.textSegments.length === 0) {
            return '';
        }

        // First shard in document doesn't have startIndex property
        const startIndex = textAnchor.textSegments[0].startIndex || 0;
        const endIndex = textAnchor.textSegments[0].endIndex;

        return document.text.substring(startIndex, endIndex);
    }

    var formData = [];

    const pages = document.pages;

    pages.forEach((page) => {
        const formFields = page.formFields;
        formFields.forEach((field) => {
            // Get the extracted field names and remove extra space from text
            const fieldName = getText(field.fieldName.textAnchor, document);
            // Confidence - How "sure" the API is that the text is correct
            const nameConfidence = field.fieldName.confidence.toFixed(4);

            const fieldValue = getText(field.fieldValue.textAnchor, document);
            const valueConfidence = field.fieldValue.confidence.toFixed(4);

            formData.push({
                fieldName: fieldName,
                fieldValue: fieldValue,
                nameConfidence: nameConfidence,
                valueConfidence: valueConfidence
            });
        });
    });

    return formData;
}

在主要函式中新增 extractFormData() 函式的呼叫,並以表格形式列印產生的物件。

/**
 * Run the codelab.
 */
async function main() {
    const projectId = 'YOUR_PROJECT_ID';
    const location = 'YOUR_PROJECT_LOCATION'; // Format is 'us' or 'eu'
    const processorId = 'YOUR_PROCESSOR_ID'; // Should be a Hexadecimal string

    // Supported File Types
    // https://cloud.google.com/document-ai/docs/processors-list#processor_form-parser
    filePath = 'form.pdf'; // The local file in your current working directory
    mimeType = 'application/pdf';

    const document = await processDocument(projectId, location, processorId, filePath, mimeType);
    const formData = extractFormData(document);

    console.log('\nThe following form key/value pairs were detected:');
    console.table(formData);
}

現在執行程式碼。如果您使用我們的範例文件,應該會看到下列輸出內容:

The following form key/value pairs were detected:
┌─────────┬────────────────────────────────────────────────────────────────┬──────────────────────────────────────────────────────────────────┬────────────────┬─────────────────┐
│ (index) │                           fieldName                            │                            fieldValue                            │ nameConfidence │ valueConfidence │
├─────────┼────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────┼────────────────┼─────────────────┤
│    0    │                       'Marital Status: '                       │                            'Single '                             │    '1.0000'    │    '1.0000'     │
│    1    │                            'DOB: '                             │                          '09/04/1986\n'                          │    '0.9999'    │    '0.9999'     │
│    2    │                            'City: '                            │                            'Towalo '                             │    '0.9996'    │    '0.9996'     │
│    3    │                          'Address: '                           │                        '24 Barney Lane '                         │    '0.9994'    │    '0.9994'     │
│    4    │                        'Referred By: '                         │                             'None\n'                             │    '0.9968'    │    '0.9968'     │
│    5    │                          'Phone #: '                           │                        '(906) 917-3486\n'                        │    '0.9961'    │    '0.9961'     │
│    6    │                           'State: '                            │                              'NJ '                               │    '0.9960'    │    '0.9960'     │
│    7    │                  'Emergency Contact Phone: '                   │                        '(906) 334-8926\n'                        │    '0.9925'    │    '0.9925'     │
│    8    │                           'Name:\n'                            │                        'Sally\nWalker\n'                         │    '0.9922'    │    '0.9922'     │
│    9    │                         'Occupation: '                         │                      'Software Engineer\n'                       │    '0.9914'    │    '0.9914'     │
│   10    │                            'Zip: '                             │                            '07082\n'                             │    '0.9904'    │    '0.9904'     │
│   11    │                           'Email: '                            │                    'Sally, waller@cmail.com '                    │    '0.9681'    │    '0.9681'     │
│   12    │                     'Emergency Contact: '                      │                          'Eva Walker '                           │    '0.9430'    │    '0.9430'     │
│   13    │ 'Describe your medical concerns (symptoms, diagnoses, etc):\n' │ 'Runny nose, mucas in throat, weakness,\naches, chills, tired\n' │    '0.7817'    │    '0.7817'     │
└─────────┴────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────┴────────────────┴─────────────────┘

10. 恭喜!

恭喜!您已成功使用 Document AI API 從手寫表單擷取資料。建議您嘗試使用其他表單圖片。

清除

如要避免系統向您的 Google Cloud 帳戶收取您在本教學課程中所用資源的相關費用:

  • 前往 Cloud Console 中的「管理資源」頁面。
  • 在專案清單中選取專案,然後按一下「刪除」。
  • 在對話方塊中輸入專案 ID,然後按一下「關閉」即可刪除專案。

瞭解詳情

授權

這項內容採用的授權為 Creative Commons 姓名標示 2.0 通用授權。