Skip to content

Commit 22dfdbf

Browse files
authored
Merge branch 'main' into dependabot/gradle/com.linkedin.dexmaker-dexmaker-mockito-2.28.6
2 parents ae12fdf + 1c862ec commit 22dfdbf

File tree

57 files changed

+843
-360
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+843
-360
lines changed

.github/workflows/ci_tests.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ jobs:
6464
- name: Add google-services.json
6565
env:
6666
INTEG_TESTS_GOOGLE_SERVICES: ${{ secrets.INTEG_TESTS_GOOGLE_SERVICES }}
67+
if: env.INTEG_TESTS_GOOGLE_SERVICES != '' && env.INTEG_TESTS_GOOGLE_SERVICES != 'null'
6768
run: |
6869
echo $INTEG_TESTS_GOOGLE_SERVICES | base64 -d > google-services.json
6970
@@ -129,6 +130,7 @@ jobs:
129130
- name: Add google-services.json
130131
env:
131132
INTEG_TESTS_GOOGLE_SERVICES: ${{ secrets.INTEG_TESTS_GOOGLE_SERVICES }}
133+
if: env.INTEG_TESTS_GOOGLE_SERVICES != '' && env.INTEG_TESTS_GOOGLE_SERVICES != 'null'
132134
run: |
133135
echo $INTEG_TESTS_GOOGLE_SERVICES | base64 -d > google-services.json
134136
- uses: google-github-actions/auth@71f986410dfbc7added4569d411d040a91dc6935 # v2.1.8

.github/workflows/post_release_cleanup.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ jobs:
2424
- name: Run post release cleanup task
2525
run: |
2626
./gradlew postReleaseCleanup
27+
./gradlew spotlessApply
2728
2829
- name: Create Pull Request
2930
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8

firebase-ai/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Unreleased
22

3+
- [feature] Added support for sending realtime audio and video in a `LiveSession`.
4+
- [changed] Removed redundant internal exception types. (#7475)
5+
6+
# 17.4.0
7+
38
- [changed] **Breaking Change**: Removed the `candidateCount` option from `LiveGenerationConfig`
49
- [changed] Added support for user interrupts for the `startAudioConversation` method in the
510
`LiveSession` class. (#7413)

firebase-ai/api.txt

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,18 @@ package com.google.firebase.ai.java {
145145
method public abstract org.reactivestreams.Publisher<com.google.firebase.ai.type.LiveServerMessage> receive();
146146
method public abstract com.google.common.util.concurrent.ListenableFuture<kotlin.Unit> send(com.google.firebase.ai.type.Content content);
147147
method public abstract com.google.common.util.concurrent.ListenableFuture<kotlin.Unit> send(String text);
148+
method public abstract com.google.common.util.concurrent.ListenableFuture<kotlin.Unit> sendAudioRealtime(com.google.firebase.ai.type.InlineData audio);
148149
method public abstract com.google.common.util.concurrent.ListenableFuture<kotlin.Unit> sendFunctionResponse(java.util.List<com.google.firebase.ai.type.FunctionResponsePart> functionList);
149-
method public abstract com.google.common.util.concurrent.ListenableFuture<kotlin.Unit> sendMediaStream(java.util.List<com.google.firebase.ai.type.MediaData> mediaChunks);
150+
method @Deprecated public abstract com.google.common.util.concurrent.ListenableFuture<kotlin.Unit> sendMediaStream(java.util.List<com.google.firebase.ai.type.MediaData> mediaChunks);
151+
method public abstract com.google.common.util.concurrent.ListenableFuture<kotlin.Unit> sendTextRealtime(String text);
152+
method public abstract com.google.common.util.concurrent.ListenableFuture<kotlin.Unit> sendVideoRealtime(com.google.firebase.ai.type.InlineData video);
150153
method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public abstract com.google.common.util.concurrent.ListenableFuture<kotlin.Unit> startAudioConversation();
151154
method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public abstract com.google.common.util.concurrent.ListenableFuture<kotlin.Unit> startAudioConversation(boolean enableInterruptions);
152155
method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public abstract com.google.common.util.concurrent.ListenableFuture<kotlin.Unit> startAudioConversation(kotlin.jvm.functions.Function1<? super com.google.firebase.ai.type.FunctionCallPart,com.google.firebase.ai.type.FunctionResponsePart>? functionCallHandler);
153156
method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public abstract com.google.common.util.concurrent.ListenableFuture<kotlin.Unit> startAudioConversation(kotlin.jvm.functions.Function1<? super com.google.firebase.ai.type.FunctionCallPart,com.google.firebase.ai.type.FunctionResponsePart>? functionCallHandler, boolean enableInterruptions);
157+
method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public abstract com.google.common.util.concurrent.ListenableFuture<kotlin.Unit> startAudioConversation(kotlin.jvm.functions.Function1<? super com.google.firebase.ai.type.FunctionCallPart,com.google.firebase.ai.type.FunctionResponsePart>? functionCallHandler, kotlin.jvm.functions.Function2<? super com.google.firebase.ai.type.Transcription?,? super com.google.firebase.ai.type.Transcription?,kotlin.Unit>? transcriptHandler, boolean enableInterruptions);
158+
method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public abstract com.google.common.util.concurrent.ListenableFuture<kotlin.Unit> startAudioConversation(kotlin.jvm.functions.Function2<? super com.google.firebase.ai.type.Transcription?,? super com.google.firebase.ai.type.Transcription?,kotlin.Unit>? transcriptHandler);
159+
method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public abstract com.google.common.util.concurrent.ListenableFuture<kotlin.Unit> startAudioConversation(kotlin.jvm.functions.Function2<? super com.google.firebase.ai.type.Transcription?,? super com.google.firebase.ai.type.Transcription?,kotlin.Unit>? transcriptHandler, boolean enableInterruptions);
154160
method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public abstract com.google.common.util.concurrent.ListenableFuture<kotlin.Unit> stopAudioConversation();
155161
method public abstract void stopReceiving();
156162
field public static final com.google.firebase.ai.java.LiveSessionFutures.Companion Companion;
@@ -171,6 +177,10 @@ package com.google.firebase.ai.type {
171177
ctor public AudioRecordInitializationFailedException(String message);
172178
}
173179

180+
public final class AudioTranscriptionConfig {
181+
ctor public AudioTranscriptionConfig();
182+
}
183+
174184
public final class BlockReason {
175185
method public String getName();
176186
method public int getOrdinal();
@@ -801,6 +811,14 @@ package com.google.firebase.ai.type {
801811
public static final class ImagenSubjectReferenceType.Companion {
802812
}
803813

814+
public final class InlineData {
815+
ctor public InlineData(byte[] data, String mimeType);
816+
method public byte[] getData();
817+
method public String getMimeType();
818+
property public final byte[] data;
819+
property public final String mimeType;
820+
}
821+
804822
public final class InlineDataPart implements com.google.firebase.ai.type.Part {
805823
ctor public InlineDataPart(byte[] inlineData, String mimeType);
806824
method public byte[] getInlineData();
@@ -828,15 +846,19 @@ package com.google.firebase.ai.type {
828846
ctor public LiveGenerationConfig.Builder();
829847
method public com.google.firebase.ai.type.LiveGenerationConfig build();
830848
method public com.google.firebase.ai.type.LiveGenerationConfig.Builder setFrequencyPenalty(Float? frequencyPenalty);
849+
method public com.google.firebase.ai.type.LiveGenerationConfig.Builder setInputAudioTranscription(com.google.firebase.ai.type.AudioTranscriptionConfig? config);
831850
method public com.google.firebase.ai.type.LiveGenerationConfig.Builder setMaxOutputTokens(Integer? maxOutputTokens);
851+
method public com.google.firebase.ai.type.LiveGenerationConfig.Builder setOutputAudioTranscription(com.google.firebase.ai.type.AudioTranscriptionConfig? config);
832852
method public com.google.firebase.ai.type.LiveGenerationConfig.Builder setPresencePenalty(Float? presencePenalty);
833853
method public com.google.firebase.ai.type.LiveGenerationConfig.Builder setResponseModality(com.google.firebase.ai.type.ResponseModality? responseModality);
834854
method public com.google.firebase.ai.type.LiveGenerationConfig.Builder setSpeechConfig(com.google.firebase.ai.type.SpeechConfig? speechConfig);
835855
method public com.google.firebase.ai.type.LiveGenerationConfig.Builder setTemperature(Float? temperature);
836856
method public com.google.firebase.ai.type.LiveGenerationConfig.Builder setTopK(Integer? topK);
837857
method public com.google.firebase.ai.type.LiveGenerationConfig.Builder setTopP(Float? topP);
838858
field public Float? frequencyPenalty;
859+
field public com.google.firebase.ai.type.AudioTranscriptionConfig? inputAudioTranscription;
839860
field public Integer? maxOutputTokens;
861+
field public com.google.firebase.ai.type.AudioTranscriptionConfig? outputAudioTranscription;
840862
field public Float? presencePenalty;
841863
field public com.google.firebase.ai.type.ResponseModality? responseModality;
842864
field public com.google.firebase.ai.type.SpeechConfig? speechConfig;
@@ -854,14 +876,18 @@ package com.google.firebase.ai.type {
854876
}
855877

856878
@com.google.firebase.ai.type.PublicPreviewAPI public final class LiveServerContent implements com.google.firebase.ai.type.LiveServerMessage {
857-
ctor public LiveServerContent(com.google.firebase.ai.type.Content? content, boolean interrupted, boolean turnComplete, boolean generationComplete);
879+
ctor @Deprecated public LiveServerContent(com.google.firebase.ai.type.Content? content, boolean interrupted, boolean turnComplete, boolean generationComplete, com.google.firebase.ai.type.Transcription? inputTranscription, com.google.firebase.ai.type.Transcription? outputTranscription);
858880
method public com.google.firebase.ai.type.Content? getContent();
859881
method public boolean getGenerationComplete();
882+
method public com.google.firebase.ai.type.Transcription? getInputTranscription();
860883
method public boolean getInterrupted();
884+
method public com.google.firebase.ai.type.Transcription? getOutputTranscription();
861885
method public boolean getTurnComplete();
862886
property public final com.google.firebase.ai.type.Content? content;
863887
property public final boolean generationComplete;
888+
property public final com.google.firebase.ai.type.Transcription? inputTranscription;
864889
property public final boolean interrupted;
890+
property public final com.google.firebase.ai.type.Transcription? outputTranscription;
865891
property public final boolean turnComplete;
866892
}
867893

@@ -891,20 +917,24 @@ package com.google.firebase.ai.type {
891917
method public kotlinx.coroutines.flow.Flow<com.google.firebase.ai.type.LiveServerMessage> receive();
892918
method public suspend Object? send(com.google.firebase.ai.type.Content content, kotlin.coroutines.Continuation<? super kotlin.Unit>);
893919
method public suspend Object? send(String text, kotlin.coroutines.Continuation<? super kotlin.Unit>);
920+
method public suspend Object? sendAudioRealtime(com.google.firebase.ai.type.InlineData audio, kotlin.coroutines.Continuation<? super kotlin.Unit>);
894921
method public suspend Object? sendFunctionResponse(java.util.List<com.google.firebase.ai.type.FunctionResponsePart> functionList, kotlin.coroutines.Continuation<? super kotlin.Unit>);
895-
method public suspend Object? sendMediaStream(java.util.List<com.google.firebase.ai.type.MediaData> mediaChunks, kotlin.coroutines.Continuation<? super kotlin.Unit>);
922+
method @Deprecated public suspend Object? sendMediaStream(java.util.List<com.google.firebase.ai.type.MediaData> mediaChunks, kotlin.coroutines.Continuation<? super kotlin.Unit>);
923+
method public suspend Object? sendTextRealtime(String text, kotlin.coroutines.Continuation<? super kotlin.Unit>);
924+
method public suspend Object? sendVideoRealtime(com.google.firebase.ai.type.InlineData video, kotlin.coroutines.Continuation<? super kotlin.Unit>);
896925
method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public suspend Object? startAudioConversation(kotlin.jvm.functions.Function1<? super com.google.firebase.ai.type.FunctionCallPart,com.google.firebase.ai.type.FunctionResponsePart>? functionCallHandler = null, boolean enableInterruptions = false, kotlin.coroutines.Continuation<? super kotlin.Unit>);
897926
method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public suspend Object? startAudioConversation(kotlin.jvm.functions.Function1<? super com.google.firebase.ai.type.FunctionCallPart,com.google.firebase.ai.type.FunctionResponsePart>? functionCallHandler = null, kotlin.coroutines.Continuation<? super kotlin.Unit>);
927+
method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public suspend Object? startAudioConversation(kotlin.jvm.functions.Function1<? super com.google.firebase.ai.type.FunctionCallPart,com.google.firebase.ai.type.FunctionResponsePart>? functionCallHandler = null, kotlin.jvm.functions.Function2<? super com.google.firebase.ai.type.Transcription?,? super com.google.firebase.ai.type.Transcription?,kotlin.Unit>? transcriptHandler = null, boolean enableInterruptions = false, kotlin.coroutines.Continuation<? super kotlin.Unit>);
898928
method public void stopAudioConversation();
899929
method public void stopReceiving();
900930
}
901931

902-
@com.google.firebase.ai.type.PublicPreviewAPI public final class MediaData {
903-
ctor public MediaData(byte[] data, String mimeType);
904-
method public byte[] getData();
905-
method public String getMimeType();
906-
property public final byte[] data;
907-
property public final String mimeType;
932+
@Deprecated @com.google.firebase.ai.type.PublicPreviewAPI public final class MediaData {
933+
ctor @Deprecated public MediaData(byte[] data, String mimeType);
934+
method @Deprecated public byte[] getData();
935+
method @Deprecated public String getMimeType();
936+
property @Deprecated public final byte[] data;
937+
property @Deprecated public final String mimeType;
908938
}
909939

910940
public final class ModalityTokenCount {
@@ -1221,6 +1251,11 @@ package com.google.firebase.ai.type {
12211251
ctor public ToolConfig(com.google.firebase.ai.type.FunctionCallingConfig? functionCallingConfig);
12221252
}
12231253

1254+
public final class Transcription {
1255+
method public String? getText();
1256+
property public final String? text;
1257+
}
1258+
12241259
public final class UnknownException extends com.google.firebase.ai.type.FirebaseAIException {
12251260
}
12261261

firebase-ai/gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
version=17.4.0
16-
latestReleasedVersion=17.3.0
15+
version=17.5.0
16+
latestReleasedVersion=17.4.0

firebase-ai/src/main/kotlin/com/google/firebase/ai/ImagenModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ package com.google.firebase.ai
1919
import com.google.firebase.FirebaseApp
2020
import com.google.firebase.ai.common.APIController
2121
import com.google.firebase.ai.common.AppCheckHeaderProvider
22-
import com.google.firebase.ai.common.ContentBlockedException
2322
import com.google.firebase.ai.common.GenerateImageRequest
23+
import com.google.firebase.ai.type.ContentBlockedException
2424
import com.google.firebase.ai.type.Dimensions
2525
import com.google.firebase.ai.type.FirebaseAIException
2626
import com.google.firebase.ai.type.ImagenEditMode

firebase-ai/src/main/kotlin/com/google/firebase/ai/LiveGenerativeModel.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,9 @@ internal constructor(
111111
modelName,
112112
config?.toInternal(),
113113
tools?.map { it.toInternal() },
114-
systemInstruction?.toInternal()
114+
systemInstruction?.toInternal(),
115+
config?.inputAudioTranscription?.toInternal(),
116+
config?.outputAudioTranscription?.toInternal()
115117
)
116118
.toInternal()
117119
val data: String = Json.encodeToString(clientMessage)
@@ -135,7 +137,7 @@ internal constructor(
135137
} catch (e: ClosedReceiveChannelException) {
136138
val reason = webSession?.closeReason?.await()
137139
val message =
138-
"Channel was closed by the server.${if(reason!=null) " Details: ${reason.message}" else "" }"
140+
"Channel was closed by the server.${if (reason != null) " Details: ${reason.message}" else ""}"
139141
throw ServiceConnectionHandshakeFailedException(message, e)
140142
}
141143
}

firebase-ai/src/main/kotlin/com/google/firebase/ai/common/APIController.kt

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,26 @@ import com.google.firebase.Firebase
2121
import com.google.firebase.FirebaseApp
2222
import com.google.firebase.ai.common.util.decodeToFlow
2323
import com.google.firebase.ai.common.util.fullModelName
24+
import com.google.firebase.ai.type.APINotConfiguredException
2425
import com.google.firebase.ai.type.CountTokensResponse
2526
import com.google.firebase.ai.type.FinishReason
27+
import com.google.firebase.ai.type.FirebaseAIException
2628
import com.google.firebase.ai.type.GRpcErrorResponse
2729
import com.google.firebase.ai.type.GenerateContentResponse
2830
import com.google.firebase.ai.type.GenerativeBackend
2931
import com.google.firebase.ai.type.GenerativeBackendEnum
3032
import com.google.firebase.ai.type.ImagenGenerationResponse
33+
import com.google.firebase.ai.type.InvalidAPIKeyException
34+
import com.google.firebase.ai.type.PromptBlockedException
3135
import com.google.firebase.ai.type.PublicPreviewAPI
36+
import com.google.firebase.ai.type.QuotaExceededException
3237
import com.google.firebase.ai.type.RequestOptions
3338
import com.google.firebase.ai.type.Response
39+
import com.google.firebase.ai.type.ResponseStoppedException
40+
import com.google.firebase.ai.type.SerializationException
41+
import com.google.firebase.ai.type.ServerException
42+
import com.google.firebase.ai.type.ServiceDisabledException
43+
import com.google.firebase.ai.type.UnsupportedUserLocationException
3444
import com.google.firebase.options
3545
import io.ktor.client.HttpClient
3646
import io.ktor.client.call.body
@@ -67,6 +77,7 @@ import kotlinx.coroutines.flow.map
6777
import kotlinx.coroutines.launch
6878
import kotlinx.coroutines.withTimeout
6979
import kotlinx.serialization.ExperimentalSerializationApi
80+
import kotlinx.serialization.json.ClassDiscriminatorMode
7081
import kotlinx.serialization.json.Json
7182

7283
@OptIn(ExperimentalSerializationApi::class)
@@ -75,6 +86,7 @@ internal val JSON = Json {
7586
prettyPrint = false
7687
isLenient = true
7788
explicitNulls = false
89+
classDiscriminatorMode = ClassDiscriminatorMode.NONE
7890
}
7991

8092
/**
@@ -149,7 +161,7 @@ internal constructor(
149161
.body<GenerateContentResponse.Internal>()
150162
.validate()
151163
} catch (e: Throwable) {
152-
throw FirebaseCommonAIException.from(e)
164+
throw FirebaseAIException.from(e)
153165
}
154166

155167
suspend fun generateImage(request: GenerateImageRequest): ImagenGenerationResponse.Internal =
@@ -162,7 +174,7 @@ internal constructor(
162174
.also { validateResponse(it) }
163175
.body<ImagenGenerationResponse.Internal>()
164176
} catch (e: Throwable) {
165-
throw FirebaseCommonAIException.from(e)
177+
throw FirebaseAIException.from(e)
166178
}
167179

168180
private fun getBidiEndpoint(location: String): String =
@@ -187,7 +199,7 @@ internal constructor(
187199
applyCommonConfiguration(request)
188200
}
189201
.map { it.validate() }
190-
.catch { throw FirebaseCommonAIException.from(it) }
202+
.catch { throw FirebaseAIException.from(it) }
191203

192204
suspend fun countTokens(request: CountTokensRequest): CountTokensResponse.Internal =
193205
try {
@@ -199,7 +211,7 @@ internal constructor(
199211
.also { validateResponse(it) }
200212
.body()
201213
} catch (e: Throwable) {
202-
throw FirebaseCommonAIException.from(e)
214+
throw FirebaseAIException.from(e)
203215
}
204216

205217
private fun HttpRequestBuilder.applyCommonHeaders() {
@@ -372,9 +384,9 @@ private fun GenerateContentResponse.Internal.validate() = apply {
372384
if ((candidates?.isEmpty() != false) && promptFeedback == null) {
373385
throw SerializationException("Error deserializing response, found no valid fields")
374386
}
375-
promptFeedback?.blockReason?.let { throw PromptBlockedException(this) }
387+
promptFeedback?.blockReason?.let { throw PromptBlockedException(this.toPublic(), null, null) }
376388
candidates
377389
?.mapNotNull { it.finishReason }
378390
?.firstOrNull { it != FinishReason.Internal.STOP }
379-
?.let { throw ResponseStoppedException(this) }
391+
?.let { throw ResponseStoppedException(this.toPublic()) }
380392
}

0 commit comments

Comments
 (0)