diff --git a/firebase-ai/api.txt b/firebase-ai/api.txt index a390a14147e..e361a25423f 100644 --- a/firebase-ai/api.txt +++ b/firebase-ai/api.txt @@ -165,6 +165,23 @@ package com.google.firebase.ai.type { public final class APINotConfiguredException extends com.google.firebase.ai.type.FirebaseAIException { } + public final class AspectRatio { + field public static final com.google.firebase.ai.type.AspectRatio.Companion Companion; + field public static final com.google.firebase.ai.type.AspectRatio LANDSCAPE_16x9; + field public static final com.google.firebase.ai.type.AspectRatio LANDSCAPE_21x9; + field public static final com.google.firebase.ai.type.AspectRatio LANDSCAPE_3x2; + field public static final com.google.firebase.ai.type.AspectRatio LANDSCAPE_4x3; + field public static final com.google.firebase.ai.type.AspectRatio LANDSCAPE_5x4; + field public static final com.google.firebase.ai.type.AspectRatio PORTRAIT_2x3; + field public static final com.google.firebase.ai.type.AspectRatio PORTRAIT_3x4; + field public static final com.google.firebase.ai.type.AspectRatio PORTRAIT_4x5; + field public static final com.google.firebase.ai.type.AspectRatio PORTRAIT_9x16; + field public static final com.google.firebase.ai.type.AspectRatio SQUARE_1x1; + } + + public static final class AspectRatio.Companion { + } + public final class AudioRecordInitializationFailedException extends com.google.firebase.ai.type.FirebaseAIException { ctor public AudioRecordInitializationFailedException(String message); } @@ -323,8 +340,13 @@ package com.google.firebase.ai.type { property public final int ordinal; field public static final com.google.firebase.ai.type.FinishReason BLOCKLIST; field public static final com.google.firebase.ai.type.FinishReason.Companion Companion; + field public static final com.google.firebase.ai.type.FinishReason IMAGE_OTHER; + field public static final com.google.firebase.ai.type.FinishReason IMAGE_PROHIBITED_CONTENT; + field public static final com.google.firebase.ai.type.FinishReason IMAGE_RECITATION; + field public static final com.google.firebase.ai.type.FinishReason IMAGE_SAFETY; field public static final com.google.firebase.ai.type.FinishReason MALFORMED_FUNCTION_CALL; field public static final com.google.firebase.ai.type.FinishReason MAX_TOKENS; + field public static final com.google.firebase.ai.type.FinishReason NO_IMAGE; field public static final com.google.firebase.ai.type.FinishReason OTHER; field public static final com.google.firebase.ai.type.FinishReason PROHIBITED_CONTENT; field public static final com.google.firebase.ai.type.FinishReason RECITATION; @@ -412,6 +434,7 @@ package com.google.firebase.ai.type { method public com.google.firebase.ai.type.GenerationConfig build(); method public com.google.firebase.ai.type.GenerationConfig.Builder setCandidateCount(Integer? candidateCount); method public com.google.firebase.ai.type.GenerationConfig.Builder setFrequencyPenalty(Float? frequencyPenalty); + method public com.google.firebase.ai.type.GenerationConfig.Builder setImageConfig(com.google.firebase.ai.type.ImageConfig? imageConfig); method public com.google.firebase.ai.type.GenerationConfig.Builder setMaxOutputTokens(Integer? maxOutputTokens); method public com.google.firebase.ai.type.GenerationConfig.Builder setPresencePenalty(Float? presencePenalty); method public com.google.firebase.ai.type.GenerationConfig.Builder setResponseMimeType(String? responseMimeType); @@ -424,6 +447,7 @@ package com.google.firebase.ai.type { method public com.google.firebase.ai.type.GenerationConfig.Builder setTopP(Float? topP); field public Integer? candidateCount; field public Float? frequencyPenalty; + field public com.google.firebase.ai.type.ImageConfig? imageConfig; field public Integer? maxOutputTokens; field public Float? presencePenalty; field public String? responseMimeType; @@ -571,6 +595,19 @@ package com.google.firebase.ai.type { public static final class HarmSeverity.Companion { } + public final class ImageConfig { + } + + public static final class ImageConfig.Builder { + ctor public ImageConfig.Builder(); + method public com.google.firebase.ai.type.ImageConfig build(); + method public com.google.firebase.ai.type.ImageConfig.Builder setAspectRatio(com.google.firebase.ai.type.AspectRatio? aspectRatio); + } + + public final class ImageConfigKt { + method public static com.google.firebase.ai.type.ImageConfig imageConfig(kotlin.jvm.functions.Function1 init); + } + public final class ImagePart implements com.google.firebase.ai.type.Part { ctor public ImagePart(android.graphics.Bitmap image); method public android.graphics.Bitmap getImage(); diff --git a/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/AspectRatio.kt b/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/AspectRatio.kt new file mode 100644 index 00000000000..5b252bbc6d2 --- /dev/null +++ b/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/AspectRatio.kt @@ -0,0 +1,33 @@ +/* + * 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.ai.type + +/** Represents the aspect ratio that the generated image should conform to. */ +public class AspectRatio private constructor(internal val internalVal: String) { + public companion object { + @JvmField public val SQUARE_1x1: AspectRatio = AspectRatio("1:1") + @JvmField public val PORTRAIT_2x3: AspectRatio = AspectRatio("2:3") + @JvmField public val LANDSCAPE_3x2: AspectRatio = AspectRatio("3:2") + @JvmField public val PORTRAIT_3x4: AspectRatio = AspectRatio("3:4") + @JvmField public val LANDSCAPE_4x3: AspectRatio = AspectRatio("4:3") + @JvmField public val PORTRAIT_4x5: AspectRatio = AspectRatio("4:5") + @JvmField public val LANDSCAPE_5x4: AspectRatio = AspectRatio("5:4") + @JvmField public val PORTRAIT_9x16: AspectRatio = AspectRatio("9:16") + @JvmField public val LANDSCAPE_16x9: AspectRatio = AspectRatio("16:9") + @JvmField public val LANDSCAPE_21x9: AspectRatio = AspectRatio("21:9") + } +} diff --git a/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Candidate.kt b/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Candidate.kt index b7671aa0ccb..c43c6adc979 100644 --- a/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Candidate.kt +++ b/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Candidate.kt @@ -237,7 +237,12 @@ public class FinishReason private constructor(public val name: String, public va BLOCKLIST, PROHIBITED_CONTENT, SPII, - MALFORMED_FUNCTION_CALL; + MALFORMED_FUNCTION_CALL, + IMAGE_SAFETY, + IMAGE_PROHIBITED_CONTENT, + IMAGE_RECITATION, + IMAGE_OTHER, + NO_IMAGE; internal object Serializer : KSerializer by FirstOrdinalSerializer(Internal::class) @@ -252,6 +257,11 @@ public class FinishReason private constructor(public val name: String, public va PROHIBITED_CONTENT -> FinishReason.PROHIBITED_CONTENT SPII -> FinishReason.SPII MALFORMED_FUNCTION_CALL -> FinishReason.MALFORMED_FUNCTION_CALL + IMAGE_SAFETY -> FinishReason.IMAGE_SAFETY + IMAGE_PROHIBITED_CONTENT -> FinishReason.IMAGE_PROHIBITED_CONTENT + IMAGE_RECITATION -> FinishReason.IMAGE_RECITATION + IMAGE_OTHER -> FinishReason.IMAGE_OTHER + NO_IMAGE -> FinishReason.NO_IMAGE else -> FinishReason.UNKNOWN } } @@ -291,6 +301,22 @@ public class FinishReason private constructor(public val name: String, public va /** The function call generated by the model is invalid. */ @JvmField public val MALFORMED_FUNCTION_CALL: FinishReason = FinishReason("MALFORMED_FUNCTION_CALL", 9) + + /** Token generation stopped because generated images has safety violations. */ + @JvmField public val IMAGE_SAFETY: FinishReason = FinishReason("IMAGE_SAFETY", 10) + + /** Image generation stopped because generated images has other prohibited content. */ + @JvmField + public val IMAGE_PROHIBITED_CONTENT: FinishReason = FinishReason("IMAGE_PROHIBITED_CONTENT", 11) + + /** Image generation stopped due to recitation. */ + @JvmField public val IMAGE_RECITATION: FinishReason = FinishReason("IMAGE_RECITATION", 12) + + /** Image generation stopped because of other miscellaneous issue. */ + @JvmField public val IMAGE_OTHER: FinishReason = FinishReason("IMAGE_OTHER", 13) + + /** The model was expected to generate an image, but none was generated. */ + @JvmField public val NO_IMAGE: FinishReason = FinishReason("NO_IMAGE", 14) } } diff --git a/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/GenerationConfig.kt b/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/GenerationConfig.kt index 7bab7fdf806..77d2752a8b5 100644 --- a/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/GenerationConfig.kt +++ b/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/GenerationConfig.kt @@ -92,6 +92,7 @@ private constructor( internal val responseSchema: Schema?, internal val responseModalities: List?, internal val thinkingConfig: ThinkingConfig?, + internal val imageConfig: ImageConfig?, ) { /** @@ -137,6 +138,7 @@ private constructor( @JvmField public var responseSchema: Schema? = null @JvmField public var responseModalities: List? = null @JvmField public var thinkingConfig: ThinkingConfig? = null + @JvmField public var imageConfig: ImageConfig? = null public fun setTemperature(temperature: Float?): Builder = apply { this.temperature = temperature @@ -170,6 +172,9 @@ private constructor( public fun setThinkingConfig(thinkingConfig: ThinkingConfig?): Builder = apply { this.thinkingConfig = thinkingConfig } + public fun setImageConfig(imageConfig: ImageConfig?): Builder = apply { + this.imageConfig = imageConfig + } /** Create a new [GenerationConfig] with the attached arguments. */ public fun build(): GenerationConfig = @@ -185,7 +190,8 @@ private constructor( responseMimeType = responseMimeType, responseSchema = responseSchema, responseModalities = responseModalities, - thinkingConfig = thinkingConfig + thinkingConfig = thinkingConfig, + imageConfig = imageConfig ) } @@ -202,7 +208,8 @@ private constructor( responseMimeType = responseMimeType, responseSchema = responseSchema?.toInternal(), responseModalities = responseModalities?.map { it.toInternal() }, - thinkingConfig = thinkingConfig?.toInternal() + thinkingConfig = thinkingConfig?.toInternal(), + imageConfig = imageConfig?.toInternal() ) @Serializable @@ -218,7 +225,8 @@ private constructor( @SerialName("frequency_penalty") val frequencyPenalty: Float? = null, @SerialName("response_schema") val responseSchema: Schema.Internal? = null, @SerialName("response_modalities") val responseModalities: List? = null, - @SerialName("thinking_config") val thinkingConfig: ThinkingConfig.Internal? = null + @SerialName("thinking_config") val thinkingConfig: ThinkingConfig.Internal? = null, + @SerialName("image_config") val imageConfig: ImageConfig.Internal? = null ) public companion object { diff --git a/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/ImageConfig.kt b/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/ImageConfig.kt new file mode 100644 index 00000000000..c6f487688a3 --- /dev/null +++ b/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/ImageConfig.kt @@ -0,0 +1,69 @@ +/* + * 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.ai.type + +import kotlinx.serialization.Serializable + +/** + * Configuration parameters to use for image generation. + * + * @property aspectRatio The aspect ratio of the generated image. + */ +public class ImageConfig internal constructor(internal val aspectRatio: AspectRatio?) { + + /** + * Builder for creating an [ImageConfig]. + * + * Mainly intended for Java interop. Kotlin consumers should use [imageConfig] for a more + * idiomatic experience. + * + * @property aspectRatio See [ImageConfig.aspectRatio]. + * @see [imageConfig] + */ + public class Builder { + @JvmField + @set:JvmSynthetic // hide void setter from Java + public var aspectRatio: AspectRatio? = null + + public fun setAspectRatio(aspectRatio: AspectRatio?): Builder = apply { + this.aspectRatio = aspectRatio + } + + /** Create a new [ImageConfig] with the attached arguments. */ + public fun build(): ImageConfig = ImageConfig(aspectRatio = aspectRatio) + } + + internal fun toInternal() = Internal(aspectRatio = aspectRatio?.internalVal) + + @Serializable internal data class Internal(val aspectRatio: String?) +} + +/** + * Helper method to construct an [ImageConfig] in a DSL-like manner. + * + * Example Usage: + * ``` + * imageConfig { + * aspectRatio = AspectRatio.LANDSCAPE_16x9 + * } + * ``` + */ +public fun imageConfig(init: ImageConfig.Builder.() -> Unit): ImageConfig { + val builder = ImageConfig.Builder() + builder.init() + return builder.build() +} diff --git a/firebase-ai/src/test/java/com/google/firebase/ai/SerializationTests.kt b/firebase-ai/src/test/java/com/google/firebase/ai/SerializationTests.kt index 177fde19a8b..df7d7e7de6f 100644 --- a/firebase-ai/src/test/java/com/google/firebase/ai/SerializationTests.kt +++ b/firebase-ai/src/test/java/com/google/firebase/ai/SerializationTests.kt @@ -148,7 +148,12 @@ internal class SerializationTests { "BLOCKLIST", "PROHIBITED_CONTENT", "SPII", - "MALFORMED_FUNCTION_CALL" + "MALFORMED_FUNCTION_CALL", + "IMAGE_SAFETY", + "IMAGE_PROHIBITED_CONTENT", + "IMAGE_RECITATION", + "IMAGE_OTHER", + "NO_IMAGE" ] }, "safetyRatings": {