Skip to content

Commit 3a72c1d

Browse files
authored
fix(ci): Update Live Session integration tests (#15664)
1 parent 5d5b33f commit 3a72c1d

File tree

1 file changed

+23
-71
lines changed

1 file changed

+23
-71
lines changed

FirebaseAI/Tests/TestApp/Tests/Integration/LiveSessionTests.swift

Lines changed: 23 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,7 @@ struct LiveSessionTests {
4848
),
4949
]),
5050
]
51-
private let textConfig = LiveGenerationConfig(
52-
responseModalities: [.text]
53-
)
54-
private let audioConfig = LiveGenerationConfig(
51+
private let generationConfig = LiveGenerationConfig(
5552
responseModalities: [.audio],
5653
outputAudioTranscription: AudioTranscriptionConfig()
5754
)
@@ -76,8 +73,8 @@ struct LiveSessionTests {
7673
role: "system",
7774
parts: """
7875
When you receive a message, if the message is a single word, assume it's the first name of a \
79-
person, and call the getLastName tool to get the last name of said person. Only respond with \
80-
the last name.
76+
person, and call the getLastName tool to get the last name of said person. Once you get the \
77+
response, say the response.
8178
""".trimmingCharacters(in: .whitespacesAndNewlines)
8279
)
8380

@@ -95,7 +92,7 @@ struct LiveSessionTests {
9592
modelName: String) async throws {
9693
let model = FirebaseAI.componentInstance(config).liveModel(
9794
modelName: modelName,
98-
generationConfig: audioConfig,
95+
generationConfig: generationConfig,
9996
systemInstruction: SystemInstructions.helloGoodbye
10097
)
10198

@@ -119,15 +116,12 @@ struct LiveSessionTests {
119116
#expect(modelResponse == "goodbye")
120117
}
121118

122-
@Test(
123-
.disabled("Temporarily disabled"),
124-
.bug("https://github.com/firebase/firebase-ios-sdk/issues/15640"),
125-
arguments: arguments
126-
)
127-
func sendVideoRealtime_receiveText(_ config: InstanceConfig, modelName: String) async throws {
119+
@Test(arguments: arguments)
120+
func sendVideoRealtime_receiveAudioOutputTranscripts(_ config: InstanceConfig,
121+
modelName: String) async throws {
128122
let model = FirebaseAI.componentInstance(config).liveModel(
129123
modelName: modelName,
130-
generationConfig: textConfig,
124+
generationConfig: generationConfig,
131125
systemInstruction: SystemInstructions.animalInVideo
132126
)
133127

@@ -152,7 +146,7 @@ struct LiveSessionTests {
152146
await session.sendAudioRealtime(audioFile.data)
153147
await session.sendAudioRealtime(Data(repeating: 0, count: audioFile.data.count))
154148

155-
let text = try await session.collectNextTextResponse()
149+
let text = try await session.collectNextAudioOutputTranscript()
156150

157151
await session.close()
158152
let modelResponse = text
@@ -164,15 +158,11 @@ struct LiveSessionTests {
164158
#expect(["kitten", "cat", "kitty"].contains(modelResponse))
165159
}
166160

167-
@Test(
168-
.disabled("Temporarily disabled"),
169-
.bug("https://github.com/firebase/firebase-ios-sdk/issues/15640"),
170-
arguments: arguments
171-
)
161+
@Test(arguments: arguments)
172162
func realtime_functionCalling(_ config: InstanceConfig, modelName: String) async throws {
173163
let model = FirebaseAI.componentInstance(config).liveModel(
174164
modelName: modelName,
175-
generationConfig: textConfig,
165+
generationConfig: generationConfig,
176166
tools: tools,
177167
systemInstruction: SystemInstructions.lastNames
178168
)
@@ -200,11 +190,9 @@ struct LiveSessionTests {
200190
functionId: functionCall.functionId
201191
),
202192
])
203-
204-
var text = try await session.collectNextTextResponse()
193+
var text = try await session.collectNextAudioOutputTranscript()
205194
if text.isEmpty {
206-
// The model sometimes sends an empty text response first
207-
text = try await session.collectNextTextResponse()
195+
text = try await session.collectNextAudioOutputTranscript()
208196
}
209197

210198
await session.close()
@@ -217,8 +205,6 @@ struct LiveSessionTests {
217205
}
218206

219207
@Test(
220-
.disabled("Temporarily disabled"),
221-
.bug("https://github.com/firebase/firebase-ios-sdk/issues/15640"),
222208
arguments: arguments.filter {
223209
// TODO: (b/450982184) Remove when Vertex AI adds support for Function IDs and Cancellation
224210
switch $0.0.apiConfig.service {
@@ -233,7 +219,7 @@ struct LiveSessionTests {
233219
modelName: String) async throws {
234220
let model = FirebaseAI.componentInstance(config).liveModel(
235221
modelName: modelName,
236-
generationConfig: textConfig,
222+
generationConfig: generationConfig,
237223
tools: tools,
238224
systemInstruction: SystemInstructions.lastNames
239225
)
@@ -266,7 +252,7 @@ struct LiveSessionTests {
266252
func realtime_interruption(_ config: InstanceConfig, modelName: String) async throws {
267253
let model = FirebaseAI.componentInstance(config).liveModel(
268254
modelName: modelName,
269-
generationConfig: audioConfig
255+
generationConfig: generationConfig
270256
)
271257

272258
let audioFile = try #require(
@@ -295,23 +281,23 @@ struct LiveSessionTests {
295281
}
296282
}
297283

298-
@Test(
299-
.disabled("Temporarily disabled"),
300-
.bug("https://github.com/firebase/firebase-ios-sdk/issues/15640"),
301-
arguments: arguments
302-
)
284+
@Test(arguments: arguments)
303285
func incremental_works(_ config: InstanceConfig, modelName: String) async throws {
304286
let model = FirebaseAI.componentInstance(config).liveModel(
305287
modelName: modelName,
306-
generationConfig: textConfig,
288+
generationConfig: generationConfig,
307289
systemInstruction: SystemInstructions.yesOrNo
308290
)
309291

310292
let session = try await model.connect()
311293
await session.sendContent("Does five plus")
312294
await session.sendContent(" five equal ten?", turnComplete: true)
313295

314-
let text = try await session.collectNextTextResponse()
296+
var text = try await session.collectNextAudioOutputTranscript()
297+
if text.isEmpty {
298+
// The model sometimes sends an empty text response first
299+
text = try await session.collectNextAudioOutputTranscript()
300+
}
315301

316302
await session.close()
317303
let modelResponse = text
@@ -339,26 +325,6 @@ struct LiveSessionTests {
339325
}
340326

341327
private extension LiveSession {
342-
/// Collects the text that the model sends for the next turn.
343-
///
344-
/// Will listen for `LiveServerContent` messages from the model,
345-
/// incrementally keeping track of any `TextPart`s it sends. Once
346-
/// the model signals that its turn is complete, the function will return
347-
/// a string concatenated of all the `TextPart`s.
348-
func collectNextTextResponse() async throws -> String {
349-
var text = ""
350-
351-
for try await content in responsesOf(LiveServerContent.self) {
352-
text += content.modelTurn?.allText() ?? ""
353-
354-
if content.isTurnComplete {
355-
break
356-
}
357-
}
358-
359-
return text
360-
}
361-
362328
/// Collects the audio output transcripts that the model sends for the next turn.
363329
///
364330
/// Will listen for `LiveServerContent` messages from the model,
@@ -395,11 +361,7 @@ private extension LiveSession {
395361
case let .toolCall(toolCall):
396362
return toolCall
397363
case let .content(content):
398-
if let text = content.modelTurn?.allText() {
399-
error += text
400-
} else {
401-
error += content.outputAudioText()
402-
}
364+
error += content.outputAudioText()
403365

404366
if content.isTurnComplete {
405367
Issue.record("The model didn't send a tool call. Text received: \(error)")
@@ -464,16 +426,6 @@ private struct NoInterruptionError: Error,
464426
var description: String { "The model never sent an interrupted message." }
465427
}
466428

467-
private extension ModelContent {
468-
/// A collection of text from all parts.
469-
///
470-
/// If this doesn't contain any `TextPart`, then an empty
471-
/// string will be returned instead.
472-
func allText() -> String {
473-
parts.compactMap { ($0 as? TextPart)?.text }.joined()
474-
}
475-
}
476-
477429
extension LiveServerContent {
478430
/// Text of the output `LiveAudioTranscript`, or an empty string if it's missing.
479431
func outputAudioText() -> String {

0 commit comments

Comments
 (0)