diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index 967614f0855..6d507598aa8 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -56,10 +56,6 @@ jobs: distribution: temurin cache: gradle - - name: Clone vertexai mock responses - if: matrix.module == ':firebase-vertexai' - run: firebase-vertexai/update_responses.sh - - name: Clone ai mock responses if: matrix.module == ':firebase-ai' run: firebase-ai/update_responses.sh diff --git a/README.md b/README.md index a537c1793b0..236028bb6a5 100644 --- a/README.md +++ b/README.md @@ -63,11 +63,6 @@ Unit tests can be executed on the command line by running ./gradlew ::check ``` -#### Vertex AI for Firebase - -See the Vertex AI for Firebase [README](firebase-vertexai#running-tests) for setup -instructions specific to that project. - ### Integration Testing These are tests that run on a hardware device or emulator. These tests have diff --git a/ci/fireci/fireciplugins/clean.py b/ci/fireci/fireciplugins/clean.py index 9f2cd6af9a5..2238cccab35 100644 --- a/ci/fireci/fireciplugins/clean.py +++ b/ci/fireci/fireciplugins/clean.py @@ -40,7 +40,6 @@ \b $ fireci clean firebase-common - $ fireci clean firebase-common firebase-vertexai Clean all projects: diff --git a/firebase-vertexai/CHANGELOG.md b/firebase-vertexai/CHANGELOG.md index 807790b2c93..4d0894e8adb 100644 --- a/firebase-vertexai/CHANGELOG.md +++ b/firebase-vertexai/CHANGELOG.md @@ -1,6 +1,3 @@ -# Unreleased - - # 16.5.0 * [changed] **Renamed / Replaced:** Vertex AI in Firebase (`firebase-vertexai`) has been renamed and replaced by the new Firebase AI SDK: `firebase-ai`. This is to accommodate the evolving set of diff --git a/firebase-vertexai/README.md b/firebase-vertexai/README.md deleted file mode 100644 index dc436cd6eb0..00000000000 --- a/firebase-vertexai/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Firebase Vertex AI SDK - -For developer documentation, please visit https://firebase.google.com/docs/vertex-ai. -This README is for contributors building and running tests for the SDK. - -## Building - -All Gradle commands should be run from the root of this repository. - -`./gradlew :firebase-vertexai:publishToMavenLocal` - -## Running Tests - -> [!IMPORTANT] -> These unit tests require mock response files, which can be downloaded by running -`./firebase-vertexai/update_responses.sh` from the root of this repository. - -Unit tests: - -`./gradlew :firebase-vertexai:check` - -Integration tests, requiring a running and connected device (emulator or real): - -`./gradlew :firebase-vertexai:deviceCheck` - -## Code Formatting - -Format Kotlin code in this SDK in Android Studio using -the [spotless plugin]([https://plugins.jetbrains.com/plugin/14912-ktfmt](https://github.com/diffplug/spotless) -by running: - -`./gradlew firebase-vertexai:spotlessApply` diff --git a/firebase-vertexai/api.txt b/firebase-vertexai/api.txt deleted file mode 100644 index 98559ca3abb..00000000000 --- a/firebase-vertexai/api.txt +++ /dev/null @@ -1,911 +0,0 @@ -// Signature format: 3.0 -package com.google.firebase.vertexai { - - @Deprecated public final class Chat { - ctor @Deprecated public Chat(com.google.firebase.vertexai.GenerativeModel model, java.util.List history = java.util.ArrayList()); - method @Deprecated public java.util.List getHistory(); - method @Deprecated public suspend Object? sendMessage(android.graphics.Bitmap prompt, kotlin.coroutines.Continuation); - method @Deprecated public suspend Object? sendMessage(com.google.firebase.vertexai.type.Content prompt, kotlin.coroutines.Continuation); - method @Deprecated public suspend Object? sendMessage(String prompt, kotlin.coroutines.Continuation); - method @Deprecated public kotlinx.coroutines.flow.Flow sendMessageStream(android.graphics.Bitmap prompt); - method @Deprecated public kotlinx.coroutines.flow.Flow sendMessageStream(com.google.firebase.vertexai.type.Content prompt); - method @Deprecated public kotlinx.coroutines.flow.Flow sendMessageStream(String prompt); - property @Deprecated public final java.util.List history; - } - - public final class FirebaseVertexAI { - method public com.google.firebase.vertexai.GenerativeModel generativeModel(String modelName); - method public com.google.firebase.vertexai.GenerativeModel generativeModel(String modelName, com.google.firebase.vertexai.type.GenerationConfig? generationConfig = null); - method public com.google.firebase.vertexai.GenerativeModel generativeModel(String modelName, com.google.firebase.vertexai.type.GenerationConfig? generationConfig = null, java.util.List? safetySettings = null); - method public com.google.firebase.vertexai.GenerativeModel generativeModel(String modelName, com.google.firebase.vertexai.type.GenerationConfig? generationConfig = null, java.util.List? safetySettings = null, java.util.List? tools = null); - method public com.google.firebase.vertexai.GenerativeModel generativeModel(String modelName, com.google.firebase.vertexai.type.GenerationConfig? generationConfig = null, java.util.List? safetySettings = null, java.util.List? tools = null, com.google.firebase.vertexai.type.ToolConfig? toolConfig = null); - method public com.google.firebase.vertexai.GenerativeModel generativeModel(String modelName, com.google.firebase.vertexai.type.GenerationConfig? generationConfig = null, java.util.List? safetySettings = null, java.util.List? tools = null, com.google.firebase.vertexai.type.ToolConfig? toolConfig = null, com.google.firebase.vertexai.type.Content? systemInstruction = null); - method public com.google.firebase.vertexai.GenerativeModel generativeModel(String modelName, com.google.firebase.vertexai.type.GenerationConfig? generationConfig = null, java.util.List? safetySettings = null, java.util.List? tools = null, com.google.firebase.vertexai.type.ToolConfig? toolConfig = null, com.google.firebase.vertexai.type.Content? systemInstruction = null, com.google.firebase.vertexai.type.RequestOptions requestOptions = com.google.firebase.vertexai.type.RequestOptions()); - method public static com.google.firebase.vertexai.FirebaseVertexAI getInstance(); - method public static com.google.firebase.vertexai.FirebaseVertexAI getInstance(com.google.firebase.FirebaseApp app); - method public static com.google.firebase.vertexai.FirebaseVertexAI getInstance(com.google.firebase.FirebaseApp app = Firebase.app, String location); - method public static com.google.firebase.vertexai.FirebaseVertexAI getInstance(String location); - method @com.google.firebase.vertexai.type.PublicPreviewAPI public com.google.firebase.vertexai.ImagenModel imagenModel(String modelName); - method @com.google.firebase.vertexai.type.PublicPreviewAPI public com.google.firebase.vertexai.ImagenModel imagenModel(String modelName, com.google.firebase.vertexai.type.ImagenGenerationConfig? generationConfig = null); - method @com.google.firebase.vertexai.type.PublicPreviewAPI public com.google.firebase.vertexai.ImagenModel imagenModel(String modelName, com.google.firebase.vertexai.type.ImagenGenerationConfig? generationConfig = null, com.google.firebase.vertexai.type.ImagenSafetySettings? safetySettings = null); - method @com.google.firebase.vertexai.type.PublicPreviewAPI public com.google.firebase.vertexai.ImagenModel imagenModel(String modelName, com.google.firebase.vertexai.type.ImagenGenerationConfig? generationConfig = null, com.google.firebase.vertexai.type.ImagenSafetySettings? safetySettings = null, com.google.firebase.vertexai.type.RequestOptions requestOptions = com.google.firebase.vertexai.type.RequestOptions()); - method @com.google.firebase.vertexai.type.PublicPreviewAPI public com.google.firebase.vertexai.LiveGenerativeModel liveModel(String modelName); - method @com.google.firebase.vertexai.type.PublicPreviewAPI public com.google.firebase.vertexai.LiveGenerativeModel liveModel(String modelName, com.google.firebase.vertexai.type.LiveGenerationConfig? generationConfig = null); - method @com.google.firebase.vertexai.type.PublicPreviewAPI public com.google.firebase.vertexai.LiveGenerativeModel liveModel(String modelName, com.google.firebase.vertexai.type.LiveGenerationConfig? generationConfig = null, java.util.List? tools = null); - method @com.google.firebase.vertexai.type.PublicPreviewAPI public com.google.firebase.vertexai.LiveGenerativeModel liveModel(String modelName, com.google.firebase.vertexai.type.LiveGenerationConfig? generationConfig = null, java.util.List? tools = null, com.google.firebase.vertexai.type.Content? systemInstruction = null); - method @com.google.firebase.vertexai.type.PublicPreviewAPI public com.google.firebase.vertexai.LiveGenerativeModel liveModel(String modelName, com.google.firebase.vertexai.type.LiveGenerationConfig? generationConfig = null, java.util.List? tools = null, com.google.firebase.vertexai.type.Content? systemInstruction = null, com.google.firebase.vertexai.type.RequestOptions requestOptions = com.google.firebase.vertexai.type.RequestOptions()); - property public static final com.google.firebase.vertexai.FirebaseVertexAI instance; - field public static final com.google.firebase.vertexai.FirebaseVertexAI.Companion Companion; - } - - public static final class FirebaseVertexAI.Companion { - method public com.google.firebase.vertexai.FirebaseVertexAI getInstance(); - method public com.google.firebase.vertexai.FirebaseVertexAI getInstance(com.google.firebase.FirebaseApp app); - method public com.google.firebase.vertexai.FirebaseVertexAI getInstance(com.google.firebase.FirebaseApp app = Firebase.app, String location); - method public com.google.firebase.vertexai.FirebaseVertexAI getInstance(String location); - property public final com.google.firebase.vertexai.FirebaseVertexAI instance; - } - - public final class FirebaseVertexAIKt { - method public static com.google.firebase.vertexai.FirebaseVertexAI getVertexAI(com.google.firebase.Firebase); - method public static com.google.firebase.vertexai.FirebaseVertexAI vertexAI(com.google.firebase.Firebase, com.google.firebase.FirebaseApp app = Firebase.app, String location = "us-central1"); - } - - @Deprecated public final class GenerativeModel { - method @Deprecated public suspend Object? countTokens(android.graphics.Bitmap prompt, kotlin.coroutines.Continuation); - method @Deprecated public suspend Object? countTokens(com.google.firebase.vertexai.type.Content[] prompt, kotlin.coroutines.Continuation); - method @Deprecated public suspend Object? countTokens(String prompt, kotlin.coroutines.Continuation); - method @Deprecated public suspend Object? generateContent(android.graphics.Bitmap prompt, kotlin.coroutines.Continuation); - method @Deprecated public suspend Object? generateContent(com.google.firebase.vertexai.type.Content[] prompt, kotlin.coroutines.Continuation); - method @Deprecated public suspend Object? generateContent(String prompt, kotlin.coroutines.Continuation); - method @Deprecated public kotlinx.coroutines.flow.Flow generateContentStream(android.graphics.Bitmap prompt); - method @Deprecated public kotlinx.coroutines.flow.Flow generateContentStream(com.google.firebase.vertexai.type.Content... prompt); - method @Deprecated public kotlinx.coroutines.flow.Flow generateContentStream(String prompt); - method @Deprecated public com.google.firebase.vertexai.Chat startChat(java.util.List history = emptyList()); - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class ImagenModel { - method @Deprecated public suspend Object? generateImages(String prompt, kotlin.coroutines.Continuation>); - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class LiveGenerativeModel { - method @Deprecated public suspend Object? connect(kotlin.coroutines.Continuation); - } - -} - -package com.google.firebase.vertexai.java { - - @Deprecated public abstract class ChatFutures { - method @Deprecated public static final com.google.firebase.vertexai.java.ChatFutures from(com.google.firebase.vertexai.Chat chat); - method @Deprecated public abstract com.google.firebase.vertexai.Chat getChat(); - method @Deprecated public abstract com.google.common.util.concurrent.ListenableFuture sendMessage(com.google.firebase.vertexai.type.Content prompt); - method @Deprecated public abstract org.reactivestreams.Publisher sendMessageStream(com.google.firebase.vertexai.type.Content prompt); - field @Deprecated public static final com.google.firebase.vertexai.java.ChatFutures.Companion Companion; - } - - @Deprecated public static final class ChatFutures.Companion { - method @Deprecated public com.google.firebase.vertexai.java.ChatFutures from(com.google.firebase.vertexai.Chat chat); - } - - @Deprecated public abstract class GenerativeModelFutures { - method @Deprecated public abstract com.google.common.util.concurrent.ListenableFuture countTokens(com.google.firebase.vertexai.type.Content... prompt); - method @Deprecated public static final com.google.firebase.vertexai.java.GenerativeModelFutures from(com.google.firebase.vertexai.GenerativeModel model); - method @Deprecated public abstract com.google.common.util.concurrent.ListenableFuture generateContent(com.google.firebase.vertexai.type.Content... prompt); - method @Deprecated public abstract org.reactivestreams.Publisher generateContentStream(com.google.firebase.vertexai.type.Content... prompt); - method @Deprecated public abstract com.google.firebase.vertexai.GenerativeModel getGenerativeModel(); - method @Deprecated public abstract com.google.firebase.vertexai.java.ChatFutures startChat(); - method @Deprecated public abstract com.google.firebase.vertexai.java.ChatFutures startChat(java.util.List history); - field @Deprecated public static final com.google.firebase.vertexai.java.GenerativeModelFutures.Companion Companion; - } - - @Deprecated public static final class GenerativeModelFutures.Companion { - method @Deprecated public com.google.firebase.vertexai.java.GenerativeModelFutures from(com.google.firebase.vertexai.GenerativeModel model); - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public abstract class ImagenModelFutures { - method @Deprecated public static final com.google.firebase.vertexai.java.ImagenModelFutures from(com.google.firebase.vertexai.ImagenModel model); - method @Deprecated public abstract com.google.common.util.concurrent.ListenableFuture> generateImages(String prompt); - method @Deprecated public abstract com.google.firebase.vertexai.ImagenModel getImageModel(); - field @Deprecated public static final com.google.firebase.vertexai.java.ImagenModelFutures.Companion Companion; - } - - @Deprecated public static final class ImagenModelFutures.Companion { - method @Deprecated public com.google.firebase.vertexai.java.ImagenModelFutures from(com.google.firebase.vertexai.ImagenModel model); - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public abstract class LiveModelFutures { - method @Deprecated public abstract com.google.common.util.concurrent.ListenableFuture connect(); - method @Deprecated public static final com.google.firebase.vertexai.java.LiveModelFutures from(com.google.firebase.vertexai.LiveGenerativeModel model); - field @Deprecated public static final com.google.firebase.vertexai.java.LiveModelFutures.Companion Companion; - } - - @Deprecated public static final class LiveModelFutures.Companion { - method @Deprecated public com.google.firebase.vertexai.java.LiveModelFutures from(com.google.firebase.vertexai.LiveGenerativeModel model); - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public abstract class LiveSessionFutures { - method @Deprecated public abstract com.google.common.util.concurrent.ListenableFuture close(); - method @Deprecated public static final com.google.firebase.vertexai.java.LiveSessionFutures from(com.google.firebase.vertexai.type.LiveSession session); - method @Deprecated public abstract org.reactivestreams.Publisher receive(); - method @Deprecated public abstract com.google.common.util.concurrent.ListenableFuture send(com.google.firebase.vertexai.type.Content content); - method @Deprecated public abstract com.google.common.util.concurrent.ListenableFuture send(String text); - method @Deprecated public abstract com.google.common.util.concurrent.ListenableFuture sendFunctionResponse(java.util.List functionList); - method @Deprecated public abstract com.google.common.util.concurrent.ListenableFuture sendMediaStream(java.util.List mediaChunks); - method @Deprecated @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public abstract com.google.common.util.concurrent.ListenableFuture startAudioConversation(); - method @Deprecated public abstract com.google.common.util.concurrent.ListenableFuture startAudioConversation(kotlin.jvm.functions.Function1? functionCallHandler); - method @Deprecated @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public abstract com.google.common.util.concurrent.ListenableFuture stopAudioConversation(); - method @Deprecated public abstract void stopReceiving(); - field @Deprecated public static final com.google.firebase.vertexai.java.LiveSessionFutures.Companion Companion; - } - - @Deprecated public static final class LiveSessionFutures.Companion { - method @Deprecated public com.google.firebase.vertexai.java.LiveSessionFutures from(com.google.firebase.vertexai.type.LiveSession session); - } - -} - -package com.google.firebase.vertexai.type { - - @Deprecated public final class AudioRecordInitializationFailedException extends com.google.firebase.vertexai.type.FirebaseVertexAIException { - ctor @Deprecated public AudioRecordInitializationFailedException(String message); - } - - @Deprecated public final class BlockReason { - method @Deprecated public String getName(); - method @Deprecated public int getOrdinal(); - property @Deprecated public final String name; - property @Deprecated public final int ordinal; - field @Deprecated public static final com.google.firebase.vertexai.type.BlockReason BLOCKLIST; - field @Deprecated public static final com.google.firebase.vertexai.type.BlockReason.Companion Companion; - field @Deprecated public static final com.google.firebase.vertexai.type.BlockReason OTHER; - field @Deprecated public static final com.google.firebase.vertexai.type.BlockReason PROHIBITED_CONTENT; - field @Deprecated public static final com.google.firebase.vertexai.type.BlockReason SAFETY; - field @Deprecated public static final com.google.firebase.vertexai.type.BlockReason UNKNOWN; - } - - @Deprecated public static final class BlockReason.Companion { - } - - @Deprecated public final class Candidate { - method @Deprecated public com.google.firebase.vertexai.type.CitationMetadata? getCitationMetadata(); - method @Deprecated public com.google.firebase.vertexai.type.Content getContent(); - method @Deprecated public com.google.firebase.vertexai.type.FinishReason? getFinishReason(); - method @Deprecated public java.util.List getSafetyRatings(); - property @Deprecated public final com.google.firebase.vertexai.type.CitationMetadata? citationMetadata; - property @Deprecated public final com.google.firebase.vertexai.type.Content content; - property @Deprecated public final com.google.firebase.vertexai.type.FinishReason? finishReason; - property @Deprecated public final java.util.List safetyRatings; - } - - @Deprecated public final class Citation { - method @Deprecated public int getEndIndex(); - method @Deprecated public String? getLicense(); - method @Deprecated public java.util.Calendar? getPublicationDate(); - method @Deprecated public int getStartIndex(); - method @Deprecated public String? getTitle(); - method @Deprecated public String? getUri(); - property @Deprecated public final int endIndex; - property @Deprecated public final String? license; - property @Deprecated public final java.util.Calendar? publicationDate; - property @Deprecated public final int startIndex; - property @Deprecated public final String? title; - property @Deprecated public final String? uri; - } - - @Deprecated public final class CitationMetadata { - method @Deprecated public java.util.List getCitations(); - property @Deprecated public final java.util.List citations; - } - - @Deprecated public final class Content { - ctor @Deprecated public Content(String? role = "user", java.util.List parts); - ctor @Deprecated public Content(java.util.List parts); - method @Deprecated public com.google.firebase.vertexai.type.Content copy(String? role = role, java.util.List parts = parts); - method @Deprecated public java.util.List getParts(); - method @Deprecated public String? getRole(); - property @Deprecated public final java.util.List parts; - property @Deprecated public final String? role; - } - - @Deprecated public static final class Content.Builder { - ctor @Deprecated public Content.Builder(); - method @Deprecated public com.google.firebase.vertexai.type.Content.Builder addFileData(String uri, String mimeType); - method @Deprecated public com.google.firebase.vertexai.type.Content.Builder addImage(android.graphics.Bitmap image); - method @Deprecated public com.google.firebase.vertexai.type.Content.Builder addInlineData(byte[] bytes, String mimeType); - method @Deprecated public com.google.firebase.vertexai.type.Content.Builder addPart(T data); - method @Deprecated public com.google.firebase.vertexai.type.Content.Builder addText(String text); - method @Deprecated public com.google.firebase.vertexai.type.Content build(); - method @Deprecated public java.util.List getParts(); - method @Deprecated public String? getRole(); - method @Deprecated public void setParts(java.util.List); - method @Deprecated public void setRole(String?); - property @Deprecated public final java.util.List parts; - property @Deprecated public final String? role; - } - - @Deprecated public final class ContentBlockedException extends com.google.firebase.vertexai.type.FirebaseVertexAIException { - } - - public final class ContentKt { - method public static com.google.firebase.vertexai.type.Content content(String? role = "user", kotlin.jvm.functions.Function1 init); - } - - @Deprecated public final class ContentModality { - method @Deprecated public int getOrdinal(); - property @Deprecated public final int ordinal; - field @Deprecated public static final com.google.firebase.vertexai.type.ContentModality AUDIO; - field @Deprecated public static final com.google.firebase.vertexai.type.ContentModality.Companion Companion; - field @Deprecated public static final com.google.firebase.vertexai.type.ContentModality DOCUMENT; - field @Deprecated public static final com.google.firebase.vertexai.type.ContentModality IMAGE; - field @Deprecated public static final com.google.firebase.vertexai.type.ContentModality TEXT; - field @Deprecated public static final com.google.firebase.vertexai.type.ContentModality UNSPECIFIED; - field @Deprecated public static final com.google.firebase.vertexai.type.ContentModality VIDEO; - } - - @Deprecated public static final class ContentModality.Companion { - } - - @Deprecated public final class CountTokensResponse { - ctor @Deprecated public CountTokensResponse(int totalTokens, Integer? totalBillableCharacters = null, java.util.List promptTokensDetails = emptyList()); - method @Deprecated public operator int component1(); - method @Deprecated public operator Integer? component2(); - method @Deprecated public operator java.util.List? component3(); - method @Deprecated public java.util.List getPromptTokensDetails(); - method @Deprecated public Integer? getTotalBillableCharacters(); - method @Deprecated public int getTotalTokens(); - property @Deprecated public final java.util.List promptTokensDetails; - property @Deprecated public final Integer? totalBillableCharacters; - property @Deprecated public final int totalTokens; - } - - @Deprecated public final class FileDataPart implements com.google.firebase.vertexai.type.Part { - ctor @Deprecated public FileDataPart(String uri, String mimeType); - method @Deprecated public String getMimeType(); - method @Deprecated public String getUri(); - property @Deprecated public final String mimeType; - property @Deprecated public final String uri; - } - - @Deprecated public final class FinishReason { - method @Deprecated public String getName(); - method @Deprecated public int getOrdinal(); - property @Deprecated public final String name; - property @Deprecated public final int ordinal; - field @Deprecated public static final com.google.firebase.vertexai.type.FinishReason BLOCKLIST; - field @Deprecated public static final com.google.firebase.vertexai.type.FinishReason.Companion Companion; - field @Deprecated public static final com.google.firebase.vertexai.type.FinishReason MALFORMED_FUNCTION_CALL; - field @Deprecated public static final com.google.firebase.vertexai.type.FinishReason MAX_TOKENS; - field @Deprecated public static final com.google.firebase.vertexai.type.FinishReason OTHER; - field @Deprecated public static final com.google.firebase.vertexai.type.FinishReason PROHIBITED_CONTENT; - field @Deprecated public static final com.google.firebase.vertexai.type.FinishReason RECITATION; - field @Deprecated public static final com.google.firebase.vertexai.type.FinishReason SAFETY; - field @Deprecated public static final com.google.firebase.vertexai.type.FinishReason SPII; - field @Deprecated public static final com.google.firebase.vertexai.type.FinishReason STOP; - field @Deprecated public static final com.google.firebase.vertexai.type.FinishReason UNKNOWN; - } - - @Deprecated public static final class FinishReason.Companion { - } - - @Deprecated public abstract class FirebaseVertexAIException extends java.lang.RuntimeException { - } - - @Deprecated public final class FunctionCallPart implements com.google.firebase.vertexai.type.Part { - ctor @Deprecated public FunctionCallPart(String name, java.util.Map args); - ctor @Deprecated public FunctionCallPart(String name, java.util.Map args, String? id = null); - method @Deprecated public java.util.Map getArgs(); - method @Deprecated public String? getId(); - method @Deprecated public String getName(); - property @Deprecated public final java.util.Map args; - property @Deprecated public final String? id; - property @Deprecated public final String name; - } - - @Deprecated public final class FunctionCallingConfig { - method @Deprecated public static com.google.firebase.vertexai.type.FunctionCallingConfig any(); - method @Deprecated public static com.google.firebase.vertexai.type.FunctionCallingConfig any(java.util.List? allowedFunctionNames = null); - method @Deprecated public static com.google.firebase.vertexai.type.FunctionCallingConfig auto(); - method @Deprecated public static com.google.firebase.vertexai.type.FunctionCallingConfig none(); - field @Deprecated public static final com.google.firebase.vertexai.type.FunctionCallingConfig.Companion Companion; - } - - @Deprecated public static final class FunctionCallingConfig.Companion { - method @Deprecated public com.google.firebase.vertexai.type.FunctionCallingConfig any(); - method @Deprecated public com.google.firebase.vertexai.type.FunctionCallingConfig any(java.util.List? allowedFunctionNames = null); - method @Deprecated public com.google.firebase.vertexai.type.FunctionCallingConfig auto(); - method @Deprecated public com.google.firebase.vertexai.type.FunctionCallingConfig none(); - } - - @Deprecated public final class FunctionDeclaration { - ctor @Deprecated public FunctionDeclaration(String name, String description, java.util.Map parameters, java.util.List optionalParameters = emptyList()); - } - - @Deprecated public final class FunctionResponsePart implements com.google.firebase.vertexai.type.Part { - ctor @Deprecated public FunctionResponsePart(String name, kotlinx.serialization.json.JsonObject response); - ctor @Deprecated public FunctionResponsePart(String name, kotlinx.serialization.json.JsonObject response, String? id = null); - method @Deprecated public String? getId(); - method @Deprecated public String getName(); - method @Deprecated public kotlinx.serialization.json.JsonObject getResponse(); - property @Deprecated public final String? id; - property @Deprecated public final String name; - property @Deprecated public final kotlinx.serialization.json.JsonObject response; - } - - @Deprecated public final class GenerateContentResponse { - ctor @Deprecated public GenerateContentResponse(java.util.List candidates, com.google.firebase.vertexai.type.PromptFeedback? promptFeedback, com.google.firebase.vertexai.type.UsageMetadata? usageMetadata); - method @Deprecated public java.util.List getCandidates(); - method @Deprecated public java.util.List getFunctionCalls(); - method @Deprecated public java.util.List getInlineDataParts(); - method @Deprecated public com.google.firebase.vertexai.type.PromptFeedback? getPromptFeedback(); - method @Deprecated public String? getText(); - method @Deprecated public com.google.firebase.vertexai.type.UsageMetadata? getUsageMetadata(); - property @Deprecated public final java.util.List candidates; - property @Deprecated public final java.util.List functionCalls; - property @Deprecated public final java.util.List inlineDataParts; - property @Deprecated public final com.google.firebase.vertexai.type.PromptFeedback? promptFeedback; - property @Deprecated public final String? text; - property @Deprecated public final com.google.firebase.vertexai.type.UsageMetadata? usageMetadata; - } - - @Deprecated public final class GenerationConfig { - field @Deprecated public static final com.google.firebase.vertexai.type.GenerationConfig.Companion Companion; - } - - @Deprecated public static final class GenerationConfig.Builder { - ctor @Deprecated public GenerationConfig.Builder(); - method @Deprecated public com.google.firebase.vertexai.type.GenerationConfig build(); - field @Deprecated public Integer? candidateCount; - field @Deprecated public Float? frequencyPenalty; - field @Deprecated public Integer? maxOutputTokens; - field @Deprecated public Float? presencePenalty; - field @Deprecated public String? responseMimeType; - field @Deprecated public java.util.List? responseModalities; - field @Deprecated public com.google.firebase.vertexai.type.Schema? responseSchema; - field @Deprecated public java.util.List? stopSequences; - field @Deprecated public Float? temperature; - field @Deprecated public Integer? topK; - field @Deprecated public Float? topP; - } - - @Deprecated public static final class GenerationConfig.Companion { - method @Deprecated public com.google.firebase.vertexai.type.GenerationConfig.Builder builder(); - } - - public final class GenerationConfigKt { - method public static com.google.firebase.vertexai.type.GenerationConfig generationConfig(kotlin.jvm.functions.Function1 init); - } - - @Deprecated public final class HarmBlockMethod { - method @Deprecated public int getOrdinal(); - property @Deprecated public final int ordinal; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmBlockMethod.Companion Companion; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmBlockMethod PROBABILITY; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmBlockMethod SEVERITY; - } - - @Deprecated public static final class HarmBlockMethod.Companion { - } - - @Deprecated public final class HarmBlockThreshold { - method @Deprecated public int getOrdinal(); - property @Deprecated public final int ordinal; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmBlockThreshold.Companion Companion; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmBlockThreshold LOW_AND_ABOVE; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmBlockThreshold MEDIUM_AND_ABOVE; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmBlockThreshold NONE; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmBlockThreshold OFF; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmBlockThreshold ONLY_HIGH; - } - - @Deprecated public static final class HarmBlockThreshold.Companion { - } - - @Deprecated public final class HarmCategory { - method @Deprecated public int getOrdinal(); - property @Deprecated public final int ordinal; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmCategory CIVIC_INTEGRITY; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmCategory.Companion Companion; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmCategory DANGEROUS_CONTENT; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmCategory HARASSMENT; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmCategory HATE_SPEECH; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmCategory SEXUALLY_EXPLICIT; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmCategory UNKNOWN; - } - - @Deprecated public static final class HarmCategory.Companion { - } - - @Deprecated public final class HarmProbability { - method @Deprecated public int getOrdinal(); - property @Deprecated public final int ordinal; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmProbability.Companion Companion; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmProbability HIGH; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmProbability LOW; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmProbability MEDIUM; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmProbability NEGLIGIBLE; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmProbability UNKNOWN; - } - - @Deprecated public static final class HarmProbability.Companion { - } - - @Deprecated public final class HarmSeverity { - method @Deprecated public int getOrdinal(); - property @Deprecated public final int ordinal; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmSeverity.Companion Companion; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmSeverity HIGH; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmSeverity LOW; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmSeverity MEDIUM; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmSeverity NEGLIGIBLE; - field @Deprecated public static final com.google.firebase.vertexai.type.HarmSeverity UNKNOWN; - } - - @Deprecated public static final class HarmSeverity.Companion { - } - - @Deprecated public final class ImagePart implements com.google.firebase.vertexai.type.Part { - ctor @Deprecated public ImagePart(android.graphics.Bitmap image); - method @Deprecated public android.graphics.Bitmap getImage(); - property @Deprecated public final android.graphics.Bitmap image; - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class ImagenAspectRatio { - field @Deprecated public static final com.google.firebase.vertexai.type.ImagenAspectRatio.Companion Companion; - field @Deprecated public static final com.google.firebase.vertexai.type.ImagenAspectRatio LANDSCAPE_16x9; - field @Deprecated public static final com.google.firebase.vertexai.type.ImagenAspectRatio LANDSCAPE_4x3; - field @Deprecated public static final com.google.firebase.vertexai.type.ImagenAspectRatio PORTRAIT_3x4; - field @Deprecated public static final com.google.firebase.vertexai.type.ImagenAspectRatio PORTRAIT_9x16; - field @Deprecated public static final com.google.firebase.vertexai.type.ImagenAspectRatio SQUARE_1x1; - } - - @Deprecated public static final class ImagenAspectRatio.Companion { - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class ImagenGenerationConfig { - ctor @Deprecated public ImagenGenerationConfig(String? negativePrompt = null, Integer? numberOfImages = 1, com.google.firebase.vertexai.type.ImagenAspectRatio? aspectRatio = null, com.google.firebase.vertexai.type.ImagenImageFormat? imageFormat = null, Boolean? addWatermark = null); - method @Deprecated public Boolean? getAddWatermark(); - method @Deprecated public com.google.firebase.vertexai.type.ImagenAspectRatio? getAspectRatio(); - method @Deprecated public com.google.firebase.vertexai.type.ImagenImageFormat? getImageFormat(); - method @Deprecated public String? getNegativePrompt(); - method @Deprecated public Integer? getNumberOfImages(); - property @Deprecated public final Boolean? addWatermark; - property @Deprecated public final com.google.firebase.vertexai.type.ImagenAspectRatio? aspectRatio; - property @Deprecated public final com.google.firebase.vertexai.type.ImagenImageFormat? imageFormat; - property @Deprecated public final String? negativePrompt; - property @Deprecated public final Integer? numberOfImages; - field @Deprecated public static final com.google.firebase.vertexai.type.ImagenGenerationConfig.Companion Companion; - } - - @Deprecated public static final class ImagenGenerationConfig.Builder { - ctor @Deprecated public ImagenGenerationConfig.Builder(); - method @Deprecated public com.google.firebase.vertexai.type.ImagenGenerationConfig build(); - method @Deprecated public com.google.firebase.vertexai.type.ImagenGenerationConfig.Builder setAddWatermark(boolean addWatermark); - method @Deprecated public com.google.firebase.vertexai.type.ImagenGenerationConfig.Builder setAspectRatio(com.google.firebase.vertexai.type.ImagenAspectRatio aspectRatio); - method @Deprecated public com.google.firebase.vertexai.type.ImagenGenerationConfig.Builder setImageFormat(com.google.firebase.vertexai.type.ImagenImageFormat imageFormat); - method @Deprecated public com.google.firebase.vertexai.type.ImagenGenerationConfig.Builder setNegativePrompt(String negativePrompt); - method @Deprecated public com.google.firebase.vertexai.type.ImagenGenerationConfig.Builder setNumberOfImages(int numberOfImages); - field @Deprecated public Boolean? addWatermark; - field @Deprecated public com.google.firebase.vertexai.type.ImagenAspectRatio? aspectRatio; - field @Deprecated public com.google.firebase.vertexai.type.ImagenImageFormat? imageFormat; - field @Deprecated public String? negativePrompt; - field @Deprecated public Integer? numberOfImages; - } - - @Deprecated public static final class ImagenGenerationConfig.Companion { - method @Deprecated public com.google.firebase.vertexai.type.ImagenGenerationConfig.Builder builder(); - } - - public final class ImagenGenerationConfigKt { - method @com.google.firebase.vertexai.type.PublicPreviewAPI public static com.google.firebase.vertexai.type.ImagenGenerationConfig imagenGenerationConfig(kotlin.jvm.functions.Function1 init); - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class ImagenGenerationResponse { - method @Deprecated public String? getFilteredReason(); - method @Deprecated public java.util.List getImages(); - property @Deprecated public final String? filteredReason; - property @Deprecated public final java.util.List images; - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class ImagenImageFormat { - method @Deprecated public Integer? getCompressionQuality(); - method @Deprecated public String getMimeType(); - method @Deprecated public static com.google.firebase.vertexai.type.ImagenImageFormat jpeg(Integer? compressionQuality = null); - method @Deprecated public static com.google.firebase.vertexai.type.ImagenImageFormat png(); - property @Deprecated public final Integer? compressionQuality; - property @Deprecated public final String mimeType; - field @Deprecated public static final com.google.firebase.vertexai.type.ImagenImageFormat.Companion Companion; - } - - @Deprecated public static final class ImagenImageFormat.Companion { - method @Deprecated public com.google.firebase.vertexai.type.ImagenImageFormat jpeg(Integer? compressionQuality = null); - method @Deprecated public com.google.firebase.vertexai.type.ImagenImageFormat png(); - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class ImagenInlineImage { - method @Deprecated public android.graphics.Bitmap asBitmap(); - method @Deprecated public byte[] getData(); - method @Deprecated public String getMimeType(); - property @Deprecated public final byte[] data; - property @Deprecated public final String mimeType; - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class ImagenPersonFilterLevel { - field @Deprecated public static final com.google.firebase.vertexai.type.ImagenPersonFilterLevel ALLOW_ADULT; - field @Deprecated public static final com.google.firebase.vertexai.type.ImagenPersonFilterLevel ALLOW_ALL; - field @Deprecated public static final com.google.firebase.vertexai.type.ImagenPersonFilterLevel BLOCK_ALL; - field @Deprecated public static final com.google.firebase.vertexai.type.ImagenPersonFilterLevel.Companion Companion; - } - - @Deprecated public static final class ImagenPersonFilterLevel.Companion { - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class ImagenSafetyFilterLevel { - field @Deprecated public static final com.google.firebase.vertexai.type.ImagenSafetyFilterLevel BLOCK_LOW_AND_ABOVE; - field @Deprecated public static final com.google.firebase.vertexai.type.ImagenSafetyFilterLevel BLOCK_MEDIUM_AND_ABOVE; - field @Deprecated public static final com.google.firebase.vertexai.type.ImagenSafetyFilterLevel BLOCK_NONE; - field @Deprecated public static final com.google.firebase.vertexai.type.ImagenSafetyFilterLevel BLOCK_ONLY_HIGH; - field @Deprecated public static final com.google.firebase.vertexai.type.ImagenSafetyFilterLevel.Companion Companion; - } - - @Deprecated public static final class ImagenSafetyFilterLevel.Companion { - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class ImagenSafetySettings { - ctor @Deprecated public ImagenSafetySettings(com.google.firebase.vertexai.type.ImagenSafetyFilterLevel safetyFilterLevel, com.google.firebase.vertexai.type.ImagenPersonFilterLevel personFilterLevel); - } - - @Deprecated public final class InlineDataPart implements com.google.firebase.vertexai.type.Part { - ctor @Deprecated public InlineDataPart(byte[] inlineData, String mimeType); - method @Deprecated public byte[] getInlineData(); - method @Deprecated public String getMimeType(); - property @Deprecated public final byte[] inlineData; - property @Deprecated public final String mimeType; - } - - @Deprecated public final class InvalidAPIKeyException extends com.google.firebase.vertexai.type.FirebaseVertexAIException { - } - - @Deprecated public final class InvalidLocationException extends com.google.firebase.vertexai.type.FirebaseVertexAIException { - } - - @Deprecated public final class InvalidStateException extends com.google.firebase.vertexai.type.FirebaseVertexAIException { - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class LiveGenerationConfig { - field @Deprecated public static final com.google.firebase.vertexai.type.LiveGenerationConfig.Companion Companion; - } - - @Deprecated public static final class LiveGenerationConfig.Builder { - ctor @Deprecated public LiveGenerationConfig.Builder(); - method @Deprecated public com.google.firebase.vertexai.type.LiveGenerationConfig build(); - method @Deprecated public com.google.firebase.vertexai.type.LiveGenerationConfig.Builder setCandidateCount(Integer? candidateCount); - method @Deprecated public com.google.firebase.vertexai.type.LiveGenerationConfig.Builder setFrequencyPenalty(Float? frequencyPenalty); - method @Deprecated public com.google.firebase.vertexai.type.LiveGenerationConfig.Builder setMaxOutputTokens(Integer? maxOutputTokens); - method @Deprecated public com.google.firebase.vertexai.type.LiveGenerationConfig.Builder setPresencePenalty(Float? presencePenalty); - method @Deprecated public com.google.firebase.vertexai.type.LiveGenerationConfig.Builder setResponseModality(com.google.firebase.vertexai.type.ResponseModality? responseModality); - method @Deprecated public com.google.firebase.vertexai.type.LiveGenerationConfig.Builder setSpeechConfig(com.google.firebase.vertexai.type.SpeechConfig? speechConfig); - method @Deprecated public com.google.firebase.vertexai.type.LiveGenerationConfig.Builder setTemperature(Float? temperature); - method @Deprecated public com.google.firebase.vertexai.type.LiveGenerationConfig.Builder setTopK(Integer? topK); - method @Deprecated public com.google.firebase.vertexai.type.LiveGenerationConfig.Builder setTopP(Float? topP); - field @Deprecated public Integer? candidateCount; - field @Deprecated public Float? frequencyPenalty; - field @Deprecated public Integer? maxOutputTokens; - field @Deprecated public Float? presencePenalty; - field @Deprecated public com.google.firebase.vertexai.type.ResponseModality? responseModality; - field @Deprecated public com.google.firebase.vertexai.type.SpeechConfig? speechConfig; - field @Deprecated public Float? temperature; - field @Deprecated public Integer? topK; - field @Deprecated public Float? topP; - } - - @Deprecated public static final class LiveGenerationConfig.Companion { - method @Deprecated public com.google.firebase.vertexai.type.LiveGenerationConfig.Builder builder(); - } - - public final class LiveGenerationConfigKt { - method public static com.google.firebase.vertexai.type.LiveGenerationConfig liveGenerationConfig(kotlin.jvm.functions.Function1 init); - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class LiveServerContent implements com.google.firebase.vertexai.type.LiveServerMessage { - ctor @Deprecated public LiveServerContent(com.google.firebase.vertexai.type.Content? content, boolean interrupted, boolean turnComplete, boolean generationComplete); - method @Deprecated public com.google.firebase.vertexai.type.Content? getContent(); - method @Deprecated public boolean getGenerationComplete(); - method @Deprecated public boolean getInterrupted(); - method @Deprecated public boolean getTurnComplete(); - property @Deprecated public final com.google.firebase.vertexai.type.Content? content; - property @Deprecated public final boolean generationComplete; - property @Deprecated public final boolean interrupted; - property @Deprecated public final boolean turnComplete; - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public interface LiveServerMessage { - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class LiveServerSetupComplete implements com.google.firebase.vertexai.type.LiveServerMessage { - ctor @Deprecated public LiveServerSetupComplete(); - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class LiveServerToolCall implements com.google.firebase.vertexai.type.LiveServerMessage { - ctor @Deprecated public LiveServerToolCall(java.util.List functionCalls); - method @Deprecated public java.util.List getFunctionCalls(); - property @Deprecated public final java.util.List functionCalls; - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class LiveServerToolCallCancellation implements com.google.firebase.vertexai.type.LiveServerMessage { - ctor @Deprecated public LiveServerToolCallCancellation(java.util.List functionIds); - method @Deprecated public java.util.List getFunctionIds(); - property @Deprecated public final java.util.List functionIds; - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class LiveSession { - method @Deprecated public suspend Object? close(kotlin.coroutines.Continuation); - method @Deprecated public kotlinx.coroutines.flow.Flow receive(); - method @Deprecated public suspend Object? send(com.google.firebase.vertexai.type.Content content, kotlin.coroutines.Continuation); - method @Deprecated public suspend Object? send(String text, kotlin.coroutines.Continuation); - method @Deprecated public suspend Object? sendFunctionResponse(java.util.List functionList, kotlin.coroutines.Continuation); - method @Deprecated public suspend Object? sendMediaStream(java.util.List mediaChunks, kotlin.coroutines.Continuation); - method @Deprecated @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public suspend Object? startAudioConversation(kotlin.jvm.functions.Function1? functionCallHandler = null, kotlin.coroutines.Continuation); - method @Deprecated public void stopAudioConversation(); - method @Deprecated public void stopReceiving(); - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class MediaData { - ctor @Deprecated public MediaData(byte[] data, String mimeType); - method @Deprecated public byte[] getData(); - method @Deprecated public String getMimeType(); - property @Deprecated public final byte[] data; - property @Deprecated public final String mimeType; - } - - @Deprecated public final class ModalityTokenCount { - method @Deprecated public operator com.google.firebase.vertexai.type.ContentModality component1(); - method @Deprecated public operator int component2(); - method @Deprecated public com.google.firebase.vertexai.type.ContentModality getModality(); - method @Deprecated public int getTokenCount(); - property @Deprecated public final com.google.firebase.vertexai.type.ContentModality modality; - property @Deprecated public final int tokenCount; - } - - @Deprecated public interface Part { - } - - public final class PartKt { - method public static com.google.firebase.vertexai.type.FileDataPart? asFileDataOrNull(com.google.firebase.vertexai.type.Part); - method public static android.graphics.Bitmap? asImageOrNull(com.google.firebase.vertexai.type.Part); - method public static com.google.firebase.vertexai.type.InlineDataPart? asInlineDataPartOrNull(com.google.firebase.vertexai.type.Part); - method public static String? asTextOrNull(com.google.firebase.vertexai.type.Part); - } - - @Deprecated public final class PromptBlockedException extends com.google.firebase.vertexai.type.FirebaseVertexAIException { - method @Deprecated public com.google.firebase.vertexai.type.GenerateContentResponse? getResponse(); - property @Deprecated public final com.google.firebase.vertexai.type.GenerateContentResponse? response; - } - - @Deprecated public final class PromptFeedback { - ctor @Deprecated public PromptFeedback(com.google.firebase.vertexai.type.BlockReason? blockReason, java.util.List safetyRatings, String? blockReasonMessage); - method @Deprecated public com.google.firebase.vertexai.type.BlockReason? getBlockReason(); - method @Deprecated public String? getBlockReasonMessage(); - method @Deprecated public java.util.List getSafetyRatings(); - property @Deprecated public final com.google.firebase.vertexai.type.BlockReason? blockReason; - property @Deprecated public final String? blockReasonMessage; - property @Deprecated public final java.util.List safetyRatings; - } - - @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level.ERROR, message="This API is part of an experimental public preview and may change in " + "backwards-incompatible ways without notice.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface PublicPreviewAPI { - } - - @Deprecated public final class QuotaExceededException extends com.google.firebase.vertexai.type.FirebaseVertexAIException { - } - - @Deprecated public final class RequestOptions { - ctor @Deprecated public RequestOptions(); - ctor @Deprecated public RequestOptions(long timeoutInMillis = 180.seconds.inWholeMilliseconds); - } - - @Deprecated public final class RequestTimeoutException extends com.google.firebase.vertexai.type.FirebaseVertexAIException { - } - - @Deprecated public final class ResponseModality { - method @Deprecated public int getOrdinal(); - property @Deprecated public final int ordinal; - field @Deprecated public static final com.google.firebase.vertexai.type.ResponseModality AUDIO; - field @Deprecated public static final com.google.firebase.vertexai.type.ResponseModality.Companion Companion; - field @Deprecated public static final com.google.firebase.vertexai.type.ResponseModality IMAGE; - field @Deprecated public static final com.google.firebase.vertexai.type.ResponseModality TEXT; - } - - @Deprecated public static final class ResponseModality.Companion { - } - - @Deprecated public final class ResponseStoppedException extends com.google.firebase.vertexai.type.FirebaseVertexAIException { - method @Deprecated public com.google.firebase.vertexai.type.GenerateContentResponse getResponse(); - property @Deprecated public final com.google.firebase.vertexai.type.GenerateContentResponse response; - } - - @Deprecated public final class SafetyRating { - method @Deprecated public Boolean? getBlocked(); - method @Deprecated public com.google.firebase.vertexai.type.HarmCategory getCategory(); - method @Deprecated public com.google.firebase.vertexai.type.HarmProbability getProbability(); - method @Deprecated public float getProbabilityScore(); - method @Deprecated public com.google.firebase.vertexai.type.HarmSeverity? getSeverity(); - method @Deprecated public Float? getSeverityScore(); - property @Deprecated public final Boolean? blocked; - property @Deprecated public final com.google.firebase.vertexai.type.HarmCategory category; - property @Deprecated public final com.google.firebase.vertexai.type.HarmProbability probability; - property @Deprecated public final float probabilityScore; - property @Deprecated public final com.google.firebase.vertexai.type.HarmSeverity? severity; - property @Deprecated public final Float? severityScore; - } - - @Deprecated public final class SafetySetting { - ctor @Deprecated public SafetySetting(com.google.firebase.vertexai.type.HarmCategory harmCategory, com.google.firebase.vertexai.type.HarmBlockThreshold threshold, com.google.firebase.vertexai.type.HarmBlockMethod? method = null); - } - - @Deprecated public final class Schema { - method @Deprecated public static com.google.firebase.vertexai.type.Schema array(com.google.firebase.vertexai.type.Schema items); - method @Deprecated public static com.google.firebase.vertexai.type.Schema array(com.google.firebase.vertexai.type.Schema items, String? description = null); - method @Deprecated public static com.google.firebase.vertexai.type.Schema array(com.google.firebase.vertexai.type.Schema items, String? description = null, boolean nullable = false); - method @Deprecated public static com.google.firebase.vertexai.type.Schema boolean(); - method @Deprecated public static com.google.firebase.vertexai.type.Schema boolean(String? description = null); - method @Deprecated public static com.google.firebase.vertexai.type.Schema boolean(String? description = null, boolean nullable = false); - method @Deprecated public static com.google.firebase.vertexai.type.Schema enumeration(java.util.List values); - method @Deprecated public static com.google.firebase.vertexai.type.Schema enumeration(java.util.List values, String? description = null); - method @Deprecated public static com.google.firebase.vertexai.type.Schema enumeration(java.util.List values, String? description = null, boolean nullable = false); - method @Deprecated public String? getDescription(); - method @Deprecated public java.util.List? getEnum(); - method @Deprecated public String? getFormat(); - method @Deprecated public com.google.firebase.vertexai.type.Schema? getItems(); - method @Deprecated public Boolean? getNullable(); - method @Deprecated public java.util.Map? getProperties(); - method @Deprecated public java.util.List? getRequired(); - method @Deprecated public String getType(); - method @Deprecated public static com.google.firebase.vertexai.type.Schema numDouble(); - method @Deprecated public static com.google.firebase.vertexai.type.Schema numDouble(String? description = null); - method @Deprecated public static com.google.firebase.vertexai.type.Schema numDouble(String? description = null, boolean nullable = false); - method @Deprecated public static com.google.firebase.vertexai.type.Schema numFloat(); - method @Deprecated public static com.google.firebase.vertexai.type.Schema numFloat(String? description = null); - method @Deprecated public static com.google.firebase.vertexai.type.Schema numFloat(String? description = null, boolean nullable = false); - method @Deprecated public static com.google.firebase.vertexai.type.Schema numInt(); - method @Deprecated public static com.google.firebase.vertexai.type.Schema numInt(String? description = null); - method @Deprecated public static com.google.firebase.vertexai.type.Schema numInt(String? description = null, boolean nullable = false); - method @Deprecated public static com.google.firebase.vertexai.type.Schema numLong(); - method @Deprecated public static com.google.firebase.vertexai.type.Schema numLong(String? description = null); - method @Deprecated public static com.google.firebase.vertexai.type.Schema numLong(String? description = null, boolean nullable = false); - method @Deprecated public static com.google.firebase.vertexai.type.Schema obj(java.util.Map properties); - method @Deprecated public static com.google.firebase.vertexai.type.Schema obj(java.util.Map properties, java.util.List optionalProperties = emptyList()); - method @Deprecated public static com.google.firebase.vertexai.type.Schema obj(java.util.Map properties, java.util.List optionalProperties = emptyList(), String? description = null); - method @Deprecated public static com.google.firebase.vertexai.type.Schema obj(java.util.Map properties, java.util.List optionalProperties = emptyList(), String? description = null, boolean nullable = false); - method @Deprecated public static com.google.firebase.vertexai.type.Schema str(); - method @Deprecated public static com.google.firebase.vertexai.type.Schema str(String? description = null); - method @Deprecated public static com.google.firebase.vertexai.type.Schema str(String? description = null, boolean nullable = false); - method @Deprecated public static com.google.firebase.vertexai.type.Schema str(String? description = null, boolean nullable = false, com.google.firebase.vertexai.type.StringFormat? format = null); - property @Deprecated public final String? description; - property @Deprecated public final java.util.List? enum; - property @Deprecated public final String? format; - property @Deprecated public final com.google.firebase.vertexai.type.Schema? items; - property @Deprecated public final Boolean? nullable; - property @Deprecated public final java.util.Map? properties; - property @Deprecated public final java.util.List? required; - property @Deprecated public final String type; - field @Deprecated public static final com.google.firebase.vertexai.type.Schema.Companion Companion; - } - - @Deprecated public static final class Schema.Companion { - method @Deprecated public com.google.firebase.vertexai.type.Schema array(com.google.firebase.vertexai.type.Schema items); - method @Deprecated public com.google.firebase.vertexai.type.Schema array(com.google.firebase.vertexai.type.Schema items, String? description = null); - method @Deprecated public com.google.firebase.vertexai.type.Schema array(com.google.firebase.vertexai.type.Schema items, String? description = null, boolean nullable = false); - method @Deprecated public com.google.firebase.vertexai.type.Schema boolean(); - method @Deprecated public com.google.firebase.vertexai.type.Schema boolean(String? description = null); - method @Deprecated public com.google.firebase.vertexai.type.Schema boolean(String? description = null, boolean nullable = false); - method @Deprecated public com.google.firebase.vertexai.type.Schema enumeration(java.util.List values); - method @Deprecated public com.google.firebase.vertexai.type.Schema enumeration(java.util.List values, String? description = null); - method @Deprecated public com.google.firebase.vertexai.type.Schema enumeration(java.util.List values, String? description = null, boolean nullable = false); - method @Deprecated public com.google.firebase.vertexai.type.Schema numDouble(); - method @Deprecated public com.google.firebase.vertexai.type.Schema numDouble(String? description = null); - method @Deprecated public com.google.firebase.vertexai.type.Schema numDouble(String? description = null, boolean nullable = false); - method @Deprecated public com.google.firebase.vertexai.type.Schema numFloat(); - method @Deprecated public com.google.firebase.vertexai.type.Schema numFloat(String? description = null); - method @Deprecated public com.google.firebase.vertexai.type.Schema numFloat(String? description = null, boolean nullable = false); - method @Deprecated public com.google.firebase.vertexai.type.Schema numInt(); - method @Deprecated public com.google.firebase.vertexai.type.Schema numInt(String? description = null); - method @Deprecated public com.google.firebase.vertexai.type.Schema numInt(String? description = null, boolean nullable = false); - method @Deprecated public com.google.firebase.vertexai.type.Schema numLong(); - method @Deprecated public com.google.firebase.vertexai.type.Schema numLong(String? description = null); - method @Deprecated public com.google.firebase.vertexai.type.Schema numLong(String? description = null, boolean nullable = false); - method @Deprecated public com.google.firebase.vertexai.type.Schema obj(java.util.Map properties); - method @Deprecated public com.google.firebase.vertexai.type.Schema obj(java.util.Map properties, java.util.List optionalProperties = emptyList()); - method @Deprecated public com.google.firebase.vertexai.type.Schema obj(java.util.Map properties, java.util.List optionalProperties = emptyList(), String? description = null); - method @Deprecated public com.google.firebase.vertexai.type.Schema obj(java.util.Map properties, java.util.List optionalProperties = emptyList(), String? description = null, boolean nullable = false); - method @Deprecated public com.google.firebase.vertexai.type.Schema str(); - method @Deprecated public com.google.firebase.vertexai.type.Schema str(String? description = null); - method @Deprecated public com.google.firebase.vertexai.type.Schema str(String? description = null, boolean nullable = false); - method @Deprecated public com.google.firebase.vertexai.type.Schema str(String? description = null, boolean nullable = false, com.google.firebase.vertexai.type.StringFormat? format = null); - } - - @Deprecated public final class SerializationException extends com.google.firebase.vertexai.type.FirebaseVertexAIException { - } - - @Deprecated public final class ServerException extends com.google.firebase.vertexai.type.FirebaseVertexAIException { - } - - @Deprecated public final class ServiceConnectionHandshakeFailedException extends com.google.firebase.vertexai.type.FirebaseVertexAIException { - ctor @Deprecated public ServiceConnectionHandshakeFailedException(String message, Throwable? cause = null); - } - - @Deprecated public final class ServiceDisabledException extends com.google.firebase.vertexai.type.FirebaseVertexAIException { - } - - @Deprecated public final class SessionAlreadyReceivingException extends com.google.firebase.vertexai.type.FirebaseVertexAIException { - ctor @Deprecated public SessionAlreadyReceivingException(); - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class SpeechConfig { - ctor @Deprecated public SpeechConfig(com.google.firebase.vertexai.type.Voices voice); - method @Deprecated public com.google.firebase.vertexai.type.Voices getVoice(); - property @Deprecated public final com.google.firebase.vertexai.type.Voices voice; - } - - @Deprecated public abstract class StringFormat { - } - - @Deprecated public static final class StringFormat.Custom extends com.google.firebase.vertexai.type.StringFormat { - ctor @Deprecated public StringFormat.Custom(String value); - } - - @Deprecated public final class TextPart implements com.google.firebase.vertexai.type.Part { - ctor @Deprecated public TextPart(String text); - method @Deprecated public String getText(); - property @Deprecated public final String text; - } - - @Deprecated public final class Tool { - method @Deprecated public static com.google.firebase.vertexai.type.Tool functionDeclarations(java.util.List functionDeclarations); - field @Deprecated public static final com.google.firebase.vertexai.type.Tool.Companion Companion; - } - - @Deprecated public static final class Tool.Companion { - method @Deprecated public com.google.firebase.vertexai.type.Tool functionDeclarations(java.util.List functionDeclarations); - } - - @Deprecated public final class ToolConfig { - ctor @Deprecated public ToolConfig(com.google.firebase.vertexai.type.FunctionCallingConfig? functionCallingConfig); - } - - @Deprecated public final class UnknownException extends com.google.firebase.vertexai.type.FirebaseVertexAIException { - } - - @Deprecated public final class UnsupportedUserLocationException extends com.google.firebase.vertexai.type.FirebaseVertexAIException { - } - - @Deprecated public final class UsageMetadata { - ctor @Deprecated public UsageMetadata(int promptTokenCount, Integer? candidatesTokenCount, int totalTokenCount, java.util.List promptTokensDetails, java.util.List candidatesTokensDetails); - method @Deprecated public Integer? getCandidatesTokenCount(); - method @Deprecated public java.util.List getCandidatesTokensDetails(); - method @Deprecated public int getPromptTokenCount(); - method @Deprecated public java.util.List getPromptTokensDetails(); - method @Deprecated public int getTotalTokenCount(); - property @Deprecated public final Integer? candidatesTokenCount; - property @Deprecated public final java.util.List candidatesTokensDetails; - property @Deprecated public final int promptTokenCount; - property @Deprecated public final java.util.List promptTokensDetails; - property @Deprecated public final int totalTokenCount; - } - - @Deprecated @com.google.firebase.vertexai.type.PublicPreviewAPI public final class Voices { - method @Deprecated public int getOrdinal(); - property @Deprecated public final int ordinal; - field @Deprecated public static final com.google.firebase.vertexai.type.Voices AOEDE; - field @Deprecated public static final com.google.firebase.vertexai.type.Voices CHARON; - field @Deprecated public static final com.google.firebase.vertexai.type.Voices.Companion Companion; - field @Deprecated public static final com.google.firebase.vertexai.type.Voices FENRIR; - field @Deprecated public static final com.google.firebase.vertexai.type.Voices KORE; - field @Deprecated public static final com.google.firebase.vertexai.type.Voices PUCK; - field @Deprecated public static final com.google.firebase.vertexai.type.Voices UNSPECIFIED; - } - - @Deprecated public static final class Voices.Companion { - } - -} - diff --git a/firebase-vertexai/consumer-rules.pro b/firebase-vertexai/consumer-rules.pro deleted file mode 100644 index f328794a748..00000000000 --- a/firebase-vertexai/consumer-rules.pro +++ /dev/null @@ -1,24 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile - --keep class com.google.firebase.vertexai.type.** { *; } --keep class com.google.firebase.vertexai.common.** { *; } diff --git a/firebase-vertexai/firebase-vertexai.gradle.kts b/firebase-vertexai/firebase-vertexai.gradle.kts deleted file mode 100644 index c73a23ba2b0..00000000000 --- a/firebase-vertexai/firebase-vertexai.gradle.kts +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@file:Suppress("UnstableApiUsage") - -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - -plugins { - id("firebase-library") - id("kotlin-android") - alias(libs.plugins.kotlinx.serialization) -} - -firebaseLibrary { - testLab.enabled = false - publishJavadoc = true - releaseNotes { - name.set("{{vertex_ai_in_firebase}}") - versionName.set("vertex-ai") - } -} - -android { - val targetSdkVersion: Int by rootProject - - namespace = "com.google.firebase.vertexai" - compileSdk = 34 - defaultConfig { - minSdk = rootProject.extra["minSdkVersion"] as Int - consumerProguardFiles("consumer-rules.pro") - multiDexEnabled = true - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - } - buildTypes { - release { - isMinifyEnabled = false - proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") - } - } - compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } - kotlinOptions { jvmTarget = "1.8" } - testOptions { - targetSdk = targetSdkVersion - unitTests { - isIncludeAndroidResources = true - isReturnDefaultValues = true - } - } - lint { - targetSdk = targetSdkVersion - baseline = file("lint-baseline.xml") - } - sourceSets { getByName("test").java.srcDirs("src/testUtil") } -} - -// Enable Kotlin "Explicit API Mode". This causes the Kotlin compiler to fail if any -// classes, methods, or properties have implicit `public` visibility. This check helps -// avoid accidentally leaking elements into the public API, requiring that any public -// element be explicitly declared as `public`. -// https://github.com/Kotlin/KEEP/blob/master/proposals/explicit-api-mode.md -// https://chao2zhang.medium.com/explicit-api-mode-for-kotlin-on-android-b8264fdd76d1 -tasks.withType().all { - if (!name.contains("test", ignoreCase = true)) { - if (!kotlinOptions.freeCompilerArgs.contains("-Xexplicit-api=strict")) { - kotlinOptions.freeCompilerArgs += "-Xexplicit-api=strict" - } - } -} - -dependencies { - implementation(libs.ktor.client.okhttp) - implementation(libs.ktor.client.core) - implementation(libs.ktor.client.websockets) - implementation(libs.ktor.client.content.negotiation) - implementation(libs.ktor.serialization.kotlinx.json) - implementation(libs.ktor.client.logging) - - api("com.google.firebase:firebase-common:22.0.0") - implementation("com.google.firebase:firebase-components:19.0.0") - implementation("com.google.firebase:firebase-annotations:17.0.0") - implementation("com.google.firebase:firebase-appcheck-interop:17.1.0") - implementation(libs.androidx.annotation) - implementation(libs.kotlinx.serialization.json) - implementation(libs.androidx.core.ktx) - implementation(libs.slf4j.nop) - implementation(libs.kotlinx.coroutines.android) - implementation(libs.kotlinx.coroutines.reactive) - implementation(libs.reactive.streams) - implementation("com.google.guava:listenablefuture:1.0") - implementation("androidx.concurrent:concurrent-futures:1.2.0") - implementation("androidx.concurrent:concurrent-futures-ktx:1.2.0") - implementation("com.google.firebase:firebase-auth-interop:18.0.0") - - testImplementation(libs.kotest.assertions.core) - testImplementation(libs.kotest.assertions) - testImplementation(libs.kotest.assertions.json) - testImplementation(libs.ktor.client.okhttp) - testImplementation(libs.ktor.client.mock) - testImplementation(libs.org.json) - testImplementation(libs.androidx.test.junit) - testImplementation(libs.androidx.test.runner) - testImplementation(libs.junit) - testImplementation(libs.kotlin.coroutines.test) - testImplementation(libs.robolectric) - testImplementation(libs.truth) - testImplementation(libs.mockito.core) - - androidTestImplementation(libs.androidx.espresso.core) - androidTestImplementation(libs.androidx.test.junit) - androidTestImplementation(libs.androidx.test.runner) - androidTestImplementation(libs.truth) -} diff --git a/firebase-vertexai/gradle.properties b/firebase-vertexai/gradle.properties deleted file mode 100644 index 6ce840e3977..00000000000 --- a/firebase-vertexai/gradle.properties +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2024 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -version=17.0.0 -latestReleasedVersion=16.5.0 diff --git a/firebase-vertexai/lint-baseline.xml b/firebase-vertexai/lint-baseline.xml deleted file mode 100644 index 5f6b1f3ebfd..00000000000 --- a/firebase-vertexai/lint-baseline.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - diff --git a/firebase-vertexai/proguard-rules.pro b/firebase-vertexai/proguard-rules.pro deleted file mode 100644 index f1b424510da..00000000000 --- a/firebase-vertexai/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile diff --git a/firebase-vertexai/src/main/AndroidManifest.xml b/firebase-vertexai/src/main/AndroidManifest.xml deleted file mode 100644 index 1a791682f4b..00000000000 --- a/firebase-vertexai/src/main/AndroidManifest.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/Chat.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/Chat.kt deleted file mode 100644 index bcf0ff5d9c0..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/Chat.kt +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai - -import android.graphics.Bitmap -import com.google.firebase.vertexai.type.Content -import com.google.firebase.vertexai.type.GenerateContentResponse -import com.google.firebase.vertexai.type.ImagePart -import com.google.firebase.vertexai.type.InlineDataPart -import com.google.firebase.vertexai.type.InvalidStateException -import com.google.firebase.vertexai.type.TextPart -import com.google.firebase.vertexai.type.content -import java.util.LinkedList -import java.util.concurrent.Semaphore -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.onCompletion -import kotlinx.coroutines.flow.onEach - -/** - * Representation of a multi-turn interaction with a model. - * - * Captures and stores the history of communication in memory, and provides it as context with each - * new message. - * - * **Note:** This object is not thread-safe, and calling [sendMessage] multiple times without - * waiting for a response will throw an [InvalidStateException]. - * - * @param model The model to use for the interaction. - * @property history The previous content from the chat that has been successfully sent and received - * from the model. This will be provided to the model for each message sent (as context for the - * discussion). - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class Chat( - private val model: GenerativeModel, - public val history: MutableList = ArrayList() -) { - private var lock = Semaphore(1) - - /** - * Sends a message using the provided [prompt]; automatically providing the existing [history] as - * context. - * - * If successful, the message and response will be added to the [history]. If unsuccessful, - * [history] will remain unchanged. - * - * @param prompt The input that, together with the history, will be given to the model as the - * prompt. - * @throws InvalidStateException if [prompt] is not coming from the 'user' role. - * @throws InvalidStateException if the [Chat] instance has an active request. - */ - public suspend fun sendMessage(prompt: Content): GenerateContentResponse { - prompt.assertComesFromUser() - attemptLock() - try { - val response = model.generateContent(*history.toTypedArray(), prompt) - history.add(prompt) - history.add(response.candidates.first().content) - return response - } finally { - lock.release() - } - } - - /** - * Sends a message using the provided [text prompt][prompt]; automatically providing the existing - * [history] as context. - * - * If successful, the message and response will be added to the [history]. If unsuccessful, - * [history] will remain unchanged. - * - * @param prompt The input that, together with the history, will be given to the model as the - * prompt. - * @throws InvalidStateException if [prompt] is not coming from the 'user' role. - * @throws InvalidStateException if the [Chat] instance has an active request. - */ - public suspend fun sendMessage(prompt: String): GenerateContentResponse { - val content = content { text(prompt) } - return sendMessage(content) - } - - /** - * Sends a message using the existing history of this chat as context and the provided image - * prompt. - * - * If successful, the message and response will be added to the history. If unsuccessful, history - * will remain unchanged. - * - * @param prompt The input that, together with the history, will be given to the model as the - * prompt. - * @throws InvalidStateException if [prompt] is not coming from the 'user' role. - * @throws InvalidStateException if the [Chat] instance has an active request. - */ - public suspend fun sendMessage(prompt: Bitmap): GenerateContentResponse { - val content = content { image(prompt) } - return sendMessage(content) - } - - /** - * Sends a message using the existing history of this chat as context and the provided [Content] - * prompt. - * - * The response from the model is returned as a stream. - * - * If successful, the message and response will be added to the history. If unsuccessful, history - * will remain unchanged. - * - * @param prompt The input that, together with the history, will be given to the model as the - * prompt. - * @throws InvalidStateException if [prompt] is not coming from the 'user' role. - * @throws InvalidStateException if the [Chat] instance has an active request. - */ - public fun sendMessageStream(prompt: Content): Flow { - prompt.assertComesFromUser() - attemptLock() - - val flow = model.generateContentStream(*history.toTypedArray(), prompt) - val bitmaps = LinkedList() - val inlineDataParts = LinkedList() - val text = StringBuilder() - - /** - * TODO: revisit when images and inline data are returned. This will cause issues with how - * things are structured in the response. eg; a text/image/text response will be (incorrectly) - * represented as image/text - */ - return flow - .onEach { - for (part in it.candidates.first().content.parts) { - when (part) { - is TextPart -> text.append(part.text) - is ImagePart -> bitmaps.add(part.image) - is InlineDataPart -> inlineDataParts.add(part) - } - } - } - .onCompletion { - lock.release() - if (it == null) { - val content = - content("model") { - for (bitmap in bitmaps) { - image(bitmap) - } - for (inlineDataPart in inlineDataParts) { - inlineData(inlineDataPart.inlineData, inlineDataPart.mimeType) - } - if (text.isNotBlank()) { - text(text.toString()) - } - } - - history.add(prompt) - history.add(content) - } - } - } - - /** - * Sends a message using the existing history of this chat as context and the provided text - * prompt. - * - * The response from the model is returned as a stream. - * - * If successful, the message and response will be added to the history. If unsuccessful, history - * will remain unchanged. - * - * @param prompt The input(s) that, together with the history, will be given to the model as the - * prompt. - * @throws InvalidStateException if [prompt] is not coming from the 'user' role. - * @throws InvalidStateException if the [Chat] instance has an active request. - */ - public fun sendMessageStream(prompt: String): Flow { - val content = content { text(prompt) } - return sendMessageStream(content) - } - - /** - * Sends a message using the existing history of this chat as context and the provided image - * prompt. - * - * The response from the model is returned as a stream. - * - * If successful, the message and response will be added to the history. If unsuccessful, history - * will remain unchanged. - * - * @param prompt The input that, together with the history, will be given to the model as the - * prompt. - * @throws InvalidStateException if [prompt] is not coming from the 'user' role. - * @throws InvalidStateException if the [Chat] instance has an active request. - */ - public fun sendMessageStream(prompt: Bitmap): Flow { - val content = content { image(prompt) } - return sendMessageStream(content) - } - - private fun Content.assertComesFromUser() { - if (role !in listOf("user", "function")) { - throw InvalidStateException("Chat prompts should come from the 'user' or 'function' role.") - } - } - - private fun attemptLock() { - if (!lock.tryAcquire()) { - throw InvalidStateException( - "This chat instance currently has an ongoing request, please wait for it to complete " + - "before sending more messages" - ) - } - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/FirebaseVertexAI.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/FirebaseVertexAI.kt deleted file mode 100644 index 411c9c0c8b1..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/FirebaseVertexAI.kt +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai - -import android.util.Log -import com.google.firebase.Firebase -import com.google.firebase.FirebaseApp -import com.google.firebase.annotations.concurrent.Blocking -import com.google.firebase.app -import com.google.firebase.appcheck.interop.InteropAppCheckTokenProvider -import com.google.firebase.auth.internal.InternalAuthProvider -import com.google.firebase.inject.Provider -import com.google.firebase.vertexai.type.Content -import com.google.firebase.vertexai.type.GenerationConfig -import com.google.firebase.vertexai.type.ImagenGenerationConfig -import com.google.firebase.vertexai.type.ImagenSafetySettings -import com.google.firebase.vertexai.type.InvalidLocationException -import com.google.firebase.vertexai.type.LiveGenerationConfig -import com.google.firebase.vertexai.type.PublicPreviewAPI -import com.google.firebase.vertexai.type.RequestOptions -import com.google.firebase.vertexai.type.SafetySetting -import com.google.firebase.vertexai.type.Tool -import com.google.firebase.vertexai.type.ToolConfig -import kotlin.coroutines.CoroutineContext - -/** Entry point for all _Vertex AI in Firebase_ functionality. */ -public class FirebaseVertexAI -internal constructor( - private val firebaseApp: FirebaseApp, - @Blocking private val blockingDispatcher: CoroutineContext, - private val location: String, - private val appCheckProvider: Provider, - private val internalAuthProvider: Provider, -) { - - /** - * Instantiates a new [GenerativeModel] given the provided parameters. - * - * @param modelName The name of the model to use, for example `"gemini-2.0-flash-exp"`. - * @param generationConfig The configuration parameters to use for content generation. - * @param safetySettings The safety bounds the model will abide to during content generation. - * @param tools A list of [Tool]s the model may use to generate content. - * @param toolConfig The [ToolConfig] that defines how the model handles the tools provided. - * @param systemInstruction [Content] instructions that direct the model to behave a certain way. - * Currently only text content is supported. - * @param requestOptions Configuration options for sending requests to the backend. - * @return The initialized [GenerativeModel] instance. - */ - @JvmOverloads - public fun generativeModel( - modelName: String, - generationConfig: GenerationConfig? = null, - safetySettings: List? = null, - tools: List? = null, - toolConfig: ToolConfig? = null, - systemInstruction: Content? = null, - requestOptions: RequestOptions = RequestOptions(), - ): GenerativeModel { - if (location.trim().isEmpty() || location.contains("/")) { - throw InvalidLocationException(location) - } - if (!modelName.startsWith(GEMINI_MODEL_NAME_PREFIX)) { - Log.w( - TAG, - """Unsupported Gemini model "${modelName}"; see - https://firebase.google.com/docs/vertex-ai/models for a list supported Gemini model names. - """ - .trimIndent() - ) - } - return GenerativeModel( - "projects/${firebaseApp.options.projectId}/locations/${location}/publishers/google/models/${modelName}", - firebaseApp.options.apiKey, - firebaseApp, - generationConfig, - safetySettings, - tools, - toolConfig, - systemInstruction, - requestOptions, - appCheckProvider.get(), - internalAuthProvider.get(), - ) - } - - /** - * Instantiates a new [LiveGenerationConfig] given the provided parameters. - * - * @param modelName The name of the model to use, for example `"gemini-2.0-flash-exp"`. - * @param generationConfig The configuration parameters to use for content generation. - * @param tools A list of [Tool]s the model may use to generate content. - * @param systemInstruction [Content] instructions that direct the model to behave a certain way. - * Currently only text content is supported. - * @param requestOptions Configuration options for sending requests to the backend. - * @return The initialized [LiveGenerativeModel] instance. - */ - @JvmOverloads - @PublicPreviewAPI - public fun liveModel( - modelName: String, - generationConfig: LiveGenerationConfig? = null, - tools: List? = null, - systemInstruction: Content? = null, - requestOptions: RequestOptions = RequestOptions(), - ): LiveGenerativeModel { - if (!modelName.startsWith(GEMINI_MODEL_NAME_PREFIX)) { - Log.w( - TAG, - """Unsupported Gemini model "$modelName"; see - https://firebase.google.com/docs/vertex-ai/models for a list supported Gemini model names. - """ - .trimIndent() - ) - } - if (location.trim().isEmpty() || location.contains("/")) { - throw InvalidLocationException(location) - } - return LiveGenerativeModel( - "projects/${firebaseApp.options.projectId}/locations/${location}/publishers/google/models/${modelName}", - firebaseApp.options.apiKey, - firebaseApp, - blockingDispatcher, - generationConfig, - tools, - systemInstruction, - location, - requestOptions, - appCheckProvider.get(), - internalAuthProvider.get(), - ) - } - - /** - * Instantiates a new [ImagenModel] given the provided parameters. - * - * @param modelName The name of the model to use, for example `"imagen-3.0-generate-001"`. - * @param generationConfig The configuration parameters to use for image generation. - * @param safetySettings The safety bounds the model will abide by during image generation. - * @param requestOptions Configuration options for sending requests to the backend. - * @return The initialized [ImagenModel] instance. - */ - @JvmOverloads - @PublicPreviewAPI - public fun imagenModel( - modelName: String, - generationConfig: ImagenGenerationConfig? = null, - safetySettings: ImagenSafetySettings? = null, - requestOptions: RequestOptions = RequestOptions(), - ): ImagenModel { - if (location.trim().isEmpty() || location.contains("/")) { - throw InvalidLocationException(location) - } - if (!modelName.startsWith(IMAGEN_MODEL_NAME_PREFIX)) { - Log.w( - TAG, - """Unsupported Imagen model "${modelName}"; see - https://firebase.google.com/docs/vertex-ai/models for a list supported Imagen model names. - """ - .trimIndent() - ) - } - return ImagenModel( - "projects/${firebaseApp.options.projectId}/locations/${location}/publishers/google/models/${modelName}", - firebaseApp.options.apiKey, - firebaseApp, - generationConfig, - safetySettings, - requestOptions, - appCheckProvider.get(), - internalAuthProvider.get(), - ) - } - - public companion object { - /** The [FirebaseVertexAI] instance for the default [FirebaseApp] */ - @JvmStatic - public val instance: FirebaseVertexAI - get() = getInstance(location = "us-central1") - - @JvmStatic public fun getInstance(app: FirebaseApp): FirebaseVertexAI = getInstance(app) - - /** - * Returns the [FirebaseVertexAI] instance for the provided [FirebaseApp] and [location]. - * - * @param location location identifier, defaults to `us-central1`; see available - * [Vertex AI regions](https://firebase.google.com/docs/vertex-ai/locations?platform=android#available-locations) - * . - */ - @JvmStatic - @JvmOverloads - public fun getInstance(app: FirebaseApp = Firebase.app, location: String): FirebaseVertexAI { - val multiResourceComponent = app[FirebaseVertexAIMultiResourceComponent::class.java] - return multiResourceComponent.get(location) - } - - private const val GEMINI_MODEL_NAME_PREFIX = "gemini-" - - private const val IMAGEN_MODEL_NAME_PREFIX = "imagen-" - - private val TAG = FirebaseVertexAI::class.java.simpleName - } -} - -/** Returns the [FirebaseVertexAI] instance of the default [FirebaseApp]. */ -public val Firebase.vertexAI: FirebaseVertexAI - get() = FirebaseVertexAI.instance - -/** Returns the [FirebaseVertexAI] instance of a given [FirebaseApp]. */ -public fun Firebase.vertexAI( - app: FirebaseApp = Firebase.app, - location: String = "us-central1" -): FirebaseVertexAI = FirebaseVertexAI.getInstance(app, location) diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/FirebaseVertexAIMultiResourceComponent.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/FirebaseVertexAIMultiResourceComponent.kt deleted file mode 100644 index 02e962951f9..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/FirebaseVertexAIMultiResourceComponent.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai - -import androidx.annotation.GuardedBy -import com.google.firebase.FirebaseApp -import com.google.firebase.annotations.concurrent.Blocking -import com.google.firebase.appcheck.interop.InteropAppCheckTokenProvider -import com.google.firebase.auth.internal.InternalAuthProvider -import com.google.firebase.inject.Provider -import kotlin.coroutines.CoroutineContext - -/** - * Multi-resource container for Vertex AI in Firebase. - * - * @hide - */ -internal class FirebaseVertexAIMultiResourceComponent( - private val app: FirebaseApp, - @Blocking val blockingDispatcher: CoroutineContext, - private val appCheckProvider: Provider, - private val internalAuthProvider: Provider, -) { - - @GuardedBy("this") private val instances: MutableMap = mutableMapOf() - - fun get(location: String): FirebaseVertexAI = - synchronized(this) { - instances[location] - ?: FirebaseVertexAI( - app, - blockingDispatcher, - location, - appCheckProvider, - internalAuthProvider - ) - .also { instances[location] = it } - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/FirebaseVertexAIRegistrar.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/FirebaseVertexAIRegistrar.kt deleted file mode 100644 index 13cb73cdb71..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/FirebaseVertexAIRegistrar.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai - -import androidx.annotation.Keep -import com.google.firebase.FirebaseApp -import com.google.firebase.annotations.concurrent.Blocking -import com.google.firebase.appcheck.interop.InteropAppCheckTokenProvider -import com.google.firebase.auth.internal.InternalAuthProvider -import com.google.firebase.components.Component -import com.google.firebase.components.ComponentRegistrar -import com.google.firebase.components.Dependency -import com.google.firebase.components.Qualified -import com.google.firebase.components.Qualified.unqualified -import com.google.firebase.platforminfo.LibraryVersionComponent -import kotlinx.coroutines.CoroutineDispatcher - -/** - * [ComponentRegistrar] for setting up [FirebaseVertexAI] and its internal dependencies. - * - * @hide - */ -@Keep -internal class FirebaseVertexAIRegistrar : ComponentRegistrar { - override fun getComponents() = - listOf( - Component.builder(FirebaseVertexAIMultiResourceComponent::class.java) - .name(LIBRARY_NAME) - .add(Dependency.required(firebaseApp)) - .add(Dependency.required(blockingDispatcher)) - .add(Dependency.optionalProvider(appCheckInterop)) - .add(Dependency.optionalProvider(internalAuthProvider)) - .factory { container -> - FirebaseVertexAIMultiResourceComponent( - container[firebaseApp], - container.get(blockingDispatcher), - container.getProvider(appCheckInterop), - container.getProvider(internalAuthProvider) - ) - } - .build(), - LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME), - ) - - private companion object { - private const val LIBRARY_NAME = "fire-vertex" - - private val firebaseApp = unqualified(FirebaseApp::class.java) - private val appCheckInterop = unqualified(InteropAppCheckTokenProvider::class.java) - private val internalAuthProvider = unqualified(InternalAuthProvider::class.java) - private val blockingDispatcher = - Qualified.qualified(Blocking::class.java, CoroutineDispatcher::class.java) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/GenerativeModel.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/GenerativeModel.kt deleted file mode 100644 index 3a04907cacc..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/GenerativeModel.kt +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai - -import android.graphics.Bitmap -import com.google.firebase.FirebaseApp -import com.google.firebase.appcheck.interop.InteropAppCheckTokenProvider -import com.google.firebase.auth.internal.InternalAuthProvider -import com.google.firebase.vertexai.common.APIController -import com.google.firebase.vertexai.common.AppCheckHeaderProvider -import com.google.firebase.vertexai.common.CountTokensRequest -import com.google.firebase.vertexai.common.GenerateContentRequest -import com.google.firebase.vertexai.type.Content -import com.google.firebase.vertexai.type.CountTokensResponse -import com.google.firebase.vertexai.type.FinishReason -import com.google.firebase.vertexai.type.FirebaseVertexAIException -import com.google.firebase.vertexai.type.GenerateContentResponse -import com.google.firebase.vertexai.type.GenerationConfig -import com.google.firebase.vertexai.type.PromptBlockedException -import com.google.firebase.vertexai.type.RequestOptions -import com.google.firebase.vertexai.type.ResponseStoppedException -import com.google.firebase.vertexai.type.SafetySetting -import com.google.firebase.vertexai.type.SerializationException -import com.google.firebase.vertexai.type.Tool -import com.google.firebase.vertexai.type.ToolConfig -import com.google.firebase.vertexai.type.content -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.map -import kotlinx.serialization.ExperimentalSerializationApi - -/** - * Represents a multimodal model (like Gemini), capable of generating content based on various input - * types. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class GenerativeModel -internal constructor( - private val modelName: String, - private val generationConfig: GenerationConfig? = null, - private val safetySettings: List? = null, - private val tools: List? = null, - private val toolConfig: ToolConfig? = null, - private val systemInstruction: Content? = null, - private val controller: APIController, -) { - internal constructor( - modelName: String, - apiKey: String, - firebaseApp: FirebaseApp, - generationConfig: GenerationConfig? = null, - safetySettings: List? = null, - tools: List? = null, - toolConfig: ToolConfig? = null, - systemInstruction: Content? = null, - requestOptions: RequestOptions = RequestOptions(), - appCheckTokenProvider: InteropAppCheckTokenProvider? = null, - internalAuthProvider: InternalAuthProvider? = null, - ) : this( - modelName, - generationConfig, - safetySettings, - tools, - toolConfig, - systemInstruction, - APIController( - apiKey, - modelName, - requestOptions, - "gl-kotlin/${KotlinVersion.CURRENT} fire/${BuildConfig.VERSION_NAME}", - firebaseApp, - AppCheckHeaderProvider(TAG, appCheckTokenProvider, internalAuthProvider), - ), - ) - - /** - * Generates new content from the input [Content] given to the model as a prompt. - * - * @param prompt The input(s) given to the model as a prompt. - * @return The content generated by the model. - * @throws [FirebaseVertexAIException] if the request failed. - * @see [FirebaseVertexAIException] for types of errors. - */ - public suspend fun generateContent(vararg prompt: Content): GenerateContentResponse = - try { - controller.generateContent(constructRequest(*prompt)).toPublic().validate() - } catch (e: Throwable) { - throw FirebaseVertexAIException.from(e) - } - - /** - * Generates new content as a stream from the input [Content] given to the model as a prompt. - * - * @param prompt The input(s) given to the model as a prompt. - * @return A [Flow] which will emit responses as they are returned by the model. - * @throws [FirebaseVertexAIException] if the request failed. - * @see [FirebaseVertexAIException] for types of errors. - */ - public fun generateContentStream(vararg prompt: Content): Flow = - controller - .generateContentStream(constructRequest(*prompt)) - .catch { throw FirebaseVertexAIException.from(it) } - .map { it.toPublic().validate() } - - /** - * Generates new content from the text input given to the model as a prompt. - * - * @param prompt The text to be send to the model as a prompt. - * @return The content generated by the model. - * @throws [FirebaseVertexAIException] if the request failed. - * @see [FirebaseVertexAIException] for types of errors. - */ - public suspend fun generateContent(prompt: String): GenerateContentResponse = - generateContent(content { text(prompt) }) - - /** - * Generates new content as a stream from the text input given to the model as a prompt. - * - * @param prompt The text to be send to the model as a prompt. - * @return A [Flow] which will emit responses as they are returned by the model. - * @throws [FirebaseVertexAIException] if the request failed. - * @see [FirebaseVertexAIException] for types of errors. - */ - public fun generateContentStream(prompt: String): Flow = - generateContentStream(content { text(prompt) }) - - /** - * Generates new content from the image input given to the model as a prompt. - * - * @param prompt The image to be converted into a single piece of [Content] to send to the model. - * @return A [GenerateContentResponse] after some delay. - * @throws [FirebaseVertexAIException] if the request failed. - * @see [FirebaseVertexAIException] for types of errors. - */ - public suspend fun generateContent(prompt: Bitmap): GenerateContentResponse = - generateContent(content { image(prompt) }) - - /** - * Generates new content as a stream from the image input given to the model as a prompt. - * - * @param prompt The image to be converted into a single piece of [Content] to send to the model. - * @return A [Flow] which will emit responses as they are returned by the model. - * @throws [FirebaseVertexAIException] if the request failed. - * @see [FirebaseVertexAIException] for types of errors. - */ - public fun generateContentStream(prompt: Bitmap): Flow = - generateContentStream(content { image(prompt) }) - - /** Creates a [Chat] instance using this model with the optionally provided history. */ - public fun startChat(history: List = emptyList()): Chat = - Chat(this, history.toMutableList()) - - /** - * Counts the number of tokens in a prompt using the model's tokenizer. - * - * @param prompt The input(s) given to the model as a prompt. - * @return The [CountTokensResponse] of running the model's tokenizer on the input. - * @throws [FirebaseVertexAIException] if the request failed. - * @see [FirebaseVertexAIException] for types of errors. - */ - public suspend fun countTokens(vararg prompt: Content): CountTokensResponse { - try { - return controller.countTokens(constructCountTokensRequest(*prompt)).toPublic() - } catch (e: Throwable) { - throw FirebaseVertexAIException.from(e) - } - } - - /** - * Counts the number of tokens in a text prompt using the model's tokenizer. - * - * @param prompt The text given to the model as a prompt. - * @return The [CountTokensResponse] of running the model's tokenizer on the input. - * @throws [FirebaseVertexAIException] if the request failed. - * @see [FirebaseVertexAIException] for types of errors. - */ - public suspend fun countTokens(prompt: String): CountTokensResponse { - return countTokens(content { text(prompt) }) - } - - /** - * Counts the number of tokens in an image prompt using the model's tokenizer. - * - * @param prompt The image given to the model as a prompt. - * @return The [CountTokensResponse] of running the model's tokenizer on the input. - * @throws [FirebaseVertexAIException] if the request failed. - * @see [FirebaseVertexAIException] for types of errors. - */ - public suspend fun countTokens(prompt: Bitmap): CountTokensResponse { - return countTokens(content { image(prompt) }) - } - - @OptIn(ExperimentalSerializationApi::class) - private fun constructRequest(vararg prompt: Content) = - GenerateContentRequest( - modelName, - prompt.map { it.toInternal() }, - safetySettings?.map { it.toInternal() }, - generationConfig?.toInternal(), - tools?.map { it.toInternal() }, - toolConfig?.toInternal(), - systemInstruction?.copy(role = "system")?.toInternal(), - ) - - private fun constructCountTokensRequest(vararg prompt: Content) = - CountTokensRequest.forVertexAI(constructRequest(*prompt)) - - private fun GenerateContentResponse.validate() = apply { - if (candidates.isEmpty() && promptFeedback == null) { - throw SerializationException("Error deserializing response, found no valid fields") - } - promptFeedback?.blockReason?.let { throw PromptBlockedException(this) } - candidates - .mapNotNull { it.finishReason } - .firstOrNull { it != FinishReason.STOP } - ?.let { throw ResponseStoppedException(this) } - } - - private companion object { - private val TAG = GenerativeModel::class.java.simpleName - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/ImagenModel.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/ImagenModel.kt deleted file mode 100644 index 30868aeb214..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/ImagenModel.kt +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai - -import com.google.firebase.FirebaseApp -import com.google.firebase.appcheck.interop.InteropAppCheckTokenProvider -import com.google.firebase.auth.internal.InternalAuthProvider -import com.google.firebase.vertexai.common.APIController -import com.google.firebase.vertexai.common.AppCheckHeaderProvider -import com.google.firebase.vertexai.common.ContentBlockedException -import com.google.firebase.vertexai.common.GenerateImageRequest -import com.google.firebase.vertexai.type.FirebaseVertexAIException -import com.google.firebase.vertexai.type.ImagenGenerationConfig -import com.google.firebase.vertexai.type.ImagenGenerationResponse -import com.google.firebase.vertexai.type.ImagenInlineImage -import com.google.firebase.vertexai.type.ImagenSafetySettings -import com.google.firebase.vertexai.type.PublicPreviewAPI -import com.google.firebase.vertexai.type.RequestOptions - -/** - * Represents a generative model (like Imagen), capable of generating images based on various input - * types. - */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ImagenModel -internal constructor( - private val modelName: String, - private val generationConfig: ImagenGenerationConfig? = null, - private val safetySettings: ImagenSafetySettings? = null, - private val controller: APIController, -) { - @JvmOverloads - internal constructor( - modelName: String, - apiKey: String, - firebaseApp: FirebaseApp, - generationConfig: ImagenGenerationConfig? = null, - safetySettings: ImagenSafetySettings? = null, - requestOptions: RequestOptions = RequestOptions(), - appCheckTokenProvider: InteropAppCheckTokenProvider? = null, - internalAuthProvider: InternalAuthProvider? = null, - ) : this( - modelName, - generationConfig, - safetySettings, - APIController( - apiKey, - modelName, - requestOptions, - "gl-kotlin/${KotlinVersion.CURRENT} fire/${BuildConfig.VERSION_NAME}", - firebaseApp, - AppCheckHeaderProvider(TAG, appCheckTokenProvider, internalAuthProvider), - ), - ) - - /** - * Generates an image, returning the result directly to the caller. - * - * @param prompt The input(s) given to the model as a prompt. - */ - public suspend fun generateImages(prompt: String): ImagenGenerationResponse = - try { - controller - .generateImage(constructRequest(prompt, null, generationConfig)) - .validate() - .toPublicInline() - } catch (e: Throwable) { - throw FirebaseVertexAIException.from(e) - } - - private fun constructRequest( - prompt: String, - gcsUri: String?, - config: ImagenGenerationConfig?, - ): GenerateImageRequest { - return GenerateImageRequest( - listOf(GenerateImageRequest.ImagenPrompt(prompt)), - GenerateImageRequest.ImagenParameters( - sampleCount = config?.numberOfImages ?: 1, - includeRaiReason = true, - addWatermark = generationConfig?.addWatermark, - personGeneration = safetySettings?.personFilterLevel?.internalVal, - negativePrompt = config?.negativePrompt, - safetySetting = safetySettings?.safetyFilterLevel?.internalVal, - storageUri = gcsUri, - aspectRatio = config?.aspectRatio?.internalVal, - imageOutputOptions = generationConfig?.imageFormat?.toInternal(), - ), - ) - } - - internal companion object { - private val TAG = ImagenModel::class.java.simpleName - internal const val DEFAULT_FILTERED_ERROR = - "Unable to show generated images. All images were filtered out because they violated Vertex AI's usage guidelines. You will not be charged for blocked images. Try rephrasing the prompt. If you think this was an error, send feedback." - } -} - -@OptIn(PublicPreviewAPI::class) -private fun ImagenGenerationResponse.Internal.validate(): ImagenGenerationResponse.Internal { - if (predictions.none { it.mimeType != null }) { - throw ContentBlockedException( - message = predictions.first { it.raiFilteredReason != null }.raiFilteredReason - ?: ImagenModel.DEFAULT_FILTERED_ERROR - ) - } - return this -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/LiveGenerativeModel.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/LiveGenerativeModel.kt deleted file mode 100644 index d384793eb68..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/LiveGenerativeModel.kt +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai - -import com.google.firebase.FirebaseApp -import com.google.firebase.annotations.concurrent.Blocking -import com.google.firebase.appcheck.interop.InteropAppCheckTokenProvider -import com.google.firebase.auth.internal.InternalAuthProvider -import com.google.firebase.vertexai.common.APIController -import com.google.firebase.vertexai.common.AppCheckHeaderProvider -import com.google.firebase.vertexai.common.JSON -import com.google.firebase.vertexai.type.Content -import com.google.firebase.vertexai.type.LiveClientSetupMessage -import com.google.firebase.vertexai.type.LiveGenerationConfig -import com.google.firebase.vertexai.type.LiveSession -import com.google.firebase.vertexai.type.PublicPreviewAPI -import com.google.firebase.vertexai.type.RequestOptions -import com.google.firebase.vertexai.type.ServiceConnectionHandshakeFailedException -import com.google.firebase.vertexai.type.Tool -import io.ktor.websocket.Frame -import io.ktor.websocket.close -import io.ktor.websocket.readBytes -import kotlin.coroutines.CoroutineContext -import kotlinx.coroutines.channels.ClosedReceiveChannelException -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonObject - -/** - * Represents a multimodal model (like Gemini) capable of real-time content generation based on - * various input types, supporting bidirectional streaming. - */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class LiveGenerativeModel -internal constructor( - private val modelName: String, - @Blocking private val blockingDispatcher: CoroutineContext, - private val config: LiveGenerationConfig? = null, - private val tools: List? = null, - private val systemInstruction: Content? = null, - private val location: String, - private val controller: APIController -) { - internal constructor( - modelName: String, - apiKey: String, - firebaseApp: FirebaseApp, - blockingDispatcher: CoroutineContext, - config: LiveGenerationConfig? = null, - tools: List? = null, - systemInstruction: Content? = null, - location: String = "us-central1", - requestOptions: RequestOptions = RequestOptions(), - appCheckTokenProvider: InteropAppCheckTokenProvider? = null, - internalAuthProvider: InternalAuthProvider? = null, - ) : this( - modelName, - blockingDispatcher, - config, - tools, - systemInstruction, - location, - APIController( - apiKey, - modelName, - requestOptions, - "gl-kotlin/${KotlinVersion.CURRENT} fire/${BuildConfig.VERSION_NAME}", - firebaseApp, - AppCheckHeaderProvider(TAG, appCheckTokenProvider, internalAuthProvider), - ), - ) - - /** - * Start a [LiveSession] with the server for bidirectional streaming. - * - * @return A [LiveSession] that you can use to stream messages to and from the server. - * @throws [ServiceConnectionHandshakeFailedException] If the client was not able to establish a - * connection with the server. - */ - @OptIn(ExperimentalSerializationApi::class) - public suspend fun connect(): LiveSession { - val clientMessage = - LiveClientSetupMessage( - modelName, - config?.toInternal(), - tools?.map { it.toInternal() }, - systemInstruction?.toInternal() - ) - .toInternal() - val data: String = Json.encodeToString(clientMessage) - try { - val webSession = controller.getWebSocketSession(location) - webSession.send(Frame.Text(data)) - val receivedJsonStr = webSession.incoming.receive().readBytes().toString(Charsets.UTF_8) - val receivedJson = JSON.parseToJsonElement(receivedJsonStr) - - return if (receivedJson is JsonObject && "setupComplete" in receivedJson) { - LiveSession(session = webSession, blockingDispatcher = blockingDispatcher) - } else { - webSession.close() - throw ServiceConnectionHandshakeFailedException("Unable to connect to the server") - } - } catch (e: ClosedReceiveChannelException) { - throw ServiceConnectionHandshakeFailedException("Channel was closed by the server", e) - } - } - - private companion object { - private val TAG = LiveGenerativeModel::class.java.simpleName - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/APIController.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/APIController.kt deleted file mode 100644 index 9f5d105328e..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/APIController.kt +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.common - -import android.util.Log -import com.google.firebase.Firebase -import com.google.firebase.FirebaseApp -import com.google.firebase.options -import com.google.firebase.vertexai.common.util.decodeToFlow -import com.google.firebase.vertexai.common.util.fullModelName -import com.google.firebase.vertexai.type.CountTokensResponse -import com.google.firebase.vertexai.type.FinishReason -import com.google.firebase.vertexai.type.GRpcErrorResponse -import com.google.firebase.vertexai.type.GenerateContentResponse -import com.google.firebase.vertexai.type.ImagenGenerationResponse -import com.google.firebase.vertexai.type.PublicPreviewAPI -import com.google.firebase.vertexai.type.RequestOptions -import com.google.firebase.vertexai.type.Response -import io.ktor.client.HttpClient -import io.ktor.client.call.body -import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.engine.okhttp.OkHttp -import io.ktor.client.plugins.HttpTimeout -import io.ktor.client.plugins.contentnegotiation.ContentNegotiation -import io.ktor.client.plugins.websocket.ClientWebSocketSession -import io.ktor.client.plugins.websocket.WebSockets -import io.ktor.client.plugins.websocket.webSocketSession -import io.ktor.client.request.HttpRequestBuilder -import io.ktor.client.request.header -import io.ktor.client.request.post -import io.ktor.client.request.preparePost -import io.ktor.client.request.setBody -import io.ktor.client.statement.HttpResponse -import io.ktor.client.statement.bodyAsChannel -import io.ktor.client.statement.bodyAsText -import io.ktor.http.ContentType -import io.ktor.http.HttpStatusCode -import io.ktor.http.contentType -import io.ktor.http.withCharset -import io.ktor.serialization.kotlinx.json.json -import io.ktor.utils.io.charsets.Charset -import kotlin.math.max -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds -import kotlinx.coroutines.CoroutineName -import kotlinx.coroutines.TimeoutCancellationException -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.channelFlow -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.launch -import kotlinx.coroutines.withTimeout -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.json.Json - -@OptIn(ExperimentalSerializationApi::class) -internal val JSON = Json { - ignoreUnknownKeys = true - prettyPrint = false - isLenient = true - explicitNulls = false -} - -/** - * Backend class for interfacing with the Gemini API. - * - * This class handles making HTTP requests to the API and streaming the responses back. - * - * @param httpEngine The HTTP client engine to be used for making requests. Defaults to CIO engine. - * Exposed primarily for DI in tests. - * @property key The API key used for authentication. - * @property model The model to use for generation. - * @property apiClient The value to pass in the `x-goog-api-client` header. - * @property headerProvider A provider that generates extra headers to include in all HTTP requests. - */ -@OptIn(PublicPreviewAPI::class) -internal class APIController -internal constructor( - private val key: String, - model: String, - private val requestOptions: RequestOptions, - httpEngine: HttpClientEngine, - private val apiClient: String, - private val firebaseApp: FirebaseApp, - private val appVersion: Int = 0, - private val googleAppId: String, - private val headerProvider: HeaderProvider?, -) { - - constructor( - key: String, - model: String, - requestOptions: RequestOptions, - apiClient: String, - firebaseApp: FirebaseApp, - headerProvider: HeaderProvider? = null, - ) : this( - key, - model, - requestOptions, - OkHttp.create(), - apiClient, - firebaseApp, - getVersionNumber(firebaseApp), - firebaseApp.options.applicationId, - headerProvider - ) - - private val model = fullModelName(model) - - private val client = - HttpClient(httpEngine) { - install(HttpTimeout) { - requestTimeoutMillis = requestOptions.timeout.inWholeMilliseconds - socketTimeoutMillis = - max(180.seconds.inWholeMilliseconds, requestOptions.timeout.inWholeMilliseconds) - } - install(WebSockets) - install(ContentNegotiation) { json(JSON) } - } - - suspend fun generateContent(request: GenerateContentRequest): GenerateContentResponse.Internal = - try { - client - .post("${requestOptions.endpoint}/${requestOptions.apiVersion}/$model:generateContent") { - applyCommonConfiguration(request) - applyHeaderProvider() - } - .also { validateResponse(it) } - .body() - .validate() - } catch (e: Throwable) { - throw FirebaseCommonAIException.from(e) - } - - suspend fun generateImage(request: GenerateImageRequest): ImagenGenerationResponse.Internal = - try { - client - .post("${requestOptions.endpoint}/${requestOptions.apiVersion}/$model:predict") { - applyCommonConfiguration(request) - applyHeaderProvider() - } - .also { validateResponse(it) } - .body() - } catch (e: Throwable) { - throw FirebaseCommonAIException.from(e) - } - - private fun getBidiEndpoint(location: String): String = - "wss://firebasevertexai.googleapis.com/ws/google.firebase.vertexai.v1beta.LlmBidiService/BidiGenerateContent/locations/$location?key=$key" - - suspend fun getWebSocketSession(location: String): ClientWebSocketSession = - client.webSocketSession(getBidiEndpoint(location)) { applyCommonHeaders() } - - fun generateContentStream( - request: GenerateContentRequest - ): Flow = - client - .postStream( - "${requestOptions.endpoint}/${requestOptions.apiVersion}/$model:streamGenerateContent?alt=sse" - ) { - applyCommonConfiguration(request) - } - .map { it.validate() } - .catch { throw FirebaseCommonAIException.from(it) } - - suspend fun countTokens(request: CountTokensRequest): CountTokensResponse.Internal = - try { - client - .post("${requestOptions.endpoint}/${requestOptions.apiVersion}/$model:countTokens") { - applyCommonConfiguration(request) - applyHeaderProvider() - } - .also { validateResponse(it) } - .body() - } catch (e: Throwable) { - throw FirebaseCommonAIException.from(e) - } - - private fun HttpRequestBuilder.applyCommonConfiguration(request: Request) { - when (request) { - is GenerateContentRequest -> setBody(request) - is CountTokensRequest -> setBody(request) - is GenerateImageRequest -> setBody(request) - } - - applyCommonHeaders() - } - - private fun HttpRequestBuilder.applyCommonHeaders() { - contentType(ContentType.Application.Json) - header("x-goog-api-key", key) - header("x-goog-api-client", apiClient) - if (firebaseApp.isDataCollectionDefaultEnabled) { - header("X-Firebase-AppId", googleAppId) - header("X-Firebase-AppVersion", appVersion) - } - } - - private suspend fun HttpRequestBuilder.applyHeaderProvider() { - if (headerProvider != null) { - try { - withTimeout(headerProvider.timeout) { - for ((tag, value) in headerProvider.generateHeaders()) { - header(tag, value) - } - } - } catch (e: TimeoutCancellationException) { - Log.w(TAG, "HeaderProvided timed out without generating headers, ignoring") - } - } - } - - /** - * Makes a POST request to the specified [url] and returns a [Flow] of deserialized response - * objects of type [R]. The response is expected to be a stream of JSON objects that are parsed in - * real-time as they are received from the server. - * - * This function is intended for internal use within the client that handles streaming responses. - * - * Example usage: - * ``` - * val client: HttpClient = HttpClient(CIO) - * val request: Request = GenerateContentRequest(...) - * val url: String = "http://example.com/stream" - * - * val responses: GenerateContentResponse = client.postStream(url) { - * setBody(request) - * contentType(ContentType.Application.Json) - * } - * responses.collect { - * println("Got a response: $it") - * } - * ``` - * - * @param R The type of the response object. - * @param url The URL to which the POST request will be made. - * @param config An optional [HttpRequestBuilder] callback for request configuration. - * @return A [Flow] of response objects of type [R]. - */ - private inline fun HttpClient.postStream( - url: String, - crossinline config: HttpRequestBuilder.() -> Unit = {}, - ): Flow = channelFlow { - launch(CoroutineName("postStream")) { - preparePost(url) { - applyHeaderProvider() - config() - } - .execute { - validateResponse(it) - - val channel = it.bodyAsChannel() - val flow = JSON.decodeToFlow(channel) - - flow.collect { send(it) } - } - } - } - - companion object { - private val TAG = APIController::class.java.simpleName - - private fun getVersionNumber(app: FirebaseApp): Int { - try { - val context = app.applicationContext - return context.packageManager.getPackageInfo(context.packageName, 0).versionCode - } catch (e: Exception) { - Log.d(TAG, "Error while getting app version: ${e.message}") - return 0 - } - } - } -} - -internal interface HeaderProvider { - val timeout: Duration - - suspend fun generateHeaders(): Map -} - -private suspend fun validateResponse(response: HttpResponse) { - if (response.status == HttpStatusCode.OK) return - - val htmlContentType = ContentType.Text.Html.withCharset(Charset.forName("utf-8")) - if (response.status == HttpStatusCode.NotFound && response.contentType() == htmlContentType) - throw ServerException( - """URL not found. Please verify the location used to create the `FirebaseVertexAI` object - | See https://cloud.google.com/vertex-ai/generative-ai/docs/learn/locations#available-regions - | for the list of available locations. Raw response: ${response.bodyAsText()}""" - .trimMargin() - ) - val text = response.bodyAsText() - val error = - try { - JSON.decodeFromString(text).error - } catch (e: Throwable) { - throw ServerException("Unexpected Response:\n$text $e") - } - val message = error.message - if (message.contains("API key not valid")) { - throw InvalidAPIKeyException(message) - } - // TODO (b/325117891): Use a better method than string matching. - if (message == "User location is not supported for the API use.") { - throw UnsupportedUserLocationException() - } - if (message.contains("quota")) { - throw QuotaExceededException(message) - } - if (message.contains("The prompt could not be submitted")) { - throw PromptBlockedException(message) - } - getServiceDisabledErrorDetailsOrNull(error)?.let { - val errorMessage = - if (it.metadata?.get("service") == "firebasevertexai.googleapis.com") { - """ - The Vertex AI in Firebase SDK requires the Vertex AI in Firebase API - (`firebasevertexai.googleapis.com`) to be enabled in your Firebase project. Enable this API - by visiting the Firebase Console at - https://console.firebase.google.com/project/${Firebase.options.projectId}/genai - and clicking "Get started". If you enabled this API recently, wait a few minutes for the - action to propagate to our systems and then retry. - """ - .trimIndent() - } else { - error.message - } - - throw ServiceDisabledException(errorMessage) - } - throw ServerException(message) -} - -private fun getServiceDisabledErrorDetailsOrNull( - error: GRpcErrorResponse.GRpcError -): GRpcErrorResponse.GRpcError.GRpcErrorDetails? { - return error.details?.firstOrNull { - it.reason == "SERVICE_DISABLED" && it.domain == "googleapis.com" - } -} - -private fun GenerateContentResponse.Internal.validate() = apply { - if ((candidates?.isEmpty() != false) && promptFeedback == null) { - throw SerializationException("Error deserializing response, found no valid fields") - } - promptFeedback?.blockReason?.let { throw PromptBlockedException(this) } - candidates - ?.mapNotNull { it.finishReason } - ?.firstOrNull { it != FinishReason.Internal.STOP } - ?.let { throw ResponseStoppedException(this) } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/AppCheckHeaderProvider.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/AppCheckHeaderProvider.kt deleted file mode 100644 index fb3b52ad46f..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/AppCheckHeaderProvider.kt +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.common - -import android.util.Log -import com.google.firebase.appcheck.interop.InteropAppCheckTokenProvider -import com.google.firebase.auth.internal.InternalAuthProvider -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds -import kotlinx.coroutines.tasks.await - -internal class AppCheckHeaderProvider( - private val logTag: String, - private val appCheckTokenProvider: InteropAppCheckTokenProvider? = null, - private val internalAuthProvider: InternalAuthProvider? = null, -) : HeaderProvider { - override val timeout: Duration - get() = 10.seconds - - override suspend fun generateHeaders(): Map { - val headers = mutableMapOf() - if (appCheckTokenProvider == null) { - Log.w(logTag, "AppCheck not registered, skipping") - } else { - val token = appCheckTokenProvider.getToken(false).await() - - if (token.error != null) { - Log.w(logTag, "Error obtaining AppCheck token", token.error) - } - // The Firebase App Check backend can differentiate between apps without App Check, and - // wrongly configured apps by verifying the value of the token, so it always needs to be - // included. - headers["X-Firebase-AppCheck"] = token.token - } - - if (internalAuthProvider == null) { - Log.w(logTag, "Auth not registered, skipping") - } else { - try { - val token = internalAuthProvider.getAccessToken(false).await() - - headers["Authorization"] = "Firebase ${token.token!!}" - } catch (e: Exception) { - Log.w(logTag, "Error getting Auth token ", e) - } - } - - return headers - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/Exceptions.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/Exceptions.kt deleted file mode 100644 index ad982f2daff..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/Exceptions.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.common - -import com.google.firebase.vertexai.type.GenerateContentResponse -import io.ktor.serialization.JsonConvertException -import kotlinx.coroutines.TimeoutCancellationException - -/** Parent class for any errors that occur. */ -internal sealed class FirebaseCommonAIException(message: String, cause: Throwable? = null) : - RuntimeException(message, cause) { - companion object { - - /** - * Converts a [Throwable] to a [FirebaseCommonAIException]. - * - * Will populate default messages as expected, and propagate the provided [cause] through the - * resulting exception. - */ - fun from(cause: Throwable): FirebaseCommonAIException = - when (cause) { - is FirebaseCommonAIException -> cause - is JsonConvertException, - is kotlinx.serialization.SerializationException -> - SerializationException( - "Something went wrong while trying to deserialize a response from the server.", - cause, - ) - is TimeoutCancellationException -> - RequestTimeoutException("The request failed to complete in the allotted time.") - else -> UnknownException("Something unexpected happened.", cause) - } - } -} - -/** Something went wrong while trying to deserialize a response from the server. */ -internal class SerializationException(message: String, cause: Throwable? = null) : - FirebaseCommonAIException(message, cause) - -/** The server responded with a non 200 response code. */ -internal class ServerException(message: String, cause: Throwable? = null) : - FirebaseCommonAIException(message, cause) - -/** The server responded that the API Key is no valid. */ -internal class InvalidAPIKeyException(message: String, cause: Throwable? = null) : - FirebaseCommonAIException(message, cause) - -/** - * A request was blocked for some reason. - * - * See the [response's][response] `promptFeedback.blockReason` for more information. - * - * @property response the full server response for the request. - */ -internal class PromptBlockedException -internal constructor( - val response: GenerateContentResponse.Internal?, - cause: Throwable? = null, - message: String? = null, -) : - FirebaseCommonAIException( - "Prompt was blocked: ${response?.promptFeedback?.blockReason?.name?: message}", - cause, - ) { - internal constructor(message: String, cause: Throwable? = null) : this(null, cause, message) -} - -/** - * The user's location (region) is not supported by the API. - * - * See the Google documentation for a - * [list of regions](https://ai.google.dev/available_regions#available_regions) (countries and - * territories) where the API is available. - */ -internal class UnsupportedUserLocationException(cause: Throwable? = null) : - FirebaseCommonAIException("User location is not supported for the API use.", cause) - -/** - * Some form of state occurred that shouldn't have. - * - * Usually indicative of consumer error. - */ -internal class InvalidStateException(message: String, cause: Throwable? = null) : - FirebaseCommonAIException(message, cause) - -/** - * A request was stopped during generation for some reason. - * - * @property response the full server response for the request - */ -internal class ResponseStoppedException( - val response: GenerateContentResponse.Internal, - cause: Throwable? = null -) : - FirebaseCommonAIException( - "Content generation stopped. Reason: ${response.candidates?.first()?.finishReason?.name}", - cause, - ) - -/** - * A request took too long to complete. - * - * Usually occurs due to a user specified [timeout][RequestOptions.timeout]. - */ -internal class RequestTimeoutException(message: String, cause: Throwable? = null) : - FirebaseCommonAIException(message, cause) - -/** The quota for this API key is depleted, retry this request at a later time. */ -internal class QuotaExceededException(message: String, cause: Throwable? = null) : - FirebaseCommonAIException(message, cause) - -/** The service is not enabled for this project. Visit the Firebase Console to enable it. */ -internal class ServiceDisabledException(message: String, cause: Throwable? = null) : - FirebaseCommonAIException(message, cause) - -/** Catch all case for exceptions not explicitly expected. */ -internal class UnknownException(message: String, cause: Throwable? = null) : - FirebaseCommonAIException(message, cause) - -internal class ContentBlockedException(message: String, cause: Throwable? = null) : - FirebaseCommonAIException(message, cause) - -internal fun makeMissingCaseException( - source: String, - ordinal: Int -): com.google.firebase.vertexai.type.SerializationException { - return com.google.firebase.vertexai.type.SerializationException( - """ - |Missing case for a $source: $ordinal - |This error indicates that one of the `toInternal` conversions needs updating. - |If you're a developer seeing this exception, please file an issue on our GitHub repo: - |https://github.com/firebase/firebase-android-sdk - """ - .trimMargin() - ) -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/Request.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/Request.kt deleted file mode 100644 index 7b0bd65e0dc..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/Request.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -@file:OptIn(ExperimentalSerializationApi::class) - -package com.google.firebase.vertexai.common - -import com.google.firebase.vertexai.common.util.fullModelName -import com.google.firebase.vertexai.type.Content -import com.google.firebase.vertexai.type.GenerationConfig -import com.google.firebase.vertexai.type.ImagenImageFormat -import com.google.firebase.vertexai.type.PublicPreviewAPI -import com.google.firebase.vertexai.type.SafetySetting -import com.google.firebase.vertexai.type.Tool -import com.google.firebase.vertexai.type.ToolConfig -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -internal interface Request - -@Serializable -internal data class GenerateContentRequest( - val model: String? = null, - val contents: List, - @SerialName("safety_settings") val safetySettings: List? = null, - @SerialName("generation_config") val generationConfig: GenerationConfig.Internal? = null, - val tools: List? = null, - @SerialName("tool_config") var toolConfig: ToolConfig.Internal? = null, - @SerialName("system_instruction") val systemInstruction: Content.Internal? = null, -) : Request - -@Serializable -internal data class CountTokensRequest( - val generateContentRequest: GenerateContentRequest? = null, - val model: String? = null, - val contents: List? = null, - val tools: List? = null, - @SerialName("system_instruction") val systemInstruction: Content.Internal? = null, - val generationConfig: GenerationConfig.Internal? = null -) : Request { - companion object { - - fun forVertexAI(generateContentRequest: GenerateContentRequest) = - CountTokensRequest( - model = generateContentRequest.model?.let { fullModelName(it) }, - contents = generateContentRequest.contents, - tools = generateContentRequest.tools, - systemInstruction = generateContentRequest.systemInstruction, - generationConfig = generateContentRequest.generationConfig, - ) - } -} - -@Serializable -internal data class GenerateImageRequest( - val instances: List, - val parameters: ImagenParameters, -) : Request { - @Serializable internal data class ImagenPrompt(val prompt: String) - - @OptIn(PublicPreviewAPI::class) - @Serializable - internal data class ImagenParameters( - val sampleCount: Int, - val includeRaiReason: Boolean, - val storageUri: String?, - val negativePrompt: String?, - val aspectRatio: String?, - val safetySetting: String?, - val personGeneration: String?, - val addWatermark: Boolean?, - val imageOutputOptions: ImagenImageFormat.Internal?, - ) -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/util/android.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/util/android.kt deleted file mode 100644 index 6de0339e032..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/util/android.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.common.util - -import android.media.AudioRecord -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.yield - -/** - * The minimum buffer size for this instance. - * - * The same as calling [AudioRecord.getMinBufferSize], except the params are pre-populated. - */ -internal val AudioRecord.minBufferSize: Int - get() = AudioRecord.getMinBufferSize(sampleRate, channelConfiguration, audioFormat) - -/** - * Reads from this [AudioRecord] and returns the data in a flow. - * - * Will yield when this instance is not recording. - */ -internal fun AudioRecord.readAsFlow() = flow { - val buffer = ByteArray(minBufferSize) - - while (true) { - if (recordingState != AudioRecord.RECORDSTATE_RECORDING) { - yield() - continue - } - - val bytesRead = read(buffer, 0, buffer.size) - if (bytesRead > 0) { - emit(buffer.copyOf(bytesRead)) - } - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/util/kotlin.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/util/kotlin.kt deleted file mode 100644 index 05e37e490ab..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/util/kotlin.kt +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.common.util - -import java.io.ByteArrayOutputStream -import java.lang.reflect.Field -import kotlin.coroutines.EmptyCoroutineContext -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Job -import kotlinx.coroutines.cancel -import kotlinx.coroutines.currentCoroutineContext -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.fold - -/** - * Removes the last character from the [StringBuilder]. - * - * If the StringBuilder is empty, calling this function will throw an [IndexOutOfBoundsException]. - * - * @return The [StringBuilder] used to make the call, for optional chaining. - * @throws IndexOutOfBoundsException if the StringBuilder is empty. - */ -internal fun StringBuilder.removeLast(): StringBuilder = - if (isEmpty()) throw IndexOutOfBoundsException("StringBuilder is empty.") - else deleteCharAt(length - 1) - -/** - * A variant of [getAnnotation][Field.getAnnotation] that provides implicit Kotlin support. - * - * Syntax sugar for: - * ``` - * getAnnotation(T::class.java) - * ``` - */ -internal inline fun Field.getAnnotation() = getAnnotation(T::class.java) - -/** - * Collects bytes from this flow and doesn't emit them back until [minSize] is reached. - * - * For example: - * ``` - * val byteArr = flowOf(byteArrayOf(1), byteArrayOf(2, 3, 4), byteArrayOf(5, 6, 7, 8)) - * val expectedResult = listOf(byteArrayOf(1, 2, 3, 4), byteArrayOf( 5, 6, 7, 8)) - * - * byteArr.accumulateUntil(4).toList() shouldContainExactly expectedResult - * ``` - * - * @param minSize The minimum about of bytes the array should have before being sent down-stream - * @param emitLeftOvers If the flow completes and there are bytes left over that don't meet the - * [minSize], send them anyways. - */ -internal fun Flow.accumulateUntil( - minSize: Int, - emitLeftOvers: Boolean = false -): Flow = flow { - val remaining = - fold(ByteArrayOutputStream()) { buffer, it -> - buffer.apply { - write(it, 0, it.size) - if (size() >= minSize) { - emit(toByteArray()) - reset() - } - } - } - - if (emitLeftOvers && remaining.size() > 0) { - emit(remaining.toByteArray()) - } -} - -/** - * Create a [Job] that is a child of the [currentCoroutineContext], if any. - * - * This is useful when you want a coroutine scope to be canceled when its parent scope is canceled, - * and you don't have full control over the parent scope, but you don't want the cancellation of the - * child to impact the parent. - * - * If the parent coroutine context does not have a job, an empty one will be created. - */ -internal suspend inline fun childJob() = Job(currentCoroutineContext()[Job] ?: Job()) - -/** - * A constant value pointing to a cancelled [CoroutineScope]. - * - * Useful when you want to initialize a mutable [CoroutineScope] in a canceled state. - */ -internal val CancelledCoroutineScope = CoroutineScope(EmptyCoroutineContext).apply { cancel() } diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/util/ktor.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/util/ktor.kt deleted file mode 100644 index abae1409d9a..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/util/ktor.kt +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@file:Suppress("DEPRECATION") // a replacement for our purposes has not been published yet - -package com.google.firebase.vertexai.common.util - -import io.ktor.utils.io.ByteChannel -import io.ktor.utils.io.ByteReadChannel -import io.ktor.utils.io.close -import io.ktor.utils.io.readUTF8Line -import io.ktor.utils.io.writeFully -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.channelFlow -import kotlinx.serialization.SerializationException -import kotlinx.serialization.json.Json - -/** - * Suspends and processes each line read from the [ByteReadChannel] until the channel is closed for - * read. - * - * This extension function facilitates processing the stream of lines in a manner that takes into - * account EOF/empty strings- and avoids calling [block] as such. - * - * Example usage: - * ``` - * val channel: ByteReadChannel = ByteReadChannel("Hello, World!") - * channel.onEachLine { - * println("Received line: $it") - * } - * ``` - * - * @param block A suspending function to process each line. - */ -internal suspend fun ByteReadChannel.onEachLine(block: suspend (String) -> Unit) { - while (!isClosedForRead) { - awaitContent() - val line = readUTF8Line()?.takeUnless { it.isEmpty() } ?: continue - block(line) - } -} - -/** - * Decodes a stream of JSON elements from the given [ByteReadChannel] into a [Flow] of objects of - * type [T]. - * - * This function takes in a stream of events, each with a set of named parts. Parts are separated by - * an HTTP \r\n newline, events are separated by a double HTTP \r\n\r\n newline. This function - * assumes every event will only contain a named "data" part with a JSON object. Each data JSON is - * decoded into an instance of [T] and emitted as it is read from the channel. - * - * Example usage: - * ``` - * val json = Json { ignoreUnknownKeys = true } // Create a Json instance with any configurations - * val channel: ByteReadChannel = ByteReadChannel("data: {\"name\":\"Alice\"}\r\n\r\ndata: {\"name\":\"Bob\"}]") - * - * json.decodeToFlow(channel).collect { person -> - * println(person.name) - * } - * ``` - * - * @param T The type of objects to decode from the JSON stream. - * @param channel The [ByteReadChannel] from which the JSON stream will be read. - * @return A [Flow] of objects of type [T]. - * @throws SerializationException in case of any decoding-specific error - * @throws IllegalArgumentException if the decoded input is not a valid instance of [T] - */ -internal inline fun Json.decodeToFlow(channel: ByteReadChannel): Flow = channelFlow { - channel.onEachLine { - val data = it.removePrefix("data:") - send(decodeFromString(data)) - } -} - -/** - * Writes the provided [bytes] to the channel and closes it. - * - * Just a wrapper around [writeFully] that closes the channel after writing is complete. - * - * @param bytes the data to send through the channel - */ -internal suspend fun ByteChannel.send(bytes: ByteArray) { - writeFully(bytes) - close() -} - -/** String separator used in SSE communication to signal the end of a message. */ -internal const val SSE_SEPARATOR = "\r\n\r\n" diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/util/serialization.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/util/serialization.kt deleted file mode 100644 index 4a2570b82d6..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/util/serialization.kt +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.common.util - -import android.util.Log -import com.google.firebase.vertexai.common.SerializationException -import kotlin.reflect.KClass -import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerialName -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.descriptors.buildClassSerialDescriptor -import kotlinx.serialization.descriptors.element -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder - -/** - * Serializer for enums that defaults to the first ordinal on unknown types. - * - * Convention is that the first enum be named `UNKNOWN`, but any name is valid. - * - * When an unknown enum value is found, the enum itself will be logged to stderr with a message - * about opening an issue on GitHub regarding the new enum value. - */ -internal class FirstOrdinalSerializer>(private val enumClass: KClass) : - KSerializer { - override val descriptor: SerialDescriptor = - buildClassSerialDescriptor("FirstOrdinalSerializer") { - for (enumValue in enumClass.enumValues()) { - element(enumValue.toString()) - } - } - - override fun deserialize(decoder: Decoder): T { - val name = decoder.decodeString() - val values = enumClass.enumValues() - - return values.firstOrNull { it.serialName == name } - ?: values.first().also { printWarning(name) } - } - - private fun printWarning(name: String) { - Log.e( - "FirstOrdinalSerializer", - """ - |Unknown enum value found: $name" - |This usually means the backend was updated, and the SDK needs to be updated to match it. - |Check if there's a new version for the SDK, otherwise please open an issue on our - |GitHub to bring it to our attention: - |https://github.com/google/google-ai-android - """ - .trimMargin(), - ) - } - - override fun serialize(encoder: Encoder, value: T) { - encoder.encodeString(value.serialName) - } -} - -/** - * Provides the name to be used in serialization for this enum value. - * - * By default an enum is serialized to its [name][Enum.name], and can be overwritten by providing a - * [SerialName] annotation. - */ -internal val > T.serialName: String - get() = declaringJavaClass.getField(name).getAnnotation()?.value ?: name - -/** - * Variant of [kotlin.enumValues] that provides support for [KClass] instances of enums. - * - * @throws SerializationException if the class is not a valid enum. Beyond runtime emily magic, this - * shouldn't really be possible. - */ -internal fun > KClass.enumValues(): Array = - java.enumConstants ?: throw SerializationException("$simpleName is not a valid enum type.") diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/util/util.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/util/util.kt deleted file mode 100644 index 97b9ffe555e..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/common/util/util.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.common.util - -/** - * Ensures the model name provided has a `models/` prefix - * - * Models must be prepended with the `models/` prefix when communicating with the backend. - */ -internal fun fullModelName(name: String): String = - name.takeIf { it.contains("/") } ?: "models/$name" diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/java/ChatFutures.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/java/ChatFutures.kt deleted file mode 100644 index c653d1930ea..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/java/ChatFutures.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.java - -import androidx.concurrent.futures.SuspendToFutureAdapter -import com.google.common.util.concurrent.ListenableFuture -import com.google.firebase.vertexai.Chat -import com.google.firebase.vertexai.type.Content -import com.google.firebase.vertexai.type.GenerateContentResponse -import com.google.firebase.vertexai.type.InvalidStateException -import kotlinx.coroutines.reactive.asPublisher -import org.reactivestreams.Publisher - -/** - * Wrapper class providing Java compatible methods for [Chat]. - * - * @see [Chat] - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public abstract class ChatFutures internal constructor() { - - /** - * Sends a message using the existing history of this chat as context and the provided [Content] - * prompt. - * - * If successful, the message and response will be added to the history. If unsuccessful, history - * will remain unchanged. - * - * @param prompt The input(s) that, together with the history, will be given to the model as the - * prompt. - * @throws InvalidStateException if [prompt] is not coming from the 'user' role - * @throws InvalidStateException if the [Chat] instance has an active request - */ - public abstract fun sendMessage(prompt: Content): ListenableFuture - - /** - * Sends a message using the existing history of this chat as context and the provided [Content] - * prompt. - * - * The response from the model is returned as a stream. - * - * If successful, the message and response will be added to the history. If unsuccessful, history - * will remain unchanged. - * - * @param prompt The input(s) that, together with the history, will be given to the model as the - * prompt. - * @throws InvalidStateException if [prompt] is not coming from the 'user' role - * @throws InvalidStateException if the [Chat] instance has an active request - */ - public abstract fun sendMessageStream(prompt: Content): Publisher - - /** Returns the [Chat] object wrapped by this object. */ - public abstract fun getChat(): Chat - - private class FuturesImpl(private val chat: Chat) : ChatFutures() { - override fun sendMessage(prompt: Content): ListenableFuture = - SuspendToFutureAdapter.launchFuture { chat.sendMessage(prompt) } - - override fun sendMessageStream(prompt: Content): Publisher = - chat.sendMessageStream(prompt).asPublisher() - - override fun getChat(): Chat = chat - } - - public companion object { - - /** @return a [ChatFutures] created around the provided [Chat] */ - @JvmStatic public fun from(chat: Chat): ChatFutures = FuturesImpl(chat) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/java/GenerativeModelFutures.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/java/GenerativeModelFutures.kt deleted file mode 100644 index 635fa14cb48..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/java/GenerativeModelFutures.kt +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.java - -import androidx.concurrent.futures.SuspendToFutureAdapter -import com.google.common.util.concurrent.ListenableFuture -import com.google.firebase.vertexai.GenerativeModel -import com.google.firebase.vertexai.java.ChatFutures.Companion.from -import com.google.firebase.vertexai.type.Content -import com.google.firebase.vertexai.type.CountTokensResponse -import com.google.firebase.vertexai.type.FirebaseVertexAIException -import com.google.firebase.vertexai.type.GenerateContentResponse -import kotlinx.coroutines.reactive.asPublisher -import org.reactivestreams.Publisher - -/** - * Wrapper class providing Java compatible methods for [GenerativeModel]. - * - * @see [GenerativeModel] - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public abstract class GenerativeModelFutures internal constructor() { - - /** - * Generates new content from the input [Content] given to the model as a prompt. - * - * @param prompt The input(s) given to the model as a prompt. - * @return The content generated by the model. - * @throws [FirebaseVertexAIException] if the request failed. - */ - public abstract fun generateContent( - vararg prompt: Content - ): ListenableFuture - - /** - * Generates new content as a stream from the input [Content] given to the model as a prompt. - * - * @param prompt The input(s) given to the model as a prompt. - * @return A [Publisher] which will emit responses as they are returned by the model. - * @throws [FirebaseVertexAIException] if the request failed. - */ - public abstract fun generateContentStream( - vararg prompt: Content - ): Publisher - - /** - * Counts the number of tokens in a prompt using the model's tokenizer. - * - * @param prompt The input(s) given to the model as a prompt. - * @return The [CountTokensResponse] of running the model's tokenizer on the input. - * @throws [FirebaseVertexAIException] if the request failed. - */ - public abstract fun countTokens(vararg prompt: Content): ListenableFuture - - /** - * Creates a [ChatFutures] instance which internally tracks the ongoing conversation with the - * model. - */ - public abstract fun startChat(): ChatFutures - - /** - * Creates a [ChatFutures] instance, initialized using the optionally provided [history]. - * - * @param history A list of previous interactions with the model to use as a starting point - */ - public abstract fun startChat(history: List): ChatFutures - - /** Returns the [GenerativeModel] object wrapped by this object. */ - public abstract fun getGenerativeModel(): GenerativeModel - - private class FuturesImpl(private val model: GenerativeModel) : GenerativeModelFutures() { - override fun generateContent( - vararg prompt: Content - ): ListenableFuture = - SuspendToFutureAdapter.launchFuture { model.generateContent(*prompt) } - - override fun generateContentStream(vararg prompt: Content): Publisher = - model.generateContentStream(*prompt).asPublisher() - - override fun countTokens(vararg prompt: Content): ListenableFuture = - SuspendToFutureAdapter.launchFuture { model.countTokens(*prompt) } - - override fun startChat(): ChatFutures = startChat(emptyList()) - - override fun startChat(history: List): ChatFutures = from(model.startChat(history)) - - override fun getGenerativeModel(): GenerativeModel = model - } - - public companion object { - - /** @return a [GenerativeModelFutures] created around the provided [GenerativeModel] */ - @JvmStatic public fun from(model: GenerativeModel): GenerativeModelFutures = FuturesImpl(model) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/java/ImagenModelFutures.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/java/ImagenModelFutures.kt deleted file mode 100644 index e24898d57b8..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/java/ImagenModelFutures.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.java - -import androidx.concurrent.futures.SuspendToFutureAdapter -import com.google.common.util.concurrent.ListenableFuture -import com.google.firebase.vertexai.ImagenModel -import com.google.firebase.vertexai.type.ImagenGenerationResponse -import com.google.firebase.vertexai.type.ImagenInlineImage -import com.google.firebase.vertexai.type.PublicPreviewAPI - -/** - * Wrapper class providing Java compatible methods for [ImagenModel]. - * - * @see [ImagenModel] - */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public abstract class ImagenModelFutures internal constructor() { - /** - * Generates an image, returning the result directly to the caller. - * - * @param prompt The main text prompt from which the image is generated. - */ - public abstract fun generateImages( - prompt: String, - ): ListenableFuture> - - /** Returns the [ImagenModel] object wrapped by this object. */ - public abstract fun getImageModel(): ImagenModel - - private class FuturesImpl(private val model: ImagenModel) : ImagenModelFutures() { - override fun generateImages( - prompt: String, - ): ListenableFuture> = - SuspendToFutureAdapter.launchFuture { model.generateImages(prompt) } - - override fun getImageModel(): ImagenModel = model - } - - public companion object { - - /** @return a [ImagenModelFutures] created around the provided [ImagenModel] */ - @JvmStatic public fun from(model: ImagenModel): ImagenModelFutures = FuturesImpl(model) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/java/LiveModelFutures.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/java/LiveModelFutures.kt deleted file mode 100644 index ea30126c00a..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/java/LiveModelFutures.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.java - -import androidx.concurrent.futures.SuspendToFutureAdapter -import com.google.common.util.concurrent.ListenableFuture -import com.google.firebase.vertexai.LiveGenerativeModel -import com.google.firebase.vertexai.type.PublicPreviewAPI -import com.google.firebase.vertexai.type.ServiceConnectionHandshakeFailedException - -/** - * Wrapper class providing Java compatible methods for [LiveGenerativeModel]. - * - * @see [LiveGenerativeModel] - */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public abstract class LiveModelFutures internal constructor() { - - /** - * Start a [LiveSessionFutures] with the server for bidirectional streaming. - * @return A [LiveSessionFutures] that you can use to stream messages to and from the server. - * @throws [ServiceConnectionHandshakeFailedException] If the client was not able to establish a - * connection with the server. - */ - public abstract fun connect(): ListenableFuture - - private class FuturesImpl(private val model: LiveGenerativeModel) : LiveModelFutures() { - override fun connect(): ListenableFuture { - return SuspendToFutureAdapter.launchFuture { LiveSessionFutures.from(model.connect()) } - } - } - - public companion object { - - /** @return a [LiveModelFutures] created around the provided [LiveGenerativeModel] */ - @JvmStatic public fun from(model: LiveGenerativeModel): LiveModelFutures = FuturesImpl(model) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/java/LiveSessionFutures.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/java/LiveSessionFutures.kt deleted file mode 100644 index 7865ed8e7d9..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/java/LiveSessionFutures.kt +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.java - -import android.Manifest.permission.RECORD_AUDIO -import androidx.annotation.RequiresPermission -import androidx.concurrent.futures.SuspendToFutureAdapter -import com.google.common.util.concurrent.ListenableFuture -import com.google.firebase.vertexai.type.Content -import com.google.firebase.vertexai.type.FunctionCallPart -import com.google.firebase.vertexai.type.FunctionResponsePart -import com.google.firebase.vertexai.type.LiveServerMessage -import com.google.firebase.vertexai.type.LiveSession -import com.google.firebase.vertexai.type.MediaData -import com.google.firebase.vertexai.type.PublicPreviewAPI -import com.google.firebase.vertexai.type.SessionAlreadyReceivingException -import io.ktor.websocket.close -import kotlinx.coroutines.reactive.asPublisher -import org.reactivestreams.Publisher - -/** - * Wrapper class providing Java compatible methods for [LiveSession]. - * - * @see [LiveSession] - */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public abstract class LiveSessionFutures internal constructor() { - - /** - * Starts an audio conversation with the model, which can only be stopped using - * [stopAudioConversation] or [close]. - * - * @param functionCallHandler A callback function that is invoked whenever the model receives a - * function call. - */ - public abstract fun startAudioConversation( - functionCallHandler: ((FunctionCallPart) -> FunctionResponsePart)? - ): ListenableFuture - - /** - * Starts an audio conversation with the model, which can only be stopped using - * [stopAudioConversation]. - */ - @RequiresPermission(RECORD_AUDIO) - public abstract fun startAudioConversation(): ListenableFuture - - /** - * Stops the audio conversation with the Gemini Server. - * - * This only needs to be called after a previous call to [startAudioConversation]. - * - * If there is no audio conversation currently active, this function does nothing. - */ - @RequiresPermission(RECORD_AUDIO) - public abstract fun stopAudioConversation(): ListenableFuture - - /** - * Stops receiving from the model. - * - * If this function is called during an ongoing audio conversation, the model's response will not - * be received, and no audio will be played; the live session object will no longer receive data - * from the server. - * - * To resume receiving data, you must either handle it directly using [receive], or indirectly by - * using [startAudioConversation]. - * - * @see close - */ - // TODO(b/410059569): Remove when fixed - public abstract fun stopReceiving() - - /** - * Sends function calling responses to the model. - * - * @param functionList The list of [FunctionResponsePart] instances indicating the function - * response from the client. - */ - public abstract fun sendFunctionResponse( - functionList: List - ): ListenableFuture - - /** - * Streams client data to the model. - * - * Calling this after [startAudioConversation] will play the response audio immediately. - * - * @param mediaChunks The list of [MediaData] instances representing the media data to be sent. - */ - public abstract fun sendMediaStream(mediaChunks: List): ListenableFuture - - /** - * Sends [data][Content] to the model. - * - * Calling this after [startAudioConversation] will play the response audio immediately. - * - * @param content Client [Content] to be sent to the model. - */ - public abstract fun send(content: Content): ListenableFuture - - /** - * Sends text to the model. - * - * Calling this after [startAudioConversation] will play the response audio immediately. - * - * @param text Text to be sent to the model. - */ - public abstract fun send(text: String): ListenableFuture - - /** - * Closes the client session. - * - * Once a [LiveSession] is closed, it can not be reopened; you'll need to start a new - * [LiveSession]. - * - * @see stopReceiving - */ - public abstract fun close(): ListenableFuture - - /** - * Receives responses from the model for both streaming and standard requests. - * - * Call [close] to stop receiving responses from the model. - * - * @return A [Publisher] which will emit [LiveServerMessage] from the model. - * - * @throws [SessionAlreadyReceivingException] when the session is already receiving. - * @see stopReceiving - */ - public abstract fun receive(): Publisher - - private class FuturesImpl(private val session: LiveSession) : LiveSessionFutures() { - - override fun receive(): Publisher = session.receive().asPublisher() - - override fun close(): ListenableFuture = - SuspendToFutureAdapter.launchFuture { session.close() } - - override fun send(text: String) = SuspendToFutureAdapter.launchFuture { session.send(text) } - - override fun send(content: Content) = - SuspendToFutureAdapter.launchFuture { session.send(content) } - - override fun sendFunctionResponse(functionList: List) = - SuspendToFutureAdapter.launchFuture { session.sendFunctionResponse(functionList) } - - override fun sendMediaStream(mediaChunks: List) = - SuspendToFutureAdapter.launchFuture { session.sendMediaStream(mediaChunks) } - - @RequiresPermission(RECORD_AUDIO) - override fun startAudioConversation( - functionCallHandler: ((FunctionCallPart) -> FunctionResponsePart)? - ) = SuspendToFutureAdapter.launchFuture { session.startAudioConversation(functionCallHandler) } - - @RequiresPermission(RECORD_AUDIO) - override fun startAudioConversation() = - SuspendToFutureAdapter.launchFuture { session.startAudioConversation() } - - override fun stopAudioConversation() = - SuspendToFutureAdapter.launchFuture { session.stopAudioConversation() } - - override fun stopReceiving() = session.stopReceiving() - } - - public companion object { - - /** @return a [LiveSessionFutures] created around the provided [LiveSession] */ - @JvmStatic public fun from(session: LiveSession): LiveSessionFutures = FuturesImpl(session) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/AudioHelper.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/AudioHelper.kt deleted file mode 100644 index e74b766d9ce..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/AudioHelper.kt +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import android.Manifest -import android.media.AudioAttributes -import android.media.AudioFormat -import android.media.AudioManager -import android.media.AudioRecord -import android.media.AudioTrack -import android.media.MediaRecorder -import android.media.audiofx.AcousticEchoCanceler -import android.util.Log -import androidx.annotation.RequiresPermission -import com.google.firebase.vertexai.common.util.readAsFlow -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.emptyFlow - -/** - * Helper class for recording audio and playing back a separate audio track at the same time. - * - * @see AudioHelper.build - * @see LiveSession.startAudioConversation - */ -@PublicPreviewAPI -internal class AudioHelper( - /** Record for recording the System microphone. */ - private val recorder: AudioRecord, - /** Track for playing back what the model says. */ - private val playbackTrack: AudioTrack, -) { - private var released: Boolean = false - - /** - * Release the system resources on the recorder and playback track. - * - * Once an [AudioHelper] has been "released", it can _not_ be used again. - * - * This method can safely be called multiple times, as it won't do anything if this instance has - * already been released. - */ - fun release() { - if (released) return - released = true - - recorder.release() - playbackTrack.release() - } - - /** - * Play the provided audio data on the playback track. - * - * Does nothing if this [AudioHelper] has been [released][release]. - * - * @throws IllegalStateException If the playback track was not properly initialized. - * @throws IllegalArgumentException If the playback data is invalid. - * @throws RuntimeException If we fail to play the audio data for some unknown reason. - */ - fun playAudio(data: ByteArray) { - if (released) return - if (data.isEmpty()) return - - if (playbackTrack.playState == AudioTrack.PLAYSTATE_STOPPED) playbackTrack.play() - - val result = playbackTrack.write(data, 0, data.size) - if (result > 0) return - if (result == 0) { - Log.w( - TAG, - "Failed to write any audio bytes to the playback track. The audio track may have been stopped or paused." - ) - return - } - - // ERROR_INVALID_OPERATION and ERROR_BAD_VALUE should never occur - when (result) { - AudioTrack.ERROR_INVALID_OPERATION -> - throw IllegalStateException("The playback track was not properly initialized.") - AudioTrack.ERROR_BAD_VALUE -> - throw IllegalArgumentException("Playback data is somehow invalid.") - AudioTrack.ERROR_DEAD_OBJECT -> { - Log.w(TAG, "Attempted to playback some audio, but the track has been released.") - release() // to ensure `released` is set and `record` is released too - } - AudioTrack.ERROR -> - throw RuntimeException("Failed to play the audio data for some unknown reason.") - } - } - - /** - * Pause the recording of the microphone, if it's recording. - * - * Does nothing if this [AudioHelper] has been [released][release]. - * - * @see resumeRecording - * - * @throws IllegalStateException If the playback track was not properly initialized. - */ - fun pauseRecording() { - if (released || recorder.recordingState == AudioRecord.RECORDSTATE_STOPPED) return - - try { - recorder.stop() - } catch (e: IllegalStateException) { - release() - throw IllegalStateException("The playback track was not properly initialized.") - } - } - - /** - * Resumes the recording of the microphone, if it's not already running. - * - * Does nothing if this [AudioHelper] has been [released][release]. - * - * @see pauseRecording - */ - fun resumeRecording() { - if (released || recorder.recordingState == AudioRecord.RECORDSTATE_RECORDING) return - - recorder.startRecording() - } - - /** - * Start perpetually recording the system microphone, and return the bytes read in a flow. - * - * Returns an empty flow if this [AudioHelper] has been [released][release]. - */ - fun listenToRecording(): Flow { - if (released) return emptyFlow() - - resumeRecording() - - return recorder.readAsFlow() - } - - companion object { - private val TAG = AudioHelper::class.simpleName - - /** - * Creates an instance of [AudioHelper] with the track and record initialized. - * - * A separate build method is necessary so that we can properly propagate the required manifest - * permission, and throw exceptions when needed. - * - * It also makes it easier to read, since the long initialization is separate from the - * constructor. - */ - @RequiresPermission(Manifest.permission.RECORD_AUDIO) - fun build(): AudioHelper { - val playbackTrack = - AudioTrack( - AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION).build(), - AudioFormat.Builder() - .setSampleRate(24000) - .setChannelMask(AudioFormat.CHANNEL_OUT_MONO) - .setEncoding(AudioFormat.ENCODING_PCM_16BIT) - .build(), - AudioTrack.getMinBufferSize( - 24000, - AudioFormat.CHANNEL_OUT_MONO, - AudioFormat.ENCODING_PCM_16BIT - ), - AudioTrack.MODE_STREAM, - AudioManager.AUDIO_SESSION_ID_GENERATE - ) - - val bufferSize = - AudioRecord.getMinBufferSize( - 16000, - AudioFormat.CHANNEL_IN_MONO, - AudioFormat.ENCODING_PCM_16BIT - ) - - if (bufferSize <= 0) - throw AudioRecordInitializationFailedException( - "Audio Record buffer size is invalid ($bufferSize)" - ) - - val recorder = - AudioRecord( - MediaRecorder.AudioSource.VOICE_COMMUNICATION, - 16000, - AudioFormat.CHANNEL_IN_MONO, - AudioFormat.ENCODING_PCM_16BIT, - bufferSize - ) - if (recorder.state != AudioRecord.STATE_INITIALIZED) - throw AudioRecordInitializationFailedException( - "Audio Record initialization has failed. State: ${recorder.state}" - ) - - if (AcousticEchoCanceler.isAvailable()) { - AcousticEchoCanceler.create(recorder.audioSessionId)?.enabled = true - } - - return AudioHelper(recorder, playbackTrack) - } - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Candidate.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Candidate.kt deleted file mode 100644 index 52dfd46239d..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Candidate.kt +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@file:OptIn(ExperimentalSerializationApi::class) - -package com.google.firebase.vertexai.type - -import com.google.firebase.vertexai.common.util.FirstOrdinalSerializer -import java.util.Calendar -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonNames - -/** - * A `Candidate` represents a single response generated by the model for a given request. - * - * @property content The actual content generated by the model. - * @property safetyRatings A list of [SafetyRating]s describing the generated content. - * @property citationMetadata Metadata about the sources used to generate this content. - * @property finishReason The reason the model stopped generating content, if it exist. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class Candidate -internal constructor( - public val content: Content, - public val safetyRatings: List, - public val citationMetadata: CitationMetadata?, - public val finishReason: FinishReason? -) { - - @Serializable - internal data class Internal( - val content: Content.Internal? = null, - val finishReason: FinishReason.Internal? = null, - val safetyRatings: List? = null, - val citationMetadata: CitationMetadata.Internal? = null, - val groundingMetadata: GroundingMetadata? = null, - ) { - internal fun toPublic(): Candidate { - val safetyRatings = safetyRatings?.mapNotNull { it.toPublic() }.orEmpty() - val citations = citationMetadata?.toPublic() - val finishReason = finishReason?.toPublic() - - return Candidate( - this.content?.toPublic() ?: content("model") {}, - safetyRatings, - citations, - finishReason - ) - } - - @Serializable - internal data class GroundingMetadata( - @SerialName("web_search_queries") val webSearchQueries: List?, - @SerialName("search_entry_point") val searchEntryPoint: SearchEntryPoint?, - @SerialName("retrieval_queries") val retrievalQueries: List?, - @SerialName("grounding_attribution") val groundingAttribution: List?, - ) { - - @Serializable - internal data class SearchEntryPoint( - @SerialName("rendered_content") val renderedContent: String?, - @SerialName("sdk_blob") val sdkBlob: String?, - ) - - @Serializable - internal data class GroundingAttribution( - val segment: Segment, - @SerialName("confidence_score") val confidenceScore: Float?, - ) { - - @Serializable - internal data class Segment( - @SerialName("start_index") val startIndex: Int, - @SerialName("end_index") val endIndex: Int, - ) - } - } - } -} - -/** - * An assessment of the potential harm of some generated content. - * - * The rating will be restricted to a particular [category]. - * - * @property category The category of harm being assessed (e.g., Hate speech). - * @property probability The likelihood of the content causing harm. - * @property probabilityScore A numerical score representing the probability of harm, between 0 and - * 1. - * @property blocked Indicates whether the content was blocked due to safety concerns. - * @property severity The severity of the potential harm. - * @property severityScore A numerical score representing the severity of harm. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class SafetyRating -internal constructor( - public val category: HarmCategory, - public val probability: HarmProbability, - public val probabilityScore: Float = 0f, - public val blocked: Boolean? = null, - public val severity: HarmSeverity? = null, - public val severityScore: Float? = null -) { - - @Serializable - internal data class Internal - @JvmOverloads - constructor( - val category: HarmCategory.Internal? = null, - val probability: HarmProbability.Internal? = null, - val blocked: Boolean? = null, // TODO(): any reason not to default to false? - val probabilityScore: Float? = null, - val severity: HarmSeverity.Internal? = null, - val severityScore: Float? = null, - ) { - - internal fun toPublic() = - /** - * Due to a bug in the backend, it's possible that we receive an invalid `SafetyRating` value, - * without either category or probability. We return null in those cases to enable filtering - * by the higher level types. - */ - if (category == null || probability == null) { - null - } else { - SafetyRating( - category = category.toPublic(), - probability = probability.toPublic(), - probabilityScore = probabilityScore ?: 0f, - blocked = blocked, - severity = severity?.toPublic(), - severityScore = severityScore - ) - } - } -} - -/** - * A collection of source attributions for a piece of content. - * - * @property citations A list of individual cited sources and the parts of the content to which they - * apply. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class CitationMetadata internal constructor(public val citations: List) { - - @Serializable - internal data class Internal - @OptIn(ExperimentalSerializationApi::class) - internal constructor(@JsonNames("citations") val citationSources: List) { - - internal fun toPublic() = CitationMetadata(citationSources.map { it.toPublic() }) - } -} - -/** - * Represents a citation of content from an external source within the model's output. - * - * When the language model generates text that includes content from another source, it should - * provide a citation to properly attribute the original source. This class encapsulates the - * metadata associated with that citation. - * - * @property title The title of the cited source, if available. - * @property startIndex The (inclusive) starting index within the model output where the cited - * content begins. - * @property endIndex The (exclusive) ending index within the model output where the cited content - * ends. - * @property uri The URI of the cited source, if available. - * @property license The license under which the cited content is distributed under, if available. - * @property publicationDate The date of publication of the cited source, if available. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class Citation -internal constructor( - public val title: String? = null, - public val startIndex: Int = 0, - public val endIndex: Int, - public val uri: String? = null, - public val license: String? = null, - public val publicationDate: Calendar? = null -) { - - @Serializable - internal data class Internal( - val title: String? = null, - val startIndex: Int = 0, - val endIndex: Int, - val uri: String? = null, - val license: String? = null, - val publicationDate: Date? = null, - ) { - - internal fun toPublic(): Citation { - val publicationDateAsCalendar = - publicationDate?.let { - val calendar = Calendar.getInstance() - // Internal `Date.year` uses 0 to represent not specified. We use 1 as default. - val year = if (it.year == null || it.year < 1) 1 else it.year - // Internal `Date.month` uses 0 to represent not specified, or is 1-12 as months. The - // month as - // expected by [Calendar] is 0-based, so we subtract 1 or use 0 as default. - val month = if (it.month == null || it.month < 1) 0 else it.month - 1 - // Internal `Date.day` uses 0 to represent not specified. We use 1 as default. - val day = if (it.day == null || it.day < 1) 1 else it.day - calendar.set(year, month, day) - calendar - } - return Citation( - title = title, - startIndex = startIndex, - endIndex = endIndex, - uri = uri, - license = license, - publicationDate = publicationDateAsCalendar - ) - } - - @Serializable - internal data class Date( - /** Year of the date. Must be between 1 and 9999, or 0 for no year. */ - val year: Int? = null, - /** 1-based index for month. Must be from 1 to 12, or 0 to specify a year without a month. */ - val month: Int? = null, - /** - * Day of a month. Must be from 1 to 31 and valid for the year and month, or 0 to specify a - * year by itself or a year and month where the day isn't significant. - */ - val day: Int? = null, - ) - } -} - -/** - * Represents the reason why the model stopped generating content. - * - * @property name The name of the finish reason. - * @property ordinal The ordinal value of the finish reason. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class FinishReason private constructor(public val name: String, public val ordinal: Int) { - - @Serializable(Internal.Serializer::class) - internal enum class Internal { - UNKNOWN, - @SerialName("FINISH_REASON_UNSPECIFIED") UNSPECIFIED, - STOP, - MAX_TOKENS, - SAFETY, - RECITATION, - OTHER, - BLOCKLIST, - PROHIBITED_CONTENT, - SPII, - MALFORMED_FUNCTION_CALL; - - internal object Serializer : KSerializer by FirstOrdinalSerializer(Internal::class) - - internal fun toPublic() = - when (this) { - MAX_TOKENS -> FinishReason.MAX_TOKENS - RECITATION -> FinishReason.RECITATION - SAFETY -> FinishReason.SAFETY - STOP -> FinishReason.STOP - OTHER -> FinishReason.OTHER - BLOCKLIST -> FinishReason.BLOCKLIST - PROHIBITED_CONTENT -> FinishReason.PROHIBITED_CONTENT - SPII -> FinishReason.SPII - MALFORMED_FUNCTION_CALL -> FinishReason.MALFORMED_FUNCTION_CALL - else -> FinishReason.UNKNOWN - } - } - public companion object { - /** A new and not yet supported value. */ - @JvmField public val UNKNOWN: FinishReason = FinishReason("UNKNOWN", 0) - - /** Model finished successfully and stopped. */ - @JvmField public val STOP: FinishReason = FinishReason("STOP", 1) - - /** Model hit the token limit. */ - @JvmField public val MAX_TOKENS: FinishReason = FinishReason("MAX_TOKENS", 2) - - /** [SafetySetting] prevented the model from outputting content. */ - @JvmField public val SAFETY: FinishReason = FinishReason("SAFETY", 3) - - /** - * The token generation was stopped because the response was flagged for unauthorized citations. - */ - @JvmField public val RECITATION: FinishReason = FinishReason("RECITATION", 4) - - /** Model stopped for another reason. */ - @JvmField public val OTHER: FinishReason = FinishReason("OTHER", 5) - - /** Token generation stopped because the content contains forbidden terms. */ - @JvmField public val BLOCKLIST: FinishReason = FinishReason("BLOCKLIST", 6) - - /** Token generation stopped for potentially containing prohibited content. */ - @JvmField public val PROHIBITED_CONTENT: FinishReason = FinishReason("PROHIBITED_CONTENT", 7) - - /** - * Token generation stopped because the content potentially contains Sensitive Personally - * Identifiable Information (SPII). - */ - @JvmField public val SPII: FinishReason = FinishReason("SPII", 8) - - /** The function call generated by the model is invalid. */ - @JvmField - public val MALFORMED_FUNCTION_CALL: FinishReason = FinishReason("MALFORMED_FUNCTION_CALL", 9) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Content.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Content.kt deleted file mode 100644 index cee5e2f51e5..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Content.kt +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import android.graphics.Bitmap -import kotlinx.serialization.EncodeDefault -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable - -/** - * Represents content sent to and received from the model. - * - * `Content` is composed of a one or more heterogeneous parts that can be represent data in - * different formats, like text or images. - * - * @param role The producer of the content. Must be either `"user"` or `"model"`. By default, it's - * `"user"`. - * @param parts An ordered list of [Part] that constitute this content. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class Content -@JvmOverloads -constructor(public val role: String? = "user", public val parts: List) { - - /** Returns a copy of this object, with the provided parameters overwriting the originals. */ - public fun copy(role: String? = this.role, parts: List = this.parts): Content { - return Content(role, parts) - } - - /** Builder class to facilitate constructing complex [Content] objects. */ - @Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" - ) - public class Builder { - - /** The producer of the content. Must be either 'user' or 'model'. By default, it's "user". */ - public var role: String? = "user" - - /** - * The mutable list of [Part]s comprising the [Content]. - * - * Prefer using the provided helper methods over modifying this list directly. - */ - public var parts: MutableList = arrayListOf() - - /** Adds a new [Part] to [parts]. */ - @JvmName("addPart") - public fun part(data: T): Content.Builder = apply { parts.add(data) } - - /** Adds a new [TextPart] with the provided [text] to [parts]. */ - @JvmName("addText") public fun text(text: String): Content.Builder = part(TextPart(text)) - - /** - * Adds a new [InlineDataPart] with the provided [bytes], which should be interpreted by the - * model based on the [mimeType], to [parts]. - */ - @JvmName("addInlineData") - public fun inlineData(bytes: ByteArray, mimeType: String): Content.Builder = - part(InlineDataPart(bytes, mimeType)) - - /** Adds a new [ImagePart] with the provided [image] to [parts]. */ - @JvmName("addImage") public fun image(image: Bitmap): Content.Builder = part(ImagePart(image)) - - /** Adds a new [FileDataPart] with the provided [uri] and [mimeType] to [parts]. */ - @JvmName("addFileData") - public fun fileData(uri: String, mimeType: String): Content.Builder = - part(FileDataPart(uri, mimeType)) - - /** Returns a new [Content] using the defined [role] and [parts]. */ - public fun build(): Content = Content(role, parts) - } - - @OptIn(ExperimentalSerializationApi::class) - internal fun toInternal() = Internal(this.role ?: "user", this.parts.map { it.toInternal() }) - - @ExperimentalSerializationApi - @Serializable - internal data class Internal( - @EncodeDefault val role: String? = "user", - val parts: List - ) { - internal fun toPublic(): Content { - val returnedParts = - parts.map { it.toPublic() }.filterNot { it is TextPart && it.text.isEmpty() } - // If all returned parts were text and empty, we coalesce them into a single one-character - // string - // part so the backend doesn't fail if we send this back as part of a multi-turn interaction. - return Content(role, returnedParts.ifEmpty { listOf(TextPart(" ")) }) - } - } -} - -/** - * Function to build a new [Content] instances in a DSL-like manner. - * - * Contains a collection of text, image, and binary parts. - * - * Example usage: - * ``` - * content("user") { - * text("Example string") - * ) - * ``` - */ -public fun content(role: String? = "user", init: Content.Builder.() -> Unit): Content { - val builder = Content.Builder() - builder.role = role - builder.init() - return builder.build() -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ContentModality.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ContentModality.kt deleted file mode 100644 index 4f1566eae1a..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ContentModality.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import com.google.firebase.vertexai.common.util.FirstOrdinalSerializer -import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -/** Content part modality. */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ContentModality private constructor(public val ordinal: Int) { - - @Serializable(Internal.Serializer::class) - internal enum class Internal { - @SerialName("MODALITY_UNSPECIFIED") UNSPECIFIED, - TEXT, - IMAGE, - VIDEO, - AUDIO, - DOCUMENT; - - internal object Serializer : KSerializer by FirstOrdinalSerializer(Internal::class) - - internal fun toPublic() = - when (this) { - TEXT -> ContentModality.TEXT - IMAGE -> ContentModality.IMAGE - VIDEO -> ContentModality.VIDEO - AUDIO -> ContentModality.AUDIO - DOCUMENT -> ContentModality.DOCUMENT - else -> ContentModality.UNSPECIFIED - } - } - - internal fun toInternal() = - when (this) { - TEXT -> "TEXT" - IMAGE -> "IMAGE" - VIDEO -> "VIDEO" - AUDIO -> "AUDIO" - DOCUMENT -> "DOCUMENT" - else -> "UNSPECIFIED" - } - public companion object { - /** Unspecified modality. */ - @JvmField public val UNSPECIFIED: ContentModality = ContentModality(0) - - /** Plain text. */ - @JvmField public val TEXT: ContentModality = ContentModality(1) - - /** Image. */ - @JvmField public val IMAGE: ContentModality = ContentModality(2) - - /** Video. */ - @JvmField public val VIDEO: ContentModality = ContentModality(3) - - /** Audio. */ - @JvmField public val AUDIO: ContentModality = ContentModality(4) - - /** Document, e.g. PDF. */ - @JvmField public val DOCUMENT: ContentModality = ContentModality(5) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/CountTokensResponse.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/CountTokensResponse.kt deleted file mode 100644 index 2c3396c83b2..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/CountTokensResponse.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.Serializable - -/** - * The model's response to a count tokens request. - * - * **Important:** The counters in this class do not include billable image, video or other non-text - * input. See [Vertex AI pricing](https://cloud.google.com/vertex-ai/generative-ai/pricing) for - * details. - * - * @property totalTokens The total number of tokens in the input given to the model as a prompt. - * @property totalBillableCharacters The total number of billable characters in the text input given - * to the model as a prompt. **Important:** this property does not include billable image, video or - * other non-text input. See - * [Vertex AI pricing](https://cloud.google.com/vertex-ai/generative-ai/pricing) for details. - * @property promptTokensDetails The breakdown, by modality, of how many tokens are consumed by the - * prompt. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class CountTokensResponse( - public val totalTokens: Int, - public val totalBillableCharacters: Int? = null, - public val promptTokensDetails: List = emptyList(), -) { - public operator fun component1(): Int = totalTokens - - public operator fun component2(): Int? = totalBillableCharacters - - public operator fun component3(): List? = promptTokensDetails - - @Serializable - internal data class Internal( - val totalTokens: Int, - val totalBillableCharacters: Int? = null, - val promptTokensDetails: List? = null - ) : Response { - - internal fun toPublic(): CountTokensResponse { - return CountTokensResponse( - totalTokens, - totalBillableCharacters ?: 0, - promptTokensDetails?.map { it.toPublic() } ?: emptyList() - ) - } - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Exceptions.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Exceptions.kt deleted file mode 100644 index 8ea94ce2086..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Exceptions.kt +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import com.google.firebase.vertexai.FirebaseVertexAI -import com.google.firebase.vertexai.common.FirebaseCommonAIException -import kotlinx.coroutines.TimeoutCancellationException - -/** Parent class for any errors that occur from the [FirebaseVertexAI] SDK. */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public abstract class FirebaseVertexAIException -internal constructor(message: String, cause: Throwable? = null) : RuntimeException(message, cause) { - - internal companion object { - - /** - * Converts a [Throwable] to a [FirebaseVertexAIException]. - * - * Will populate default messages as expected, and propagate the provided [cause] through the - * resulting exception. - */ - internal fun from(cause: Throwable): FirebaseVertexAIException = - when (cause) { - is FirebaseVertexAIException -> cause - is FirebaseCommonAIException -> - when (cause) { - is com.google.firebase.vertexai.common.SerializationException -> - SerializationException(cause.message ?: "", cause.cause) - is com.google.firebase.vertexai.common.ServerException -> - ServerException(cause.message ?: "", cause.cause) - is com.google.firebase.vertexai.common.InvalidAPIKeyException -> - InvalidAPIKeyException(cause.message ?: "") - is com.google.firebase.vertexai.common.PromptBlockedException -> - PromptBlockedException(cause.response?.toPublic(), cause.cause) - is com.google.firebase.vertexai.common.UnsupportedUserLocationException -> - UnsupportedUserLocationException(cause.cause) - is com.google.firebase.vertexai.common.InvalidStateException -> - InvalidStateException(cause.message ?: "", cause) - is com.google.firebase.vertexai.common.ResponseStoppedException -> - ResponseStoppedException(cause.response.toPublic(), cause.cause) - is com.google.firebase.vertexai.common.RequestTimeoutException -> - RequestTimeoutException(cause.message ?: "", cause.cause) - is com.google.firebase.vertexai.common.ServiceDisabledException -> - ServiceDisabledException(cause.message ?: "", cause.cause) - is com.google.firebase.vertexai.common.UnknownException -> - UnknownException(cause.message ?: "", cause.cause) - is com.google.firebase.vertexai.common.ContentBlockedException -> - ContentBlockedException(cause.message ?: "", cause.cause) - is com.google.firebase.vertexai.common.QuotaExceededException -> - QuotaExceededException(cause.message ?: "", cause.cause) - else -> UnknownException(cause.message ?: "", cause) - } - is TimeoutCancellationException -> - RequestTimeoutException("The request failed to complete in the allotted time.") - else -> UnknownException("Something unexpected happened.", cause) - } - - /** - * Catch any exception thrown in the [callback] block and rethrow it as a - * [FirebaseVertexAIException]. - * - * Will return whatever the [callback] returns as well. - * - * @see catch - */ - internal suspend fun catchAsync(callback: suspend () -> T): T { - try { - return callback() - } catch (e: Exception) { - throw from(e) - } - } - - /** - * Catch any exception thrown in the [callback] block and rethrow it as a - * [FirebaseVertexAIException]. - * - * Will return whatever the [callback] returns as well. - * - * @see catchAsync - */ - internal fun catch(callback: () -> T): T { - try { - return callback() - } catch (e: Exception) { - throw from(e) - } - } - } -} - -/** Something went wrong while trying to deserialize a response from the server. */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class SerializationException -internal constructor(message: String, cause: Throwable? = null) : - FirebaseVertexAIException(message, cause) - -/** The server responded with a non 200 response code. */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ServerException internal constructor(message: String, cause: Throwable? = null) : - FirebaseVertexAIException(message, cause) - -/** The provided API Key is not valid. */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class InvalidAPIKeyException -internal constructor(message: String, cause: Throwable? = null) : - FirebaseVertexAIException(message, cause) - -/** - * A request was blocked. - * - * See the [response's][response] `promptFeedback.blockReason` for more information. - * - * @property response The full server response. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class PromptBlockedException -internal constructor( - public val response: GenerateContentResponse?, - cause: Throwable? = null, - message: String? = null, -) : - FirebaseVertexAIException( - "Prompt was blocked: ${response?.promptFeedback?.blockReason?.name?: message}", - cause, - ) { - internal constructor(message: String, cause: Throwable? = null) : this(null, cause, message) -} - -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ContentBlockedException -internal constructor(message: String, cause: Throwable? = null) : - FirebaseVertexAIException(message, cause) - -/** - * The user's location (region) is not supported by the API. - * - * See the documentation for a - * [list of regions](https://firebase.google.com/docs/vertex-ai/locations?platform=android#available-locations) - * (countries and territories) where the API is available. - */ -// TODO(rlazo): Add secondary constructor to pass through the message? -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class UnsupportedUserLocationException internal constructor(cause: Throwable? = null) : - FirebaseVertexAIException("User location is not supported for the API use.", cause) - -/** - * Some form of state occurred that shouldn't have. - * - * Usually indicative of consumer error. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class InvalidStateException internal constructor(message: String, cause: Throwable? = null) : - FirebaseVertexAIException(message, cause) - -/** - * A request was stopped during generation for some reason. - * - * @property response The full server response. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ResponseStoppedException -internal constructor(public val response: GenerateContentResponse, cause: Throwable? = null) : - FirebaseVertexAIException( - "Content generation stopped. Reason: ${response.candidates.first().finishReason?.name}", - cause, - ) - -/** - * A request took too long to complete. - * - * Usually occurs due to a user specified [timeout][RequestOptions.timeout]. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class RequestTimeoutException -internal constructor(message: String, cause: Throwable? = null) : - FirebaseVertexAIException(message, cause) - -/** - * The specified Vertex AI location is invalid. - * - * For a list of valid locations, see - * [Vertex AI locations.](https://cloud.google.com/vertex-ai/generative-ai/docs/learn/locations#available-regions) - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class InvalidLocationException -internal constructor(location: String, cause: Throwable? = null) : - FirebaseVertexAIException("Invalid location \"${location}\"", cause) - -/** - * The service is not enabled for this Firebase project. Learn how to enable the required services - * in the - * [Firebase documentation.](https://firebase.google.com/docs/vertex-ai/faq-and-troubleshooting#required-apis) - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ServiceDisabledException -internal constructor(message: String, cause: Throwable? = null) : - FirebaseVertexAIException(message, cause) - -/** - * The request has hit a quota limit. Learn more about quotas in the - * [Firebase documentation.](https://firebase.google.com/docs/vertex-ai/quotas) - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class QuotaExceededException -internal constructor(message: String, cause: Throwable? = null) : - FirebaseVertexAIException(message, cause) - -/** Streaming session already receiving. */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class SessionAlreadyReceivingException : - FirebaseVertexAIException( - "This session is already receiving. Please call stopReceiving() before calling this again." - ) - -/** Audio record initialization failures for audio streaming */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class AudioRecordInitializationFailedException(message: String) : - FirebaseVertexAIException(message) - -/** Handshake failed with the server */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ServiceConnectionHandshakeFailedException(message: String, cause: Throwable? = null) : - FirebaseVertexAIException(message, cause) - -/** Catch all case for exceptions not explicitly expected. */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class UnknownException internal constructor(message: String, cause: Throwable? = null) : - FirebaseVertexAIException(message, cause) diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/FunctionCallingConfig.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/FunctionCallingConfig.kt deleted file mode 100644 index 4305064f37c..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/FunctionCallingConfig.kt +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -/** - * The configuration that specifies the function calling behavior. - * - * See the static methods in the `companion object` for the list of available behaviors. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class FunctionCallingConfig -internal constructor( - internal val mode: Mode, - internal val allowedFunctionNames: List? = null -) { - - /** Configuration for dictating when the model should call the attached function. */ - internal enum class Mode { - /** - * The default behavior for function calling. The model calls functions to answer queries at its - * discretion - */ - AUTO, - - /** The model always predicts a provided function call to answer every query. */ - ANY, - - /** - * The model will never predict a function call to answer a query. This can also be achieved by - * not passing any tools to the model. - */ - NONE, - } - - @Serializable - internal data class Internal( - val mode: Mode, - @SerialName("allowed_function_names") val allowedFunctionNames: List? = null - ) { - @Serializable - enum class Mode { - @SerialName("MODE_UNSPECIFIED") UNSPECIFIED, - AUTO, - ANY, - NONE, - } - } - - public companion object { - /** - * The default behavior for function calling. The model calls functions to answer queries at its - * discretion. - */ - @JvmStatic public fun auto(): FunctionCallingConfig = FunctionCallingConfig(Mode.AUTO) - - /** The model always predicts a provided function call to answer every query. */ - @JvmStatic - @JvmOverloads - public fun any(allowedFunctionNames: List? = null): FunctionCallingConfig = - FunctionCallingConfig(Mode.ANY, allowedFunctionNames) - - /** - * The model will never predict a function call to answer a query. This can also be achieved by - * not passing any tools to the model. - */ - @JvmStatic public fun none(): FunctionCallingConfig = FunctionCallingConfig(Mode.NONE) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/FunctionDeclaration.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/FunctionDeclaration.kt deleted file mode 100644 index af07dc40188..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/FunctionDeclaration.kt +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.Serializable - -/** - * Defines a function that the model can use as a tool. - * - * When generating responses, the model might need external information or require the application - * to perform an action. `FunctionDeclaration` provides the necessary information for the model to - * create a [FunctionCallPart], which instructs the client to execute the corresponding function. - * The client then sends the result back to the model as a [FunctionResponsePart]. - * - * For example - * - * ``` - * val getExchangeRate = FunctionDeclaration( - * name = "getExchangeRate", - * description = "Get the exchange rate for currencies between countries.", - * parameters = mapOf( - * "currencyFrom" to Schema.str("The currency to convert from."), - * "currencyTo" to Schema.str("The currency to convert to.") - * ) - * ) - * ``` - * - * See the - * [Use the Gemini API for function calling](https://firebase.google.com/docs/vertex-ai/function-calling?platform=android) - * guide for more information on function calling. - * - * @param name The name of the function. - * @param description The description of what the function does and its output. To improve the - * effectiveness of the model, the description should be clear and detailed. - * @param parameters The map of parameters names to their [Schema] the function accepts as - * arguments. - * @param optionalParameters The list of parameter names that the model can omit when invoking this - * function. - * @see Schema - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class FunctionDeclaration( - internal val name: String, - internal val description: String, - internal val parameters: Map, - internal val optionalParameters: List = emptyList(), -) { - internal val schema: Schema = - Schema.obj(properties = parameters, optionalProperties = optionalParameters, nullable = false) - - internal fun toInternal() = Internal(name, "", schema.toInternal()) - - @Serializable - internal data class Internal( - val name: String, - val description: String, - val parameters: Schema.Internal - ) -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/GenerateContentResponse.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/GenerateContentResponse.kt deleted file mode 100644 index afddffb8a15..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/GenerateContentResponse.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.Serializable - -/** - * A response from the model. - * - * @property candidates The list of [Candidate] responses generated by the model. - * @property promptFeedback Feedback about the prompt send to the model to generate this response. - * When streaming, it's only populated in the first response. - * @property usageMetadata Information about the number of tokens in the prompt and in the response. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class GenerateContentResponse( - public val candidates: List, - public val promptFeedback: PromptFeedback?, - public val usageMetadata: UsageMetadata?, -) { - /** - * Convenience field representing all the text parts in the response as a single string, if they - * exists. - */ - public val text: String? by lazy { - candidates.first().content.parts.filterIsInstance().joinToString(" ") { it.text } - } - - /** Convenience field to list all the [FunctionCallPart]s in the response, if they exist. */ - public val functionCalls: List by lazy { - candidates.first().content.parts.filterIsInstance() - } - - /** - * Convenience field representing all the [InlineDataPart]s in the first candidate, if they exist. - * - * This also includes any [ImagePart], but they will be represented as [InlineDataPart] instead. - */ - public val inlineDataParts: List by lazy { - candidates.first().content.parts.let { parts -> - parts.filterIsInstance().map { it.toInlineDataPart() } + - parts.filterIsInstance() - } - } - - @Serializable - internal data class Internal( - val candidates: List? = null, - val promptFeedback: PromptFeedback.Internal? = null, - val usageMetadata: UsageMetadata.Internal? = null, - ) : Response { - internal fun toPublic(): GenerateContentResponse { - return GenerateContentResponse( - candidates?.map { it.toPublic() }.orEmpty(), - promptFeedback?.toPublic(), - usageMetadata?.toPublic() - ) - } - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/GenerationConfig.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/GenerationConfig.kt deleted file mode 100644 index 9dfcb822b2c..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/GenerationConfig.kt +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -/** - * Configuration parameters to use for content generation. - * - * @property temperature A parameter controlling the degree of randomness in token selection. A - * temperature of 0 means that the highest probability tokens are always selected. In this case, - * responses for a given prompt are mostly deterministic, but a small amount of variation is still - * possible. - * - * @property topK The `topK` parameter changes how the model selects tokens for output. A `topK` of - * 1 means the selected token is the most probable among all the tokens in the model's vocabulary, - * while a `topK` of 3 means that the next token is selected from among the 3 most probable using - * the `temperature`. For each token selection step, the `topK` tokens with the highest - * probabilities are sampled. Tokens are then further filtered based on `topP` with the final token - * selected using `temperature` sampling. Defaults to 40 if unspecified. - * - * @property topP The `topP` parameter changes how the model selects tokens for output. Tokens are - * selected from the most to least probable until the sum of their probabilities equals the `topP` - * value. For example, if tokens A, B, and C have probabilities of 0.3, 0.2, and 0.1 respectively - * and the topP value is 0.5, then the model will select either A or B as the next token by using - * the `temperature` and exclude C as a candidate. Defaults to 0.95 if unset. - * - * @property candidateCount The maximum number of generated response messages to return. This value - * must be between [1, 8], inclusive. If unset, this will default to 1. - * - * - Note: Only unique candidates are returned. Higher temperatures are more likely to produce - * unique candidates. Setting `temperature` to 0 will always produce exactly one candidate - * regardless of the `candidateCount`. - * - * @property presencePenalty Positive penalties. - * - * @property frequencyPenalty Frequency penalties. - * - * @property maxOutputTokens Specifies the maximum number of tokens that can be generated in the - * response. The number of tokens per word varies depending on the language outputted. Defaults to 0 - * (unbounded). - * - * @property stopSequences A set of up to 5 `String`s that will stop output generation. If - * specified, the API will stop at the first appearance of a stop sequence. The stop sequence will - * not be included as part of the response. - * - * @property responseMimeType Output response MIME type of the generated candidate text (IANA - * standard). - * - * Supported MIME types depend on the model used, but could include: - * - `text/plain`: Text output; the default behavior if unspecified. - * - `application/json`: JSON response in the candidates. - * - * @property responseSchema Output schema of the generated candidate text. If set, a compatible - * [responseMimeType] must also be set. - * - * @property responseModalities The format of data in which the model should respond with. - * - * Compatible MIME types: - * - `application/json`: Schema for JSON response. - * - * Refer to the - * [Control generated output](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/control-generated-output) - * guide for more details. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class GenerationConfig -private constructor( - internal val temperature: Float?, - internal val topK: Int?, - internal val topP: Float?, - internal val candidateCount: Int?, - internal val maxOutputTokens: Int?, - internal val presencePenalty: Float?, - internal val frequencyPenalty: Float?, - internal val stopSequences: List?, - internal val responseMimeType: String?, - internal val responseSchema: Schema?, - internal val responseModalities: List?, -) { - - /** - * Builder for creating a [GenerationConfig]. - * - * Mainly intended for Java interop. Kotlin consumers should use [generationConfig] for a more - * idiomatic experience. - * - * @property temperature See [GenerationConfig.temperature]. - * - * @property topK See [GenerationConfig.topK]. - * - * @property topP See [GenerationConfig.topP]. - * - * @property presencePenalty See [GenerationConfig.presencePenalty] - * - * @property frequencyPenalty See [GenerationConfig.frequencyPenalty] - * - * @property candidateCount See [GenerationConfig.candidateCount]. - * - * @property maxOutputTokens See [GenerationConfig.maxOutputTokens]. - * - * @property stopSequences See [GenerationConfig.stopSequences]. - * - * @property responseMimeType See [GenerationConfig.responseMimeType]. - * - * @property responseSchema See [GenerationConfig.responseSchema]. - * - * @property responseModalities See [GenerationConfig.responseModalities]. - * - * @see [generationConfig] - */ - @Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" - ) - public class Builder { - @JvmField public var temperature: Float? = null - @JvmField public var topK: Int? = null - @JvmField public var topP: Float? = null - @JvmField public var candidateCount: Int? = null - @JvmField public var maxOutputTokens: Int? = null - @JvmField public var presencePenalty: Float? = null - @JvmField public var frequencyPenalty: Float? = null - @JvmField public var stopSequences: List? = null - @JvmField public var responseMimeType: String? = null - @JvmField public var responseSchema: Schema? = null - @JvmField public var responseModalities: List? = null - - /** Create a new [GenerationConfig] with the attached arguments. */ - public fun build(): GenerationConfig = - GenerationConfig( - temperature = temperature, - topK = topK, - topP = topP, - candidateCount = candidateCount, - maxOutputTokens = maxOutputTokens, - stopSequences = stopSequences, - presencePenalty = presencePenalty, - frequencyPenalty = frequencyPenalty, - responseMimeType = responseMimeType, - responseSchema = responseSchema, - responseModalities = responseModalities - ) - } - - internal fun toInternal() = - Internal( - temperature = temperature, - topP = topP, - topK = topK, - candidateCount = candidateCount, - maxOutputTokens = maxOutputTokens, - stopSequences = stopSequences, - frequencyPenalty = frequencyPenalty, - presencePenalty = presencePenalty, - responseMimeType = responseMimeType, - responseSchema = responseSchema?.toInternal(), - responseModalities = responseModalities?.map { it.toInternal() } - ) - - @Serializable - internal data class Internal( - val temperature: Float?, - @SerialName("top_p") val topP: Float?, - @SerialName("top_k") val topK: Int?, - @SerialName("candidate_count") val candidateCount: Int?, - @SerialName("max_output_tokens") val maxOutputTokens: Int?, - @SerialName("stop_sequences") val stopSequences: List?, - @SerialName("response_mime_type") val responseMimeType: String? = null, - @SerialName("presence_penalty") val presencePenalty: Float? = null, - @SerialName("frequency_penalty") val frequencyPenalty: Float? = null, - @SerialName("response_schema") val responseSchema: Schema.Internal? = null, - @SerialName("response_modalities") val responseModalities: List? = null - ) - - public companion object { - - /** - * Alternative casing for [GenerationConfig.Builder]: - * ``` - * val config = GenerationConfig.builder() - * ``` - */ - public fun builder(): Builder = Builder() - } -} - -/** - * Helper method to construct a [GenerationConfig] in a DSL-like manner. - * - * Example Usage: - * ``` - * generationConfig { - * temperature = 0.75f - * topP = 0.5f - * topK = 30 - * candidateCount = 4 - * maxOutputTokens = 300 - * stopSequences = listOf("in conclusion", "-----", "do you need") - * } - * ``` - */ -public fun generationConfig(init: GenerationConfig.Builder.() -> Unit): GenerationConfig { - val builder = GenerationConfig.builder() - builder.init() - return builder.build() -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/HarmBlockMethod.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/HarmBlockMethod.kt deleted file mode 100644 index ffe87023d4c..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/HarmBlockMethod.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import com.google.firebase.vertexai.common.makeMissingCaseException -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -/** - * Specifies how the block method computes the score that will be compared against the - * [HarmBlockThreshold] in [SafetySetting]. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class HarmBlockMethod private constructor(public val ordinal: Int) { - internal fun toInternal() = - when (this) { - SEVERITY -> Internal.SEVERITY - PROBABILITY -> Internal.PROBABILITY - else -> throw makeMissingCaseException("HarmBlockMethod", ordinal) - } - - @Serializable - internal enum class Internal { - @SerialName("HARM_BLOCK_METHOD_UNSPECIFIED") UNSPECIFIED, - SEVERITY, - PROBABILITY, - } - public companion object { - /** - * The harm block method uses both probability and severity scores. See [HarmSeverity] and - * [HarmProbability]. - */ - @JvmField public val SEVERITY: HarmBlockMethod = HarmBlockMethod(0) - - /** The harm block method uses the probability score. See [HarmProbability]. */ - @JvmField public val PROBABILITY: HarmBlockMethod = HarmBlockMethod(1) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/HarmBlockThreshold.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/HarmBlockThreshold.kt deleted file mode 100644 index 90fa451ad49..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/HarmBlockThreshold.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import com.google.firebase.vertexai.common.makeMissingCaseException -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -/** Represents the threshold for a [HarmCategory] to be allowed by [SafetySetting]. */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class HarmBlockThreshold private constructor(public val ordinal: Int) { - - internal fun toInternal() = - when (this) { - OFF -> Internal.OFF - NONE -> Internal.BLOCK_NONE - ONLY_HIGH -> Internal.BLOCK_ONLY_HIGH - MEDIUM_AND_ABOVE -> Internal.BLOCK_MEDIUM_AND_ABOVE - LOW_AND_ABOVE -> Internal.BLOCK_LOW_AND_ABOVE - else -> throw makeMissingCaseException("HarmBlockThreshold", ordinal) - } - - @Serializable - internal enum class Internal { - @SerialName("HARM_BLOCK_THRESHOLD_UNSPECIFIED") UNSPECIFIED, - BLOCK_LOW_AND_ABOVE, - BLOCK_MEDIUM_AND_ABOVE, - BLOCK_ONLY_HIGH, - BLOCK_NONE, - OFF - } - - public companion object { - /** Content with negligible harm is allowed. */ - @JvmField public val LOW_AND_ABOVE: HarmBlockThreshold = HarmBlockThreshold(0) - - /** Content with negligible to low harm is allowed. */ - @JvmField public val MEDIUM_AND_ABOVE: HarmBlockThreshold = HarmBlockThreshold(1) - - /** Content with negligible to medium harm is allowed. */ - @JvmField public val ONLY_HIGH: HarmBlockThreshold = HarmBlockThreshold(2) - - /** All content is allowed regardless of harm. */ - @JvmField public val NONE: HarmBlockThreshold = HarmBlockThreshold(3) - - /** - * All content is allowed regardless of harm. - * - * The same as [NONE], but metadata when the corresponding [HarmCategory] occurs will **NOT** be - * present in the response. - */ - @JvmField public val OFF: HarmBlockThreshold = HarmBlockThreshold(4) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/HarmCategory.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/HarmCategory.kt deleted file mode 100644 index 1850282e757..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/HarmCategory.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import com.google.firebase.vertexai.common.makeMissingCaseException -import com.google.firebase.vertexai.common.util.FirstOrdinalSerializer -import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -/** Category for a given harm rating. */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class HarmCategory private constructor(public val ordinal: Int) { - internal fun toInternal() = - when (this) { - HARASSMENT -> Internal.HARASSMENT - HATE_SPEECH -> Internal.HATE_SPEECH - SEXUALLY_EXPLICIT -> Internal.SEXUALLY_EXPLICIT - DANGEROUS_CONTENT -> Internal.DANGEROUS_CONTENT - CIVIC_INTEGRITY -> Internal.CIVIC_INTEGRITY - UNKNOWN -> Internal.UNKNOWN - else -> throw makeMissingCaseException("HarmCategory", ordinal) - } - @Serializable(Internal.Serializer::class) - internal enum class Internal { - UNKNOWN, - @SerialName("HARM_CATEGORY_HARASSMENT") HARASSMENT, - @SerialName("HARM_CATEGORY_HATE_SPEECH") HATE_SPEECH, - @SerialName("HARM_CATEGORY_SEXUALLY_EXPLICIT") SEXUALLY_EXPLICIT, - @SerialName("HARM_CATEGORY_DANGEROUS_CONTENT") DANGEROUS_CONTENT, - @SerialName("HARM_CATEGORY_CIVIC_INTEGRITY") CIVIC_INTEGRITY; - - internal object Serializer : KSerializer by FirstOrdinalSerializer(Internal::class) - - internal fun toPublic() = - when (this) { - HARASSMENT -> HarmCategory.HARASSMENT - HATE_SPEECH -> HarmCategory.HATE_SPEECH - SEXUALLY_EXPLICIT -> HarmCategory.SEXUALLY_EXPLICIT - DANGEROUS_CONTENT -> HarmCategory.DANGEROUS_CONTENT - CIVIC_INTEGRITY -> HarmCategory.CIVIC_INTEGRITY - else -> HarmCategory.UNKNOWN - } - } - public companion object { - /** A new and not yet supported value. */ - @JvmField public val UNKNOWN: HarmCategory = HarmCategory(0) - - /** Harassment content. */ - @JvmField public val HARASSMENT: HarmCategory = HarmCategory(1) - - /** Hate speech and content. */ - @JvmField public val HATE_SPEECH: HarmCategory = HarmCategory(2) - - /** Sexually explicit content. */ - @JvmField public val SEXUALLY_EXPLICIT: HarmCategory = HarmCategory(3) - - /** Dangerous content. */ - @JvmField public val DANGEROUS_CONTENT: HarmCategory = HarmCategory(4) - - /** Content that may be used to harm civic integrity. */ - @JvmField public val CIVIC_INTEGRITY: HarmCategory = HarmCategory(5) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/HarmProbability.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/HarmProbability.kt deleted file mode 100644 index 78c679ef935..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/HarmProbability.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import com.google.firebase.vertexai.common.util.FirstOrdinalSerializer -import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -/** Represents the probability that some [HarmCategory] is applicable in a [SafetyRating]. */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class HarmProbability private constructor(public val ordinal: Int) { - @Serializable(Internal.Serializer::class) - internal enum class Internal { - UNKNOWN, - @SerialName("HARM_PROBABILITY_UNSPECIFIED") UNSPECIFIED, - NEGLIGIBLE, - LOW, - MEDIUM, - HIGH; - - internal object Serializer : KSerializer by FirstOrdinalSerializer(Internal::class) - - internal fun toPublic() = - when (this) { - HIGH -> HarmProbability.HIGH - MEDIUM -> HarmProbability.MEDIUM - LOW -> HarmProbability.LOW - NEGLIGIBLE -> HarmProbability.NEGLIGIBLE - else -> HarmProbability.UNKNOWN - } - } - public companion object { - /** A new and not yet supported value. */ - @JvmField public val UNKNOWN: HarmProbability = HarmProbability(0) - - /** Probability for harm is negligible. */ - @JvmField public val NEGLIGIBLE: HarmProbability = HarmProbability(1) - - /** Probability for harm is low. */ - @JvmField public val LOW: HarmProbability = HarmProbability(2) - - /** Probability for harm is medium. */ - @JvmField public val MEDIUM: HarmProbability = HarmProbability(3) - - /** Probability for harm is high. */ - @JvmField public val HIGH: HarmProbability = HarmProbability(4) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/HarmSeverity.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/HarmSeverity.kt deleted file mode 100644 index c01db75ec8e..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/HarmSeverity.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import com.google.firebase.vertexai.common.util.FirstOrdinalSerializer -import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -/** Represents the severity of a [HarmCategory] being applicable in a [SafetyRating]. */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class HarmSeverity private constructor(public val ordinal: Int) { - @Serializable(Internal.Serializer::class) - internal enum class Internal { - UNKNOWN, - @SerialName("HARM_SEVERITY_UNSPECIFIED") UNSPECIFIED, - @SerialName("HARM_SEVERITY_NEGLIGIBLE") NEGLIGIBLE, - @SerialName("HARM_SEVERITY_LOW") LOW, - @SerialName("HARM_SEVERITY_MEDIUM") MEDIUM, - @SerialName("HARM_SEVERITY_HIGH") HIGH; - - internal object Serializer : KSerializer by FirstOrdinalSerializer(Internal::class) - - internal fun toPublic() = - when (this) { - HIGH -> HarmSeverity.HIGH - MEDIUM -> HarmSeverity.MEDIUM - LOW -> HarmSeverity.LOW - NEGLIGIBLE -> HarmSeverity.NEGLIGIBLE - else -> HarmSeverity.UNKNOWN - } - } - public companion object { - /** A new and not yet supported value. */ - @JvmField public val UNKNOWN: HarmSeverity = HarmSeverity(0) - - /** Severity for harm is negligible. */ - @JvmField public val NEGLIGIBLE: HarmSeverity = HarmSeverity(1) - - /** Low level of harm severity. */ - @JvmField public val LOW: HarmSeverity = HarmSeverity(2) - - /** Medium level of harm severity. */ - @JvmField public val MEDIUM: HarmSeverity = HarmSeverity(3) - - /** High level of harm severity. */ - @JvmField public val HIGH: HarmSeverity = HarmSeverity(4) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenAspectRatio.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenAspectRatio.kt deleted file mode 100644 index 6243ce27770..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenAspectRatio.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -/** Represents the aspect ratio that the generated image should conform to. */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ImagenAspectRatio private constructor(internal val internalVal: String) { - public companion object { - /** A square image, useful for icons, profile pictures, etc. */ - @JvmField public val SQUARE_1x1: ImagenAspectRatio = ImagenAspectRatio("1:1") - /** A portrait image in 3:4, the aspect ratio of older TVs. */ - @JvmField public val PORTRAIT_3x4: ImagenAspectRatio = ImagenAspectRatio("3:4") - /** A landscape image in 4:3, the aspect ratio of older TVs. */ - @JvmField public val LANDSCAPE_4x3: ImagenAspectRatio = ImagenAspectRatio("4:3") - /** A portrait image in 9:16, the aspect ratio of modern monitors and phone screens. */ - @JvmField public val PORTRAIT_9x16: ImagenAspectRatio = ImagenAspectRatio("9:16") - /** A landscape image in 16:9, the aspect ratio of modern monitors and phone screens. */ - @JvmField public val LANDSCAPE_16x9: ImagenAspectRatio = ImagenAspectRatio("16:9") - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenGCSImage.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenGCSImage.kt deleted file mode 100644 index 380bfa3c30b..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenGCSImage.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -/** - * Represents an Imagen-generated image that is contained in Google Cloud Storage. - * - * @param gcsUri Contains the `gs://` URI for the image. - * @param mimeType Contains the MIME type of the image (for example, `"image/png"`). - */ -@PublicPreviewAPI -internal class ImagenGCSImage -internal constructor(public val gcsUri: String, public val mimeType: String) {} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenGenerationConfig.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenGenerationConfig.kt deleted file mode 100644 index 508f28e62d7..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenGenerationConfig.kt +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -/** - * Contains extra settings to configure image generation. - * - * @param negativePrompt This string contains things that should be explicitly excluded from - * generated images. - * @param numberOfImages How many images should be generated. - * @param aspectRatio The aspect ratio of the generated images. - * @param imageFormat The file format/compression of the generated images. - * @param addWatermark Adds an invisible watermark to mark the image as AI generated. - */ -import kotlin.jvm.JvmField - -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ImagenGenerationConfig( - public val negativePrompt: String? = null, - public val numberOfImages: Int? = 1, - public val aspectRatio: ImagenAspectRatio? = null, - public val imageFormat: ImagenImageFormat? = null, - public val addWatermark: Boolean? = null, -) { - /** - * Builder for creating a [ImagenGenerationConfig]. - * - * This is mainly intended for Java interop. For Kotlin, use [imagenGenerationConfig] for a more - * idiomatic experience. - */ - @Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" - ) - public class Builder { - @JvmField public var negativePrompt: String? = null - @JvmField public var numberOfImages: Int? = 1 - @JvmField public var aspectRatio: ImagenAspectRatio? = null - @JvmField public var imageFormat: ImagenImageFormat? = null - @JvmField public var addWatermark: Boolean? = null - - /** See [ImagenGenerationConfig.negativePrompt]. */ - public fun setNegativePrompt(negativePrompt: String): Builder = apply { - this.negativePrompt = negativePrompt - } - - /** See [ImagenGenerationConfig.numberOfImages]. */ - public fun setNumberOfImages(numberOfImages: Int): Builder = apply { - this.numberOfImages = numberOfImages - } - - /** See [ImagenGenerationConfig.aspectRatio]. */ - public fun setAspectRatio(aspectRatio: ImagenAspectRatio): Builder = apply { - this.aspectRatio = aspectRatio - } - - /** See [ImagenGenerationConfig.imageFormat]. */ - public fun setImageFormat(imageFormat: ImagenImageFormat): Builder = apply { - this.imageFormat = imageFormat - } - - /** See [ImagenGenerationConfig.addWatermark]. */ - public fun setAddWatermark(addWatermark: Boolean): Builder = apply { - this.addWatermark = addWatermark - } - - /** - * Alternative casing for [ImagenGenerationConfig.Builder]: - * ``` - * val config = GenerationConfig.builder() - * ``` - */ - public fun build(): ImagenGenerationConfig = - ImagenGenerationConfig( - negativePrompt = negativePrompt, - numberOfImages = numberOfImages, - aspectRatio = aspectRatio, - imageFormat = imageFormat, - addWatermark = addWatermark, - ) - } - - public companion object { - public fun builder(): Builder = Builder() - } -} - -/** - * Helper method to construct a [ImagenGenerationConfig] in a DSL-like manner. - * - * Example Usage: - * ``` - * imagenGenerationConfig { - * negativePrompt = "People, black and white, painting" - * numberOfImages = 1 - * aspectRatio = ImagenAspecRatio.SQUARE_1x1 - * imageFormat = ImagenImageFormat.png() - * addWatermark = false - * } - * ``` - */ -@PublicPreviewAPI -public fun imagenGenerationConfig( - init: ImagenGenerationConfig.Builder.() -> Unit -): ImagenGenerationConfig { - val builder = ImagenGenerationConfig.builder() - builder.init() - return builder.build() -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenGenerationResponse.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenGenerationResponse.kt deleted file mode 100644 index acc1b54b563..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenGenerationResponse.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import android.util.Base64 -import com.google.firebase.vertexai.ImagenModel -import kotlinx.serialization.Serializable - -/** - * Represents a response from a call to [ImagenModel.generateImages] - * - * @param images contains the generated images - * @param filteredReason if fewer images were generated than were requested, this field will contain - * the reason they were filtered out. - */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ImagenGenerationResponse -internal constructor(public val images: List, public val filteredReason: String?) { - - @Serializable - internal data class Internal(val predictions: List) { - internal fun toPublicGCS() = - ImagenGenerationResponse( - images = predictions.filter { it.mimeType != null }.map { it.toPublicGCS() }, - null, - ) - - internal fun toPublicInline() = - ImagenGenerationResponse( - images = predictions.filter { it.mimeType != null }.map { it.toPublicInline() }, - null, - ) - } - - @Serializable - internal data class ImagenImageResponse( - val bytesBase64Encoded: String? = null, - val gcsUri: String? = null, - val mimeType: String? = null, - val raiFilteredReason: String? = null, - ) { - internal fun toPublicInline() = - ImagenInlineImage(Base64.decode(bytesBase64Encoded!!, Base64.NO_WRAP), mimeType!!) - - internal fun toPublicGCS() = ImagenGCSImage(gcsUri!!, mimeType!!) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenImageFormat.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenImageFormat.kt deleted file mode 100644 index afd309047cb..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenImageFormat.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.Serializable - -/** - * Represents the format an image should be returned in. - * - * @param mimeType A string (like `"image/jpeg"`) specifying the encoding MIME type of the image. - * @param compressionQuality an int (1-100) representing the quality of the image; a lower number - * means the image is permitted to be lower quality to reduce size. This parameter is not relevant - * for every MIME type. - */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ImagenImageFormat -private constructor(public val mimeType: String, public val compressionQuality: Int?) { - - internal fun toInternal() = Internal(mimeType, compressionQuality) - - @Serializable internal data class Internal(val mimeType: String, val compressionQuality: Int?) - - public companion object { - /** - * An [ImagenImageFormat] representing a JPEG image. - * - * @param compressionQuality an int (1-100) representing the quality of the image; a lower - * number means the image is permitted to be lower quality to reduce size. - */ - @JvmStatic - public fun jpeg(compressionQuality: Int? = null): ImagenImageFormat { - return ImagenImageFormat("image/jpeg", compressionQuality) - } - - /** An [ImagenImageFormat] representing a PNG image */ - @JvmStatic - public fun png(): ImagenImageFormat { - return ImagenImageFormat("image/png", null) - } - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenInlineImage.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenInlineImage.kt deleted file mode 100644 index 9af3e779082..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenInlineImage.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import android.graphics.Bitmap -import android.graphics.BitmapFactory - -/** - * Represents an Imagen-generated image that is returned as inline data. - * - * @property data The raw image bytes in JPEG or PNG format, as specified by [mimeType]. - * @property mimeType The IANA standard MIME type of the image data; either `"image/png"` or - * `"image/jpeg"`; to request a different format, see [ImagenGenerationConfig.imageFormat]. - */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ImagenInlineImage -internal constructor(public val data: ByteArray, public val mimeType: String) { - - /** - * Returns the image as an Android OS native [Bitmap] so that it can be saved or sent to the UI. - */ - public fun asBitmap(): Bitmap { - return BitmapFactory.decodeByteArray(data, 0, data.size) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenPersonFilterLevel.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenPersonFilterLevel.kt deleted file mode 100644 index 8d4de743345..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenPersonFilterLevel.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -/** A filter used to prevent images from containing depictions of children or people. */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ImagenPersonFilterLevel private constructor(internal val internalVal: String) { - public companion object { - /** No filters applied. */ - @JvmField public val ALLOW_ALL: ImagenPersonFilterLevel = ImagenPersonFilterLevel("allow_all") - /** Filters out any images containing depictions of children. */ - @JvmField - public val ALLOW_ADULT: ImagenPersonFilterLevel = ImagenPersonFilterLevel("allow_adult") - /** Filters out any images containing depictions of people. */ - @JvmField public val BLOCK_ALL: ImagenPersonFilterLevel = ImagenPersonFilterLevel("dont_allow") - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenSafetyFilterLevel.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenSafetyFilterLevel.kt deleted file mode 100644 index 72a325737ba..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenSafetyFilterLevel.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -/** Used for safety filtering. */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ImagenSafetyFilterLevel private constructor(internal val internalVal: String) { - public companion object { - /** Strongest filtering level, most strict blocking. */ - @JvmField - public val BLOCK_LOW_AND_ABOVE: ImagenSafetyFilterLevel = - ImagenSafetyFilterLevel("block_low_and_above") - /** Block some problematic prompts and responses. */ - @JvmField - public val BLOCK_MEDIUM_AND_ABOVE: ImagenSafetyFilterLevel = - ImagenSafetyFilterLevel("block_medium_and_above") - /** - * Reduces the number of requests blocked due to safety filters. May increase objectionable - * content generated by the Imagen model. - */ - @JvmField - public val BLOCK_ONLY_HIGH: ImagenSafetyFilterLevel = ImagenSafetyFilterLevel("block_only_high") - /** Turns off all optional safety filters. */ - @JvmField public val BLOCK_NONE: ImagenSafetyFilterLevel = ImagenSafetyFilterLevel("block_none") - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenSafetySettings.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenSafetySettings.kt deleted file mode 100644 index f619c8985d3..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ImagenSafetySettings.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -/** - * A configuration for filtering unsafe content or images containing people. - * - * @param safetyFilterLevel Used to filter unsafe content. - * @param personFilterLevel Used to filter images containing people. - */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ImagenSafetySettings( - internal val safetyFilterLevel: ImagenSafetyFilterLevel, - internal val personFilterLevel: ImagenPersonFilterLevel, -) {} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/LiveClientSetupMessage.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/LiveClientSetupMessage.kt deleted file mode 100644 index 6b751961ed2..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/LiveClientSetupMessage.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable - -/** - * First message in a live session. - * - * Contains configuration that will be used for the duration of the session. - */ -@OptIn(ExperimentalSerializationApi::class) -@PublicPreviewAPI -internal class LiveClientSetupMessage( - val model: String, - // Some config options are supported in generateContent but not in bidi and vise versa; so bidi - // needs its own config class - val generationConfig: LiveGenerationConfig.Internal?, - val tools: List?, - val systemInstruction: Content.Internal? -) { - @Serializable - internal class Internal(val setup: LiveClientSetup) { - @Serializable - internal data class LiveClientSetup( - val model: String, - val generationConfig: LiveGenerationConfig.Internal?, - val tools: List?, - val systemInstruction: Content.Internal? - ) - } - - fun toInternal() = - Internal(Internal.LiveClientSetup(model, generationConfig, tools, systemInstruction)) -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/LiveGenerationConfig.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/LiveGenerationConfig.kt deleted file mode 100644 index c3a51042641..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/LiveGenerationConfig.kt +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -/** - * Configuration parameters to use for live content generation. - * - * @property temperature A parameter controlling the degree of randomness in token selection. A - * temperature of 0 means that the highest probability tokens are always selected. In this case, - * responses for a given prompt are mostly deterministic, but a small amount of variation is still - * possible. - * - * @property topK The `topK` parameter changes how the model selects tokens for output. A `topK` of - * 1 means the selected token is the most probable among all the tokens in the model's vocabulary, - * while a `topK` of 3 means that the next token is selected from among the 3 most probable using - * the `temperature`. For each token selection step, the `topK` tokens with the highest - * probabilities are sampled. Tokens are then further filtered based on `topP` with the final token - * selected using `temperature` sampling. Defaults to 40 if unspecified. - * - * @property topP The `topP` parameter changes how the model selects tokens for output. Tokens are - * selected from the most to least probable until the sum of their probabilities equals the `topP` - * value. For example, if tokens A, B, and C have probabilities of 0.3, 0.2, and 0.1 respectively - * and the topP value is 0.5, then the model will select either A or B as the next token by using - * the `temperature` and exclude C as a candidate. Defaults to 0.95 if unset. - * - * @property candidateCount The maximum number of generated response messages to return. This value - * must be between [1, 8], inclusive. If unset, this will default to 1. - * - * - Note: Only unique candidates are returned. Higher temperatures are more likely to produce - * unique candidates. Setting `temperature` to 0 will always produce exactly one candidate - * regardless of the `candidateCount`. - * - * @property presencePenalty Positive penalties. - * - * @property frequencyPenalty Frequency penalties. - * - * @property maxOutputTokens Specifies the maximum number of tokens that can be generated in the - * response. The number of tokens per word varies depending on the language outputted. Defaults to 0 - * (unbounded). - * - * @property responseModality Specifies the format of the data in which the server responds to - * requests - * - * @property speechConfig Specifies the voice configuration of the audio response from the server. - * - * Refer to the - * [Control generated output](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/control-generated-output) - * guide for more details. - */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class LiveGenerationConfig -private constructor( - internal val temperature: Float?, - internal val topK: Int?, - internal val topP: Float?, - internal val candidateCount: Int?, - internal val maxOutputTokens: Int?, - internal val presencePenalty: Float?, - internal val frequencyPenalty: Float?, - internal val responseModality: ResponseModality?, - internal val speechConfig: SpeechConfig? -) { - - /** - * Builder for creating a [LiveGenerationConfig]. - * - * Mainly intended for Java interop. Kotlin consumers should use [liveGenerationConfig] for a more - * idiomatic experience. - * - * @property temperature See [LiveGenerationConfig.temperature]. - * - * @property topK See [LiveGenerationConfig.topK]. - * - * @property topP See [LiveGenerationConfig.topP]. - * - * @property presencePenalty See [LiveGenerationConfig.presencePenalty] - * - * @property frequencyPenalty See [LiveGenerationConfig.frequencyPenalty] - * - * @property candidateCount See [LiveGenerationConfig.candidateCount]. - * - * @property maxOutputTokens See [LiveGenerationConfig.maxOutputTokens]. - * - * @property responseModality See [LiveGenerationConfig.responseModality] - * - * @property speechConfig See [LiveGenerationConfig.speechConfig] - */ - @Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" - ) - public class Builder { - @JvmField public var temperature: Float? = null - @JvmField public var topK: Int? = null - @JvmField public var topP: Float? = null - @JvmField public var candidateCount: Int? = null - @JvmField public var maxOutputTokens: Int? = null - @JvmField public var presencePenalty: Float? = null - @JvmField public var frequencyPenalty: Float? = null - @JvmField public var responseModality: ResponseModality? = null - @JvmField public var speechConfig: SpeechConfig? = null - - public fun setTemperature(temperature: Float?): Builder = apply { - this.temperature = temperature - } - public fun setTopK(topK: Int?): Builder = apply { this.topK = topK } - public fun setTopP(topP: Float?): Builder = apply { this.topP = topP } - public fun setCandidateCount(candidateCount: Int?): Builder = apply { - this.candidateCount = candidateCount - } - public fun setMaxOutputTokens(maxOutputTokens: Int?): Builder = apply { - this.maxOutputTokens = maxOutputTokens - } - public fun setPresencePenalty(presencePenalty: Float?): Builder = apply { - this.presencePenalty = presencePenalty - } - public fun setFrequencyPenalty(frequencyPenalty: Float?): Builder = apply { - this.frequencyPenalty = frequencyPenalty - } - public fun setResponseModality(responseModality: ResponseModality?): Builder = apply { - this.responseModality = responseModality - } - public fun setSpeechConfig(speechConfig: SpeechConfig?): Builder = apply { - this.speechConfig = speechConfig - } - - /** Create a new [LiveGenerationConfig] with the attached arguments. */ - public fun build(): LiveGenerationConfig = - LiveGenerationConfig( - temperature = temperature, - topK = topK, - topP = topP, - candidateCount = candidateCount, - maxOutputTokens = maxOutputTokens, - presencePenalty = presencePenalty, - frequencyPenalty = frequencyPenalty, - speechConfig = speechConfig, - responseModality = responseModality - ) - } - - internal fun toInternal(): Internal { - return Internal( - temperature = temperature, - topP = topP, - topK = topK, - candidateCount = candidateCount, - maxOutputTokens = maxOutputTokens, - frequencyPenalty = frequencyPenalty, - presencePenalty = presencePenalty, - speechConfig = speechConfig?.toInternal(), - responseModalities = - if (responseModality != null) listOf(responseModality.toInternal()) else null - ) - } - - @Serializable - internal data class Internal( - val temperature: Float?, - @SerialName("top_p") val topP: Float?, - @SerialName("top_k") val topK: Int?, - @SerialName("candidate_count") val candidateCount: Int?, - @SerialName("max_output_tokens") val maxOutputTokens: Int?, - @SerialName("presence_penalty") val presencePenalty: Float? = null, - @SerialName("frequency_penalty") val frequencyPenalty: Float? = null, - @SerialName("speech_config") val speechConfig: SpeechConfig.Internal? = null, - @SerialName("response_modalities") val responseModalities: List? = null - ) - - public companion object { - - /** - * Alternative casing for [LiveGenerationConfig.Builder]: - * ``` - * val config = LiveGenerationConfig.builder() - * ``` - */ - public fun builder(): Builder = Builder() - } -} - -/** - * Helper method to construct a [LiveGenerationConfig] in a DSL-like manner. - * - * Example Usage: - * ``` - * liveGenerationConfig { - * temperature = 0.75f - * topP = 0.5f - * topK = 30 - * candidateCount = 4 - * maxOutputTokens = 300 - * ... - * } - * ``` - */ -@OptIn(PublicPreviewAPI::class) -public fun liveGenerationConfig( - init: LiveGenerationConfig.Builder.() -> Unit -): LiveGenerationConfig { - val builder = LiveGenerationConfig.builder() - builder.init() - return builder.build() -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/LiveServerMessage.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/LiveServerMessage.kt deleted file mode 100644 index c59624e0882..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/LiveServerMessage.kt +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.DeserializationStrategy -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonContentPolymorphicSerializer -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonNull -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.jsonObject - -/** - * Parent interface for responses from the model during live interactions. - * - * @see LiveServerContent - * @see LiveServerToolCall - * @see LiveServerToolCallCancellation - * @see LiveServerSetupComplete - */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public interface LiveServerMessage - -/** - * Incremental server update generated by the model in response to client messages. - * - * Content is generated as quickly as possible, and not in realtime. You may choose to buffer and - * play it out in realtime. - */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class LiveServerContent( - /** - * The content that the model has generated as part of the current conversation with the user. - * - * This can be `null` if there is no content. - */ - public val content: Content?, - - /** - * The model was interrupted by the client while generating data. - * - * An interruption occurs when the client sends a message while the model is actively sending - * data. - */ - public val interrupted: Boolean, - - /** - * The model has finished sending data in the current turn. - * - * Generation will only start in response to additional client messages. - * - * Can be set alongside [content], indicating that the [content] is the last in the turn. - * - * @see generationComplete - */ - public val turnComplete: Boolean, - - /** - * The model has finished _generating_ data for the current turn. - * - * For realtime playback, there will be a delay between when the model finishes generating content - * and the client has finished playing back the generated content. [generationComplete] indicates - * that the model is done generating data, while [turnComplete] indicates the model is waiting for - * additional client messages. Sending a message during this delay may cause an [interrupted] - * message to be sent. - * - * Note that if the model was [interrupted], this will not be set. The model will go from - * [interrupted] -> [turnComplete]. - */ - public val generationComplete: Boolean, -) : LiveServerMessage { - @OptIn(ExperimentalSerializationApi::class) - @Serializable - internal data class Internal( - val modelTurn: Content.Internal? = null, - val interrupted: Boolean = false, - val turnComplete: Boolean = false, - val generationComplete: Boolean = false - ) - @Serializable - internal data class InternalWrapper(val serverContent: Internal) : InternalLiveServerMessage { - @OptIn(ExperimentalSerializationApi::class) - override fun toPublic() = - LiveServerContent( - serverContent.modelTurn?.toPublic(), - serverContent.interrupted, - serverContent.turnComplete, - serverContent.generationComplete - ) - } -} - -/** The model is ready to receive client messages. */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class LiveServerSetupComplete : LiveServerMessage { - @Serializable - internal data class Internal(val setupComplete: JsonObject) : InternalLiveServerMessage { - override fun toPublic() = LiveServerSetupComplete() - } -} - -/** - * Request for the client to execute the provided [functionCalls]. - * - * The client should return matching [FunctionResponsePart], where the `id` fields correspond to - * individual [FunctionCallPart]s. - * - * @property functionCalls A list of [FunctionCallPart] to run and return responses for. - */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class LiveServerToolCall(public val functionCalls: List) : - LiveServerMessage { - @Serializable - internal data class Internal( - val functionCalls: List = emptyList() - ) - @Serializable - internal data class InternalWrapper(val toolCall: Internal) : InternalLiveServerMessage { - override fun toPublic() = - LiveServerToolCall( - toolCall.functionCalls.map { functionCall -> - FunctionCallPart( - name = functionCall.name, - args = functionCall.args.orEmpty().mapValues { it.value ?: JsonNull } - ) - } - ) - } -} - -/** - * Notification for the client to cancel a previous function call from [LiveServerToolCall]. - * - * You do not need to send [FunctionResponsePart]s for the cancelled [FunctionCallPart]s. - * - * @property functionIds A list of `id`s matching the `id` provided in a previous - * [LiveServerToolCall], where only the provided `id`s should be cancelled. - */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class LiveServerToolCallCancellation(public val functionIds: List) : - LiveServerMessage { - @Serializable internal data class Internal(val functionIds: List = emptyList()) - @Serializable - internal data class InternalWrapper(val toolCallCancellation: Internal) : - InternalLiveServerMessage { - override fun toPublic() = LiveServerToolCallCancellation(toolCallCancellation.functionIds) - } -} - -@PublicPreviewAPI -@Serializable(LiveServerMessageSerializer::class) -internal sealed interface InternalLiveServerMessage { - fun toPublic(): LiveServerMessage -} - -@OptIn(PublicPreviewAPI::class) -internal object LiveServerMessageSerializer : - JsonContentPolymorphicSerializer(InternalLiveServerMessage::class) { - @OptIn(PublicPreviewAPI::class) - override fun selectDeserializer( - element: JsonElement - ): DeserializationStrategy { - val jsonObject = element.jsonObject - return when { - "serverContent" in jsonObject -> LiveServerContent.InternalWrapper.serializer() - "setupComplete" in jsonObject -> LiveServerSetupComplete.Internal.serializer() - "toolCall" in jsonObject -> LiveServerToolCall.InternalWrapper.serializer() - "toolCallCancellation" in jsonObject -> - LiveServerToolCallCancellation.InternalWrapper.serializer() - else -> - throw SerializationException( - "The given subclass of LiveServerMessage (${javaClass.simpleName}) is not supported in the serialization yet." - ) - } - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/LiveSession.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/LiveSession.kt deleted file mode 100644 index 072320674c7..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/LiveSession.kt +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import android.Manifest.permission.RECORD_AUDIO -import android.media.AudioFormat -import android.media.AudioTrack -import android.util.Log -import androidx.annotation.RequiresPermission -import com.google.firebase.annotations.concurrent.Blocking -import com.google.firebase.vertexai.common.JSON -import com.google.firebase.vertexai.common.util.CancelledCoroutineScope -import com.google.firebase.vertexai.common.util.accumulateUntil -import com.google.firebase.vertexai.common.util.childJob -import io.ktor.client.plugins.websocket.ClientWebSocketSession -import io.ktor.websocket.Frame -import io.ktor.websocket.close -import io.ktor.websocket.readBytes -import java.util.concurrent.ConcurrentLinkedQueue -import java.util.concurrent.atomic.AtomicBoolean -import kotlin.coroutines.CoroutineContext -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.cancel -import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.buffer -import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onCompletion -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.isActive -import kotlinx.coroutines.launch -import kotlinx.coroutines.yield -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json - -/** Represents a live WebSocket session capable of streaming content to and from the server. */ -@PublicPreviewAPI -@OptIn(ExperimentalSerializationApi::class) -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class LiveSession -internal constructor( - private val session: ClientWebSocketSession, - @Blocking private val blockingDispatcher: CoroutineContext, - private var audioHelper: AudioHelper? = null -) { - /** - * Coroutine scope that we batch data on for [startAudioConversation]. - * - * Makes it easy to stop all the work with [stopAudioConversation] by just cancelling the scope. - */ - private var scope = CancelledCoroutineScope - - /** - * Playback audio data sent from the model. - * - * Effectively, this is what the model is saying. - */ - private val playBackQueue = ConcurrentLinkedQueue() - - /** - * Toggled whenever [receive] and [stopReceiving] are called. - * - * Used to ensure only one flow is consuming the playback at once. - */ - private val startedReceiving = AtomicBoolean(false) - - /** - * Starts an audio conversation with the model, which can only be stopped using - * [stopAudioConversation] or [close]. - * - * @param functionCallHandler A callback function that is invoked whenever the model receives a - * function call. The [FunctionResponsePart] that the callback function returns will be - * automatically sent to the model. - */ - @RequiresPermission(RECORD_AUDIO) - public suspend fun startAudioConversation( - functionCallHandler: ((FunctionCallPart) -> FunctionResponsePart)? = null - ) { - FirebaseVertexAIException.catchAsync { - if (scope.isActive) { - Log.w( - TAG, - "startAudioConversation called after the recording has already started. " + - "Call stopAudioConversation to close the previous connection." - ) - return@catchAsync - } - - scope = CoroutineScope(blockingDispatcher + childJob()) - audioHelper = AudioHelper.build() - - recordUserAudio() - processModelResponses(functionCallHandler) - listenForModelPlayback() - } - } - - /** - * Stops the audio conversation with the model. - * - * This only needs to be called after a previous call to [startAudioConversation]. - * - * If there is no audio conversation currently active, this function does nothing. - */ - public fun stopAudioConversation() { - FirebaseVertexAIException.catch { - if (!startedReceiving.getAndSet(false)) return@catch - - scope.cancel() - playBackQueue.clear() - - audioHelper?.release() - audioHelper = null - } - } - - /** - * Receives responses from the model for both streaming and standard requests. - * - * Call [close] to stop receiving responses from the model. - * - * @return A [Flow] which will emit [LiveServerMessage] from the model. - * - * @throws [SessionAlreadyReceivingException] when the session is already receiving. - * @see stopReceiving - */ - public fun receive(): Flow = - FirebaseVertexAIException.catch { - if (startedReceiving.getAndSet(true)) { - throw SessionAlreadyReceivingException() - } - - // TODO(b/410059569): Remove when fixed - flow { - while (true) { - val response = session.incoming.tryReceive() - if (response.isClosed || !startedReceiving.get()) break - - response - .getOrNull() - ?.let { - JSON.decodeFromString( - it.readBytes().toString(Charsets.UTF_8) - ) - } - ?.let { emit(it.toPublic()) } - - yield() - } - } - .onCompletion { stopAudioConversation() } - .catch { throw FirebaseVertexAIException.from(it) } - - // TODO(b/410059569): Add back when fixed - } - - /** - * Stops receiving from the model. - * - * If this function is called during an ongoing audio conversation, the model's response will not - * be received, and no audio will be played; the live session object will no longer receive data - * from the server. - * - * To resume receiving data, you must either handle it directly using [receive], or indirectly by - * using [startAudioConversation]. - * - * @see close - */ - // TODO(b/410059569): Remove when fixed - public fun stopReceiving() { - FirebaseVertexAIException.catch { - if (!startedReceiving.getAndSet(false)) return@catch - - scope.cancel() - playBackQueue.clear() - - audioHelper?.release() - audioHelper = null - } - } - - /** - * Sends function calling responses to the model. - * - * **NOTE:** If you're using [startAudioConversation], the method will handle sending function - * responses to the model for you. You do _not_ need to call this method in that case. - * - * @param functionList The list of [FunctionResponsePart] instances indicating the function - * response from the client. - */ - public suspend fun sendFunctionResponse(functionList: List) { - FirebaseVertexAIException.catchAsync { - val jsonString = - Json.encodeToString( - BidiGenerateContentToolResponseSetup(functionList.map { it.toInternalFunctionCall() }) - .toInternal() - ) - session.send(Frame.Text(jsonString)) - } - } - - /** - * Streams client data to the model. - * - * Calling this after [startAudioConversation] will play the response audio immediately. - * - * @param mediaChunks The list of [MediaData] instances representing the media data to be sent. - */ - public suspend fun sendMediaStream( - mediaChunks: List, - ) { - FirebaseVertexAIException.catchAsync { - val jsonString = - Json.encodeToString( - BidiGenerateContentRealtimeInputSetup(mediaChunks.map { (it.toInternal()) }).toInternal() - ) - session.send(Frame.Text(jsonString)) - } - } - - /** - * Sends [data][Content] to the model. - * - * Calling this after [startAudioConversation] will play the response audio immediately. - * - * @param content Client [Content] to be sent to the model. - */ - public suspend fun send(content: Content) { - FirebaseVertexAIException.catchAsync { - val jsonString = - Json.encodeToString( - BidiGenerateContentClientContentSetup(listOf(content.toInternal()), true).toInternal() - ) - session.send(Frame.Text(jsonString)) - } - } - - /** - * Sends text to the model. - * - * Calling this after [startAudioConversation] will play the response audio immediately. - * - * @param text Text to be sent to the model. - */ - public suspend fun send(text: String) { - FirebaseVertexAIException.catchAsync { send(Content.Builder().text(text).build()) } - } - - /** - * Closes the client session. - * - * Once a [LiveSession] is closed, it can not be reopened; you'll need to start a new - * [LiveSession]. - * - * @see stopReceiving - */ - public suspend fun close() { - FirebaseVertexAIException.catchAsync { - session.close() - stopAudioConversation() - } - } - - /** Listen to the user's microphone and send the data to the model. */ - private fun recordUserAudio() { - // Buffer the recording so we can keep recording while data is sent to the server - audioHelper - ?.listenToRecording() - ?.buffer(UNLIMITED) - ?.accumulateUntil(MIN_BUFFER_SIZE) - ?.onEach { sendMediaStream(listOf(MediaData(it, "audio/pcm"))) } - ?.catch { throw FirebaseVertexAIException.from(it) } - ?.launchIn(scope) - } - - /** - * Processes responses from the model during an audio conversation. - * - * Audio messages are added to [playBackQueue]. - * - * Launched asynchronously on [scope]. - * - * @param functionCallHandler A callback function that is invoked whenever the server receives a - * function call. - */ - private fun processModelResponses( - functionCallHandler: ((FunctionCallPart) -> FunctionResponsePart)? - ) { - receive() - .onEach { - when (it) { - is LiveServerToolCall -> { - if (it.functionCalls.isEmpty()) { - Log.w( - TAG, - "The model sent a tool call request, but it was missing functions to call." - ) - } else if (functionCallHandler != null) { - // It's fine to suspend here since you can't have a function call running concurrently - // with an audio response - sendFunctionResponse(it.functionCalls.map(functionCallHandler).toList()) - } else { - Log.w( - TAG, - "Function calls were present in the response, but a functionCallHandler was not provided." - ) - } - } - is LiveServerToolCallCancellation -> { - Log.w( - TAG, - "The model sent a tool cancellation request, but tool cancellation is not supported when using startAudioConversation()." - ) - } - is LiveServerContent -> { - if (it.interrupted) { - playBackQueue.clear() - } else { - val audioParts = it.content?.parts?.filterIsInstance().orEmpty() - for (part in audioParts) { - playBackQueue.add(part.inlineData) - } - } - } - is LiveServerSetupComplete -> { - // we should only get this message when we initially `connect` in LiveGenerativeModel - Log.w( - TAG, - "The model sent LiveServerSetupComplete after the connection was established." - ) - } - } - } - .launchIn(scope) - } - - /** - * Listens for playback data from the model and plays the audio. - * - * Polls [playBackQueue] for data, and calls [AudioHelper.playAudio] when data is received. - * - * Launched asynchronously on [scope]. - */ - private fun listenForModelPlayback() { - scope.launch { - while (isActive) { - val playbackData = playBackQueue.poll() - if (playbackData == null) { - // The model playback queue is complete, so we can continue recording - // TODO(b/408223520): Conditionally resume when param is added - audioHelper?.resumeRecording() - yield() - } else { - /** - * We pause the recording while the model is speaking to avoid interrupting it because of - * no echo cancellation - */ - // TODO(b/408223520): Conditionally pause when param is added - audioHelper?.pauseRecording() - - audioHelper?.playAudio(playbackData) - } - } - } - } - - /** - * Incremental update of the current conversation delivered from the client. - * - * Effectively, a message from the client to the model. - */ - internal class BidiGenerateContentClientContentSetup( - val turns: List, - val turnComplete: Boolean - ) { - @Serializable - internal class Internal(val clientContent: BidiGenerateContentClientContent) { - @Serializable - internal data class BidiGenerateContentClientContent( - val turns: List, - val turnComplete: Boolean - ) - } - - fun toInternal() = Internal(Internal.BidiGenerateContentClientContent(turns, turnComplete)) - } - - /** Client generated responses to a [LiveServerToolCall]. */ - internal class BidiGenerateContentToolResponseSetup( - val functionResponses: List - ) { - @Serializable - internal data class Internal(val toolResponse: BidiGenerateContentToolResponse) { - @Serializable - internal data class BidiGenerateContentToolResponse( - val functionResponses: List - ) - } - - fun toInternal() = Internal(Internal.BidiGenerateContentToolResponse(functionResponses)) - } - - /** - * User input that is sent to the model in real time. - * - * End of turn is derived from user activity (eg; end of speech). - */ - internal class BidiGenerateContentRealtimeInputSetup(val mediaChunks: List) { - @Serializable - internal class Internal(val realtimeInput: BidiGenerateContentRealtimeInput) { - @Serializable - internal data class BidiGenerateContentRealtimeInput( - val mediaChunks: List - ) - } - fun toInternal() = Internal(Internal.BidiGenerateContentRealtimeInput(mediaChunks)) - } - - private companion object { - val TAG = LiveSession::class.java.simpleName - val MIN_BUFFER_SIZE = - AudioTrack.getMinBufferSize( - 24000, - AudioFormat.CHANNEL_OUT_MONO, - AudioFormat.ENCODING_PCM_16BIT - ) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/MediaData.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/MediaData.kt deleted file mode 100644 index 3b3b38f89f3..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/MediaData.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import android.util.Base64 -import kotlinx.serialization.Serializable - -/** - * Represents the media data to be sent to the server - * - * @param data Byte array representing the data to be sent. - * @param mimeType an IANA standard MIME type. For supported MIME type values see the - * [Firebase documentation](https://firebase.google.com/docs/vertex-ai/input-file-requirements). - */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class MediaData(public val data: ByteArray, public val mimeType: String) { - @Serializable - internal class Internal( - val data: String, - val mimeType: String, - ) - - internal fun toInternal(): Internal { - return Internal(Base64.encodeToString(data, BASE_64_FLAGS), mimeType) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ModalityTokenCount.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ModalityTokenCount.kt deleted file mode 100644 index 0bb6de78baf..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ModalityTokenCount.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.Serializable - -/** - * Represents token counting info for a single modality. - * - * @property modality The modality associated with this token count. - * @property tokenCount The number of tokens counted. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ModalityTokenCount -private constructor(public val modality: ContentModality, public val tokenCount: Int) { - - public operator fun component1(): ContentModality = modality - - public operator fun component2(): Int = tokenCount - - @Serializable - internal data class Internal( - val modality: ContentModality.Internal, - val tokenCount: Int? = null - ) { - internal fun toPublic() = ModalityTokenCount(modality.toPublic(), tokenCount ?: 0) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Part.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Part.kt deleted file mode 100644 index 833065074e6..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Part.kt +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import android.graphics.Bitmap -import android.graphics.BitmapFactory -import java.io.ByteArrayOutputStream -import kotlinx.serialization.DeserializationStrategy -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.SerializationException -import kotlinx.serialization.json.JsonContentPolymorphicSerializer -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonNull -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.jsonObject -import org.json.JSONObject - -/** Interface representing data sent to and received from requests. */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public interface Part {} - -/** Represents text or string based data sent to and received from requests. */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class TextPart(public val text: String) : Part { - - @Serializable internal data class Internal(val text: String) : InternalPart -} - -/** - * Represents image data sent to and received from requests. The image is converted client-side to - * JPEG encoding at 80% quality before being sent to the server. - * - * @param image [Bitmap] to convert into a [Part] - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ImagePart(public val image: Bitmap) : Part { - - internal fun toInlineDataPart() = - InlineDataPart( - android.util.Base64.decode(encodeBitmapToBase64Jpeg(image), BASE_64_FLAGS), - "image/jpeg" - ) -} - -/** - * Represents binary data with an associated MIME type sent to and received from requests. - * - * @param inlineData the binary data as a [ByteArray] - * @param mimeType an IANA standard MIME type. For supported values, see the - * [Vertex AI documentation](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/send-multimodal-prompts#media_requirements) - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class InlineDataPart(public val inlineData: ByteArray, public val mimeType: String) : Part { - - @Serializable - internal data class Internal(@SerialName("inlineData") val inlineData: InlineData) : - InternalPart { - - @Serializable - internal data class InlineData(@SerialName("mimeType") val mimeType: String, val data: Base64) - } -} - -/** - * Represents function call name and params received from requests. - * - * @param name the name of the function to call - * @param args the function parameters and values as a [Map] - * @param id Unique id of the function call. If present, the returned [FunctionResponsePart] should - * have a matching `id` field. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class FunctionCallPart -@JvmOverloads -constructor( - public val name: String, - public val args: Map, - public val id: String? = null -) : Part { - - @Serializable - internal data class Internal(val functionCall: FunctionCall) : InternalPart { - - @Serializable - internal data class FunctionCall( - val name: String, - val args: Map? = null, - val id: String? = null - ) - } -} - -/** - * Represents function call output to be returned to the model when it requests a function call. - * - * @param name The name of the called function. - * @param response The response produced by the function as a [JSONObject]. - * @param id Matching `id` for a [FunctionCallPart], if one was provided. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class FunctionResponsePart -@JvmOverloads -constructor( - public val name: String, - public val response: JsonObject, - public val id: String? = null -) : Part { - - @Serializable - internal data class Internal(val functionResponse: FunctionResponse) : InternalPart { - - @Serializable - internal data class FunctionResponse( - val name: String, - val response: JsonObject, - val id: String? = null - ) - } - - internal fun toInternalFunctionCall(): Internal.FunctionResponse { - return Internal.FunctionResponse(name, response, id) - } -} - -/** - * Represents file data stored in Cloud Storage for Firebase, referenced by URI. - * - * @param uri The `"gs://"`-prefixed URI of the file in Cloud Storage for Firebase, for example, - * `"gs://bucket-name/path/image.jpg"` - * @param mimeType an IANA standard MIME type. For supported MIME type values see the - * [Firebase documentation](https://firebase.google.com/docs/vertex-ai/input-file-requirements). - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class FileDataPart(public val uri: String, public val mimeType: String) : Part { - - @Serializable - internal data class Internal(@SerialName("file_data") val fileData: FileData) : InternalPart { - - @Serializable - internal data class FileData( - @SerialName("mime_type") val mimeType: String, - @SerialName("file_uri") val fileUri: String, - ) - } -} - -/** Returns the part as a [String] if it represents text, and null otherwise */ -public fun Part.asTextOrNull(): String? = (this as? TextPart)?.text - -/** Returns the part as a [Bitmap] if it represents an image, and null otherwise */ -public fun Part.asImageOrNull(): Bitmap? = (this as? ImagePart)?.image - -/** Returns the part as a [InlineDataPart] if it represents inline data, and null otherwise */ -public fun Part.asInlineDataPartOrNull(): InlineDataPart? = this as? InlineDataPart - -/** Returns the part as a [FileDataPart] if it represents a file, and null otherwise */ -public fun Part.asFileDataOrNull(): FileDataPart? = this as? FileDataPart - -internal typealias Base64 = String - -internal const val BASE_64_FLAGS = android.util.Base64.NO_WRAP - -@Serializable(PartSerializer::class) internal sealed interface InternalPart - -internal object PartSerializer : - JsonContentPolymorphicSerializer(InternalPart::class) { - override fun selectDeserializer(element: JsonElement): DeserializationStrategy { - val jsonObject = element.jsonObject - return when { - "text" in jsonObject -> TextPart.Internal.serializer() - "functionCall" in jsonObject -> FunctionCallPart.Internal.serializer() - "functionResponse" in jsonObject -> FunctionResponsePart.Internal.serializer() - "inlineData" in jsonObject -> InlineDataPart.Internal.serializer() - "fileData" in jsonObject -> FileDataPart.Internal.serializer() - else -> throw SerializationException("Unknown Part type") - } - } -} - -internal fun Part.toInternal(): InternalPart { - return when (this) { - is TextPart -> TextPart.Internal(text) - is ImagePart -> - InlineDataPart.Internal( - InlineDataPart.Internal.InlineData("image/jpeg", encodeBitmapToBase64Jpeg(image)) - ) - is InlineDataPart -> - InlineDataPart.Internal( - InlineDataPart.Internal.InlineData( - mimeType, - android.util.Base64.encodeToString(inlineData, BASE_64_FLAGS) - ) - ) - is FunctionCallPart -> - FunctionCallPart.Internal(FunctionCallPart.Internal.FunctionCall(name, args, id)) - is FunctionResponsePart -> - FunctionResponsePart.Internal( - FunctionResponsePart.Internal.FunctionResponse(name, response, id) - ) - is FileDataPart -> - FileDataPart.Internal(FileDataPart.Internal.FileData(mimeType = mimeType, fileUri = uri)) - else -> - throw com.google.firebase.vertexai.type.SerializationException( - "The given subclass of Part (${javaClass.simpleName}) is not supported in the serialization yet." - ) - } -} - -private fun encodeBitmapToBase64Jpeg(input: Bitmap): String { - ByteArrayOutputStream().let { - input.compress(Bitmap.CompressFormat.JPEG, 80, it) - return android.util.Base64.encodeToString(it.toByteArray(), BASE_64_FLAGS) - } -} - -internal fun InternalPart.toPublic(): Part { - return when (this) { - is TextPart.Internal -> TextPart(text) - is InlineDataPart.Internal -> { - val data = android.util.Base64.decode(inlineData.data, BASE_64_FLAGS) - if (inlineData.mimeType.contains("image")) { - ImagePart(decodeBitmapFromImage(data)) - } else { - InlineDataPart(data, inlineData.mimeType) - } - } - is FunctionCallPart.Internal -> - FunctionCallPart( - functionCall.name, - functionCall.args.orEmpty().mapValues { it.value ?: JsonNull }, - functionCall.id - ) - is FunctionResponsePart.Internal -> - FunctionResponsePart(functionResponse.name, functionResponse.response, functionResponse.id) - is FileDataPart.Internal -> FileDataPart(fileData.mimeType, fileData.fileUri) - else -> - throw com.google.firebase.vertexai.type.SerializationException( - "Unsupported part type \"${javaClass.simpleName}\" provided. This model may not be supported by this SDK." - ) - } -} - -private fun decodeBitmapFromImage(input: ByteArray) = - BitmapFactory.decodeByteArray(input, 0, input.size) diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/PromptFeedback.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/PromptFeedback.kt deleted file mode 100644 index c7a57628a64..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/PromptFeedback.kt +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import com.google.firebase.vertexai.common.util.FirstOrdinalSerializer -import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -/** - * Feedback on the prompt provided in the request. - * - * @param blockReason The reason that content was blocked, if at all. - * @param safetyRatings A list of relevant [SafetyRating]. - * @param blockReasonMessage A message describing the reason that content was blocked, if any. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class PromptFeedback( - public val blockReason: BlockReason?, - public val safetyRatings: List, - public val blockReasonMessage: String? -) { - - @Serializable - internal data class Internal( - val blockReason: BlockReason.Internal? = null, - val safetyRatings: List? = null, - val blockReasonMessage: String? = null, - ) { - - internal fun toPublic(): PromptFeedback { - val safetyRatings = safetyRatings?.mapNotNull { it.toPublic() }.orEmpty() - return PromptFeedback(blockReason?.toPublic(), safetyRatings, blockReasonMessage) - } - } -} - -/** Describes why content was blocked. */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class BlockReason private constructor(public val name: String, public val ordinal: Int) { - - @Serializable(Internal.Serializer::class) - internal enum class Internal { - UNKNOWN, - @SerialName("BLOCKED_REASON_UNSPECIFIED") UNSPECIFIED, - SAFETY, - OTHER, - BLOCKLIST, - PROHIBITED_CONTENT; - - internal object Serializer : KSerializer by FirstOrdinalSerializer(Internal::class) - - internal fun toPublic() = - when (this) { - SAFETY -> BlockReason.SAFETY - OTHER -> BlockReason.OTHER - BLOCKLIST -> BlockReason.BLOCKLIST - PROHIBITED_CONTENT -> BlockReason.PROHIBITED_CONTENT - else -> BlockReason.UNKNOWN - } - } - public companion object { - /** A new and not yet supported value. */ - @JvmField public val UNKNOWN: BlockReason = BlockReason("UNKNOWN", 0) - - /** Content was blocked for violating provided [SafetySetting]. */ - @JvmField public val SAFETY: BlockReason = BlockReason("SAFETY", 1) - - /** Content was blocked for another reason. */ - @JvmField public val OTHER: BlockReason = BlockReason("OTHER", 2) - - /** Content was blocked for another reason. */ - @JvmField public val BLOCKLIST: BlockReason = BlockReason("BLOCKLIST", 3) - - /** Candidates blocked due to the terms which are included from the terminology blocklist. */ - @JvmField public val PROHIBITED_CONTENT: BlockReason = BlockReason("PROHIBITED_CONTENT", 4) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/PublicPreviewAPI.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/PublicPreviewAPI.kt deleted file mode 100644 index 50f9880f3be..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/PublicPreviewAPI.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -@Retention(AnnotationRetention.BINARY) -@RequiresOptIn( - level = RequiresOptIn.Level.ERROR, - message = - "This API is part of an experimental public preview and may change in " + - "backwards-incompatible ways without notice.", -) -public annotation class PublicPreviewAPI() diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/RequestOptions.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/RequestOptions.kt deleted file mode 100644 index 4d129d2acaf..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/RequestOptions.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds -import kotlin.time.DurationUnit -import kotlin.time.toDuration - -/** Configurable options unique to how requests to the backend are performed. */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class RequestOptions -internal constructor( - internal val timeout: Duration, - internal val endpoint: String = "https://firebasevertexai.googleapis.com", - internal val apiVersion: String = "v1beta", -) { - - /** - * Constructor for RequestOptions. - * - * @param timeoutInMillis the maximum amount of time, in milliseconds, for a request to take, from - * the first request to first response. - */ - @JvmOverloads - public constructor( - timeoutInMillis: Long = 180.seconds.inWholeMilliseconds - ) : this(timeout = timeoutInMillis.toDuration(DurationUnit.MILLISECONDS)) -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ResponseModality.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ResponseModality.kt deleted file mode 100644 index 455dbb1d466..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ResponseModality.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import com.google.firebase.vertexai.common.util.FirstOrdinalSerializer -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable - -/** Represents the type of content present in a response (e.g., text, image, audio). */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ResponseModality private constructor(public val ordinal: Int) { - - @Serializable(Internal.Serializer::class) - internal enum class Internal { - TEXT, - IMAGE, - AUDIO; - - internal object Serializer : KSerializer by FirstOrdinalSerializer(Internal::class) - - internal fun toPublic() = - when (this) { - TEXT -> ResponseModality.TEXT - IMAGE -> ResponseModality.IMAGE - else -> ResponseModality.AUDIO - } - } - - internal fun toInternal() = - when (this) { - TEXT -> "TEXT" - IMAGE -> "IMAGE" - else -> "AUDIO" - } - public companion object { - - /** Represents a plain text response modality. */ - @JvmField public val TEXT: ResponseModality = ResponseModality(1) - - /** Represents an image response modality. */ - @JvmField public val IMAGE: ResponseModality = ResponseModality(2) - - /** Represents an audio response modality. */ - @JvmField public val AUDIO: ResponseModality = ResponseModality(4) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/SafetySetting.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/SafetySetting.kt deleted file mode 100644 index 168b74b680c..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/SafetySetting.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.Serializable - -/** - * A configuration for a [HarmBlockThreshold] of some [HarmCategory] allowed and blocked in - * responses. - * - * @param harmCategory The relevant [HarmCategory]. - * @param threshold The threshold form harm allowable. - * @param method Specify if the threshold is used for probability or severity score, if not - * specified it will default to [HarmBlockMethod.PROBABILITY]. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class SafetySetting( - internal val harmCategory: HarmCategory, - internal val threshold: HarmBlockThreshold, - internal val method: HarmBlockMethod? = null, -) { - internal fun toInternal() = - Internal(harmCategory.toInternal(), threshold.toInternal(), method?.toInternal()) - - @Serializable - internal data class Internal( - val category: HarmCategory.Internal, - val threshold: HarmBlockThreshold.Internal, - val method: HarmBlockMethod.Internal? = null, - ) -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Schema.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Schema.kt deleted file mode 100644 index 160a5841321..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Schema.kt +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.Serializable - -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public abstract class StringFormat private constructor(internal val value: String) { - @Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" - ) - public class Custom(value: String) : StringFormat(value) -} - -/** - * Definition of a data type. - * - * These types can be objects, but also primitives and arrays. Represents a select subset of an - * [OpenAPI 3.0 schema object](https://spec.openapis.org/oas/v3.0.3#schema). - * - * **Note:** While optional, including a `description` field in your `Schema` is strongly - * encouraged. The more information the model has about what it's expected to generate, the better - * the results. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class Schema -internal constructor( - public val type: String, - public val description: String? = null, - public val format: String? = null, - public val nullable: Boolean? = null, - public val enum: List? = null, - public val properties: Map? = null, - public val required: List? = null, - public val items: Schema? = null, -) { - - public companion object { - /** - * Returns a [Schema] representing a boolean value. - * - * @param description An optional description of what the boolean should contain or represent. - * @param nullable Indicates whether the value can be `null`. Defaults to `false`. - */ - @JvmStatic - @JvmOverloads - public fun boolean(description: String? = null, nullable: Boolean = false): Schema = - Schema( - description = description, - nullable = nullable, - type = "BOOLEAN", - ) - - /** - * Returns a [Schema] for a 32-bit signed integer number. - * - * **Important:** This [Schema] provides a hint to the model that it should generate a 32-bit - * integer, but only guarantees that the value will be an integer. Therefore it's *possible* - * that decoding it as an `Int` variable (or `int` in Java) could overflow. - * - * @param description An optional description of what the integer should contain or represent. - * @param nullable Indicates whether the value can be `null`. Defaults to `false`. - */ - @JvmStatic - @JvmName("numInt") - @JvmOverloads - public fun integer(description: String? = null, nullable: Boolean = false): Schema = - Schema( - description = description, - format = "int32", - nullable = nullable, - type = "INTEGER", - ) - - /** - * Returns a [Schema] for a 64-bit signed integer number. - * - * @param description An optional description of what the number should contain or represent. - * @param nullable Indicates whether the value can be `null`. Defaults to `false`. - */ - @JvmStatic - @JvmName("numLong") - @JvmOverloads - public fun long(description: String? = null, nullable: Boolean = false): Schema = - Schema( - description = description, - nullable = nullable, - type = "INTEGER", - ) - - /** - * Returns a [Schema] for a double-precision floating-point number. - * - * @param description An optional description of what the number should contain or represent. - * @param nullable Indicates whether the value can be `null`. Defaults to `false`. - */ - @JvmStatic - @JvmName("numDouble") - @JvmOverloads - public fun double(description: String? = null, nullable: Boolean = false): Schema = - Schema(description = description, nullable = nullable, type = "NUMBER") - - /** - * Returns a [Schema] for a single-precision floating-point number. - * - * **Important:** This [Schema] provides a hint to the model that it should generate a - * single-precision floating-point number, but only guarantees that the value will be a number. - * Therefore it's *possible* that decoding it as a `Float` variable (or `float` in Java) could - * overflow. - * - * @param description An optional description of what the number should contain or represent. - * @param nullable Indicates whether the value can be `null`. Defaults to `false`. - */ - @JvmStatic - @JvmName("numFloat") - @JvmOverloads - public fun float(description: String? = null, nullable: Boolean = false): Schema = - Schema(description = description, nullable = nullable, type = "NUMBER", format = "float") - - /** - * Returns a [Schema] for a string. - * - * @param description An optional description of what the string should contain or represent. - * @param nullable Indicates whether the value can be `null`. Defaults to `false`. - * @param format An optional pattern that values need to adhere to. - */ - @JvmStatic - @JvmName("str") - @JvmOverloads - public fun string( - description: String? = null, - nullable: Boolean = false, - format: StringFormat? = null - ): Schema = - Schema( - description = description, - format = format?.value, - nullable = nullable, - type = "STRING" - ) - - /** - * Returns a [Schema] for a complex data type. - * - * This schema instructs the model to produce data of type object, which has keys of type - * `String` and values of type [Schema]. - * - * **Example:** A `city` could be represented with the following object `Schema`. - * ``` - * Schema.obj(mapOf( - * "name" to Schema.string(), - * "population" to Schema.integer() - * )) - * ``` - * - * @param properties The map of the object's property names to their [Schema]s. - * @param optionalProperties The list of optional properties. They must correspond to the keys - * provided in the `properties` map. By default it's empty, signaling the model that all - * properties are to be included. - * @param description An optional description of what the object represents. - * @param nullable Indicates whether the value can be `null`. Defaults to `false`. - */ - @JvmStatic - @JvmOverloads - public fun obj( - properties: Map, - optionalProperties: List = emptyList(), - description: String? = null, - nullable: Boolean = false, - ): Schema { - if (!properties.keys.containsAll(optionalProperties)) { - throw IllegalArgumentException( - "All optional properties must be present in properties. Missing: ${optionalProperties.minus(properties.keys)}" - ) - } - return Schema( - description = description, - nullable = nullable, - properties = properties, - required = properties.keys.minus(optionalProperties.toSet()).toList(), - type = "OBJECT", - ) - } - - /** - * Returns a [Schema] for an array. - * - * @param items The [Schema] of the elements stored in the array. - * @param description An optional description of what the array represents. - * @param nullable Indicates whether the value can be `null`. Defaults to `false`. - */ - @JvmStatic - @JvmOverloads - public fun array( - items: Schema, - description: String? = null, - nullable: Boolean = false - ): Schema = - Schema( - description = description, - nullable = nullable, - items = items, - type = "ARRAY", - ) - - /** - * Returns a [Schema] for an enumeration. - * - * For example, the cardinal directions can be represented as: - * - * ``` - * Schema.enumeration(listOf("north", "east", "south", "west"), "Cardinal directions") - * ``` - * - * @param values The list of valid values for this enumeration - * @param description The description of what the parameter should contain or represent - * @param nullable Indicates whether the value can be `null`. Defaults to `false`. - */ - @JvmStatic - @JvmOverloads - public fun enumeration( - values: List, - description: String? = null, - nullable: Boolean = false - ): Schema = - Schema( - description = description, - format = "enum", - nullable = nullable, - enum = values, - type = "STRING", - ) - } - - internal fun toInternal(): Internal = - Internal( - type, - description, - format, - nullable, - enum, - properties?.mapValues { it.value.toInternal() }, - required, - items?.toInternal(), - ) - @Serializable - internal data class Internal( - val type: String, - val description: String? = null, - val format: String? = null, - val nullable: Boolean? = false, - val enum: List? = null, - val properties: Map? = null, - val required: List? = null, - val items: Internal? = null, - ) -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/SpeechConfig.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/SpeechConfig.kt deleted file mode 100644 index a81a3c365fb..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/SpeechConfig.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -/** Speech configuration class for setting up the voice of the server's response. */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class SpeechConfig( - /** The voice to be used for the server's speech response. */ - public val voice: Voices -) { - - @Serializable - internal data class Internal(@SerialName("voice_config") val voiceConfig: VoiceConfigInternal) { - @Serializable - internal data class VoiceConfigInternal( - @SerialName("prebuilt_voice_config") val prebuiltVoiceConfig: Voices.Internal, - ) - } - - internal fun toInternal(): Internal { - return Internal(Internal.VoiceConfigInternal(prebuiltVoiceConfig = voice.toInternal())) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Tool.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Tool.kt deleted file mode 100644 index caf3f229763..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Tool.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonObject - -/** - * Contains a set of function declarations that the model has access to. These can be used to gather - * information, or complete tasks - * - * @param functionDeclarations The set of functions that this tool allows the model access to - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class Tool -internal constructor(internal val functionDeclarations: List?) { - internal fun toInternal() = Internal(functionDeclarations?.map { it.toInternal() } ?: emptyList()) - @Serializable - internal data class Internal( - val functionDeclarations: List? = null, - // This is a json object because it is not possible to make a data class with no parameters. - val codeExecution: JsonObject? = null, - ) - public companion object { - - /** - * Creates a [Tool] instance that provides the model with access to the [functionDeclarations]. - * - * @param functionDeclarations The list of functions that this tool allows the model access to. - */ - @JvmStatic - public fun functionDeclarations(functionDeclarations: List): Tool { - return Tool(functionDeclarations) - } - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ToolConfig.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ToolConfig.kt deleted file mode 100644 index 631e6b98f46..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/ToolConfig.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -/** - * Contains configuration for the function calling tools of the model. This can be used to change - * when the model can predict function calls. - * - * @param functionCallingConfig The config for function calling - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class ToolConfig(internal val functionCallingConfig: FunctionCallingConfig?) { - - internal fun toInternal() = - Internal( - functionCallingConfig?.let { - FunctionCallingConfig.Internal( - when (it.mode) { - FunctionCallingConfig.Mode.ANY -> FunctionCallingConfig.Internal.Mode.ANY - FunctionCallingConfig.Mode.AUTO -> FunctionCallingConfig.Internal.Mode.AUTO - FunctionCallingConfig.Mode.NONE -> FunctionCallingConfig.Internal.Mode.NONE - }, - it.allowedFunctionNames - ) - } - ) - - @Serializable - internal data class Internal( - @SerialName("function_calling_config") - val functionCallingConfig: FunctionCallingConfig.Internal? - ) -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Type.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Type.kt deleted file mode 100644 index a35000c7da5..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Type.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonObject -import org.json.JSONObject - -internal sealed interface Response - -@Serializable -internal data class GRpcErrorResponse(val error: GRpcError) : Response { - - @Serializable - internal data class GRpcError( - val code: Int, - val message: String, - val details: List? = null - ) { - - @Serializable - internal data class GRpcErrorDetails( - val reason: String? = null, - val domain: String? = null, - val metadata: Map? = null - ) - } -} - -internal fun JSONObject.toInternal() = Json.decodeFromString(toString()) - -internal fun JsonObject.toPublic() = JSONObject(toString()) diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/UsageMetadata.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/UsageMetadata.kt deleted file mode 100644 index 8ed4fcc4177..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/UsageMetadata.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.Serializable - -/** - * Usage metadata about response(s). - * - * @param promptTokenCount Number of tokens in the request. - * @param candidatesTokenCount Number of tokens in the response(s). - * @param totalTokenCount Total number of tokens. - * @param promptTokensDetails The breakdown, by modality, of how many tokens are consumed by the - * prompt. - * @param candidatesTokensDetails The breakdown, by modality, of how many tokens are consumed by the - * candidates. - */ -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class UsageMetadata( - public val promptTokenCount: Int, - public val candidatesTokenCount: Int?, - public val totalTokenCount: Int, - public val promptTokensDetails: List, - public val candidatesTokensDetails: List, -) { - - @Serializable - internal data class Internal( - val promptTokenCount: Int? = null, - val candidatesTokenCount: Int? = null, - val totalTokenCount: Int? = null, - val promptTokensDetails: List? = null, - val candidatesTokensDetails: List? = null, - ) { - - internal fun toPublic(): UsageMetadata = - UsageMetadata( - promptTokenCount ?: 0, - candidatesTokenCount ?: 0, - totalTokenCount ?: 0, - promptTokensDetails = promptTokensDetails?.map { it.toPublic() } ?: emptyList(), - candidatesTokensDetails = candidatesTokensDetails?.map { it.toPublic() } ?: emptyList() - ) - } -} diff --git a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Voices.kt b/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Voices.kt deleted file mode 100644 index f4c6470fc41..00000000000 --- a/firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/Voices.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.type - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -/** Various voices supported by the server */ -@PublicPreviewAPI -@Deprecated( - """The Vertex AI in Firebase SDK (firebase-vertexai) has been replaced with the FirebaseAI SDK (firebase-ai) to accommodate the evolving set of supported features and services. -For migration details, see the migration guide: https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk""" -) -public class Voices private constructor(public val ordinal: Int) { - - @Serializable internal data class Internal(@SerialName("voice_name") val voiceName: String) - - @Serializable - internal enum class InternalEnum { - CHARON, - AOEDE, - FENRIR, - KORE, - PUCK; - internal fun toPublic() = - when (this) { - CHARON -> Voices.CHARON - AOEDE -> Voices.AOEDE - FENRIR -> Voices.FENRIR - KORE -> Voices.KORE - else -> Voices.PUCK - } - } - - internal fun toInternal(): Internal { - return when (this) { - CHARON -> Internal(InternalEnum.CHARON.name) - AOEDE -> Internal(InternalEnum.AOEDE.name) - FENRIR -> Internal(InternalEnum.FENRIR.name) - KORE -> Internal(InternalEnum.KORE.name) - else -> Internal(InternalEnum.PUCK.name) - } - } - - public companion object { - /** - * Unspecified voice. - * - * Will use the default voice of the model. - */ - @JvmField public val UNSPECIFIED: Voices = Voices(0) - - /** Represents the Charon voice. */ - @JvmField public val CHARON: Voices = Voices(1) - - /** Represents the Aoede voice. */ - @JvmField public val AOEDE: Voices = Voices(2) - - /** Represents the Fenrir voice. */ - @JvmField public val FENRIR: Voices = Voices(3) - - /** Represents the Kore voice. */ - @JvmField public val KORE: Voices = Voices(4) - - /** Represents the Puck voice. */ - @JvmField public val PUCK: Voices = Voices(5) - } -} diff --git a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/GenerativeModelTesting.kt b/firebase-vertexai/src/test/java/com/google/firebase/vertexai/GenerativeModelTesting.kt deleted file mode 100644 index e66918ad52f..00000000000 --- a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/GenerativeModelTesting.kt +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai - -import com.google.firebase.FirebaseApp -import com.google.firebase.vertexai.common.APIController -import com.google.firebase.vertexai.common.JSON -import com.google.firebase.vertexai.common.util.doBlocking -import com.google.firebase.vertexai.type.Candidate -import com.google.firebase.vertexai.type.Content -import com.google.firebase.vertexai.type.GenerateContentResponse -import com.google.firebase.vertexai.type.RequestOptions -import com.google.firebase.vertexai.type.ServerException -import com.google.firebase.vertexai.type.TextPart -import com.google.firebase.vertexai.type.content -import io.kotest.assertions.json.shouldContainJsonKey -import io.kotest.assertions.json.shouldContainJsonKeyValue -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.matchers.collections.shouldNotBeEmpty -import io.kotest.matchers.string.shouldContain -import io.kotest.matchers.types.shouldBeInstanceOf -import io.ktor.client.engine.mock.MockEngine -import io.ktor.client.engine.mock.respond -import io.ktor.http.HttpHeaders -import io.ktor.http.HttpStatusCode -import io.ktor.http.content.TextContent -import io.ktor.http.headersOf -import kotlin.time.Duration.Companion.seconds -import kotlinx.coroutines.withTimeout -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.encodeToString -import org.junit.Before -import org.junit.Test -import org.mockito.Mockito - -internal class GenerativeModelTesting { - private val TEST_CLIENT_ID = "test" - private val TEST_APP_ID = "1:android:12345" - private val TEST_VERSION = 1 - - private var mockFirebaseApp: FirebaseApp = Mockito.mock() - - @Before - fun setup() { - Mockito.`when`(mockFirebaseApp.isDataCollectionDefaultEnabled).thenReturn(false) - } - - @Test - fun `system calling in request`() = doBlocking { - val mockEngine = MockEngine { - respond( - generateContentResponseAsJsonString("text response"), - HttpStatusCode.OK, - headersOf(HttpHeaders.ContentType, "application/json") - ) - } - - val apiController = - APIController( - "super_cool_test_key", - "gemini-1.5-flash", - RequestOptions(timeout = 5.seconds, endpoint = "https://my.custom.endpoint"), - mockEngine, - TEST_CLIENT_ID, - mockFirebaseApp, - TEST_VERSION, - TEST_APP_ID, - null, - ) - - val generativeModel = - GenerativeModel( - "gemini-1.5-flash", - systemInstruction = content { text("system instruction") }, - controller = apiController - ) - - withTimeout(5.seconds) { generativeModel.generateContent("my test prompt") } - - mockEngine.requestHistory.shouldNotBeEmpty() - - val request = mockEngine.requestHistory.first().body - request.shouldBeInstanceOf() - - request.text.let { - it shouldContainJsonKey "system_instruction" - it.shouldContainJsonKeyValue("$.system_instruction.role", "system") - it.shouldContainJsonKeyValue("$.system_instruction.parts[0].text", "system instruction") - } - } - - @Test - fun `exception thrown when using invalid location`() = doBlocking { - val mockEngine = MockEngine { - respond( - """ - - Error 404 (Not Found)!!1 - """ - .trimIndent(), - HttpStatusCode.NotFound, - headersOf(HttpHeaders.ContentType, "text/html; charset=utf-8") - ) - } - - val apiController = - APIController( - "super_cool_test_key", - "gemini-1.5-flash", - RequestOptions(), - mockEngine, - TEST_CLIENT_ID, - mockFirebaseApp, - TEST_VERSION, - TEST_APP_ID, - null, - ) - - // Creating the - val generativeModel = - GenerativeModel( - "projects/PROJECTID/locations/INVALID_LOCATION/publishers/google/models/gemini-1.5-flash", - controller = apiController - ) - - val exception = - shouldThrow { - withTimeout(5.seconds) { generativeModel.generateContent("my test prompt") } - } - - // Let's not be too strict on the wording to avoid breaking the test unnecessarily. - exception.message shouldContain "location" - } - - @OptIn(ExperimentalSerializationApi::class) - private fun generateContentResponseAsJsonString(text: String): String { - return JSON.encodeToString( - GenerateContentResponse.Internal( - listOf(Candidate.Internal(Content.Internal(parts = listOf(TextPart.Internal(text))))) - ) - ) - } -} diff --git a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/SchemaTests.kt b/firebase-vertexai/src/test/java/com/google/firebase/vertexai/SchemaTests.kt deleted file mode 100644 index 4701d516ff5..00000000000 --- a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/SchemaTests.kt +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai - -import com.google.firebase.vertexai.type.Schema -import com.google.firebase.vertexai.type.StringFormat -import io.kotest.assertions.json.shouldEqualJson -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json -import org.junit.Test - -internal class SchemaTests { - @Test - fun `basic schema declaration`() { - val schemaDeclaration = - Schema.array( - Schema.obj( - mapOf( - "name" to Schema.string(), - "country" to Schema.string(), - "population" to Schema.integer(), - "coordinates" to - Schema.obj( - mapOf( - "latitude" to Schema.double(), - "longitude" to Schema.double(), - ) - ), - "hemisphere" to - Schema.obj( - mapOf( - "latitudinal" to Schema.enumeration(listOf("N", "S")), - "longitudinal" to Schema.enumeration(listOf("E", "W")), - ) - ), - "elevation" to Schema.double(), - "isCapital" to Schema.boolean(), - "foundingDate" to Schema.string(nullable = true, format = StringFormat.Custom("date")), - ), - optionalProperties = listOf("population") - ) - ) - - val expectedJson = - """ - { - "type": "ARRAY", - "items": { - "type": "OBJECT", - "properties": { - "name": {"type": "STRING"}, - "country": {"type": "STRING"}, - "population": {"type": "INTEGER", "format": "int32"}, - "coordinates": { - "type": "OBJECT", - "properties": { - "latitude": {"type": "NUMBER"}, - "longitude": {"type": "NUMBER"} - }, - "required": ["latitude","longitude"] - }, - "hemisphere": { - "type": "OBJECT", - "properties": { - "latitudinal": {"type": "STRING","format": "enum","enum": ["N","S"]}, - "longitudinal": {"type": "STRING","format": "enum","enum": ["E","W"]} - }, - "required": ["latitudinal","longitudinal"] - }, - "elevation": {"type": "NUMBER"}, - "isCapital": {"type": "BOOLEAN"}, - "foundingDate": {"type": "STRING","format": "date","nullable": true} - }, - "required": [ - "name","country","coordinates","hemisphere","elevation", - "isCapital","foundingDate"] - } - } - """ - .trimIndent() - - Json.encodeToString(schemaDeclaration.toInternal()).shouldEqualJson(expectedJson) - } - - @Test - fun `full schema declaration`() { - val schemaDeclaration = - Schema.array( - Schema.obj( - description = "generic description", - nullable = true, - properties = - mapOf( - "name" to Schema.string(description = null, nullable = false, format = null), - "country" to - Schema.string( - description = "country name", - nullable = true, - format = StringFormat.Custom("custom format") - ), - "population" to Schema.long(description = "population count", nullable = true), - "coordinates" to - Schema.obj( - description = "coordinates", - nullable = true, - properties = - mapOf( - "latitude" to Schema.double(description = "latitude", nullable = false), - "longitude" to Schema.double(description = "longitude", nullable = false), - ) - ), - "hemisphere" to - Schema.obj( - description = "hemisphere", - nullable = false, - properties = - mapOf( - "latitudinal" to - Schema.enumeration( - listOf("N", "S"), - description = "latitudinal", - nullable = true - ), - "longitudinal" to - Schema.enumeration( - listOf("E", "W"), - description = "longitudinal", - nullable = true - ), - ), - ), - "elevation" to Schema.float(description = "elevation", nullable = false), - "isCapital" to - Schema.boolean( - description = "True if the city is the capital of the country", - nullable = false - ), - "foundingDate" to - Schema.string( - description = "Founding date", - nullable = true, - format = StringFormat.Custom("date") - ), - ) - ) - ) - - val expectedJson = - """ - { - "type": "ARRAY", - "items": { - "type": "OBJECT", - "description": "generic description", - "nullable": true, - "properties": { - "name": {"type": "STRING"}, - "country": {"type": "STRING", "description": "country name", "format": "custom format", "nullable": true}, - "population": {"type": "INTEGER", "description": "population count", "nullable": true}, - "coordinates": { - "type": "OBJECT", - "description": "coordinates", - "nullable": true, - "properties": { - "latitude": {"type": "NUMBER", "description": "latitude"}, - "longitude": {"type": "NUMBER", "description": "longitude"} - }, - "required": ["latitude","longitude"] - }, - "hemisphere": { - "type": "OBJECT", - "description": "hemisphere", - "properties": { - "latitudinal": { - "type": "STRING", - "description": "latitudinal", - "format": "enum", - "nullable": true, - "enum": ["N","S"] - }, - "longitudinal": { - "type": "STRING", - "description": "longitudinal", - "format": "enum", - "nullable": true, - "enum": ["E","W"] - } - }, - "required": ["latitudinal","longitudinal"] - }, - "elevation": {"type": "NUMBER", "description": "elevation", "format": "float"}, - "isCapital": {"type": "BOOLEAN", "description": "True if the city is the capital of the country"}, - "foundingDate": {"type": "STRING", "description": "Founding date", "format": "date", "nullable": true} - }, - "required": [ - "name","country","population","coordinates","hemisphere", - "elevation","isCapital","foundingDate" - ] - } - } - - """ - .trimIndent() - - Json.encodeToString(schemaDeclaration.toInternal()).shouldEqualJson(expectedJson) - } -} diff --git a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/SerializationTests.kt b/firebase-vertexai/src/test/java/com/google/firebase/vertexai/SerializationTests.kt deleted file mode 100644 index cf6a40680e5..00000000000 --- a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/SerializationTests.kt +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai - -import com.google.firebase.vertexai.common.util.descriptorToJson -import com.google.firebase.vertexai.type.Candidate -import com.google.firebase.vertexai.type.CountTokensResponse -import com.google.firebase.vertexai.type.GenerateContentResponse -import com.google.firebase.vertexai.type.ModalityTokenCount -import com.google.firebase.vertexai.type.Schema -import io.kotest.assertions.json.shouldEqualJson -import org.junit.Test - -internal class SerializationTests { - @Test - fun `test countTokensResponse serialization as Json`() { - val expectedJsonAsString = - """ - { - "id": "CountTokensResponse", - "type": "object", - "properties": { - "totalTokens": { - "type": "integer" - }, - "totalBillableCharacters": { - "type": "integer" - }, - "promptTokensDetails": { - "type": "array", - "items": { - "${'$'}ref": "ModalityTokenCount" - } - } - } - } - """ - .trimIndent() - val actualJson = descriptorToJson(CountTokensResponse.Internal.serializer().descriptor) - expectedJsonAsString shouldEqualJson actualJson.toString() - } - - @Test - fun `test modalityTokenCount serialization as Json`() { - val expectedJsonAsString = - """ - { - "id": "ModalityTokenCount", - "type": "object", - "properties": { - "modality": { - "type": "string", - "enum": [ - "UNSPECIFIED", - "TEXT", - "IMAGE", - "VIDEO", - "AUDIO", - "DOCUMENT" - ] - }, - "tokenCount": { - "type": "integer" - } - } - } - """ - .trimIndent() - val actualJson = descriptorToJson(ModalityTokenCount.Internal.serializer().descriptor) - expectedJsonAsString shouldEqualJson actualJson.toString() - } - - @Test - fun `test GenerateContentResponse serialization as Json`() { - val expectedJsonAsString = - """ - { - "id": "GenerateContentResponse", - "type": "object", - "properties": { - "candidates": { - "type": "array", - "items": { - "${'$'}ref": "Candidate" - } - }, - "promptFeedback": { - "${'$'}ref": "PromptFeedback" - }, - "usageMetadata": { - "${'$'}ref": "UsageMetadata" - } - } - } - """ - .trimIndent() - val actualJson = descriptorToJson(GenerateContentResponse.Internal.serializer().descriptor) - expectedJsonAsString shouldEqualJson actualJson.toString() - } - - @Test - fun `test Candidate serialization as Json`() { - val expectedJsonAsString = - """ - { - "id": "Candidate", - "type": "object", - "properties": { - "content": { - "${'$'}ref": "Content" - }, - "finishReason": { - "type": "string", - "enum": [ - "UNKNOWN", - "UNSPECIFIED", - "STOP", - "MAX_TOKENS", - "SAFETY", - "RECITATION", - "OTHER", - "BLOCKLIST", - "PROHIBITED_CONTENT", - "SPII", - "MALFORMED_FUNCTION_CALL" - ] - }, - "safetyRatings": { - "type": "array", - "items": { - "${'$'}ref": "SafetyRating" - } - }, - "citationMetadata": { - "${'$'}ref": "CitationMetadata" - }, - "groundingMetadata": { - "${'$'}ref": "GroundingMetadata" - } - } - } - """ - .trimIndent() - val actualJson = descriptorToJson(Candidate.Internal.serializer().descriptor) - expectedJsonAsString shouldEqualJson actualJson.toString() - } - - @Test - fun `test Schema serialization as Json`() { - /** - * Unlike the actual schema in the background, we don't represent "type" as an enum, but rather - * as a string. This is because we restrict what values can be used (using helper methods, - * rather than type). - */ - val expectedJsonAsString = - """ - { - "id": "Schema", - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "format": { - "type": "string" - }, - "description": { - "type": "string" - }, - "nullable": { - "type": "boolean" - }, - "items": { - "${'$'}ref": "Schema" - }, - "enum": { - "type": "array", - "items": { - "type": "string" - } - }, - "properties": { - "type": "object", - "additionalProperties": { - "${'$'}ref": "Schema" - } - }, - "required": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - """ - .trimIndent() - val actualJson = descriptorToJson(Schema.Internal.serializer().descriptor) - expectedJsonAsString shouldEqualJson actualJson.toString() - } -} diff --git a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/VertexAIStreamingSnapshotTests.kt b/firebase-vertexai/src/test/java/com/google/firebase/vertexai/VertexAIStreamingSnapshotTests.kt deleted file mode 100644 index 05090264292..00000000000 --- a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/VertexAIStreamingSnapshotTests.kt +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai - -import com.google.firebase.vertexai.type.BlockReason -import com.google.firebase.vertexai.type.FinishReason -import com.google.firebase.vertexai.type.HarmCategory -import com.google.firebase.vertexai.type.InvalidAPIKeyException -import com.google.firebase.vertexai.type.PromptBlockedException -import com.google.firebase.vertexai.type.ResponseStoppedException -import com.google.firebase.vertexai.type.SerializationException -import com.google.firebase.vertexai.type.ServerException -import com.google.firebase.vertexai.type.TextPart -import com.google.firebase.vertexai.util.goldenVertexStreamingFile -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.matchers.nulls.shouldNotBeNull -import io.kotest.matchers.shouldBe -import io.kotest.matchers.string.shouldContain -import io.ktor.http.HttpStatusCode -import kotlin.time.Duration.Companion.seconds -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.toList -import kotlinx.coroutines.withTimeout -import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner - -@RunWith(RobolectricTestRunner::class) -internal class VertexAIStreamingSnapshotTests { - private val testTimeout = 5.seconds - - @Test - fun `short reply`() = - goldenVertexStreamingFile("streaming-success-basic-reply-short.txt") { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { - val responseList = responses.toList() - responseList.isEmpty() shouldBe false - responseList.first().candidates.first().finishReason shouldBe FinishReason.STOP - responseList.first().candidates.first().content.parts.isEmpty() shouldBe false - responseList.first().candidates.first().safetyRatings.isEmpty() shouldBe false - } - } - - @Test - fun `long reply`() = - goldenVertexStreamingFile("streaming-success-basic-reply-long.txt") { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { - val responseList = responses.toList() - responseList.isEmpty() shouldBe false - responseList.last().candidates.first().apply { - finishReason shouldBe FinishReason.STOP - content.parts.isEmpty() shouldBe false - } - } - } - - @Test - fun `invalid safety ratings during image generation`() = - goldenVertexStreamingFile("streaming-success-image-invalid-safety-ratings.txt") { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { - val responseList = responses.toList() - - responseList.isEmpty() shouldBe false - } - } - - @Test - fun `unknown enum in safety ratings`() = - goldenVertexStreamingFile("streaming-success-unknown-safety-enum.txt") { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { - val responseList = responses.toList() - - responseList.isEmpty() shouldBe false - responseList.any { - it.candidates.any { it.safetyRatings.any { it.category == HarmCategory.UNKNOWN } } - } shouldBe true - } - } - - @Test - fun `unknown enum in finish reason`() = - goldenVertexStreamingFile("streaming-failure-unknown-finish-enum.txt") { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { - val exception = shouldThrow { responses.collect() } - exception.response.candidates.first().finishReason shouldBe FinishReason.UNKNOWN - } - } - - @Test - fun `quotes escaped`() = - goldenVertexStreamingFile("streaming-success-quotes-escaped.txt") { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { - val responseList = responses.toList() - - responseList.isEmpty() shouldBe false - val part = responseList.first().candidates.first().content.parts.first() as? TextPart - part.shouldNotBeNull() - part.text shouldContain "\"" - } - } - - @Test - fun `prompt blocked for safety`() = - goldenVertexStreamingFile("streaming-failure-prompt-blocked-safety.txt") { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { - val exception = shouldThrow { responses.collect() } - exception.response?.promptFeedback?.blockReason shouldBe BlockReason.SAFETY - } - } - - @Test - fun `prompt blocked for safety with message`() = - goldenVertexStreamingFile("streaming-failure-prompt-blocked-safety-with-message.txt") { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { - val exception = shouldThrow { responses.collect() } - exception.response?.promptFeedback?.blockReason shouldBe BlockReason.SAFETY - exception.response?.promptFeedback?.blockReasonMessage shouldBe "Reasons" - } - } - - @Test - fun `empty content`() = - goldenVertexStreamingFile("streaming-failure-empty-content.txt") { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { shouldThrow { responses.collect() } } - } - - @Test - fun `http errors`() = - goldenVertexStreamingFile( - "streaming-failure-http-error.txt", - HttpStatusCode.PreconditionFailed - ) { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { shouldThrow { responses.collect() } } - } - - @Test - fun `stopped for safety`() = - goldenVertexStreamingFile("streaming-failure-finish-reason-safety.txt") { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { - val exception = shouldThrow { responses.collect() } - exception.response.candidates.first().finishReason shouldBe FinishReason.SAFETY - } - } - - @Test - fun `citation parsed correctly`() = - goldenVertexStreamingFile("streaming-success-citations.txt") { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { - val responseList = responses.toList() - responseList.any { - it.candidates.any { it.citationMetadata?.citations?.isNotEmpty() ?: false } - } shouldBe true - } - } - - @Test - fun `stopped for recitation`() = - goldenVertexStreamingFile("streaming-failure-recitation-no-content.txt") { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { - val exception = shouldThrow { responses.collect() } - exception.response.candidates.first().finishReason shouldBe FinishReason.RECITATION - } - } - - @Test - fun `image rejected`() = - goldenVertexStreamingFile("streaming-failure-image-rejected.txt", HttpStatusCode.BadRequest) { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { shouldThrow { responses.collect() } } - } - - @Test - fun `unknown model`() = - goldenVertexStreamingFile("streaming-failure-unknown-model.txt", HttpStatusCode.NotFound) { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { shouldThrow { responses.collect() } } - } - - @Test - fun `invalid api key`() = - goldenVertexStreamingFile("streaming-failure-api-key.txt", HttpStatusCode.BadRequest) { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { shouldThrow { responses.collect() } } - } - - @Test - fun `invalid json`() = - goldenVertexStreamingFile("streaming-failure-invalid-json.txt") { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { shouldThrow { responses.collect() } } - } - - @Test - fun `malformed content`() = - goldenVertexStreamingFile("streaming-failure-malformed-content.txt") { - val responses = model.generateContentStream("prompt") - - withTimeout(testTimeout) { shouldThrow { responses.collect() } } - } -} diff --git a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/VertexAIUnarySnapshotTests.kt b/firebase-vertexai/src/test/java/com/google/firebase/vertexai/VertexAIUnarySnapshotTests.kt deleted file mode 100644 index 527b4fc4876..00000000000 --- a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/VertexAIUnarySnapshotTests.kt +++ /dev/null @@ -1,592 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai - -import com.google.firebase.vertexai.type.BlockReason -import com.google.firebase.vertexai.type.ContentBlockedException -import com.google.firebase.vertexai.type.ContentModality -import com.google.firebase.vertexai.type.FinishReason -import com.google.firebase.vertexai.type.FunctionCallPart -import com.google.firebase.vertexai.type.HarmCategory -import com.google.firebase.vertexai.type.HarmProbability -import com.google.firebase.vertexai.type.HarmSeverity -import com.google.firebase.vertexai.type.InvalidAPIKeyException -import com.google.firebase.vertexai.type.PromptBlockedException -import com.google.firebase.vertexai.type.PublicPreviewAPI -import com.google.firebase.vertexai.type.QuotaExceededException -import com.google.firebase.vertexai.type.ResponseStoppedException -import com.google.firebase.vertexai.type.SerializationException -import com.google.firebase.vertexai.type.ServerException -import com.google.firebase.vertexai.type.ServiceDisabledException -import com.google.firebase.vertexai.type.TextPart -import com.google.firebase.vertexai.type.UnsupportedUserLocationException -import com.google.firebase.vertexai.util.goldenVertexUnaryFile -import com.google.firebase.vertexai.util.shouldNotBeNullOrEmpty -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.inspectors.forAtLeastOne -import io.kotest.matchers.collections.shouldNotBeEmpty -import io.kotest.matchers.nulls.shouldNotBeNull -import io.kotest.matchers.should -import io.kotest.matchers.shouldBe -import io.kotest.matchers.shouldNotBe -import io.kotest.matchers.string.shouldContain -import io.kotest.matchers.string.shouldNotBeEmpty -import io.kotest.matchers.types.shouldBeInstanceOf -import io.ktor.http.HttpStatusCode -import java.util.Calendar -import kotlin.time.Duration.Companion.seconds -import kotlinx.coroutines.withTimeout -import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.json.jsonObject -import kotlinx.serialization.json.jsonPrimitive -import org.json.JSONArray -import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner - -@OptIn(PublicPreviewAPI::class) -@RunWith(RobolectricTestRunner::class) -internal class VertexAIUnarySnapshotTests { - private val testTimeout = 5.seconds - - @Test - fun `short reply`() = - goldenVertexUnaryFile("unary-success-basic-reply-short.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - - response.candidates.isEmpty() shouldBe false - response.candidates.first().finishReason shouldBe FinishReason.STOP - response.candidates.first().content.parts.isEmpty() shouldBe false - response.candidates.first().safetyRatings.isEmpty() shouldBe false - } - } - - @Test - fun `long reply`() = - goldenVertexUnaryFile("unary-success-basic-reply-long.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - - response.candidates.isEmpty() shouldBe false - response.candidates.first().finishReason shouldBe FinishReason.STOP - response.candidates.first().content.parts.isEmpty() shouldBe false - response.candidates.first().safetyRatings.isEmpty() shouldBe false - } - } - - @Test - fun `response with detailed token-based usageMetadata`() = - goldenVertexUnaryFile("unary-success-basic-response-long-usage-metadata.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - - response.candidates.isEmpty() shouldBe false - response.candidates.first().finishReason shouldBe FinishReason.STOP - response.candidates.first().content.parts.isEmpty() shouldBe false - response.usageMetadata shouldNotBe null - response.usageMetadata?.apply { - totalTokenCount shouldBe 1913 - candidatesTokenCount shouldBe 76 - promptTokensDetails?.forAtLeastOne { - it.modality shouldBe ContentModality.IMAGE - it.tokenCount shouldBe 1806 - } - candidatesTokensDetails?.forAtLeastOne { - it.modality shouldBe ContentModality.TEXT - it.tokenCount shouldBe 76 - } - } - } - } - - @Test - fun `unknown enum in safety ratings`() = - goldenVertexUnaryFile("unary-success-unknown-enum-safety-ratings.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - - response.candidates.isEmpty() shouldBe false - val candidate = response.candidates.first() - candidate.safetyRatings.any { it.category == HarmCategory.UNKNOWN } shouldBe true - response.promptFeedback?.safetyRatings?.any { it.category == HarmCategory.UNKNOWN } shouldBe - true - } - } - - @Test - fun `invalid safety ratings during image generation`() = - goldenVertexUnaryFile("unary-success-image-invalid-safety-ratings.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - - response.candidates.isEmpty() shouldBe false - } - } - - @Test - fun `unknown enum in finish reason`() = - goldenVertexUnaryFile("unary-failure-unknown-enum-finish-reason.json") { - withTimeout(testTimeout) { - shouldThrow { model.generateContent("prompt") } should - { - it.response.candidates.first().finishReason shouldBe FinishReason.UNKNOWN - } - } - } - - @Test - fun `unknown enum in block reason`() = - goldenVertexUnaryFile("unary-failure-unknown-enum-prompt-blocked.json") { - withTimeout(testTimeout) { - shouldThrow { model.generateContent("prompt") } should - { - it.response?.promptFeedback?.blockReason shouldBe BlockReason.UNKNOWN - } - } - } - - @Test - fun `quotes escaped`() = - goldenVertexUnaryFile("unary-success-quote-reply.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - - response.candidates.isEmpty() shouldBe false - response.candidates.first().content.parts.isEmpty() shouldBe false - val part = response.candidates.first().content.parts.first() as TextPart - part.text shouldContain "\"" - } - } - - @Test - fun `safetyRatings missing`() = - goldenVertexUnaryFile("unary-success-missing-safety-ratings.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - - response.candidates.isEmpty() shouldBe false - response.candidates.first().content.parts.isEmpty() shouldBe false - response.candidates.first().safetyRatings.isEmpty() shouldBe true - response.promptFeedback?.safetyRatings?.isEmpty() shouldBe true - } - } - - @Test - fun `safetyRatings including severity`() = - goldenVertexUnaryFile("unary-success-including-severity.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - - response.candidates.isEmpty() shouldBe false - response.candidates.first().safetyRatings.isEmpty() shouldBe false - response.candidates.first().safetyRatings.all { - it.probability == HarmProbability.NEGLIGIBLE - } shouldBe true - response.candidates.first().safetyRatings.all { - it.severity == HarmSeverity.NEGLIGIBLE - } shouldBe true - response.candidates.first().safetyRatings.all { it.severityScore != null } shouldBe true - } - } - - @Test - fun `function call has no arguments field`() = - goldenVertexUnaryFile("unary-success-function-call-empty-arguments.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - val content = response.candidates.shouldNotBeNullOrEmpty().first().content - content.shouldNotBeNull() - val callPart = content.parts.shouldNotBeNullOrEmpty().first() as FunctionCallPart - - callPart.name shouldBe "current_time" - callPart.args shouldBe emptyMap() - } - } - - @Test - fun `prompt blocked for safety`() = - goldenVertexUnaryFile("unary-failure-prompt-blocked-safety.json") { - withTimeout(testTimeout) { - shouldThrow { model.generateContent("prompt") } should - { - it.response?.promptFeedback?.blockReason shouldBe BlockReason.SAFETY - } - } - } - - @Test - fun `prompt blocked for safety with message`() = - goldenVertexUnaryFile("unary-failure-prompt-blocked-safety-with-message.json") { - withTimeout(testTimeout) { - shouldThrow { model.generateContent("prompt") } should - { - it.response?.promptFeedback?.blockReason shouldBe BlockReason.SAFETY - it.response?.promptFeedback?.blockReasonMessage shouldContain "Reasons" - } - } - } - - @Test - fun `empty content`() = - goldenVertexUnaryFile("unary-failure-empty-content.json") { - withTimeout(testTimeout) { - shouldThrow { model.generateContent("prompt") } - } - } - - @Test - fun `http error`() = - goldenVertexUnaryFile("unary-failure-http-error.json", HttpStatusCode.PreconditionFailed) { - withTimeout(testTimeout) { shouldThrow { model.generateContent("prompt") } } - } - - @Test - fun `user location error`() = - goldenVertexUnaryFile( - "unary-failure-unsupported-user-location.json", - HttpStatusCode.PreconditionFailed, - ) { - withTimeout(testTimeout) { - shouldThrow { model.generateContent("prompt") } - } - } - - @Test - fun `stopped for safety`() = - goldenVertexUnaryFile("unary-failure-finish-reason-safety.json") { - withTimeout(testTimeout) { - val exception = shouldThrow { model.generateContent("prompt") } - exception.response.candidates.first().finishReason shouldBe FinishReason.SAFETY - exception.response.candidates.first().safetyRatings.forAtLeastOne { - it.category shouldBe HarmCategory.HARASSMENT - it.probability shouldBe HarmProbability.LOW - it.severity shouldBe HarmSeverity.LOW - } - } - } - - @Test - fun `quota exceeded`() = - goldenVertexUnaryFile("unary-failure-quota-exceeded.json", HttpStatusCode.BadRequest) { - withTimeout(testTimeout) { - shouldThrow { model.generateContent("prompt") } - } - } - - @Test - fun `stopped for safety with no content`() = - goldenVertexUnaryFile("unary-failure-finish-reason-safety-no-content.json") { - withTimeout(testTimeout) { - val exception = shouldThrow { model.generateContent("prompt") } - exception.response.candidates.first().finishReason shouldBe FinishReason.SAFETY - } - } - - @Test - fun `citation returns correctly`() = - goldenVertexUnaryFile("unary-success-citations.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - - response.candidates.isEmpty() shouldBe false - response.candidates.first().citationMetadata?.citations?.size shouldBe 3 - response.candidates.first().citationMetadata?.citations?.forAtLeastOne { - it.publicationDate?.get(Calendar.YEAR) shouldBe 2019 - it.publicationDate?.get(Calendar.DAY_OF_MONTH) shouldBe 10 - } - } - } - - @Test - fun `citation returns correctly with missing license and startIndex`() = - goldenVertexUnaryFile("unary-success-citations-nolicense.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - - response.candidates.isEmpty() shouldBe false - response.candidates.first().citationMetadata?.citations?.isEmpty() shouldBe false - // Verify the values in the citation source - val firstCitation = response.candidates.first().citationMetadata?.citations?.first() - if (firstCitation != null) { - with(firstCitation) { - license shouldBe null - startIndex shouldBe 0 - } - } - } - } - - @Test - fun `response includes usage metadata`() = - goldenVertexUnaryFile("unary-success-usage-metadata.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - - response.candidates.isEmpty() shouldBe false - response.candidates.first().finishReason shouldBe FinishReason.STOP - response.usageMetadata shouldNotBe null - response.usageMetadata?.totalTokenCount shouldBe 363 - response.usageMetadata?.promptTokensDetails?.isEmpty() shouldBe true - } - } - - @Test - fun `response includes partial usage metadata`() = - goldenVertexUnaryFile("unary-success-partial-usage-metadata.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - - response.candidates.isEmpty() shouldBe false - response.candidates.first().finishReason shouldBe FinishReason.STOP - response.usageMetadata shouldNotBe null - response.usageMetadata?.promptTokenCount shouldBe 6 - response.usageMetadata?.totalTokenCount shouldBe 0 - } - } - - @Test - fun `properly translates json text`() = - goldenVertexUnaryFile("unary-success-constraint-decoding-json.json") { - val response = model.generateContent("prompt") - - response.candidates.isEmpty() shouldBe false - with(response.candidates.first().content.parts.first().shouldBeInstanceOf()) { - shouldNotBeNull() - val jsonArr = JSONArray(text) - jsonArr.length() shouldBe 3 - for (i in 0 until jsonArr.length()) { - with(jsonArr.getJSONObject(i)) { - shouldNotBeNull() - getString("name").shouldNotBeEmpty() - getJSONArray("colors").length() shouldBe 5 - } - } - } - } - - @Test - fun `invalid response`() = - goldenVertexUnaryFile("unary-failure-invalid-response.json") { - withTimeout(testTimeout) { - shouldThrow { model.generateContent("prompt") } - } - } - - @Test - fun `malformed content`() = - goldenVertexUnaryFile("unary-failure-malformed-content.json") { - withTimeout(testTimeout) { - shouldThrow { model.generateContent("prompt") } - } - } - - @Test - fun `invalid api key`() = - goldenVertexUnaryFile("unary-failure-api-key.json", HttpStatusCode.BadRequest) { - withTimeout(testTimeout) { - shouldThrow { model.generateContent("prompt") } - } - } - - @Test - fun `image rejected`() = - goldenVertexUnaryFile("unary-failure-image-rejected.json", HttpStatusCode.BadRequest) { - withTimeout(testTimeout) { shouldThrow { model.generateContent("prompt") } } - } - - @Test - fun `unknown model`() = - goldenVertexUnaryFile("unary-failure-unknown-model.json", HttpStatusCode.NotFound) { - withTimeout(testTimeout) { shouldThrow { model.generateContent("prompt") } } - } - - @Test - fun `service disabled`() = - goldenVertexUnaryFile( - "unary-failure-firebaseml-api-not-enabled.json", - HttpStatusCode.Forbidden - ) { - withTimeout(testTimeout) { - shouldThrow { model.generateContent("prompt") } - } - } - - @Test - fun `function call contains null param`() = - goldenVertexUnaryFile("unary-success-function-call-null.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - val callPart = (response.candidates.first().content.parts.first() as FunctionCallPart) - - callPart.args["season"] shouldBe JsonPrimitive(null) - } - } - - @Test - fun `function call contains json literal`() = - goldenVertexUnaryFile("unary-success-function-call-json-literal.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - val content = response.candidates.shouldNotBeNullOrEmpty().first().content - val callPart = - content.let { - it.shouldNotBeNull() - it.parts.shouldNotBeEmpty() - it.parts.first().shouldBeInstanceOf() - } - - callPart.args["current"] shouldBe JsonPrimitive(true) - } - } - - @Test - fun `function call with complex json literal parses correctly`() = - goldenVertexUnaryFile("unary-success-function-call-complex-json-literal.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - val content = response.candidates.shouldNotBeNullOrEmpty().first().content - val callPart = - content.let { - it.shouldNotBeNull() - it.parts.shouldNotBeEmpty() - it.parts.first().shouldBeInstanceOf() - } - - callPart.args["current"] shouldBe JsonPrimitive(true) - callPart.args["testObject"]!!.jsonObject["testProperty"]!!.jsonPrimitive.content shouldBe - "string property" - } - } - - @Test - fun `function call contains no arguments`() = - goldenVertexUnaryFile("unary-success-function-call-no-arguments.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - val callPart = response.functionCalls.shouldNotBeEmpty().first() - - callPart.name shouldBe "current_time" - callPart.args.isEmpty() shouldBe true - } - } - - @Test - fun `function call contains arguments`() = - goldenVertexUnaryFile("unary-success-function-call-with-arguments.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - val callPart = response.functionCalls.shouldNotBeEmpty().first() - - callPart.name shouldBe "sum" - callPart.args["x"] shouldBe JsonPrimitive(4) - callPart.args["y"] shouldBe JsonPrimitive(5) - } - } - - @Test - fun `function call with parallel calls`() = - goldenVertexUnaryFile("unary-success-function-call-parallel-calls.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - val callList = response.functionCalls - - callList.size shouldBe 3 - callList.forEach { - it.name shouldBe "sum" - it.args.size shouldBe 2 - } - } - } - - @Test - fun `function call with mixed content`() = - goldenVertexUnaryFile("unary-success-function-call-mixed-content.json") { - withTimeout(testTimeout) { - val response = model.generateContent("prompt") - val callList = response.functionCalls - - response.text shouldBe "The sum of [1, 2, 3] is" - callList.size shouldBe 2 - callList.forEach { it.args.size shouldBe 2 } - } - } - - @Test - fun `countTokens succeeds`() = - goldenVertexUnaryFile("unary-success-total-tokens.json") { - withTimeout(testTimeout) { - val response = model.countTokens("prompt") - - response.totalTokens shouldBe 6 - response.totalBillableCharacters shouldBe 16 - response.promptTokensDetails.isEmpty() shouldBe true - } - } - - @Test - fun `countTokens with modality fields returned`() = - goldenVertexUnaryFile("unary-success-detailed-token-response.json") { - withTimeout(testTimeout) { - val response = model.countTokens("prompt") - - response.totalTokens shouldBe 1837 - response.totalBillableCharacters shouldBe 117 - response.promptTokensDetails shouldNotBe null - response.promptTokensDetails?.forAtLeastOne { - it.modality shouldBe ContentModality.IMAGE - it.tokenCount shouldBe 1806 - } - } - } - - @Test - fun `countTokens succeeds with no billable characters`() = - goldenVertexUnaryFile("unary-success-no-billable-characters.json") { - withTimeout(testTimeout) { - val response = model.countTokens("prompt") - - response.totalTokens shouldBe 258 - response.totalBillableCharacters shouldBe 0 - } - } - - @Test - fun `countTokens fails with model not found`() = - goldenVertexUnaryFile("unary-failure-model-not-found.json", HttpStatusCode.NotFound) { - withTimeout(testTimeout) { shouldThrow { model.countTokens("prompt") } } - } - - @Test - fun `generateImages should throw when all images filtered`() = - goldenVertexUnaryFile("unary-failure-generate-images-all-filtered.json") { - withTimeout(testTimeout) { - shouldThrow { imagenModel.generateImages("prompt") } - } - } - - @Test - fun `generateImages should throw when prompt blocked`() = - goldenVertexUnaryFile( - "unary-failure-generate-images-prompt-blocked.json", - HttpStatusCode.BadRequest, - ) { - withTimeout(testTimeout) { - shouldThrow { imagenModel.generateImages("prompt") } - } - } -} diff --git a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/common/APIControllerTests.kt b/firebase-vertexai/src/test/java/com/google/firebase/vertexai/common/APIControllerTests.kt deleted file mode 100644 index 0d668849156..00000000000 --- a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/common/APIControllerTests.kt +++ /dev/null @@ -1,435 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.common - -import com.google.firebase.FirebaseApp -import com.google.firebase.vertexai.BuildConfig -import com.google.firebase.vertexai.common.util.commonTest -import com.google.firebase.vertexai.common.util.createResponses -import com.google.firebase.vertexai.common.util.doBlocking -import com.google.firebase.vertexai.common.util.prepareStreamingResponse -import com.google.firebase.vertexai.type.Content -import com.google.firebase.vertexai.type.CountTokensResponse -import com.google.firebase.vertexai.type.FunctionCallingConfig -import com.google.firebase.vertexai.type.RequestOptions -import com.google.firebase.vertexai.type.TextPart -import com.google.firebase.vertexai.type.Tool -import com.google.firebase.vertexai.type.ToolConfig -import io.kotest.assertions.json.shouldContainJsonKey -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.matchers.shouldBe -import io.kotest.matchers.string.shouldContain -import io.ktor.client.engine.mock.MockEngine -import io.ktor.client.engine.mock.respond -import io.ktor.content.TextContent -import io.ktor.http.HttpHeaders -import io.ktor.http.HttpStatusCode -import io.ktor.http.headersOf -import io.ktor.utils.io.ByteChannel -import io.ktor.utils.io.close -import io.ktor.utils.io.writeFully -import kotlin.time.Duration -import kotlin.time.Duration.Companion.milliseconds -import kotlin.time.Duration.Companion.seconds -import kotlinx.coroutines.delay -import kotlinx.coroutines.withTimeout -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.JsonObject -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.Parameterized -import org.mockito.Mockito - -private val TEST_CLIENT_ID = "genai-android/test" - -private val TEST_APP_ID = "1:android:12345" - -private val TEST_VERSION = 1 - -internal class APIControllerTests { - private val testTimeout = 5.seconds - - @Test - fun `(generateContentStream) emits responses as they come in`() = commonTest { - val response = createResponses("The", " world", " is", " a", " beautiful", " place!") - val bytes = prepareStreamingResponse(response) - - bytes.forEach { channel.writeFully(it) } - val responses = apiController.generateContentStream(textGenerateContentRequest("test")) - - withTimeout(testTimeout) { - responses.collect { - it.candidates?.isEmpty() shouldBe false - channel.close() - } - } - } - - @Test - fun `(generateContent) respects a custom timeout`() = - commonTest(requestOptions = RequestOptions(2.seconds)) { - shouldThrow { - withTimeout(testTimeout) { - apiController.generateContent(textGenerateContentRequest("test")) - } - } - } -} - -@OptIn(ExperimentalSerializationApi::class) -internal class RequestFormatTests { - - private val mockFirebaseApp = Mockito.mock() - - @Before - fun setup() { - Mockito.`when`(mockFirebaseApp.isDataCollectionDefaultEnabled).thenReturn(false) - } - - @Test - fun `using default endpoint`() = doBlocking { - val channel = ByteChannel(autoFlush = true) - val mockEngine = MockEngine { - respond(channel, HttpStatusCode.OK, headersOf(HttpHeaders.ContentType, "application/json")) - } - prepareStreamingResponse(createResponses("Random")).forEach { channel.writeFully(it) } - val controller = - APIController( - "super_cool_test_key", - "gemini-pro-1.5", - RequestOptions(), - mockEngine, - "genai-android/${BuildConfig.VERSION_NAME}", - mockFirebaseApp, - TEST_VERSION, - TEST_APP_ID, - null, - ) - - withTimeout(5.seconds) { - controller.generateContentStream(textGenerateContentRequest("cats")).collect { - it.candidates?.isEmpty() shouldBe false - channel.close() - } - } - - mockEngine.requestHistory.first().url.host shouldBe "firebasevertexai.googleapis.com" - } - - @Test - fun `using custom endpoint`() = doBlocking { - val channel = ByteChannel(autoFlush = true) - val mockEngine = MockEngine { - respond(channel, HttpStatusCode.OK, headersOf(HttpHeaders.ContentType, "application/json")) - } - prepareStreamingResponse(createResponses("Random")).forEach { channel.writeFully(it) } - val controller = - APIController( - "super_cool_test_key", - "gemini-pro-1.5", - RequestOptions(timeout = 5.seconds, endpoint = "https://my.custom.endpoint"), - mockEngine, - TEST_CLIENT_ID, - mockFirebaseApp, - TEST_VERSION, - TEST_APP_ID, - null, - ) - - withTimeout(5.seconds) { - controller.generateContentStream(textGenerateContentRequest("cats")).collect { - it.candidates?.isEmpty() shouldBe false - channel.close() - } - } - - mockEngine.requestHistory.first().url.host shouldBe "my.custom.endpoint" - } - - @Test - fun `client id header is set correctly in the request`() = doBlocking { - val response = JSON.encodeToString(CountTokensResponse.Internal(totalTokens = 10)) - val mockEngine = MockEngine { - respond(response, HttpStatusCode.OK, headersOf(HttpHeaders.ContentType, "application/json")) - } - - val controller = - APIController( - "super_cool_test_key", - "gemini-pro-1.5", - RequestOptions(), - mockEngine, - TEST_CLIENT_ID, - mockFirebaseApp, - TEST_VERSION, - TEST_APP_ID, - null, - ) - - withTimeout(5.seconds) { controller.countTokens(textCountTokenRequest("cats")) } - - mockEngine.requestHistory.first().headers["x-goog-api-client"] shouldBe TEST_CLIENT_ID - } - - @Test - fun `ml monitoring header is set correctly if data collection is enabled`() = doBlocking { - val response = JSON.encodeToString(CountTokensResponse.Internal(totalTokens = 10)) - val mockEngine = MockEngine { - respond(response, HttpStatusCode.OK, headersOf(HttpHeaders.ContentType, "application/json")) - } - - Mockito.`when`(mockFirebaseApp.isDataCollectionDefaultEnabled).thenReturn(true) - - val controller = - APIController( - "super_cool_test_key", - "gemini-pro-1.5", - RequestOptions(), - mockEngine, - TEST_CLIENT_ID, - mockFirebaseApp, - TEST_VERSION, - TEST_APP_ID, - null, - ) - - withTimeout(5.seconds) { controller.countTokens(textCountTokenRequest("cats")) } - - mockEngine.requestHistory.first().headers["X-Firebase-AppId"] shouldBe TEST_APP_ID - mockEngine.requestHistory.first().headers["X-Firebase-AppVersion"] shouldBe - TEST_VERSION.toString() - } - - @Test - fun `ToolConfig serialization contains correct keys`() = doBlocking { - val channel = ByteChannel(autoFlush = true) - val mockEngine = MockEngine { - respond(channel, HttpStatusCode.OK, headersOf(HttpHeaders.ContentType, "application/json")) - } - prepareStreamingResponse(createResponses("Random")).forEach { channel.writeFully(it) } - - val controller = - APIController( - "super_cool_test_key", - "gemini-pro-1.5", - RequestOptions(), - mockEngine, - TEST_CLIENT_ID, - mockFirebaseApp, - TEST_VERSION, - TEST_APP_ID, - null, - ) - - withTimeout(5.seconds) { - controller - .generateContentStream( - GenerateContentRequest( - model = "unused", - contents = listOf(Content.Internal(parts = listOf(TextPart.Internal("Arbitrary")))), - toolConfig = - ToolConfig.Internal( - FunctionCallingConfig.Internal( - mode = FunctionCallingConfig.Internal.Mode.ANY, - allowedFunctionNames = listOf("allowedFunctionName") - ) - ) - ), - ) - .collect { channel.close() } - } - - val requestBodyAsText = (mockEngine.requestHistory.first().body as TextContent).text - - requestBodyAsText shouldContainJsonKey "tool_config.function_calling_config.mode" - requestBodyAsText shouldContainJsonKey - "tool_config.function_calling_config.allowed_function_names" - } - - @Test - fun `headers from HeaderProvider are added to the request`() = doBlocking { - val response = JSON.encodeToString(CountTokensResponse.Internal(totalTokens = 10)) - val mockEngine = MockEngine { - respond(response, HttpStatusCode.OK, headersOf(HttpHeaders.ContentType, "application/json")) - } - - val testHeaderProvider = - object : HeaderProvider { - override val timeout: Duration - get() = 5.seconds - - override suspend fun generateHeaders(): Map = - mapOf("header1" to "value1", "header2" to "value2") - } - - val controller = - APIController( - "super_cool_test_key", - "gemini-pro-1.5", - RequestOptions(), - mockEngine, - TEST_CLIENT_ID, - mockFirebaseApp, - TEST_VERSION, - TEST_APP_ID, - testHeaderProvider, - ) - - withTimeout(5.seconds) { controller.countTokens(textCountTokenRequest("cats")) } - - mockEngine.requestHistory.first().headers["header1"] shouldBe "value1" - mockEngine.requestHistory.first().headers["header2"] shouldBe "value2" - } - - @Test - fun `headers from HeaderProvider are ignored if timeout`() = doBlocking { - val response = JSON.encodeToString(CountTokensResponse.Internal(totalTokens = 10)) - val mockEngine = MockEngine { - respond(response, HttpStatusCode.OK, headersOf(HttpHeaders.ContentType, "application/json")) - } - - val testHeaderProvider = - object : HeaderProvider { - override val timeout: Duration - get() = 5.milliseconds - - override suspend fun generateHeaders(): Map { - delay(10.milliseconds) - return mapOf("header1" to "value1") - } - } - - val controller = - APIController( - "super_cool_test_key", - "gemini-pro-1.5", - RequestOptions(), - mockEngine, - TEST_CLIENT_ID, - mockFirebaseApp, - TEST_VERSION, - TEST_APP_ID, - testHeaderProvider, - ) - - withTimeout(5.seconds) { controller.countTokens(textCountTokenRequest("cats")) } - - mockEngine.requestHistory.first().headers.contains("header1") shouldBe false - } - - @Test - fun `code execution tool serialization contains correct keys`() = doBlocking { - val channel = ByteChannel(autoFlush = true) - val mockEngine = MockEngine { - respond(channel, HttpStatusCode.OK, headersOf(HttpHeaders.ContentType, "application/json")) - } - prepareStreamingResponse(createResponses("Random")).forEach { channel.writeFully(it) } - - val controller = - APIController( - "super_cool_test_key", - "gemini-pro-1.5", - RequestOptions(), - mockEngine, - TEST_CLIENT_ID, - mockFirebaseApp, - TEST_VERSION, - TEST_APP_ID, - null, - ) - - withTimeout(5.seconds) { - controller - .generateContentStream( - GenerateContentRequest( - model = "unused", - contents = listOf(Content.Internal(parts = listOf(TextPart.Internal("Arbitrary")))), - tools = listOf(Tool.Internal(codeExecution = JsonObject(emptyMap()))), - ) - ) - .collect { channel.close() } - } - - val requestBodyAsText = (mockEngine.requestHistory.first().body as TextContent).text - - requestBodyAsText shouldContainJsonKey "tools[0].codeExecution" - } -} - -@RunWith(Parameterized::class) -internal class ModelNamingTests(private val modelName: String, private val actualName: String) { - private val mockFirebaseApp = Mockito.mock() - - @Before - fun setup() { - Mockito.`when`(mockFirebaseApp.isDataCollectionDefaultEnabled).thenReturn(false) - } - - @Test - fun `request should include right model name`() = doBlocking { - val channel = ByteChannel(autoFlush = true) - val mockEngine = MockEngine { - respond(channel, HttpStatusCode.OK, headersOf(HttpHeaders.ContentType, "application/json")) - } - prepareStreamingResponse(createResponses("Random")).forEach { channel.writeFully(it) } - val controller = - APIController( - "super_cool_test_key", - modelName, - RequestOptions(), - mockEngine, - TEST_CLIENT_ID, - mockFirebaseApp, - TEST_VERSION, - TEST_APP_ID, - null, - ) - - withTimeout(5.seconds) { - controller.generateContentStream(textGenerateContentRequest("cats")).collect { - it.candidates?.isEmpty() shouldBe false - channel.close() - } - } - - mockEngine.requestHistory.first().url.encodedPath shouldContain actualName - } - - companion object { - @JvmStatic - @Parameterized.Parameters - fun data() = - listOf( - arrayOf("gemini-pro", "models/gemini-pro"), - arrayOf("x/gemini-pro", "x/gemini-pro"), - arrayOf("models/gemini-pro", "models/gemini-pro"), - arrayOf("/modelname", "/modelname"), - arrayOf("modifiedNaming/mymodel", "modifiedNaming/mymodel"), - ) - } -} - -internal fun textGenerateContentRequest(prompt: String) = - GenerateContentRequest( - model = "unused", - contents = listOf(Content.Internal(parts = listOf(TextPart.Internal(prompt)))), - ) - -internal fun textCountTokenRequest(prompt: String) = - CountTokensRequest(generateContentRequest = textGenerateContentRequest(prompt)) diff --git a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/common/EnumUpdateTests.kt b/firebase-vertexai/src/test/java/com/google/firebase/vertexai/common/EnumUpdateTests.kt deleted file mode 100644 index 769adbd4cd8..00000000000 --- a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/common/EnumUpdateTests.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.common - -import com.google.firebase.vertexai.type.HarmBlockMethod -import com.google.firebase.vertexai.type.HarmBlockThreshold -import com.google.firebase.vertexai.type.HarmCategory -import org.junit.Test - -/** - * Fetches all the `@JvmStatic` properties of a class that are instances of the class itself. - * - * For example, given the following class: - * ```kt - * public class HarmCategory private constructor(public val ordinal: Int) { - * public companion object { - * @JvmField public val UNKNOWN: HarmCategory = HarmCategory(0) - * @JvmField public val HARASSMENT: HarmCategory = HarmCategory(1) - * } - * } - * ``` - * This function will yield: - * ```kt - * [UNKNOWN, HARASSMENT] - * ``` - */ -internal inline fun getEnumValues(): List { - return T::class - .java - .declaredFields - .filter { it.type == T::class.java } - .mapNotNull { it.get(null) as? T } -} - -/** - * Ensures that whenever any of our "pseudo-enums" are updated, that the conversion layer is also - * updated. - */ -internal class EnumUpdateTests { - @Test - fun `HarmCategory#toInternal() covers all values`() { - val values = getEnumValues() - values.forEach { it.toInternal() } - } - - @Test - fun `HarmBlockMethod#toInternal() covers all values`() { - val values = getEnumValues() - values.forEach { it.toInternal() } - } - - @Test - fun `HarmBlockThreshold#toInternal() covers all values`() { - val values = getEnumValues() - values.forEach { it.toInternal() } - } -} diff --git a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/common/util/descriptorToJson.kt b/firebase-vertexai/src/test/java/com/google/firebase/vertexai/common/util/descriptorToJson.kt deleted file mode 100644 index 31d9156bc75..00000000000 --- a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/common/util/descriptorToJson.kt +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.common.util - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.descriptors.SerialKind -import kotlinx.serialization.descriptors.StructureKind -import kotlinx.serialization.descriptors.elementDescriptors -import kotlinx.serialization.descriptors.elementNames -import kotlinx.serialization.json.JsonArray -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.JsonObjectBuilder -import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.json.buildJsonObject -import kotlinx.serialization.json.put -import kotlinx.serialization.json.putJsonObject - -/** - * Returns a [JsonObject] representing the classes in the hierarchy of a serialization [descriptor]. - * - * The format of the JSON object is similar to that of a Discovery Document, but restricted to these - * fields: - * - id - * - type - * - properties - * - items - * - $ref - * - * @param descriptor The [SerialDescriptor] to process. - */ -@OptIn(ExperimentalSerializationApi::class) -internal fun descriptorToJson(descriptor: SerialDescriptor): JsonObject { - return buildJsonObject { - put("id", simpleNameFromSerialName(descriptor.serialName)) - put("type", typeNameFromKind(descriptor.kind)) - if (descriptor.kind != StructureKind.CLASS) { - throw UnsupportedOperationException("Only classes can be serialized to JSON for now.") - } - // For top-level enums, add them directly. - if (descriptor.serialName == "FirstOrdinalSerializer") { - addEnumDescription(descriptor) - } else { - addObjectProperties(descriptor) - } - } -} - -@OptIn(ExperimentalSerializationApi::class) -internal fun JsonObjectBuilder.addListDescription(descriptor: SerialDescriptor) = - putJsonObject("items") { - val itemDescriptor = descriptor.elementDescriptors.first() - val nestedIsPrimitive = (descriptor.elementsCount == 1 && itemDescriptor.kind is PrimitiveKind) - if (nestedIsPrimitive) { - put("type", typeNameFromKind(itemDescriptor.kind)) - } else { - put("\$ref", simpleNameFromSerialName(itemDescriptor.serialName)) - } - } - -@OptIn(ExperimentalSerializationApi::class) -internal fun JsonObjectBuilder.addEnumDescription(descriptor: SerialDescriptor): JsonElement? { - put("type", typeNameFromKind(SerialKind.ENUM)) - return put("enum", JsonArray(descriptor.elementNames.map { JsonPrimitive(it) })) -} - -@OptIn(ExperimentalSerializationApi::class) -internal fun JsonObjectBuilder.addObjectProperties(descriptor: SerialDescriptor): JsonElement? { - return putJsonObject("properties") { - for (i in 0 until descriptor.elementsCount) { - val elementDescriptor = descriptor.getElementDescriptor(i) - val elementName = descriptor.getElementName(i) - putJsonObject(elementName) { - when (elementDescriptor.kind) { - StructureKind.LIST -> { - put("type", typeNameFromKind(elementDescriptor.kind)) - addListDescription(elementDescriptor) - } - StructureKind.CLASS -> { - if (elementDescriptor.serialName.startsWith("FirstOrdinalSerializer")) { - addEnumDescription(elementDescriptor) - } else { - put("\$ref", simpleNameFromSerialName(elementDescriptor.serialName)) - } - } - StructureKind.MAP -> { - put("type", typeNameFromKind(elementDescriptor.kind)) - putJsonObject("additionalProperties") { - put( - "\$ref", - simpleNameFromSerialName(elementDescriptor.getElementDescriptor(1).serialName) - ) - } - } - else -> { - put("type", typeNameFromKind(elementDescriptor.kind)) - } - } - } - } - } -} - -@OptIn(ExperimentalSerializationApi::class) -internal fun typeNameFromKind(kind: SerialKind): String { - return when (kind) { - PrimitiveKind.BOOLEAN -> "boolean" - PrimitiveKind.BYTE -> "integer" - PrimitiveKind.CHAR -> "string" - PrimitiveKind.DOUBLE -> "number" - PrimitiveKind.FLOAT -> "number" - PrimitiveKind.INT -> "integer" - PrimitiveKind.LONG -> "integer" - PrimitiveKind.SHORT -> "integer" - PrimitiveKind.STRING -> "string" - StructureKind.CLASS -> "object" - StructureKind.LIST -> "array" - SerialKind.ENUM -> "string" - StructureKind.MAP -> "object" - /* Only add new cases if they show up in actual test scenarios. */ - else -> TODO() - } -} - -/** - * Extracts the name expected for a class from its serial name. - * - * Our serialization classes are nested within the public-facing classes, and that's the name we - * want in the json output. There are two class names - * - * - `com.google.firebase.vertexai.type.Content.Internal` for regular scenarios - * - `com.google.firebase.vertexai.type.Content.Internal.SomeClass` for nested classes in the - * serializer. - * - * For the later time we need the second to last component, for the former we need the last - * component. - * - * Additionally, given that types can be nullable, we need to strip the `?` from the end of the - * name. - */ -internal fun simpleNameFromSerialName(serialName: String): String = - serialName - .split(".") - .let { - if (it.last().startsWith("Internal")) { - it[it.size - 2] - } else { - it.last() - } - } - .replace("?", "") diff --git a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/common/util/kotlin.kt b/firebase-vertexai/src/test/java/com/google/firebase/vertexai/common/util/kotlin.kt deleted file mode 100644 index e9044f564c2..00000000000 --- a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/common/util/kotlin.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.common.util - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.runBlocking - -/** - * Runs the given [block] using [runBlocking] on the current thread for side effect. - * - * Using this function is like [runBlocking] with default context (which runs the given block on the - * calling thread) but forces the return type to be `Unit`, which is helpful when implementing - * suspending tests as expression functions: - * ``` - * @Test - * fun myTest() = doBlocking {...} - * ``` - */ -internal fun doBlocking(block: suspend CoroutineScope.() -> Unit) { - runBlocking(block = block) -} diff --git a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/common/util/tests.kt b/firebase-vertexai/src/test/java/com/google/firebase/vertexai/common/util/tests.kt deleted file mode 100644 index 320cf381467..00000000000 --- a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/common/util/tests.kt +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@file:Suppress("DEPRECATION") // a replacement for our purposes has not been published yet - -package com.google.firebase.vertexai.common.util - -import com.google.firebase.FirebaseApp -import com.google.firebase.vertexai.common.APIController -import com.google.firebase.vertexai.common.JSON -import com.google.firebase.vertexai.type.Candidate -import com.google.firebase.vertexai.type.Content -import com.google.firebase.vertexai.type.GenerateContentResponse -import com.google.firebase.vertexai.type.RequestOptions -import com.google.firebase.vertexai.type.TextPart -import io.ktor.client.engine.mock.MockEngine -import io.ktor.client.engine.mock.respond -import io.ktor.http.HttpHeaders -import io.ktor.http.HttpStatusCode -import io.ktor.http.headersOf -import io.ktor.utils.io.ByteChannel -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.encodeToString -import org.mockito.Mockito - -private val TEST_CLIENT_ID = "genai-android/test" -private val TEST_APP_ID = "1:android:12345" -private val TEST_VERSION = 1 - -internal fun prepareStreamingResponse( - response: List -): List = response.map { "data: ${JSON.encodeToString(it)}$SSE_SEPARATOR".toByteArray() } - -@OptIn(ExperimentalSerializationApi::class) -internal fun createResponses(vararg text: String): List { - val candidates = - text.map { Candidate.Internal(Content.Internal(parts = listOf(TextPart.Internal(it)))) } - - return candidates.map { GenerateContentResponse.Internal(candidates = listOf(it)) } -} - -/** - * Wrapper around common instances needed in tests. - * - * @param channel A [ByteChannel] for sending responses through the mock HTTP engine - * @param apiController A [APIController] that consumes the [channel] - * @see commonTest - * @see send - */ -internal data class CommonTestScope(val channel: ByteChannel, val apiController: APIController) - -/** A test that runs under a [CommonTestScope]. */ -internal typealias CommonTest = suspend CommonTestScope.() -> Unit - -/** - * Common test block for providing a [CommonTestScope] during tests. - * - * Example usage: - * ``` - * @Test - * fun `(generateContent) generates a proper response`() = commonTest { - * val request = createRequest("say something nice") - * val response = createResponse("The world is a beautiful place!") - * - * channel.send(prepareResponse(response)) - * - * withTimeout(testTimeout) { - * val data = controller.generateContent(request) - * data.candidates.shouldNotBeEmpty() - * } - * } - * ``` - * - * @param status An optional [HttpStatusCode] to return as a response - * @param requestOptions Optional [RequestOptions] to utilize in the underlying controller - * @param block The test contents themselves, with the [CommonTestScope] implicitly provided - * @see CommonTestScope - */ -internal fun commonTest( - status: HttpStatusCode = HttpStatusCode.OK, - requestOptions: RequestOptions = RequestOptions(), - block: CommonTest, -) = doBlocking { - val mockFirebaseApp = Mockito.mock() - Mockito.`when`(mockFirebaseApp.isDataCollectionDefaultEnabled).thenReturn(false) - - val channel = ByteChannel(autoFlush = true) - val apiController = - APIController( - "super_cool_test_key", - "gemini-pro", - requestOptions, - MockEngine { - respond(channel, status, headersOf(HttpHeaders.ContentType, "application/json")) - }, - TEST_CLIENT_ID, - mockFirebaseApp, - TEST_VERSION, - TEST_APP_ID, - null, - ) - CommonTestScope(channel, apiController).block() -} diff --git a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/util/kotlin.kt b/firebase-vertexai/src/test/java/com/google/firebase/vertexai/util/kotlin.kt deleted file mode 100644 index 53d9de032ae..00000000000 --- a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/util/kotlin.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.vertexai.util - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.runBlocking - -/** - * Runs the given [block] using [runBlocking] on the current thread for side effect. - * - * Using this function is like [runBlocking] with default context (which runs the given block on the - * calling thread) but forces the return type to be `Unit`, which is helpful when implementing - * suspending tests as expression functions: - * ``` - * @Test - * fun myTest() = doBlocking {...} - * ``` - */ -internal fun doBlocking(block: suspend CoroutineScope.() -> Unit) { - runBlocking(block = block) -} diff --git a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/util/tests.kt b/firebase-vertexai/src/test/java/com/google/firebase/vertexai/util/tests.kt deleted file mode 100644 index 3640821771e..00000000000 --- a/firebase-vertexai/src/test/java/com/google/firebase/vertexai/util/tests.kt +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@file:OptIn(PublicPreviewAPI::class) - -package com.google.firebase.vertexai.util - -import com.google.firebase.FirebaseApp -import com.google.firebase.vertexai.GenerativeModel -import com.google.firebase.vertexai.ImagenModel -import com.google.firebase.vertexai.common.APIController -import com.google.firebase.vertexai.type.PublicPreviewAPI -import com.google.firebase.vertexai.type.RequestOptions -import io.kotest.matchers.collections.shouldNotBeEmpty -import io.kotest.matchers.nulls.shouldNotBeNull -import io.ktor.client.engine.mock.MockEngine -import io.ktor.client.engine.mock.respond -import io.ktor.http.HttpHeaders -import io.ktor.http.HttpStatusCode -import io.ktor.http.headersOf -import io.ktor.utils.io.ByteChannel -import io.ktor.utils.io.close -import io.ktor.utils.io.writeFully -import java.io.File -import kotlinx.coroutines.launch -import org.mockito.Mockito - -internal val TEST_CLIENT_ID = "firebase-vertexai-android/test" -internal val TEST_APP_ID = "1:android:12345" -internal val TEST_VERSION = 1 - -/** String separator used in SSE communication to signal the end of a message. */ -internal const val SSE_SEPARATOR = "\r\n\r\n" - -/** - * Writes the provided [bytes] to the channel and closes it. - * - * Just a wrapper around [writeFully] that closes the channel after writing is complete. - * - * @param bytes the data to send through the channel - */ -internal suspend fun ByteChannel.send(bytes: ByteArray) { - writeFully(bytes) - close() -} - -/** - * Wrapper around common instances needed in tests. - * - * @param channel A [ByteChannel] for sending responses through the mock HTTP engine - * @param apiController A [APIController] that consumes the [channel] - * @see commonTest - * @see send - */ -internal data class CommonTestScope( - val channel: ByteChannel, - val model: GenerativeModel, - val imagenModel: ImagenModel, -) - -/** A test that runs under a [CommonTestScope]. */ -internal typealias CommonTest = suspend CommonTestScope.() -> Unit - -/** - * Common test block for providing a [CommonTestScope] during tests. - * - * Example usage: - * ``` - * @Test - * fun `(generateContent) generates a proper response`() = commonTest { - * val request = createRequest("say something nice") - * val response = createResponse("The world is a beautiful place!") - * - * channel.send(prepareResponse(response)) - * - * withTimeout(testTimeout) { - * val data = controller.generateContent(request) - * data.candidates.shouldNotBeEmpty() - * } - * } - * ``` - * - * @param status An optional [HttpStatusCode] to return as a response - * @param requestOptions Optional [RequestOptions] to utilize in the underlying controller - * @param block The test contents themselves, with the [CommonTestScope] implicitly provided - * @see CommonTestScope - */ -@OptIn(PublicPreviewAPI::class) -internal fun commonTest( - status: HttpStatusCode = HttpStatusCode.OK, - requestOptions: RequestOptions = RequestOptions(), - block: CommonTest, -) = doBlocking { - val channel = ByteChannel(autoFlush = true) - val mockFirebaseApp = Mockito.mock() - Mockito.`when`(mockFirebaseApp.isDataCollectionDefaultEnabled).thenReturn(false) - - val apiController = - APIController( - "super_cool_test_key", - "gemini-pro", - requestOptions, - MockEngine { - respond(channel, status, headersOf(HttpHeaders.ContentType, "application/json")) - }, - TEST_CLIENT_ID, - mockFirebaseApp, - TEST_VERSION, - TEST_APP_ID, - null, - ) - val model = GenerativeModel("cool-model-name", controller = apiController) - val imagenModel = ImagenModel("cooler-model-name", controller = apiController) - CommonTestScope(channel, model, imagenModel).block() -} - -/** - * A variant of [commonTest] for performing *streaming-based* snapshot tests. - * - * Loads the *Golden File* and automatically parses the messages from it; providing it to the - * channel. - * - * @param name The name of the *Golden File* to load - * @param httpStatusCode An optional [HttpStatusCode] to return as a response - * @param block The test contents themselves, with a [CommonTestScope] implicitly provided - * @see goldenVertexUnaryFile - */ -internal fun goldenStreamingFile( - name: String, - httpStatusCode: HttpStatusCode = HttpStatusCode.OK, - block: CommonTest, -) = doBlocking { - val goldenFile = loadGoldenFile(name) - val messages = goldenFile.readLines().filter { it.isNotBlank() } - - commonTest(httpStatusCode) { - launch { - for (message in messages) { - channel.writeFully("$message$SSE_SEPARATOR".toByteArray()) - } - channel.close() - } - - block() - } -} - -/** - * A variant of [goldenStreamingFile] for testing vertexAI - * - * Loads the *Golden File* and automatically parses the messages from it; providing it to the - * channel. - * - * @param name The name of the *Golden File* to load - * @param httpStatusCode An optional [HttpStatusCode] to return as a response - * @param block The test contents themselves, with a [CommonTestScope] implicitly provided - * @see goldenStreamingFile - */ -internal fun goldenVertexStreamingFile( - name: String, - httpStatusCode: HttpStatusCode = HttpStatusCode.OK, - block: CommonTest, -) = goldenStreamingFile("vertexai/$name", httpStatusCode, block) - -/** - * A variant of [commonTest] for performing snapshot tests. - * - * Loads the *Golden File* and automatically provides it to the channel. - * - * @param name The name of the *Golden File* to load - * @param httpStatusCode An optional [HttpStatusCode] to return as a response - * @param block The test contents themselves, with a [CommonTestScope] implicitly provided - * @see goldenStreamingFile - */ -internal fun goldenUnaryFile( - name: String, - httpStatusCode: HttpStatusCode = HttpStatusCode.OK, - block: CommonTest, -) = doBlocking { - commonTest(httpStatusCode) { - val goldenFile = loadGoldenFile(name) - val message = goldenFile.readText() - - launch { channel.send(message.toByteArray()) } - - block() - } -} - -/** - * A variant of [goldenUnaryFile] for vertexai tests Loads the *Golden File* and automatically - * provides it to the channel. - * - * @param name The name of the *Golden File* to load - * @param httpStatusCode An optional [HttpStatusCode] to return as a response - * @param block The test contents themselves, with a [CommonTestScope] implicitly provided - * @see goldenUnaryFile - */ -internal fun goldenVertexUnaryFile( - name: String, - httpStatusCode: HttpStatusCode = HttpStatusCode.OK, - block: CommonTest, -) = goldenUnaryFile("vertexai/$name", httpStatusCode, block) - -/** - * Loads a *Golden File* from the resource directory. - * - * Expects golden files to live under `golden-files` in the resource files. - * - * @see goldenUnaryFile - */ -internal fun loadGoldenFile(path: String): File = - loadResourceFile("vertexai-sdk-test-data/mock-responses/$path") - -/** Loads a file from the test resources directory. */ -internal fun loadResourceFile(path: String) = File("src/test/resources/$path") - -/** - * Ensures that a collection is neither null or empty. - * - * Syntax sugar for [shouldNotBeNull] and [shouldNotBeEmpty]. - */ -inline fun Collection?.shouldNotBeNullOrEmpty(): Collection { - shouldNotBeNull() - shouldNotBeEmpty() - return this -} diff --git a/firebase-vertexai/src/test/resources/README.md b/firebase-vertexai/src/test/resources/README.md deleted file mode 100644 index cba0fad1813..00000000000 --- a/firebase-vertexai/src/test/resources/README.md +++ /dev/null @@ -1,2 +0,0 @@ -Mock response files should be cloned into this directory to run unit tests. See -the Vertex AI for Firebase [README](../../..#running-tests) for instructions. \ No newline at end of file diff --git a/firebase-vertexai/src/testUtil/java/com/google/firebase/vertexai/JavaCompileTests.java b/firebase-vertexai/src/testUtil/java/com/google/firebase/vertexai/JavaCompileTests.java deleted file mode 100644 index 8f2020d818f..00000000000 --- a/firebase-vertexai/src/testUtil/java/com/google/firebase/vertexai/JavaCompileTests.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package java.com.google.firebase.vertexai; - -import android.graphics.Bitmap; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.firebase.concurrent.FirebaseExecutors; -import com.google.firebase.vertexai.FirebaseVertexAI; -import com.google.firebase.vertexai.GenerativeModel; -import com.google.firebase.vertexai.LiveGenerativeModel; -import com.google.firebase.vertexai.java.ChatFutures; -import com.google.firebase.vertexai.java.GenerativeModelFutures; -import com.google.firebase.vertexai.java.LiveModelFutures; -import com.google.firebase.vertexai.java.LiveSessionFutures; -import com.google.firebase.vertexai.type.BlockReason; -import com.google.firebase.vertexai.type.Candidate; -import com.google.firebase.vertexai.type.Citation; -import com.google.firebase.vertexai.type.CitationMetadata; -import com.google.firebase.vertexai.type.Content; -import com.google.firebase.vertexai.type.ContentModality; -import com.google.firebase.vertexai.type.CountTokensResponse; -import com.google.firebase.vertexai.type.FileDataPart; -import com.google.firebase.vertexai.type.FinishReason; -import com.google.firebase.vertexai.type.FunctionCallPart; -import com.google.firebase.vertexai.type.FunctionResponsePart; -import com.google.firebase.vertexai.type.GenerateContentResponse; -import com.google.firebase.vertexai.type.GenerationConfig; -import com.google.firebase.vertexai.type.HarmCategory; -import com.google.firebase.vertexai.type.HarmProbability; -import com.google.firebase.vertexai.type.HarmSeverity; -import com.google.firebase.vertexai.type.ImagePart; -import com.google.firebase.vertexai.type.InlineDataPart; -import com.google.firebase.vertexai.type.LiveGenerationConfig; -import com.google.firebase.vertexai.type.LiveServerContent; -import com.google.firebase.vertexai.type.LiveServerMessage; -import com.google.firebase.vertexai.type.LiveServerSetupComplete; -import com.google.firebase.vertexai.type.LiveServerToolCall; -import com.google.firebase.vertexai.type.LiveServerToolCallCancellation; -import com.google.firebase.vertexai.type.MediaData; -import com.google.firebase.vertexai.type.ModalityTokenCount; -import com.google.firebase.vertexai.type.Part; -import com.google.firebase.vertexai.type.PromptFeedback; -import com.google.firebase.vertexai.type.ResponseModality; -import com.google.firebase.vertexai.type.SafetyRating; -import com.google.firebase.vertexai.type.SpeechConfig; -import com.google.firebase.vertexai.type.TextPart; -import com.google.firebase.vertexai.type.UsageMetadata; -import com.google.firebase.vertexai.type.Voices; -import java.util.Calendar; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executor; -import kotlinx.serialization.json.JsonElement; -import kotlinx.serialization.json.JsonNull; -import kotlinx.serialization.json.JsonObject; -import org.junit.Assert; -import org.reactivestreams.Publisher; -import org.reactivestreams.Subscriber; -import org.reactivestreams.Subscription; - -/** - * Tests in this file exist to be compiled, not invoked - */ -public class JavaCompileTests { - - public void initializeJava() throws Exception { - FirebaseVertexAI vertex = FirebaseVertexAI.getInstance(); - GenerativeModel model = vertex.generativeModel("fake-model-name", getConfig()); - LiveGenerativeModel live = vertex.liveModel("fake-model-name", getLiveConfig()); - GenerativeModelFutures futures = GenerativeModelFutures.from(model); - LiveModelFutures liveFutures = LiveModelFutures.from(live); - testFutures(futures); - testLiveFutures(liveFutures); - } - - private GenerationConfig getConfig() { - return new GenerationConfig.Builder().build(); - // TODO b/406558430 GenerationConfig.Builder.setParts returns void - } - - private LiveGenerationConfig getLiveConfig() { - return new LiveGenerationConfig.Builder() - .setTopK(10) - .setTopP(11.0F) - .setTemperature(32.0F) - .setCandidateCount(1) - .setMaxOutputTokens(0xCAFEBABE) - .setFrequencyPenalty(1.0F) - .setPresencePenalty(2.0F) - .setResponseModality(ResponseModality.AUDIO) - .setSpeechConfig(new SpeechConfig(Voices.AOEDE)) - .build(); - } - - private void testFutures(GenerativeModelFutures futures) throws Exception { - Content content = - new Content.Builder() - .addText("Fake prompt") - .addFileData("fakeuri", "image/png") - .addInlineData(new byte[] {}, "text/json") - .addImage(Bitmap.createBitmap(0, 0, Bitmap.Config.HARDWARE)) - .addPart(new FunctionCallPart("fakeFunction", Map.of("fakeArg", JsonNull.INSTANCE))) - .build(); - // TODO b/406558430 Content.Builder.setParts and Content.Builder.setRole return void - Executor executor = FirebaseExecutors.directExecutor(); - ListenableFuture countResponse = futures.countTokens(content); - validateCountTokensResponse(countResponse.get()); - ListenableFuture generateResponse = futures.generateContent(content); - validateGenerateContentResponse(generateResponse.get()); - ChatFutures chat = futures.startChat(); - ListenableFuture future = chat.sendMessage(content); - future.addListener( - () -> { - try { - validateGenerateContentResponse(future.get()); - } catch (Exception e) { - // Ignore - } - }, - executor); - Publisher responsePublisher = futures.generateContentStream(content); - responsePublisher.subscribe( - new Subscriber() { - private boolean complete = false; - - @Override - public void onSubscribe(Subscription s) { - s.request(Long.MAX_VALUE); - } - - @Override - public void onNext(GenerateContentResponse response) { - Assert.assertFalse(complete); - validateGenerateContentResponse(response); - } - - @Override - public void onError(Throwable t) { - // Ignore - } - - @Override - public void onComplete() { - complete = true; - } - }); - } - - public void validateCountTokensResponse(CountTokensResponse response) { - int tokens = response.getTotalTokens(); - Integer billable = response.getTotalBillableCharacters(); - Assert.assertEquals(tokens, response.component1()); - Assert.assertEquals(billable, response.component2()); - Assert.assertEquals(response.getPromptTokensDetails(), response.component3()); - for (ModalityTokenCount count : response.getPromptTokensDetails()) { - ContentModality modality = count.getModality(); - int tokenCount = count.getTokenCount(); - } - } - - public void validateGenerateContentResponse(GenerateContentResponse response) { - List candidates = response.getCandidates(); - if (candidates.size() == 1 - && candidates.get(0).getContent().getParts().stream() - .anyMatch(p -> p instanceof TextPart && !((TextPart) p).getText().isEmpty())) { - String text = response.getText(); - Assert.assertNotNull(text); - Assert.assertFalse(text.isBlank()); - } - validateCandidates(candidates); - validateFunctionCalls(response.getFunctionCalls()); - validatePromptFeedback(response.getPromptFeedback()); - validateUsageMetadata(response.getUsageMetadata()); - } - - public void validateCandidates(List candidates) { - for (Candidate candidate : candidates) { - validateCitationMetadata(candidate.getCitationMetadata()); - FinishReason reason = candidate.getFinishReason(); - validateSafetyRatings(candidate.getSafetyRatings()); - validateCitationMetadata(candidate.getCitationMetadata()); - validateContent(candidate.getContent()); - } - } - - public void validateContent(Content content) { - String role = content.getRole(); - for (Part part : content.getParts()) { - if (part instanceof TextPart) { - String text = ((TextPart) part).getText(); - } else if (part instanceof ImagePart) { - Bitmap bitmap = ((ImagePart) part).getImage(); - } else if (part instanceof InlineDataPart) { - String mime = ((InlineDataPart) part).getMimeType(); - byte[] data = ((InlineDataPart) part).getInlineData(); - } else if (part instanceof FileDataPart) { - String mime = ((FileDataPart) part).getMimeType(); - String uri = ((FileDataPart) part).getUri(); - } - } - } - - public void validateCitationMetadata(CitationMetadata metadata) { - if (metadata != null) { - for (Citation citation : metadata.getCitations()) { - String uri = citation.getUri(); - String license = citation.getLicense(); - Calendar calendar = citation.getPublicationDate(); - int startIndex = citation.getStartIndex(); - int endIndex = citation.getEndIndex(); - Assert.assertTrue(startIndex <= endIndex); - } - } - } - - public void validateFunctionCalls(List parts) { - if (parts != null) { - for (FunctionCallPart part : parts) { - String functionName = part.getName(); - Map args = part.getArgs(); - Assert.assertFalse(functionName.isBlank()); - } - } - } - - public void validatePromptFeedback(PromptFeedback feedback) { - if (feedback != null) { - String message = feedback.getBlockReasonMessage(); - BlockReason reason = feedback.getBlockReason(); - validateSafetyRatings(feedback.getSafetyRatings()); - } - } - - public void validateSafetyRatings(List ratings) { - for (SafetyRating rating : ratings) { - Boolean blocked = rating.getBlocked(); - HarmCategory category = rating.getCategory(); - HarmProbability probability = rating.getProbability(); - float score = rating.getProbabilityScore(); - HarmSeverity severity = rating.getSeverity(); - Float severityScore = rating.getSeverityScore(); - if (severity != null) { - Assert.assertNotNull(severityScore); - } - } - } - - public void validateUsageMetadata(UsageMetadata metadata) { - if (metadata != null) { - int totalTokens = metadata.getTotalTokenCount(); - int promptTokenCount = metadata.getPromptTokenCount(); - for (ModalityTokenCount count : metadata.getPromptTokensDetails()) { - ContentModality modality = count.getModality(); - int tokenCount = count.getTokenCount(); - } - Integer candidatesTokenCount = metadata.getCandidatesTokenCount(); - for (ModalityTokenCount count : metadata.getCandidatesTokensDetails()) { - ContentModality modality = count.getModality(); - int tokenCount = count.getTokenCount(); - } - } - } - - private void testLiveFutures(LiveModelFutures futures) throws Exception { - LiveSessionFutures session = futures.connect().get(); - session - .receive() - .subscribe( - new Subscriber() { - @Override - public void onSubscribe(Subscription s) { - s.request(Long.MAX_VALUE); - } - - @Override - public void onNext(LiveServerMessage response) { - validateLiveContentResponse(response); - } - - @Override - public void onError(Throwable t) { - // Ignore - } - - @Override - public void onComplete() { - // Also ignore - } - }); - - session.send("Fake message"); - session.send(new Content.Builder().addText("Fake message").build()); - - byte[] bytes = new byte[] {(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE}; - session.sendMediaStream(List.of(new MediaData(bytes, "image/jxl"))); - - FunctionResponsePart functionResponse = - new FunctionResponsePart("myFunction", new JsonObject(Map.of())); - session.sendFunctionResponse(List.of(functionResponse, functionResponse)); - - session.startAudioConversation(part -> functionResponse); - session.startAudioConversation(); - session.stopAudioConversation(); - session.stopReceiving(); - session.close(); - } - - private void validateLiveContentResponse(LiveServerMessage message) { - if (message instanceof LiveServerContent) { - LiveServerContent content = (LiveServerContent) message; - validateContent(content.getContent()); - boolean complete = content.getGenerationComplete(); - boolean interrupted = content.getInterrupted(); - boolean turnComplete = content.getTurnComplete(); - } else if (message instanceof LiveServerSetupComplete) { - LiveServerSetupComplete setup = (LiveServerSetupComplete) message; - // No methods - } else if (message instanceof LiveServerToolCall) { - LiveServerToolCall call = (LiveServerToolCall) message; - validateFunctionCalls(call.getFunctionCalls()); - } else if (message instanceof LiveServerToolCallCancellation) { - LiveServerToolCallCancellation cancel = (LiveServerToolCallCancellation) message; - List functions = cancel.getFunctionIds(); - } - } -} diff --git a/firebase-vertexai/update_responses.sh b/firebase-vertexai/update_responses.sh deleted file mode 100755 index 7d6ea18e0ee..00000000000 --- a/firebase-vertexai/update_responses.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash - -# Copyright 2024 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# This script replaces mock response files for Vertex AI unit tests with a fresh -# clone of the shared repository of Vertex AI test data. - -RESPONSES_VERSION='v13.*' # The major version of mock responses to use -REPO_NAME="vertexai-sdk-test-data" -REPO_LINK="https://github.com/FirebaseExtended/$REPO_NAME.git" - -set -x - -cd "$(dirname "$0")/src/test/resources" || exit -rm -rf "$REPO_NAME" -git clone "$REPO_LINK" --quiet || exit -cd "$REPO_NAME" || exit - -# Find and checkout latest tag matching major version -TAG=$(git tag -l "$RESPONSES_VERSION" --sort=v:refname | tail -n1) -if [ -z "$TAG" ]; then - echo "Error: No tag matching '$RESPONSES_VERSION' found in $REPO_NAME" - exit -fi -git checkout "$TAG" --quiet diff --git a/plugins/src/test/kotlin/com/google/firebase/gradle/plugins/GenerateBomReleaseNotesTests.kt b/plugins/src/test/kotlin/com/google/firebase/gradle/plugins/GenerateBomReleaseNotesTests.kt index 182d7d0ffb2..299a99e0f14 100644 --- a/plugins/src/test/kotlin/com/google/firebase/gradle/plugins/GenerateBomReleaseNotesTests.kt +++ b/plugins/src/test/kotlin/com/google/firebase/gradle/plugins/GenerateBomReleaseNotesTests.kt @@ -166,11 +166,6 @@ class GenerateBomReleaseNotesTests : FunSpec() { artifactId = "firebase-analytics", version = "10.0.0", ), - ArtifactDependency( - groupId = "com.google.firebase", - artifactId = "firebase-vertexai", - version = "10.0.0", - ), ) val newDependencies = listOf( @@ -184,11 +179,6 @@ class GenerateBomReleaseNotesTests : FunSpec() { artifactId = "firebase-firestore", version = "10.0.0", ), - ArtifactDependency( - groupId = "com.google.firebase", - artifactId = "firebase-vertexai", - version = "11.0.0", - ), ) val oldBom = makeBom("1.0.0", oldDependencies) val newBom = makeBom("2.0.0", newDependencies) @@ -228,11 +218,6 @@ class GenerateBomReleaseNotesTests : FunSpec() { N/A 10.0.0 - - com.google.firebase:firebase-vertexai - 10.0.0 - 11.0.0 - diff --git a/plugins/src/test/resources/Bom/filled-bom.pom b/plugins/src/test/resources/Bom/filled-bom.pom index 77d347ac842..1a7229d5c49 100644 --- a/plugins/src/test/resources/Bom/filled-bom.pom +++ b/plugins/src/test/resources/Bom/filled-bom.pom @@ -103,11 +103,6 @@ firebase-crashlytics-ktx 19.3.0 - - com.google.firebase - firebase-vertexai - 16.0.2 - com.google.firebase firebase-inappmessaging diff --git a/plugins/src/test/resources/GMaven/group-index.xml b/plugins/src/test/resources/GMaven/group-index.xml index 08c5511d838..6a0492ee80b 100644 --- a/plugins/src/test/resources/GMaven/group-index.xml +++ b/plugins/src/test/resources/GMaven/group-index.xml @@ -109,7 +109,6 @@ - diff --git a/subprojects.cfg b/subprojects.cfg index e42fd66e518..c527c25b7a8 100644 --- a/subprojects.cfg +++ b/subprojects.cfg @@ -45,7 +45,6 @@ firebase-sessions firebase-sessions:benchmark firebase-sessions:test-app firebase-storage -firebase-vertexai protolite-well-known-types encoders