Skip to content

Commit 8de99bb

Browse files
author
David Motsonashvili
committed
add overloaded api
1 parent 33ccc69 commit 8de99bb

File tree

3 files changed

+40
-5
lines changed

3 files changed

+40
-5
lines changed

firebase-ai/api.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,7 @@ package com.google.firebase.ai.type {
921921
method public suspend Object? sendVideoRealtime(com.google.firebase.ai.type.InlineData video, kotlin.coroutines.Continuation<? super kotlin.Unit>);
922922
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>);
923923
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>);
924+
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.Function1<? super com.google.firebase.ai.type.LiveServerMessage,kotlin.Unit>? transcriptHandler = null, boolean enableInterruptions = false, kotlin.coroutines.Continuation<? super kotlin.Unit>);
924925
method public void stopAudioConversation();
925926
method public void stopReceiving();
926927
}

firebase-ai/src/main/kotlin/com/google/firebase/ai/type/LiveServerMessage.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,17 @@ public class LiveServerContent(
108108
@Serializable
109109
internal data class InternalWrapper(val serverContent: Internal) : InternalLiveServerMessage {
110110
@OptIn(ExperimentalSerializationApi::class)
111-
override fun toPublic() =
112-
LiveServerContent(
111+
override fun toPublic(): LiveServerContent {
112+
// WhenMajor(Revisit the decision to make these have default values)
113+
return LiveServerContent(
113114
serverContent.modelTurn?.toPublic(),
114115
serverContent.interrupted ?: false,
115116
serverContent.turnComplete ?: false,
116117
serverContent.generationComplete ?: false,
117118
serverContent.inputTranscription?.toPublic(),
118119
serverContent.outputTranscription?.toPublic()
119120
)
121+
}
120122
}
121123
}
122124

firebase-ai/src/main/kotlin/com/google/firebase/ai/type/LiveSession.kt

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import com.google.firebase.ai.common.JSON
2828
import com.google.firebase.ai.common.util.CancelledCoroutineScope
2929
import com.google.firebase.ai.common.util.accumulateUntil
3030
import com.google.firebase.ai.common.util.childJob
31-
import com.google.firebase.ai.type.MediaData.Internal
3231
import com.google.firebase.annotations.concurrent.Blocking
3332
import io.ktor.client.plugins.websocket.DefaultClientWebSocketSession
3433
import io.ktor.websocket.Frame
@@ -120,6 +119,35 @@ internal constructor(
120119
functionCallHandler: ((FunctionCallPart) -> FunctionResponsePart)? = null,
121120
enableInterruptions: Boolean = false,
122121
) {
122+
startAudioConversation(
123+
functionCallHandler = functionCallHandler,
124+
enableInterruptions = enableInterruptions
125+
)
126+
}
127+
128+
/**
129+
* Starts an audio conversation with the model, which can only be stopped using
130+
* [stopAudioConversation] or [close].
131+
*
132+
* @param functionCallHandler A callback function that is invoked whenever the model receives a
133+
* function call. The [FunctionResponsePart] that the callback function returns will be
134+
* automatically sent to the model.
135+
*
136+
* @param transcriptHandler A callback function that is invoked whenever the model receives a
137+
* transcript.
138+
*
139+
* @param enableInterruptions If enabled, allows the user to speak over or interrupt the model's
140+
* ongoing reply.
141+
*
142+
* **WARNING**: The user interruption feature relies on device-specific support, and may not be
143+
* consistently available.
144+
*/
145+
@RequiresPermission(RECORD_AUDIO)
146+
public suspend fun startAudioConversation(
147+
functionCallHandler: ((FunctionCallPart) -> FunctionResponsePart)? = null,
148+
transcriptHandler: ((LiveServerMessage) -> Unit)? = null,
149+
enableInterruptions: Boolean = false,
150+
) {
123151

124152
val context = firebaseApp.applicationContext
125153
if (
@@ -142,7 +170,7 @@ internal constructor(
142170
audioHelper = AudioHelper.build()
143171

144172
recordUserAudio()
145-
processModelResponses(functionCallHandler)
173+
processModelResponses(functionCallHandler, transcriptHandler)
146174
listenForModelPlayback(enableInterruptions)
147175
}
148176
}
@@ -390,7 +418,8 @@ internal constructor(
390418
* function call.
391419
*/
392420
private fun processModelResponses(
393-
functionCallHandler: ((FunctionCallPart) -> FunctionResponsePart)?
421+
functionCallHandler: ((FunctionCallPart) -> FunctionResponsePart)?,
422+
transcriptHandler: ((LiveServerMessage) -> Unit)?
394423
) {
395424
receive()
396425
.onEach {
@@ -419,6 +448,9 @@ internal constructor(
419448
)
420449
}
421450
is LiveServerContent -> {
451+
if (it.outputTranscription != null || it.inputTranscription != null) {
452+
transcriptHandler?.invoke(it)
453+
}
422454
if (it.interrupted) {
423455
playBackQueue.clear()
424456
} else {

0 commit comments

Comments
 (0)