Skip to content

Add developer api to bidi. #7196

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions firebase-ai/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Unreleased
* [feature] added support for Imagen Editing, including inpainting, outpainting, control, style
transfer, and subject references (#7075)
* [feature] **Preview:** Added support for bidirectional streaming in Gemini Developer Api

# 17.0.0
* [feature] Added support for configuring the "thinking" budget when using Gemini
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import com.google.firebase.ai.type.GenerativeBackend
import com.google.firebase.ai.type.GenerativeBackendEnum
import com.google.firebase.ai.type.ImagenGenerationConfig
import com.google.firebase.ai.type.ImagenSafetySettings
import com.google.firebase.ai.type.InvalidStateException
import com.google.firebase.ai.type.LiveGenerationConfig
import com.google.firebase.ai.type.PublicPreviewAPI
import com.google.firebase.ai.type.RequestOptions
Expand Down Expand Up @@ -124,6 +123,7 @@ internal constructor(
systemInstruction: Content? = null,
requestOptions: RequestOptions = RequestOptions(),
): LiveGenerativeModel {

if (!modelName.startsWith(GEMINI_MODEL_NAME_PREFIX)) {
Log.w(
TAG,
Expand All @@ -138,7 +138,7 @@ internal constructor(
GenerativeBackendEnum.VERTEX_AI ->
"projects/${firebaseApp.options.projectId}/locations/${backend.location}/publishers/google/models/${modelName}"
GenerativeBackendEnum.GOOGLE_AI ->
throw InvalidStateException("Live Model is not yet available on the Google AI backend")
"projects/${firebaseApp.options.projectId}/models/${modelName}"
},
firebaseApp.options.apiKey,
firebaseApp,
Expand All @@ -150,6 +150,7 @@ internal constructor(
requestOptions,
appCheckProvider.get(),
internalAuthProvider.get(),
backend
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.google.firebase.ai.common.APIController
import com.google.firebase.ai.common.AppCheckHeaderProvider
import com.google.firebase.ai.common.JSON
import com.google.firebase.ai.type.Content
import com.google.firebase.ai.type.GenerativeBackend
import com.google.firebase.ai.type.LiveClientSetupMessage
import com.google.firebase.ai.type.LiveGenerationConfig
import com.google.firebase.ai.type.LiveSession
Expand Down Expand Up @@ -54,7 +55,7 @@ internal constructor(
private val tools: List<Tool>? = null,
private val systemInstruction: Content? = null,
private val location: String,
private val controller: APIController
private val controller: APIController,
) {
internal constructor(
modelName: String,
Expand All @@ -68,6 +69,7 @@ internal constructor(
requestOptions: RequestOptions = RequestOptions(),
appCheckTokenProvider: InteropAppCheckTokenProvider? = null,
internalAuthProvider: InternalAuthProvider? = null,
generativeBackend: GenerativeBackend,
) : this(
modelName,
blockingDispatcher,
Expand All @@ -82,6 +84,7 @@ internal constructor(
"gl-kotlin/${KotlinVersion.CURRENT}-ai fire/${BuildConfig.VERSION_NAME}",
firebaseApp,
AppCheckHeaderProvider(TAG, appCheckTokenProvider, internalAuthProvider),
generativeBackend
),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import com.google.firebase.ai.type.CountTokensResponse
import com.google.firebase.ai.type.FinishReason
import com.google.firebase.ai.type.GRpcErrorResponse
import com.google.firebase.ai.type.GenerateContentResponse
import com.google.firebase.ai.type.GenerativeBackend
import com.google.firebase.ai.type.GenerativeBackendEnum
import com.google.firebase.ai.type.ImagenGenerationResponse
import com.google.firebase.ai.type.PublicPreviewAPI
import com.google.firebase.ai.type.RequestOptions
Expand Down Expand Up @@ -99,6 +101,7 @@ internal constructor(
private val appVersion: Int = 0,
private val googleAppId: String,
private val headerProvider: HeaderProvider?,
private val backend: GenerativeBackend? = null
) {

constructor(
Expand All @@ -108,6 +111,7 @@ internal constructor(
apiClient: String,
firebaseApp: FirebaseApp,
headerProvider: HeaderProvider? = null,
backend: GenerativeBackend? = null,
) : this(
key,
model,
Expand All @@ -117,7 +121,8 @@ internal constructor(
firebaseApp,
getVersionNumber(firebaseApp),
firebaseApp.options.applicationId,
headerProvider
headerProvider,
backend
)

private val model = fullModelName(model)
Expand Down Expand Up @@ -161,7 +166,13 @@ internal constructor(
}

private fun getBidiEndpoint(location: String): String =
"wss://firebasevertexai.googleapis.com/ws/google.firebase.vertexai.v1beta.LlmBidiService/BidiGenerateContent/locations/$location?key=$key"
when (backend?.backend) {
GenerativeBackendEnum.VERTEX_AI,
null ->
"wss://firebasevertexai.googleapis.com/ws/google.firebase.vertexai.v1beta.LlmBidiService/BidiGenerateContent/locations/$location?key=$key"
GenerativeBackendEnum.GOOGLE_AI ->
"wss://firebasevertexai.googleapis.com/ws/google.firebase.vertexai.v1beta.GenerativeService/BidiGenerateContent?key=$key"
}

suspend fun getWebSocketSession(location: String): ClientWebSocketSession =
client.webSocketSession(getBidiEndpoint(location)) { applyCommonHeaders() }
Expand Down