[GAS Gemini API]#03 Gemini APIで画像認識をしてみよう

Gemini APIAI

どうも。Kenny(tsujikenzo)です。このシリーズでは、 「GASでGemini APIを使おう」 について、全3回でお送りします。

前回のおさらい

前回は、「Gemini APIを使う下準備」をお送りしました。

今回は最終回で、「Gemini APIで画像認識をしてみよう」をお届けします。本当に最終回かなぁ。(夢が膨らんでます)

全体の流れ

今回は、Gemini APIのVision(画像認識)というCapabilityを使って、「写真を与えると文字列を返す」というアプリを作成してみたいと思います。もちろんGoogle Apps Scriptです。

以下が、全体の流れです。

  1. Google Drive上に画像ファイルをアップロードする
  2. 画像タイプを確認する
  3. エンドポイントとメソッドを確認する(APIキーは取得済み)
  4. リクエストボディを作成する
  5. リクエストを送信する
  6. レスポンスを取得する

事前準備

Google Driveのお好きな場所に、フォルダを作成し、ネコちゃんなどの写真を入れておきます。向きは正常に回転しておきましょう。

この時、リンクを知ってる誰でも閲覧できるように、フォルダと写真の共有権限を与えておきましょう。 

そして、画像のファイルIDをメモしておきます。

ファイルIdは”  ”です。

画像のファイルIDは、リンクの共有や、新しいウィンドウで開いてから確認します。よく引っ掛かるポイントなので。 

画像は、PNGかJPEGかを確認しておきましょう。Visionは、以下の5種類をサポートしています。

  • PNG – image/png
  • JPEG – image/jpeg
  • WEBP – image/webp
  • HEIC – image/heic
  • HEIF – image/heif

エンドポイントは、引き続きgenerateContentと同様です。 https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent

メソッドは、POSTです。

Visionに必要な画像の下処理

Pythonなどでは、デスクトップに保存してある画像をVisionにアップしたりできます。しかしながらGASは、Google Driveのblobオブジェクトとして画像を操作します。

画像をblobオブジェクトに変換し、さらにbase64でエンコード(バイナリデータをテキストデータに変換する)して、送信します。

Geminiの公式サイトには、以下のように書かれています。

画像ペイロードの合計サイズが20MB未満の場合は、base64でエンコードされた画像をアップロードするか、ローカルに保存されている画像ファイルを直接アップロードすることをおすすめします。

実際のコードはこちらです。最後に全文表示しますので、ご安心ください。

// Google Drive から画像ファイルの Blob データを取得
const imageBlob = DriveApp.getFileById(fileId).getBlob();

// 画像データを Base64 エンコード
const imageData = Utilities.base64Encode(imageBlob.getBytes());

リクエストボディの作成

Visionにリクエストを送信するさいに、いちばん肝心なのが、リクエストボディです。

配列になっていたり、プロパティがたくさんあったり、リファレンスが無かったり大変ですが、とりあえず以下の構造をコピペで大丈夫です。

コード内のtextプロパティには、プロンプトを入力します。ChatGPTなどでおなじみなので、みなさんの方が得意かもしれません。

mine_typeも間違えないように入力しましょう。本来なら画像を自動で判定して変数にもたせたりできるのですが。

 // リクエストボディを設定
  const payload = {
    "contents": [
      {
        "parts": [
          { "text": "画像に映っているものを日本語で完結に教えてください" },
          {
            "inline_data": {
              "mime_type": "image/jpeg", // 画像の MIME タイプを適切に設定してください
              "data": imageData
            }
          }
        ]
      }
    ]
  };

リクエストを送信する

リクエストを送信するのは、UrlFetchApp.fetch()メソッドです。

リクエストが成功すると、レスポンスが返ってきますので、responseという変数に格納しましょう。

// リクエストオプションを設定
  const options = {
    "method": "post",
    "headers": headers,
    "payload": JSON.stringify(payload)
  };

// HTTP リクエストを送信
 const response = UrlFetchApp.fetch(url, options);

レスポンスの中身を確認する

レスポンスの中身がどうなっているのか、リファレンスが見当たらなくて苦労しましたが、どうやらこのようなJSONになっているようです。

{ candidates: 
   [ { content: [Object],
       finishReason: 'STOP',
       avgLogprobs: -0.15607019454713852 } ],
  usageMetadata: 
   { promptTokenCount: 263,
     candidatesTokenCount: 63,
     totalTokenCount: 326 },
  modelVersion: 'gemini-1.5-flash' }

いちばん重要なデータは、content: [Object]に入っているようです。

なので、JSON.parse()メソッドでオブジェクトに変換してから、目的地までアクセスしていきます。

 // レスポンスを JSON 形式に変換
 const json = JSON.parse(response.getContentText());

 // 画像に関する情報を取得
 const information = json.candidates[0].content.parts[0].text;

ソースコード全文

という流れですが、全文はコチラです。

うまくいかないばあいは、例外処理も書いていますので、どんなエラーがでるか確認しましょう。

/**
 * Gemini APIのVision Capabilities を使用して、
 * Google Drive上の画像ファイルに関する情報を取得する関数
 *
 * @return {string} 画像に関する情報
 */
function generateImageCaption() {

  // API キーを設定
  const apiKey = "あなたのAPIキー";

    //ファイルIDを指定
  const fileId = "Google Drive上のファイルID";

  // リクエスト URL を設定
  const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=${apiKey}`;

  // リクエストヘッダーを設定
  const headers = {
    'Content-Type': 'application/json'
  };

  // Google Drive から画像ファイルの Blob データを取得
  const imageBlob = DriveApp.getFileById(fileId).getBlob();

  // 画像データを Base64 エンコード
  const imageData = Utilities.base64Encode(imageBlob.getBytes());

  // リクエストボディを設定
  const payload = {
    "contents": [
      {
        "parts": [
          { "text": "画像に映っているものを日本語で完結に教えてください" },
          {
            "inline_data": {
              "mime_type": "image/jpeg", // 画像のMIME タイプを適切に設定してください
              "data": imageData
            }
          }
        ]
      }
    ]
  };

  // リクエストオプションを設定
  const options = {
    "method": "post",
    "headers": headers,
    "payload": JSON.stringify(payload)
  };

  // HTTP リクエストを送信
  try {
    const response = UrlFetchApp.fetch(url, options);

    // レスポンスを JSON 形式に変換
    const json = JSON.parse(response.getContentText());

    // 画像に関する情報を取得
    const information = json.candidates[0].content.parts[0].text; 

    // 画像に関する情報を返す
   console.log(information)
   console.log(JSON.stringify(json.candidates[0].content))

    return information;
  } catch (error) {
    // エラーハンドリング
    console.error('Gemini API リクエストエラー:', error);
    return "画像情報の取得に失敗しました。";
  }
}

実行してみると、画像解析結果を返していると思います。(ちょっぴり感動します) 

番外編(OCRもすごい)

なにがすごいって、OCR(文字認識)です。わたしはGoogle DriveのOCRは精度がいまいちなので使っていませんでした。

でも、これならバッチリですね。 

恐るべしマルチモーダルAIです。 

今後は、社内の経費レシートや請求書などをスキャンしたばあいは、PDFではなく、画像で保存していく流れだと思います。

まとめ

以上で、「Gemini APIで画像認識をしてみよう」をお送りしました。

これができるようになるということは・・・、あんなことやこんなこと、社内でアイディア出しをしてもいいですね。

わたしは、市場で見つけた海産物の写真をスマホからGoogle Driveにアップしたら見積もりを作成するアプリでも作ろうかしら。

ワクワクですね。最終回でした。

このシリーズの目次

タイトルとURLをコピーしました