OCRサービスで抽出したテキストデータをChatGPTに解析させる

はじめに

記事の対象者と目的

こんにちは!株式会社エンラプト開発チームです。本記事では、OCR(光学的文字認識)のサービスを活用したアプリケーション開発に関心がある皆さんに向けて、ChatGPTと組み合わせてOCRを利用する具体的な方法や特徴を解説します。

OCRサービスを利用すれば画像からテキストを抽出できますが、そのままのテキストではデータとして利用しづらい無秩序な形になってしまっています。
しかしながらChatGPTを利用することで、OCRから抽出したテキストを各項目へマッピングし、使用しやすいフォーマットに変更することが可能になります。

成果物

レシートの画像のURLを指定するとそのレシートの画像から日付、商品名、商品ごとの金額、合計金額をjson形式で出力してくれるアプリケーションを作成しました。

無題のプレゼンテーション.jpg

今回作成したアプリケーションのコードはgithubに公開しています。

https://github.com/Enrapt/OCR-ChatGPT/tree/develop

OCRサービス

OCR(Optical Character Recognition)とは、画像や紙媒体に印刷されたテキストを、機械が読み込み可能なテキストに変換する技術です。
いくつかの代表的なサービスを紹介します。

  1. Google Cloud Vision API
    Google Cloud Vision APIは、Googleが提供するOCRサービスです。APIを使用することで、画像内のテキストを検出して、そのテキストをテキストファイルやデータベースに出力することができます。また、多言語対応もしており、40種類以上の言語をサポートしています。
  2. Microsoft Azure Computer Vision
    Microsoft Azure Computer Visionは、Microsoftが提供するOCRサービスです。APIを使用することで、画像内のテキストを検出して、そのテキストをテキストファイルやデータベースに出力することができます。多言語対応もしており、60種類以上の言語をサポートしています。
  3. Amazon Textract
    Amazon Textractは、Amazonが提供するOCRサービスです。APIを使用することで、画像内のテキストを検出して、そのテキストをテキストファイルやデータベースに出力することができます。また、テーブルやフォームの検出にも対応しています。

Enraptでは、Azureを主に使用しているため、今回はMicrosoft Azure Computer Visionを使用します。

ちなみにこの中で日本語に対応しているサービスは

  • Google Cloud Vision API
  • Microsoft Azure Computer Vision

になります。

※Amazon Textractは2023/04/06現在は日本語対応していません。

Computer Vision | Microsoft Azureの使用

Computer VisionはC#,Python,JavaScriptなどのプログラミング言語や、Vision StudioというWeb上のUIキットツールを使用して利用することが可能です。

今回アプリケーションを作成する場合にはJavaScriptで利用しますが、使用例をVision Studioを使用して簡単にお見せします。

こちらがOCRを利用したテキスト抽出の結果になります。

スクリーンショット 2023-03-31 13.37.48.png

かなりの文字を読み取れてはいますが、まだ完璧ではありません。

また、出力結果はテキストのみのデータと、JSONデータがあります。

ChatGPTの使用

ChatGPTは、OpenAIが開発した自然言語処理の技術であり、GPT-3.5アーキテクチャに基づく大規模な言語モデルです。ChatGPTは、多様な言語タスクに対応できるように訓練され、人工知能による自然な対話を実現することができます。

ChatGPTは、テキストデータを自然言語処理して、質問に答えたり、文章の要約を作成することができます。例えば、日本語の新聞記事の見出しを抽出する場合、ChatGPTを使用して「この文章は何についてですか?」と質問することができます。ChatGPTは、質問に答えるためにテキストデータを解析し、見出しを特定することができます。

OCRで読み取ったデータはテキスト同士の順番、文脈やつながりまでは判断できません。そこでChatGPTを利用することにより、データに対してkeyとvalueを持たせたり、利用しやすいフォーマットに変換することが可能になります。

ChatGPTの概要に関しては、こちらで詳しく説明しています。

https://qiita.com/enrapt/items/9b5b3b0d4523af20a0c0

実際に先ほどのテキストをChatGPTに入力し、日付、商品名、商品ごとの金額、合計金額を抽出してみます。

スクリーンショット 2023-03-31 14.31.02.png
スクリーンショット 2023-03-31 14.31.16.png

求めていた結果を出力することができました。

アプリケーションの作成

実用的な使用例として、コンビニのレシートから日付、商品名、商品ごとの金額、合計金額を抽出してみます。
今回はそれぞれのAPIを利用して、コマンドラインで動くアプリケーションを作成してみます。

こちらはアプリケーションのデータフロー図になります。
Data Flow Diagram (Logical).png

実際に読み取るレシートはVision Studioで使用したものと同じものを使います。
receipt.JPG

Computer Vision APIの利用

こちらの公式ドキュメントを参考にアプリケーションを構築します。

https://qiita.com/sonesuke/items/981925cfcc610a602e94

今回はJavaScriptを使用してアプリケーションを構築します。

APIの利用にはkeyとendpointが必要になります。
Azure PortalのComputer Visionリソースの[key and endpoint]ページに記載があります。
キーは1と2がありますが、どちらを利用しても問題ありません。

スクリーンショット 2023-04-03 15.55.36.png

キーやエンドポイント、APIキーは公開してしまうと悪用される可能性があるため、環境変数などに設定し外部から読み取られないような工夫が必要になります。

後述しますが、今回はdotenvを使用します。

Open AI APIの利用

ChatGPTもAPIを利用し、nodeから実行できるように設定しましょう。
下記URLにアクセスしてAPI Keyを発行します。

https://platform.openai.com/account/api-keys

スクリーンショット 2023-04-03 15.59.08.png

必要なライブラリのインストール

azureやopenAIのAPIの利用のため、必要なライブラリをインストールします。

npm install @azure/cognitiveservices-computervision dotenv openai

envファイルの作成

Computer Visionのキーやエンドポイント、openAI API Keyをenvファイルに設定します。

COMPUTER_VISION_KEY=XXX
COMPUTER_VISION_ENDPOINT=XXX
OPENAI_API_KEY=sk-XXX

index.jsの作成

"use strict";

require("dotenv").config();
const { Configuration, OpenAIApi } = require("openai");
const sleep = require("util").promisify(setTimeout);
const ComputerVisionClient =
  require("@azure/cognitiveservices-computervision").ComputerVisionClient;
const ApiKeyCredentials = require("@azure/ms-rest-js").ApiKeyCredentials;
/**
 * 認証情報
 * This single client is used for all examples.
 */
const computerVisionKey = process.env.COMPUTER_VISION_KEY;
const computerVisionEndpoint = process.env.COMPUTER_VISION_ENDPOINT;

const computerVisionClient = new ComputerVisionClient(
  new ApiKeyCredentials({
    inHeader: { "Ocp-Apim-Subscription-Key": computerVisionKey },
  }),
  computerVisionEndpoint
);
const configuration = new Configuration({
  apiKey: process.env.OPENAI_API_KEY,
});
/**
 * END - 認証情報
 */

const openai = new OpenAIApi(configuration);

// 読み取りを実行し、URL からの結果を待つ関数
async function readTextFromURL(client, url) {
  // read() メソッドを使用して URL から印刷画像のテキストを読み込みます
  let result = await client.read(url);
  // オペレーション ID は operationLocation (URL) の最後のパス セグメントです
  let operation = result.operationLocation.split("/").slice(-1)[0];

  // 読み取りが完了するまで待機します
  while (result.status !== "succeeded") {
    await sleep(1000);
    result = await client.getReadResult(operation);
  }
  return result.analyzeResult.readResults; // 結果の最初のページを返します。
}

// ページの読み取り結果を抽出し、テキストを配列に格納します
async function extractTextArrayFromReadResults(readResults) {
  const array = [];
  for (const page in readResults) {
    const result = readResults[page];
    if (result.lines.length) {
      for (const line of result.lines) {
        array.push(line.text);
      }
    } else {
      console.log("No recognized text.");
    }
  }
  return array;
}

// テキストをJSON形式に変換する関数
async function convertOCRTextToJSON(content) {
  // OpenAI APIを使用して、GPT-3.5モデルを呼び出す
  const response = await openai.createChatCompletion({
    model: "gpt-3.5-turbo-0301",
    messages: [
      // JSON形式に変換するための指示を含むシステムのメッセージと、OCRで取得したテキストを含むユーザーのメッセージを送信する
      {
        role: "system",
        content:
          "以下の[テキスト]を[制約]に従って[出力フォーマット]で出力してください。[制約]* 出力は[出力フォーマット]のみ出力してください。* [出力フォーマット]以外の余計な文章は出力しないでください。[出力フォーマット]```json { '明細': [{  '商品名': 'テスト',  '金額': 1000}],'合計金額': 10000} ``` [テキスト] ",
      },
      { role: "user", content: content },
    ],
  });

  // OpenAI APIからの応答のうち、返答の内容を抽出する
  const answerOpenAI = await response.data.choices[0].message?.content;
  return answerOpenAI;
}

// OCR APIを利用して画像のURLからテキストを抽出し、テキストデータをopenAIに渡してJSON形式に変換する
async function convertImageToJSON() {
  // コマンドライン引数から、印刷されたテキストや手書きのテキストを含むURLを取得する。今回はコマンドライン引数からURLを取得。
  const printedTextSampleURL = process.argv[2];

  // Computer Vision APIを使用して、指定されたURLから印刷画像のテキストを認識する
  const printedResult = await readTextFromURL(
    computerVisionClient,
    printedTextSampleURL
  );
  const extractTextArray = await extractTextArrayFromReadResults(printedResult);
  const parsedData = await convertOCRTextToJSON(extractTextArray.join("\n"));
  console.log(parsedData);
}

convertImageToJSON();

こちらのコードでは、printedTextSampleURLに指定された画像を読み取り、resultという変数にjsonデータが格納されます。
今回CLIで実行したいので、画像のURL部分はターミナルから渡せるように設定しています。

readTextFromURLという関数はAzure Cognitive ServicesのOCR APIを使って、与えられた URLから画像に含まれるテキストを読み取り、テキストを返すコードです。
画像に含まれるテキストを読み取るために、OCR APIを使用します。

APIが読み取りオペレーションを開始し、成功するまでsleepで結果を待ちます。
オペレーションが完了すると、読み取り結果が返され、result.analyzeResult.readResults によって、画像から読み取られたテキストが返されます。

実行するとURLで指定した画像データから取得されたテキストがgpt3.5-turboによって整形したJSONに変換され出力されます。

プロンプトについて

プロンプトには以下のような命令を記載しています。

以下の[テキスト]を[制約]に従って[出力フォーマット]で出力してください。

[制約]
* 出力は[出力フォーマット]のみ出力してください。
* [出力フォーマット]以外の余計な文章は出力しないでください。
* [出力フォーマット] \```json{ '明細': [{  '商品名': 'テスト',  '金額': 1000}],'合計金額': 10000} ```
\
 [テキスト]

制約条件を詳細に設定することで、出力結果を安定して同じ結果を出すことができます。
良いプロンプトには現在いくつかのテンプレートがあるため、そちらを利用してみるのも良いでしょう。

https://qiita.com/sonesuke/items/981925cfcc610a602e94

実行手順

nodeでjavascirptファイルを実行します。

node index.js 画像のURL

出力結果

{
  "明細": [
    {
      "商品名": "7プレミアムロックアイス 1.1kg",
      "金額": 258
    },
    {
      "商品名": "キリン淡麗グリーンラベル 500ml",
      "金額": 228
    },
    {
      "商品名": "スコッチウイスキーハイボール LS500ml",
      "金額": 258
    },
    {
      "商品名": "ジャガイモゴコチモッツァレラチーズ",
      "金額": 135
    },
    {
      "商品名": "鶏むね肉サラダ",
      "金額": 440
    },
    {
      "商品名": "三ツ矢特濃ピーチスカッシュ 500",
      "金額": 150
    },
    {
      "商品名": "7Pおでん",
      "金額": 248
    },
    {
      "商品名": "7P穂先メンマ",
      "金額": 128
    }
  ],
  "合計金額": 1977
}

このように取得したい情報を抽出し、データのリレーションまでjsonで出力することができました。
出力結果はプロンプトを変更することで自由にカスタマイズ可能です。

さらにGoogle Sheets APIを組み込むことで、取得したデータを自動的にspreadsheetに書き込み家計簿管理をすることも可能です。

利用するにあたっての注意

  • 機密情報の取り扱い:顧客データ、個人情報など機密情報に関してはMicrosoftのポリシーに留意する必要があります。詳細については、MicrosoftセキュリティセンターのCognitive Servicesのページを参照してください。また、OpenAIに関しても同等です。
  • レシートの読み取り精度:レシートによっては正しく金額や商品名を読み取れないものもありました。条件としては、レシートが長過ぎないもの。印刷が薄くないこと。レシート自体の状態が悪くないことなどが挙げられます。
  • 手書きテキストの読み取り精度:手書きの日本語テキストの読み取り精度はまだ正確に読み取れないことも多いです。使用にはconfidenceに閾値を設定するなどの工夫が必要です。
  • コスト:Azure Computer Vision APIの利用コストはfreeレベルで毎月5000件までになります。S1レベルは0 ~ 100 万トランザクションの利用の場合,1,000トランザクションあたり¥136.386です。詳細
    Open AI APIの利用コストはOpen AIについて紹介した記事に載せていますので、そちらを参照してください。

まとめ

この記事では、Azure Computer VisionとChatGPTを組み合わせて画像から必要な日本語のテキストを取得する方法を紹介しました。
応用すれば

  • 確定申告に必要な帳簿の作成の自動化
  • 履歴書の仕分け
  • 申請書類のデータ化

など、ビジネスシーンでの利用が考えられます。この記事を参考に是非ともお試しください。

また、株式会社エンラプトでは、OpenAIのサービスを使ったソリューションの研究を日々行っています。もし、弊社のサービスや採用に関心があればお気軽にお問い合わせください。ホームページにはOpenAIサービスを利用したFAQチャットもご用意しています。

それでは、最後までご覧いただきありがとうございました!

コメントを残す

%d人のブロガーが「いいね」をつけました。