どうも。Kenny(tsujikenzo)です。このシリーズでは、 「GASでGemini APIを使おう」 について、全3回でお送りします。
前回のおさらい
前回は、「Gemini APIを使う下準備」をお送りしました。
今回は最終回で、「Gemini APIで画像認識をしてみよう」をお届けします。本当に最終回かなぁ。(夢が膨らんでます)
全体の流れ
今回は、Gemini APIのVision(画像認識)というCapabilityを使って、「写真を与えると文字列を返す」というアプリを作成してみたいと思います。もちろんGoogle Apps Scriptです。
以下が、全体の流れです。
- Google Drive上に画像ファイルをアップロードする
- 画像タイプを確認する
- エンドポイントとメソッドを確認する(APIキーは取得済み)
- リクエストボディを作成する
- リクエストを送信する
- レスポンスを取得する
事前準備
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にアップしたら見積もりを作成するアプリでも作ろうかしら。
ワクワクですね。最終回でした。