マルチモーダル リクエストにサイズの大きいファイルを含め、Cloud Storage for Firebase を使用してファイルを管理する

Vertex AI Gemini API を API プロバイダとして使用している場合にのみ使用できます。

Firebase AI Logic SDK を使用してアプリから Vertex AI Gemini API を呼び出すと、画像、PDF、動画、音声などのマルチモーダル入力に基づいてテキストを生成するよう Gemini モデルにプロンプトを表示できます。

入力のテキスト以外の部分(メディア ファイルなど)については、必要に応じて Cloud Storage for Firebase を使用してリクエストにファイルを含めることができます。この機能について知っておくべきことは次のとおりです。

  • Vertex AI Gemini API を使用している場合は、マルチモーダル リクエスト(テキスト生成とチャットの両方など)で Cloud Storage for Firebase を使用できます。このガイドのでは、テキストと画像の基本的な入力方法を示しています。

  • リクエスト入力で、ファイルの MIME タイプと Cloud Storage for Firebase URL(常に gs:// で始まる)を指定します。これらの値は、Cloud Storage バケットにアップロードされたファイルに自動的に割り当てられるメタデータです。

  • サポートされているファイル形式と URL を使用する必要があります。


このソリューション ガイドでは、Cloud Storage for Firebase を設定し、アプリから Cloud Storage for Firebase バケットにファイルをアップロードしてから、Gemini API へのマルチモーダル リクエストにファイルの MIME タイプと Cloud Storage for Firebase URL を含める方法について説明します。

コード例を確認しますか?または、Cloud Storage for Firebase をすでに設定していて、マルチモーダル リクエストで使用する準備ができている場合。

コード例に移動

アプリで Cloud Storage for Firebase を使用する理由

Cloud Storage for Firebase は、Google Cloud Storage と同じ高速で安全かつスケーラブルなインフラストラクチャを使用して BLOB とファイルを保存し、クライアント SDK はモバイルアプリとウェブアプリ専用に構築されています。

Firebase AI Logic SDK の場合、リクエストの最大サイズは 20 MB です。リクエストが大きすぎると、HTTP 413 エラーが発生します。ファイルのサイズによってリクエストの合計サイズが 20 MB を超える場合は、Cloud Storage for Firebase URL を使用して、マルチモーダル リクエストにファイルを含めます。ただし、ファイルが小さい場合は、インライン データとして直接渡すことができます(ただし、インライン データとして提供されたファイルは転送中に base64 にエンコードされるため、リクエストのサイズが大きくなります)。

Cloud Storage for Firebase を使用するその他のメリットは次のとおりです。

  • エンドユーザーがアプリから Cloud Storage for Firebase バケットに画像を直接アップロードできるようにし、ファイルの MIME タイプと Cloud Storage for Firebase URL(ファイルの識別子)を指定するだけで、それらの画像をマルチモーダル プロンプトに含めることができます。

  • エンドユーザーが画像を送信する必要がある場合、特にネットワーク品質が低い場合や不安定な場合は、エンドユーザーの時間と帯域幅を節約できます。

    • ファイルのアップロードまたはダウンロードが中断された場合、Cloud Storage for Firebase SDK は中断した場所からオペレーションを自動的に再開します。
    • アップロードされた同じファイルは、エンドユーザーがアプリで必要なたびに(新しいマルチモーダル リクエストなど)同じファイルをアップロードしなくても、複数回使用できます。
  • Firebase Security Rules を使用すると、Cloud Storage for Firebase に保存されているファイルへのエンドユーザーのアクセスを制限できます。これにより、承認されたユーザーのみがファイルのアップロード、ダウンロード、削除を行えるようになります。

  • バケット内のファイルには Firebase または Google Cloud からアクセスできます。これにより、Google Cloud Storage API を使用して、画像のフィルタリングや動画のコード変換といったサーバー側の処理を柔軟に行うことができます。

サポートされているファイルと URL の種類

Firebase AI Logic SDK で Cloud Storage for Firebase URL を使用する場合のファイルと URL の要件は次のとおりです。

  • ファイルは、マルチモーダル リクエストの入力ファイルの要件を満たしている必要があります。これには、MIME タイプやファイルサイズなどの要件が含まれます。

  • ファイルは Cloud Storage for Firebase バケットに保存する必要があります(つまり、バケットは Firebase Security Rules などの Firebase サービスからアクセスできます)。Firebase コンソールでバケットを表示できる場合は、Cloud Storage for Firebase バケットです。

  • Cloud Storage for Firebase バケットは、アプリを登録した Firebase プロジェクトと同じ Firebase プロジェクトに存在する必要があります。

  • ファイルの Cloud Storage for Firebase URL は、すべての Google Cloud Storage URL の構築方法である gs:// で始まる必要があります。

  • ファイルの URL は「ブラウザ」の URL(インターネットで見つけた画像の URL など)にすることはできません。

また、バケットの Firebase Security Rules で、ファイルへの適切なアクセスが許可されている必要があります。例:

  • 公開ルールがある場合、すべてのユーザーまたはクライアントがファイルにアクセスできます。

  • 堅牢なルール (強く推奨)がある場合、Firebase は、ログインしているユーザーまたはクライアントがファイルに十分なアクセス権を持っていることを確認してから、提供された URL で呼び出しを許可します。

Firebase AI LogicCloud Storage for Firebase URL を使用する

Vertex AI Gemini API を API プロバイダとして使用している場合にのみ使用できます。

ステップ 1: Cloud Storage for Firebase を設定する

Cloud Storage for Firebase の設定に関する詳細な手順については、スタートガイド(iOS+ | Android | ウェブ | Flutter | Unity)をご覧ください。

必要な大まかなタスクは次のとおりです。

  1. Firebase プロジェクトで Cloud Storage for Firebase バケットを作成またはインポートします。

  2. このバケットに Firebase Security Rules を適用します。Rules を使用すると、承認されたエンドユーザーへのアクセスを制限することで、ファイルを保護できます。

  3. アプリに Cloud Storage for Firebase のクライアント ライブラリを追加します。

    このタスクはスキップできますが、その場合は、リクエストに MIME タイプと URL の値を常に明示的に含める必要があります。

ステップ 2: バケットにファイルをアップロードする

Cloud Storage のドキュメントでは、バケットにファイルをアップロードするさまざまな方法について説明しています。たとえば、エンドユーザーのデバイスから、カメラの写真や動画などのローカル ファイルをアップロードできます。詳細: iOS+ | Android | ウェブ | Flutter | Unity

ファイルをバケットにアップロードすると、Cloud Storage は次の 2 つの情報をファイルに自動的に適用します。これらの値はリクエストに含める必要があります(このガイドの次のステップを参照)。

  • MIME タイプ: ファイルのメディアタイプ(image/png など)。アップロード中に MIME タイプの自動検出が試行され、そのメタデータがバケット内のオブジェクトに適用されます。ただし、アップロード時に MIME タイプを任意で指定できます。

  • Cloud Storage for Firebase URL: ファイルの固有識別子です。先頭は gs:// でなければなりません。

ステップ 3: ファイルの MIME タイプと URL をマルチモーダル リクエストに含める

バケットにファイルを保存したら、リクエストに MIME タイプと URL を含めることができます。これらの例はストリーミング以外の generateContent リクエストを示していますが、ストリーミングとチャットを含む URL を使用することもできます。

リクエストにファイルを含めるには、次のいずれかの方法を使用します。

オプション 1: ストレージ参照を使用して MIME タイプと URL を含める

この例を試す前に、Firebase AI Logic SDK のスタートガイドの手順を完了していることを確認してください。

このオプションは、ファイルをバケットにアップロードした直後に、リクエストにファイル(ストレージ参照経由)をすぐに含める場合に使用します。この呼び出しには、MIME タイプと Cloud Storage for Firebase URL の両方が必要です。

Swift

// Upload an image file using Cloud Storage for Firebase.
let storageRef = Storage.storage().reference(withPath: "images/image.jpg")
guard let imageURL = Bundle.main.url(forResource: "image", withExtension: "jpg") else {
  fatalError("File 'image.jpg' not found in main bundle.")
}
let metadata = try await storageRef.putFileAsync(from: imageURL)

// Get the MIME type and Cloud Storage for Firebase URL.
guard let mimeType = metadata.contentType else {
  fatalError("The MIME type of the uploaded image is nil.")
}
// Construct a URL in the required format.
let storageURL = "gs://\(storageRef.bucket)/\(storageRef.fullPath)"

let prompt = "What's in this picture?"
// Construct the imagePart with the MIME type and the URL.
let imagePart = FileDataPart(uri: storageURL, mimeType: mimeType)

// To generate text output, call generateContent with the prompt and the imagePart.
let result = try await model.generateContent(prompt, imagePart)
if let text = result.text {
  print(text)
}

Kotlin

Kotlin の場合、この SDK のメソッドは suspend 関数であり、コルーチンスコープから呼び出す必要があります。
// Upload an image file using Cloud Storage for Firebase.
val storageRef = Firebase.storage.reference.child("images/image.jpg")
val fileUri = Uri.fromFile(File("image.jpg"))
try {
    val taskSnapshot = storageRef.putFile(fileUri).await()
    // Get the MIME type and Cloud Storage for Firebase file path.
    val mimeType = taskSnapshot.metadata?.contentType
    val bucket = taskSnapshot.metadata?.bucket
    val filePath = taskSnapshot.metadata?.path

    if (mimeType != null && bucket != null) {
        // Construct a URL in the required format.
        val storageUrl = "gs://$bucket/$filePath"
        // Construct a prompt that includes text, the MIME type, and the URL.
        val prompt = content {
            fileData(mimeType = mimeType, uri = storageUrl)
            text("What's in this picture?")
        }
        // To generate text output, call generateContent with the prompt.
        val response = generativeModel.generateContent(prompt)
        println(response.text)
    }
} catch (e: StorageException) {
    // An error occurred while uploading the file.
} catch (e: GoogleGenerativeAIException) {
    // An error occurred while generating text.
}

Java

Java の場合、この SDK のメソッドは ListenableFuture を返します。
// Upload an image file using Cloud Storage for Firebase.
StorageReference storage = FirebaseStorage.getInstance().getReference("images/image.jpg");
Uri fileUri = Uri.fromFile(new File("images/image.jpg"));

storage.putFile(fileUri).addOnSuccessListener(taskSnapshot -> {
    // Get the MIME type and Cloud Storage for Firebase file path.
    String mimeType = taskSnapshot.getMetadata().getContentType();
    String bucket = taskSnapshot.getMetadata().getBucket();
    String filePath = taskSnapshot.getMetadata().getPath();

    if (mimeType != null && bucket != null) {
        // Construct a URL in the required format.
        String storageUrl = "gs://" + bucket + "/" + filePath;
        // Create a prompt that includes text, the MIME type, and the URL.
        Content prompt = new Content.Builder()
                .addFileData(storageUrl, mimeType)
                .addText("What's in this picture?")
                .build();

        // To generate text output, call generateContent with the prompt.
        GenerativeModelFutures modelFutures = GenerativeModelFutures.from(model);
        ListenableFuture<GenerateContentResponse> response = modelFutures.generateContent(prompt);
        Futures.addCallback(response, new FutureCallback<>() {
            @Override
            public void onSuccess(GenerateContentResponse result) {
                String resultText = result.getText();
                System.out.println(resultText);
            }

            @Override
            public void onFailure(@NonNull Throwable t) {
                t.printStackTrace();
            }
        }, executor);
    }
}).addOnFailureListener(e -> {
    // An error occurred while uploading the file.
    e.printStackTrace();
});

Web

// Upload an image file using Cloud Storage for Firebase.
const storageRef = ref(storage, "image.jpg");
const uploadResult = await uploadBytes(storageRef, file);

// Get the MIME type and Cloud Storage for Firebase URL.
// toString() is the simplest way to construct the Cloud Storage for Firebase URL
// in the required format.
const mimeType = uploadResult.metadata.contentType;
const storageUrl = uploadResult.ref.toString();

// Construct the imagePart with the MIME type and the URL.
const imagePart = { fileData: { mimeType, fileUri: storageUrl }};

// To generate text output, call generateContent with the prompt and imagePart.
const result = await model.generateContent([prompt, imagePart]);
console.log(result.response.text());

Dart

// Upload an image file using Cloud Storage for Firebase.
final storageRef = FirebaseStorage.instance.ref();
final imageRef = storageRef.child("images/image.jpg");
await imageRef.putData(data);

// Get the MIME type and Cloud Storage for Firebase file path.
final metadata = await imageRef.getMetadata();
final mimeType = metadata.contentType;
final bucket = imageRef.bucket;
final fullPath = imageRef.fullPath;

final prompt = TextPart("What's in the picture?");
// Construct a URL in the required format.
final storageUrl = 'gs://$bucket/$fullPath';
// Construct the filePart with the MIME type and the URL.
final filePart = FileData(mimeType, storageUrl);
// To generate text output, call generateContent with the text and the filePart.
final response = await model.generateContent([
  Content.multi([prompt, filePart])
]);
print(response.text);

Unity

var storageRef = FirebaseStorage.DefaultInstance.GetReference("images/image.jpg");
var metadata = await storageRef.PutFileAsync(filePathToJpg);

// Get the MIME type and Cloud Storage for Firebase URL.
var mimeType = metadata.ContentType;
// Construct a URL in the required format.
var storageURL = new Uri($"gs://{storageRef.Bucket}/{storageRef.Path}");

var prompt = ModelContent.Text("What's in this picture?");
// Construct a FileData that explicitly includes the MIME type and
// Cloud Storage for Firebase URL values.
var fileData = ModelContent.FileData(mimeType, storageURL);

// To generate text output, call GenerateContentAsync with the prompt and fileData.
var response = await model.GenerateContentAsync(new [] { prompt, fileData });
UnityEngine.Debug.Log(response.Text ?? "No text in response.");

オプション 2: MIME タイプと URL を明示的に含める

この例を試す前に、Firebase AI Logic SDK のスタートガイドの手順を完了していることを確認してください。

MIME タイプと Cloud Storage for Firebase URL の値がわかっていて、マルチモーダル リクエストに明示的に含める場合は、このオプションを使用します。この呼び出しには、MIME タイプと URL の両方が必要です。

Swift

let prompt = "What's in this picture?"
// Construct an imagePart that explicitly includes the MIME type and
// Cloud Storage for Firebase URL values.
let imagePart = FileDataPart(uri: "gs://bucket-name/path/image.jpg", mimeType: "image/jpeg")

// To generate text output, call generateContent with the prompt and imagePart.
let result = try await model.generateContent(prompt, imagePart)
if let text = result.text {
  print(text)
}

Kotlin

Kotlin の場合、この SDK のメソッドは suspend 関数であり、コルーチンスコープから呼び出す必要があります。
// Construct a prompt that explicitly includes the MIME type and Cloud Storage for Firebase URL values.
val prompt = content {
    fileData(mimeType = "image/jpeg", uri = "gs://bucket-name/path/image.jpg")
    text("What's in this picture?")
}
// To generate text output, call generateContent with the prompt.
val response = generativeModel.generateContent(prompt)
println(response.text)

Java

Java の場合、この SDK のメソッドは ListenableFuture を返します。
// Construct a prompt that explicitly includes the MIME type and Cloud Storage for Firebase URL values.
Content prompt = new Content.Builder()
        .addFilePart("gs://bucket-name/path/image.jpg", "image/jpeg")
        .addText("What's in this picture?")
        .build();

// To generate text output, call generateContent with the prompt
GenerativeModelFutures modelFutures = GenerativeModelFutures.from(model);
ListenableFuture<GenerateContentResponse> response = modelFutures.generateContent(prompt);
Futures.addCallback(response, new FutureCallback<>() {
    @Override
    public void onSuccess(GenerateContentResponse result) {
        String resultText = result.getText();
        System.out.println(resultText);
    }

    @Override
    public void onFailure(@NonNull Throwable t) {
        t.printStackTrace();
    }
}, executor);

Web

const prompt = "What's in this picture?";
// Construct an imagePart that explicitly includes the MIME type and Cloud Storage for Firebase URL values.
const imagePart = { fileData: { mimeType: "image/jpeg", fileUri: "gs://bucket-name/path/image.jpg" }};

// To generate text output, call generateContent with the prompt and imagePart.
const result = await model.generateContent([prompt, imagePart]);
console.log(result.response.text());

Dart

final prompt = TextPart("What's in the picture?");
// Construct a filePart that explicitly includes the MIME type and Cloud Storage for Firebase URL values.
final filePart = FileData('image/jpeg', 'gs://bucket-name/path/image.jpg'),
// To generate text output, call generateContent with the prompt and filePart.
final response = await model.generateContent([
  Content.multi([prompt, filePart])
]);
print(response.text);

Unity

var prompt = ModelContent.Text("What's in this picture?");
// Construct a FileData that explicitly includes the MIME type and
// Cloud Storage for Firebase URL values.
var fileData = ModelContent.FileData(
  mimeType: "image/jpeg",
  uri: new Uri("gs://bucket-name/path/image.jpg")
);

// To generate text output, call GenerateContentAsync with the prompt and fileData.
var response = await model.GenerateContentAsync(new [] { prompt, fileData });
UnityEngine.Debug.Log(response.Text ?? "No text in response.");