はじめに

今回はGemini Pro Visionで画像をスキャン(OCRを実行)してテキストを読み取り、読み取ったテキストを埋め込んだプロンプトをtext-bisonにロードして結果を出力してみました。

今回やってみたことで何が解決できるの?

画像をスキャンして文字列をおこし、テキスト生成すると何ができるようになるかというとたとえば、以下のような心配事を解決できるようになります。

  • Webページで紹介したい画像(スクリーンショット)があるけど、見せてはいけない情報とかないかな?
  • たくさんスクショ撮ったけど、マスキングすべき画像ってどれくらいあるのかな?
  • 画像一枚につき、見せてはいけない情報がどれくらい含まれているのかな?

など、普通だったら画像を一枚一枚丁寧に開いてチェックすると思います。
とはいえ、すべての画像を漏れなくチェックできているかは丁寧に作業したとしても不安はつきません!

今回使ったもの

今回はモデルに「gemini-1.0-pro-vision-001」を使いました。
Gemini Pro Visionはテキスト、画像、ビデオをインプットにできるマルチモーダルAIモデルです。
実行にはCloud Shellを利用しましたが、同様の環境が用意できるのであれば、Vertex AI Workbenchでも問題ありません。

  • Google Cloud Account:asia-northeast1 (東京)
  • 画像のスキャン:gemini-1.0-pro-vision-001
  • テキスト生成:text-bison@002
  • Python 3.9.2:3.9以上で実行しています
  • PNG形式の画像のみが保存されているCloud Storageのバケット

必要なPythonのパッケージ

  • google-cloud-storage 2.14.0
  • google-cloud-aiplatform 1.38.1

実行方法

Google Cloudのトップページを開きます。
ようこそ

Cloud Shellを開きます。

エディタを開きます。

Open Folderをクリックします。場所は/home/{ユーザ名}としました。※{ユーザ名}にはユーザ名が入ります。
今回の検証で使った環境では/home/ke-yamadaとなっています。

画面左側にあるExplorerからファイルを新規で作成します。名前はmain.pyとします。

以下のコードをmain.pyに貼り付けます。bucket_nameはスキャンしたいPNG形式の画像が保存されているバケット名を指定します。
project_idには現在開いているプロジェクトのIDを指定します。「プロジェクト名とプロジェクトIDとは何か」をについて知りたい場合はここを参照してください。

バケット名には「画像を保存したGCSのバケット名」を入れてください。

from google.cloud import storage
import vertexai
from vertexai.preview.generative_models import GenerativeModel, Part
from vertexai.preview.language_models import TextGenerationModel

project_id = "プロジェクトID"
bucket_name = "バケット名"


def generate(image: Part):
    vertexai.init(project=project_id, location="asia-northeast1")
    responses = GenerativeModel("gemini-1.0-pro-vision-001").generate_content(
        [image, """画像に含まれているテキストを抜き出してください。"""],
        generation_config={
            "max_output_tokens": 2048,
            "temperature": 0.4,
            "top_p": 1,
            "top_k": 32
        }
    )

    if responses.candidates:
        response_text = responses.candidates[0].text

        check_prompt = """
質問:以下の情報に含まれてはいけないテキストはありますか?回答は回答方法に従って答えてください。
{}
---
含まれてはいけないテキスト
- メールアドレス
- 会社と名のつくもの
- 個人を特定できる名前
- backlog
---
出力形式
「含まれている」または「含まれていない」のいずれかでお願いします。
含まれている場合は含まれているテキストを抜き出してください。
        """.format(response_text)
        generation_model = TextGenerationModel.from_pretrained(
            'text-bison@002')
        answer = generation_model.predict(
            check_prompt,
            temperature=0.2, max_output_tokens=1024,
            top_k=40, top_p=0.8).text

        print("Answer: ", answer)

    else:
        print("No response")


def list_blobs(bucket_name):
    client = storage.Client()
    bucket = client.bucket(bucket_name)
    blobs = client.list_blobs(bucket)
    return blobs


if __name__ == "__main__":

    for blob in list_blobs(bucket_name):
        print("---")
        gcs_file_name = f"gs://{bucket_name}/{blob.name}"
        print(gcs_file_name)
        generate(Part.from_uri(
            gcs_file_name, mime_type="image/png"))

ターミナルを開きます。

以下のコマンドを実行します。注意事項としてGCSに保存されている画像の数だけ実行されるため、実行回数と課金に気をつけてください。
なお、アカウントを作成したばかりの方にはクレジットが付与されていると思われるので実行内容に応じてクレジットが消費されます。

pyhton main.py

実行結果に期待していることと実行結果

今回作成したPythonスクリプトでは特定の情報(含まれてはいけないテキスト)が画像に含まれていると含まれている旨と含まれていたテキストを返します。
含まれてはいけないテキストとは以下に示した内容です。

  • メールアドレス
  • 会社と名のつくもの
  • 個人を特定できる名前
  • backlogという文字列

実際に実行してみたところ以下のようになりました。

想定した実行結果

check_gcs_info.png:何も検出されない
check_name_plate.png:私の名前とメールアドレスと社名
check_username1.png:名前
check_username2.png:名前
check_username3.png:私以外の名前とbacklogのURL
check_use_name_and_company_name.png:私の名前と社名

実行結果
check_gcs_info.png:何も検出されない
check_name_plate.png:私の名前とメールアドレスと社名
check_username1.png:名前
check_username2.png:名前、事業部名称
check_username3.png:私以外の名前とbacklogのURL
check_use_name_and_company_name.png何も検出されない

掲載しても良い画像になりますが、check_use_name_and_company_name.pngは以下の画像です。

引用元:Google Cloud Partner Tech Blog Challenge の 2023 年度受賞者発表

本来であれば、アイレット株式会社山田顕人という2つ情報を取得できていないとダメですが、今回の実行では画像から文字列が認識できませんでした。(複数回実行したら検出できたパターンもありました)

加えて、check_username2.pngにおいては名前だけの抽出で良いところを事業部名称まで取得しています。これも本来であれば、名前だけの取得で十分です。おそらく、事業部名称を会社名と誤認した可能性が考えられます。

また、レスポンスでは「含まれている」と「含まれていない」の2パターンの回答を期待しましたが
実際には「含まれている」、「含まれていない」、「含まれているテキストはありません」という3つの回答になり、ちょっとした表現の違いも見受けられました。白黒だけでなく、グレーゾーンみたいな判定もありそうです。

まとめ

今回はGemini Pro Visionによる画像スキャンを試してみました。
何度か実行してみましたが、プロンプトの良し悪しで文字列の検出率が大きく変わってきそうなところです。
プロンプトをしっかり書けば、事前チェックのAIとして一役買いそうです。

参考

gemini-sdk-overview-reference