🦉

Cloud Storageへの画像アップロードをトリガーに生成AI(Gemini)を動かしたい

2025/01/03に公開

はじめに(簡単に自己紹介)

こんにちは。ラムネと申します。
私は地方でエンジニアをしています。勤務先の企業がGoogle Cloudのパートナーとなり、それに伴い、私自身もGoogle Cloudの勉強を頑張っている最中です。
いくつか資格も取得しましたが、業務への活用のためには、次のステップとして、具体的な構築手順&設定を実践してみることが大切だなと感じています。

そこで、座学から業務活用へステップアップするためにGoogle Cloudに関連するトピックについて実際に手を動かして学んでみたいというコンセプトで記事を投稿していきたいと思います。
(アプトプットの機会も少ないため、Zennを活用してみたいと思います。)

やりたいこと

今回はCloud Storageに画像をアップロードしたタイミングで、生成AIを呼び出して、アップロードした画像に何が描かれているのかを説明してもらうような機能を作成してみたいと思います。

構成と簡単なフローは以下のようになるかと思います。

今回は、①画像をアップロードは手動で行うものとして、②、③、④、⑤について作成していきます。

ポイントになる部分を簡単にご紹介

上記の機能を作成するにあたり、ポイントになる部分が2点ほどあるので、先にご紹介します。

1. Cloud Storage トリガー

上記フロー図の②に相当する部分です。
Cloud Storage トリガーは、Cloud Storageの内容変更に応じて、Cloud Functions (Cloud Run functions)の関数を呼び出すことができる機能になっています。

Cloud Storageのイベント(オブジェクトの作成/更新/削除など)に応じて設定した関数を起動することができます。

詳しくはこちらをご確認ください。
https://cloud.google.com/functions/docs/calling/storage?hl=ja

2. Vertex AI API for Gemini

上記フローの③、④に相当する部分です。
プログラミング言語SDK(今回はPython)を使用してVertex AIのGemini APIにリクエストを送信、回答を取得することができます。

こちらをCloud Functionsの関数内で使用することで、Geminiにプロンプトを送信&回答を取得することができます。
https://cloud.google.com/vertex-ai/generative-ai/docs/start/quickstarts/quickstart-multimodal?hl=ja

ここまで、ポイントとなる機能を説明ベースでご紹介しました。

実践編

それでは、実際に作成してみましょう。

Cloud Storageの作成

まず画像をアップロードする入り口となる部分のCloud Storageを作成します。

コンソール上で「Cloud Storage」を選択し、「バケットを作成」から以下の設定でバケットを作成します。

項目 設定値(例)
バケット名 任意 (gcs-trigger-demo)
ロケーションタイプ Region
ロケーション asia-northeast1

※その他の設定はデフォルトでOKです。
※バケット名は世界で一意である必要があります。任意で命名してください。

Cloud Functionsの作成

次にCloud Functionsの設定(トリガーの設定)を行います。

コンソール上で「Cloud Run」を選択し、上部の「関数を作成」をクリックします。

構成の設定は以下のようにします。

項目 設定値(例)
サービス名 任意 (describe-image-with-gemini)
リージョン asia-northeast1
ランタイム Python 3.12

構成の下の「トリガーを追加」> 「Cloud Storage トリガー」を選択します。

Eventarcトリガーの設定を以下のように設定します。

項目 設定値(例)
トリガーの名前 任意(変更なしでOK)
トリガーのタイプ Googleのソース
イベントプロバイダ Cloud Storage
イベントタイプ google.cloud.storage.object.v1.finalized
イベントデータのコンテンツタイプ application/json
バケット 作成したCloud Storageのバケット名
サービスアカウント Default compute service account
サービスURLパス /

ここまで設定したら「トリガーを保存」をクリックします。
残りの設定についても、続けて設定します。

項目 設定値(例)
認証 認証が必要
課金 リクエストベース
Ingress 内部
サービスアカウント Default compute service account

※その他の設定はデフォルトでOKです。
※サービスアカウントは、「セキュリティ」タブから設定します。

ここまで設定したら「作成」をクリックします。

Cloud Functions内のソースコード

作成すると、次のような画面に遷移すると思います。

Cloud Functionsでは、コンソール内部のテキストエディタで簡単にコードを編集&デプロイできることも特徴になっています。Cloud Storage トリガーを設定すると、サンプルコードが初期表示されます。

まずはこのままのコードをデプロイしてみましょう。
「保存して再デプロイ」をクリックします。上部のサービス名が✅になれば成功です。

一旦、動作チェック

ここまで設定できたら、一度動作チェックをしてみましょう。
Cloud Storageから適当なファイルをアップロードします。

コンソール上で「Cloud Storage」から、先ほど作成したバケットを選択します。「アップロード」から適当なファイルをアップロードします。

アップロードしたら、Cloud Runのログを確認し、アップロードされたファイル情報を確認してみます。

コンソール上で「Cloud Run」から、先ほど作成したサービスを選択します。
「ログ」タブから最近のエントリを確認します。

✅上記のコードでprint()した項目がログ出力されていることがわかります。
✅私の場合は、「gcs-trigger-demo」バケットに「example.txt」ファイルをアップロードしました。(以下のログ出力でも合っています。)

Gemini APIとの連携

ここまで、画像アップロードを検知して、バケット名とファイル名を取得することができました。
ここからは、プロンプト+画像をGeminiにリクエストする部分を作成します。

コンソール上で「Cloud Run」から、先ほど作成したサービスを選択します。
「ソース」タブを開きます。

「ソースを編集」をクリックして、以下のコードを貼り付けます。

main.py
import functions_framework
import vertexai
from vertexai.generative_models import GenerativeModel, Part

# Triggered by a change in a storage bucket
@functions_framework.cloud_event
def main(cloud_event):
    # Cloud Storageのアップロードトリガー情報を取得
    data = cloud_event.data

    # アップロード画像が格納されているバケット名とオブジェクト名を取得
    bucket_name = data["bucket"]
    object_name = data["name"]

    # Geminiへリクエスト
    prompt_text = "添付した画像に描かれている内容を教えてください。"
    gcs_uri = "gs://"+ bucket_name + "/" + object_name
    # TODO: mime_typeに自身のアップロードする画像の拡張子を設定
    mime_type = "image/png"
    response_text = describe_image_with_gemini(prompt_text, gcs_uri, mime_type)

    # 結果の出力
    print("Response by Gemini:")
    print(response_text)
    
def describe_image_with_gemini(prompt_text, gcs_uri, mime_type):
    # TODO:projectに自身のプロジェクトIDを入力
    vertexai.init(project="YOUR_PROJECT_ID", location="asia-northeast1")
    model = GenerativeModel("gemini-1.5-flash-002")
    response = model.generate_content(
        [
            Part.from_uri(gcs_uri, mime_type=mime_type),
            prompt_text,
        ]
    )
    return response.text

requirements.txt
functions-framework==3.*
vertexai

変更したら、「保存して再デプロイ」をクリックします。
ここまでで作成完了です。

動作チェック

最後に、画像をアップロードして、Geminiに解説してもらいましょう。
Cloud Storageに以下の画像をアップロードしてみます。

以前に動物園で撮影したフクロウの画像です。
アップロードしたら、先ほどと同じ手順でCloud Runのログを確認してみましょう。

Geminiの回答を見ると、フクロウの画像だと認識してくれました。
足に青いタグが付いているなど、細かい部分も説明してくれています。

皆さんの試した画像はいかがでしょうか。

Discussion