在多模態要求中包含大型檔案,並使用 Cloud Storage for Firebase 管理檔案

只有在 Vertex AI Gemini API 是 API 供應商時,才能使用這項功能。

使用 Firebase AI Logic SDK 從應用程式呼叫 Vertex AI Gemini API 時,您可以提示 Gemini 模型根據多模態輸入內容 (例如圖片、PDF、影片和音訊) 生成文字。

如要為輸入內容的非文字部分 (例如媒體檔案) 加上註解,可以視需要使用 Cloud Storage for Firebase 在要求中加入檔案。以下是這項功能的高階須知:

  • 如果您使用 Vertex AI Gemini API,可以搭配任何多模態要求 (例如文字生成和對話)。Cloud Storage for Firebase本指南中的範例會顯示基本的文字和圖片輸入內容。

  • 您可以在要求輸入內容中,指定檔案的 MIME 類型和 Cloud Storage for Firebase 網址 (一律以 gs:// 開頭)。這些值是系統自動指派給上傳至 Cloud Storage bucket 的任何檔案的中繼資料。

  • 你必須使用支援的檔案類型和網址


本解決方案指南說明如何設定 Cloud Storage for Firebase、從應用程式將檔案上傳至 Cloud Storage for Firebase 值區,然後在傳送至 Gemini API 的多模態要求中加入檔案的 MIME 類型和 Cloud Storage for Firebase 網址。

要查看程式碼範例嗎?或者,您是否已設定 Cloud Storage for Firebase,並準備好開始搭配多模態要求使用?

直接查看程式碼範例

為什麼要在應用程式中使用 Cloud Storage for Firebase

Cloud Storage for FirebaseGoogle Cloud Storage 使用相同的快速、安全且可擴充基礎架構來儲存 Blob 和檔案,且 用戶端 SDK 專為行動和網路應用程式建構。

Firebase AI Logic SDK 的要求大小上限為 20 MB。 如果要求過大,系統會傳回 HTTP 413 錯誤。如果檔案大小會導致要求總大小超過 20 MB,請使用 Cloud Storage for Firebase 網址將檔案納入多模態要求。 不過,如果檔案很小,通常可以直接以內嵌資料的形式傳遞 (請注意,以內嵌資料形式提供的檔案在傳輸過程中會編碼為 base64,這會增加要求的大小)。

使用 Cloud Storage for Firebase 的其他好處:

  • 您可以讓使用者直接從應用程式將圖片上傳至 Cloud Storage for Firebase bucket,然後只要指定檔案的 MIME 類型和 Cloud Storage for Firebase 網址 (檔案的 ID),即可在多模態提示中加入這些圖片。

  • 如果使用者需要提供圖片,這項功能可節省他們的時間和頻寬, 特別是網路品質不佳或不穩定的使用者。

    • 如果檔案上傳或下載作業中斷,Cloud Storage for Firebase SDK 會自動從中斷處重新開始作業。
    • 使用者不必在應用程式中每次需要時都上傳相同檔案 (例如在新的多模態要求中),即可多次使用同一個上傳檔案。
  • 您可以透過 Firebase Security Rules 限制使用者存取 Cloud Storage for Firebase 中儲存的檔案,只允許授權使用者上傳、下載或刪除檔案。

  • 您可以從 Firebase 或 Google Cloud存取 bucket 中的檔案,彈性地執行伺服器端處理作業,例如使用 Google Cloud Storage API 篩選圖片或轉碼影片。

系統支援哪些類型的檔案和網址?

如要使用 Firebase AI Logic SDK 搭配網址,檔案和網址必須符合下列規定:Cloud Storage for Firebase

  • 檔案必須符合多模態要求輸入檔案的規定。包括 MIME 類型和檔案大小等規定。

  • 檔案必須儲存在 Cloud Storage for Firebase 值區中 (也就是 Firebase 服務 (例如 Firebase Security Rules) 可存取的值區)。如果可以在 Firebase 控制台中查看值區,則該值區為 Cloud Storage for Firebase 值區。

  • Cloud Storage for Firebase 值區必須位於您註冊應用程式的 Firebase 專案中。

  • 檔案的 Cloud Storage for Firebase 網址開頭必須是 gs://,這是所有 Google Cloud Storage 網址的建構方式。

  • 檔案網址不得為「瀏覽器」網址 (例如你在網路上找到的圖片網址)。

此外,值區的 Firebase Security Rules 必須允許適當的檔案存取權。例如:

  • 如果您有公開規則任何使用者或用戶端都能存取檔案。

  • 如果您有嚴格的規則 (強烈建議),Firebase 會先檢查登入的使用者或用戶端是否有足夠的檔案存取權,然後才會允許透過提供的網址進行呼叫。

搭配 Firebase AI Logic 使用 Cloud Storage for Firebase 網址

只有在 Vertex AI Gemini API 是 API 供應商時,才能使用這項功能。

步驟 1:設定 Cloud Storage for Firebase

如需設定 Cloud Storage for Firebase 的詳細操作說明,請參閱入門指南: iOS+ | Android | Web | Flutter | Unity

您需要完成的高階工作如下:

  1. 在 Firebase 專案中建立或匯入 Cloud Storage for Firebase bucket。

  2. Firebase Security Rules 套用至這個值區。Rules 限制只有獲得授權的使用者才能存取檔案,確保檔案安全無虞。

  3. Cloud Storage for Firebase 的用戶端程式庫新增至應用程式。

    請注意,您可以略過這項工作,但之後一律 必須在要求中明確加入 MIME 類型和網址值

步驟 2:將檔案上傳至 bucket

Cloud Storage 說明文件中,您可以瞭解將檔案上傳至值區的所有不同方式。舉例來說,您可以上傳使用者裝置上的本機檔案,例如相機中的相片和影片。瞭解詳情: iOS+ | Android | 網站 | Flutter | Unity

將檔案上傳至值區時,Cloud Storage 會自動將下列兩項資訊套用至檔案。您必須在要求中加入這些值 (如本指南的下一個步驟所示)。

  • MIME 類型:這是檔案的媒體類型 (例如 image/png)。 上傳期間,我們會自動偵測 MIME 類型,並將該中繼資料套用至 bucket 中的物件。不過,您可以在上傳時選擇指定 MIME 類型。

  • Cloud Storage for Firebase 網址:這是檔案的專屬 ID。 網址開頭必須是 gs://

步驟 3:在多模態要求中加入檔案的 MIME 類型和網址

將檔案儲存在值區後,您可以在要求中加入檔案的 MIME 類型和網址。請注意,這些範例顯示非串流 generateContent 要求,但您也可以使用含串流和即時通訊的網址。

如要在要求中加入檔案,請使用下列任一選項:

方法 1:使用 Storage 參照納入 MIME 類型和網址

嘗試這個範例之前,請確認您已完成 Firebase AI Logic SDK 的入門指南

如果您剛將檔案上傳至值區,並想立即在要求中加入檔案 (透過 Storage 參照),請使用這個選項。呼叫需要 MIME 類型和 Cloud Storage for Firebase 網址。

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 中的方法是暫停函式,需要從 Coroutine 範圍呼叫。
// 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 類型和網址

嘗試這個範例之前,請確認您已完成 Firebase AI Logic SDK 的入門指南

如果您知道 MIME 類型和 Cloud Storage for Firebase URL 的值,且想在多模態要求中明確加入這些值,請使用這個選項。這項呼叫需要 MIME 類型和網址。

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 中的方法是暫停函式,需要從 Coroutine 範圍呼叫。
// 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.");