14
14
import 'dart:io' ;
15
15
import 'dart:typed_data' ;
16
16
import 'dart:async' ;
17
-
17
+ import 'package:path_provider/path_provider.dart' ;
18
18
import 'package:flutter/material.dart' ;
19
19
import 'package:firebase_vertexai/firebase_vertexai.dart' ;
20
20
import '../widgets/message_widget.dart' ;
@@ -55,6 +55,14 @@ class _BidiPageState extends State<BidiPage> {
55
55
);
56
56
}
57
57
58
+ @override
59
+ void dispose () {
60
+ if (_session_opening) {
61
+ _session.close ();
62
+ }
63
+ super .dispose ();
64
+ }
65
+
58
66
@override
59
67
Widget build (BuildContext context) {
60
68
return Scaffold (
@@ -135,7 +143,8 @@ class _BidiPageState extends State<BidiPage> {
135
143
if (! _loading)
136
144
IconButton (
137
145
onPressed: () async {
138
- await _sendTextPrompt (textPrompt: _textController.text);
146
+ await _sendPremadeAudioPayload ();
147
+ // await _sendTextPrompt(textPrompt: _textController.text);
139
148
},
140
149
icon: Icon (
141
150
Icons .send,
@@ -144,6 +153,15 @@ class _BidiPageState extends State<BidiPage> {
144
153
)
145
154
else
146
155
const CircularProgressIndicator (),
156
+ IconButton (
157
+ onPressed: () async {
158
+ await _checkWsStatus ();
159
+ },
160
+ icon: Icon (
161
+ Icons .check,
162
+ color: Theme .of (context).colorScheme.primary,
163
+ ),
164
+ )
147
165
],
148
166
),
149
167
),
@@ -178,6 +196,7 @@ class _BidiPageState extends State<BidiPage> {
178
196
if (! _session_opening) {
179
197
_session = await widget.model.connect (model: modelName, config: config);
180
198
_session_opening = true ;
199
+ unawaited (_handle_response ());
181
200
} else {
182
201
await _session! .close ();
183
202
await _audioManager.stop ();
@@ -219,15 +238,14 @@ class _BidiPageState extends State<BidiPage> {
219
238
220
239
Future <void > _stopRecording () async {
221
240
await _audioRecorder.stopRecording ();
222
- var audioPrompt = await _audioRecorder.getAudioBytes (fromFile : true );
223
- // await _streamAudioChunks(audioPrompt, 'audio/pcm');
224
- //await _sendAudioPrompt(audioPrompt);
225
- await _sendAudioRealtime (audioPrompt);
241
+ var audioPrompt = await _audioRecorder.getAudioBytes ();
242
+ await _streamAudioChunks (audioPrompt, 'audio/pcm' );
243
+ // await _sendAudioPrompt(audioPrompt);
244
+ // await _sendAudioRealtime(audioPrompt);
226
245
}
227
246
228
247
List <Uint8List > _splitIntoChunks (Uint8List audioData, int chunkSize) {
229
248
final chunks = < Uint8List > [];
230
- const chunkSize = 1024 ;
231
249
232
250
for (var i = 0 ; i < audioData.length; i += chunkSize) {
233
251
final end =
@@ -246,8 +264,7 @@ class _BidiPageState extends State<BidiPage> {
246
264
final streamController = StreamController <InlineDataPart >();
247
265
for (var chunk in chunks) {
248
266
if (identical (chunk, chunks.last)) {
249
- final lastData =
250
- InlineDataPart ('audio/pcm' , chunk, willContinue: false );
267
+ final lastData = InlineDataPart ('audio/pcm' , chunk, willContinue: true );
251
268
streamController.add (lastData);
252
269
} else {
253
270
final data = InlineDataPart ('audio/pcm' , chunk, willContinue: true );
@@ -262,8 +279,8 @@ class _BidiPageState extends State<BidiPage> {
262
279
// Process the message received from the server
263
280
print ('Received message: $message ' );
264
281
}
265
- print ('Stream all audio chunk to server' );
266
- await _handle_response_audio ();
282
+ print ('Send all audio chunk to server' );
283
+ _session. printWsStatus ();
267
284
setState (() {
268
285
_loading = false ;
269
286
});
@@ -273,7 +290,7 @@ class _BidiPageState extends State<BidiPage> {
273
290
setState (() {
274
291
_loading = true ;
275
292
});
276
- final chunks = _splitIntoChunks (audio, 1024 );
293
+ final chunks = _splitIntoChunks (audio, 512 );
277
294
278
295
final media_chunks = < InlineDataPart > [];
279
296
for (var chunk in chunks) {
@@ -288,8 +305,7 @@ class _BidiPageState extends State<BidiPage> {
288
305
}
289
306
await _session! .stream (mediaChunks: media_chunks);
290
307
print ('Stream realtime audio chunk to server in one request' );
291
-
292
- await _handle_response_audio ();
308
+ _session.printWsStatus ();
293
309
setState (() {
294
310
_loading = false ;
295
311
});
@@ -300,16 +316,36 @@ class _BidiPageState extends State<BidiPage> {
300
316
_loading = true ;
301
317
});
302
318
final prompt = Content .inlineData ('audio/pcm' , audio);
303
- await _session! .send (input: prompt, turnComplete : true );
319
+ await _session! .send (input: prompt);
304
320
305
321
print ('Sent audio chunk to server' );
322
+ _session.printWsStatus ();
323
+ setState (() {
324
+ _loading = false ;
325
+ });
326
+ }
327
+
328
+ Future <void > _sendPremadeAudioPayload () async {
329
+ setState (() {
330
+ _loading = true ;
331
+ });
332
+ final dir = await getDownloadsDirectory ();
333
+ final path = '${dir !.path }/audio_payload.json' ;
334
+
335
+ final file = File (path! );
336
+ final dataDump = await file.readAsString ();
337
+
338
+ _session! .dumpData (dataDump);
306
339
307
- await _handle_response_audio ();
308
340
setState (() {
309
341
_loading = false ;
310
342
});
311
343
}
312
344
345
+ Future <void > _checkWsStatus () async {
346
+ _session! .printWsStatus ();
347
+ }
348
+
313
349
Future <void > _sendTextPrompt ({String ? textPrompt}) async {
314
350
setState (() {
315
351
_loading = true ;
@@ -330,15 +366,16 @@ class _BidiPageState extends State<BidiPage> {
330
366
331
367
await _session! .send (input: prompt, turnComplete: true );
332
368
print ('Prompt sent to server' );
333
- await _handle_response_audio ();
369
+ _session.printWsStatus ();
370
+ // await _handle_response();
334
371
}
335
372
336
373
setState (() {
337
374
_loading = false ;
338
375
});
339
376
}
340
377
341
- Future <void > _handle_response_audio () async {
378
+ Future <void > _handle_response () async {
342
379
final responseStream = _session! .receive ();
343
380
var chunkBuilder = BytesBuilder ();
344
381
var audioIndex = 0 ;
@@ -394,9 +431,11 @@ class _BidiPageState extends State<BidiPage> {
394
431
24000 ,
395
432
);
396
433
_audioManager.addAudio (chunk);
434
+ audioIndex = 0 ;
435
+ chunkBuilder.clear ();
397
436
}
398
437
399
- break ; // Exit the loop if the turn is complete
438
+ // break; // Exit the loop if the turn is complete
400
439
}
401
440
}
402
441
}
0 commit comments