@@ -88,12 +88,12 @@ class _ChatWidgetState extends State<ChatWidget> {
8888
8989 initFirebase ().then ((value) {
9090 _model = FirebaseVertexAI .instance.generativeModel (
91- model: 'gemini-1.5-pro -preview-0409 ' ,
91+ model: 'gemini-1.5-flash -preview-0514 ' ,
9292 );
9393 _functionCallModel = FirebaseVertexAI .instance.generativeModel (
94- model: 'gemini-1.5-pro -preview-0409 ' ,
94+ model: 'gemini-1.5-flash -preview-0514 ' ,
9595 tools: [
96- Tool (functionDeclarations: [exchangeRateTool])
96+ Tool (functionDeclarations: [exchangeRateTool]),
9797 ],
9898 );
9999 _chat = _model.startChat ();
@@ -108,23 +108,33 @@ class _ChatWidgetState extends State<ChatWidget> {
108108 {
109109 'date' : arguments['currencyDate' ],
110110 'base' : arguments['currencyFrom' ],
111- 'rates' : < String , Object ? > {arguments['currencyTo' ] as String : 0.091 }
111+ 'rates' : < String , Object ? > {arguments['currencyTo' ]! as String : 0.091 },
112112 };
113113
114114 final exchangeRateTool = FunctionDeclaration (
115- 'findExchangeRate' ,
116- 'Returns the exchange rate between currencies on given date.' ,
117- Schema (SchemaType .object, properties: {
118- 'currencyDate' : Schema (SchemaType .string,
119- description: 'A date in YYYY-MM-DD format or '
120- 'the exact value "latest" if a time period is not specified.' ),
121- 'currencyFrom' : Schema (SchemaType .string,
122- description: 'The currency code of the currency to convert from, '
123- 'such as "USD".' ),
124- 'currencyTo' : Schema (SchemaType .string,
125- description: 'The currency code of the currency to convert to, '
126- 'such as "USD".' )
127- }));
115+ 'findExchangeRate' ,
116+ 'Returns the exchange rate between currencies on given date.' ,
117+ Schema (
118+ SchemaType .object,
119+ properties: {
120+ 'currencyDate' : Schema (
121+ SchemaType .string,
122+ description: 'A date in YYYY-MM-DD format or '
123+ 'the exact value "latest" if a time period is not specified.' ,
124+ ),
125+ 'currencyFrom' : Schema (
126+ SchemaType .string,
127+ description: 'The currency code of the currency to convert from, '
128+ 'such as "USD".' ,
129+ ),
130+ 'currencyTo' : Schema (
131+ SchemaType .string,
132+ description: 'The currency code of the currency to convert to, '
133+ 'such as "USD".' ,
134+ ),
135+ },
136+ ),
137+ );
128138
129139 Future <void > initFirebase () async {
130140 await Firebase .initializeApp ();
@@ -166,7 +176,7 @@ class _ChatWidgetState extends State<ChatWidget> {
166176 );
167177
168178 return Padding (
169- padding: const EdgeInsets .all (8.0 ),
179+ padding: const EdgeInsets .all (8 ),
170180 child: Column (
171181 mainAxisAlignment: MainAxisAlignment .center,
172182 crossAxisAlignment: CrossAxisAlignment .start,
@@ -198,18 +208,31 @@ class _ChatWidgetState extends State<ChatWidget> {
198208 focusNode: _textFieldFocus,
199209 decoration: textFieldDecoration,
200210 controller: _textController,
201- onSubmitted: (String value) {
202- _sendChatMessage (value);
203- },
211+ onSubmitted: _sendChatMessage,
204212 ),
205213 ),
206214 const SizedBox .square (
207215 dimension: 15 ,
208216 ),
209217 IconButton (
218+ tooltip: 'tokenCount Test' ,
210219 onPressed: ! _loading
211220 ? () async {
212- _testFunctionCalling ();
221+ await _testCountToken ();
222+ }
223+ : null ,
224+ icon: Icon (
225+ Icons .numbers,
226+ color: _loading
227+ ? Theme .of (context).colorScheme.secondary
228+ : Theme .of (context).colorScheme.primary,
229+ ),
230+ ),
231+ IconButton (
232+ tooltip: 'function calling Test' ,
233+ onPressed: ! _loading
234+ ? () async {
235+ await _testFunctionCalling ();
213236 }
214237 : null ,
215238 icon: Icon (
@@ -220,9 +243,10 @@ class _ChatWidgetState extends State<ChatWidget> {
220243 ),
221244 ),
222245 IconButton (
246+ tooltip: 'image prompt' ,
223247 onPressed: ! _loading
224248 ? () async {
225- _sendImagePrompt (_textController.text);
249+ await _sendImagePrompt (_textController.text);
226250 }
227251 : null ,
228252 icon: Icon (
@@ -232,10 +256,24 @@ class _ChatWidgetState extends State<ChatWidget> {
232256 : Theme .of (context).colorScheme.primary,
233257 ),
234258 ),
259+ IconButton (
260+ tooltip: 'storage prompt' ,
261+ onPressed: ! _loading
262+ ? () async {
263+ await _sendStorageUriPrompt (_textController.text);
264+ }
265+ : null ,
266+ icon: Icon (
267+ Icons .folder,
268+ color: _loading
269+ ? Theme .of (context).colorScheme.secondary
270+ : Theme .of (context).colorScheme.primary,
271+ ),
272+ ),
235273 if (! _loading)
236274 IconButton (
237275 onPressed: () async {
238- _sendChatMessage (_textController.text);
276+ await _sendChatMessage (_textController.text);
239277 },
240278 icon: Icon (
241279 Icons .send,
@@ -252,6 +290,49 @@ class _ChatWidgetState extends State<ChatWidget> {
252290 );
253291 }
254292
293+ Future <void > _sendStorageUriPrompt (String message) async {
294+ setState (() {
295+ _loading = true ;
296+ });
297+ try {
298+ final content = [
299+ Content .multi ([
300+ TextPart (message),
301+ FileData (
302+ 'image/jpeg' ,
303+ 'gs://vertex-ai-example-ef5a2.appspot.com/foodpic.jpg' ,
304+ ),
305+ ]),
306+ ];
307+ _generatedContent.add ((image: null , text: message, fromUser: true ));
308+
309+ var response = await _model.generateContent (content);
310+ var text = response.text;
311+ _generatedContent.add ((image: null , text: text, fromUser: false ));
312+
313+ if (text == null ) {
314+ _showError ('No response from API.' );
315+ return ;
316+ } else {
317+ setState (() {
318+ _loading = false ;
319+ _scrollDown ();
320+ });
321+ }
322+ } catch (e) {
323+ _showError (e.toString ());
324+ setState (() {
325+ _loading = false ;
326+ });
327+ } finally {
328+ _textController.clear ();
329+ setState (() {
330+ _loading = false ;
331+ });
332+ _textFieldFocus.requestFocus ();
333+ }
334+ }
335+
255336 Future <void > _sendImagePrompt (String message) async {
256337 setState (() {
257338 _loading = true ;
@@ -265,18 +346,22 @@ class _ChatWidgetState extends State<ChatWidget> {
265346 // The only accepted mime types are image/*.
266347 DataPart ('image/jpeg' , catBytes.buffer.asUint8List ()),
267348 DataPart ('image/jpeg' , sconeBytes.buffer.asUint8List ()),
268- ])
349+ ]),
269350 ];
270- _generatedContent.add ((
271- image: Image .asset ("assets/images/cat.jpg" ),
272- text: message,
273- fromUser: true
274- ));
275- _generatedContent.add ((
276- image: Image .asset ("assets/images/scones.jpg" ),
277- text: null ,
278- fromUser: true
279- ));
351+ _generatedContent.add (
352+ (
353+ image: Image .asset ('assets/images/cat.jpg' ),
354+ text: message,
355+ fromUser: true
356+ ),
357+ );
358+ _generatedContent.add (
359+ (
360+ image: Image .asset ('assets/images/scones.jpg' ),
361+ text: null ,
362+ fromUser: true
363+ ),
364+ );
280365
281366 var response = await _model.generateContent (content);
282367 var text = response.text;
@@ -361,7 +446,8 @@ class _ChatWidgetState extends State<ChatWidget> {
361446 // Throw an exception if the model attempted to call a function that was
362447 // not declared.
363448 _ => throw UnimplementedError (
364- 'Function not implemented: ${functionCall .name }' )
449+ 'Function not implemented: ${functionCall .name }' ,
450+ )
365451 };
366452 // Send the response to the model so that it can use the result to generate
367453 // text for the user.
@@ -377,6 +463,22 @@ class _ChatWidgetState extends State<ChatWidget> {
377463 }
378464 }
379465
466+ Future <void > _testCountToken () async {
467+ setState (() {
468+ _loading = true ;
469+ });
470+
471+ const prompt = 'tell a short story' ;
472+ var response = await _model.countTokens ([Content .text (prompt)]);
473+ print (
474+ 'token: ${response .totalTokens }, billable characters: ${response .totalBillableCharacters }' ,
475+ );
476+
477+ setState (() {
478+ _loading = false ;
479+ });
480+ }
481+
380482 void _showError (String message) {
381483 showDialog <void >(
382484 context: context,
@@ -392,7 +494,7 @@ class _ChatWidgetState extends State<ChatWidget> {
392494 Navigator .of (context).pop ();
393495 },
394496 child: const Text ('OK' ),
395- )
497+ ),
396498 ],
397499 );
398500 },
@@ -419,23 +521,27 @@ class MessageWidget extends StatelessWidget {
419521 isFromUser ? MainAxisAlignment .end : MainAxisAlignment .start,
420522 children: [
421523 Flexible (
422- child: Container (
423- constraints: const BoxConstraints (maxWidth: 600 ),
424- decoration: BoxDecoration (
425- color: isFromUser
426- ? Theme .of (context).colorScheme.primaryContainer
427- : Theme .of (context).colorScheme.surfaceVariant,
428- borderRadius: BorderRadius .circular (18 ),
429- ),
430- padding: const EdgeInsets .symmetric (
431- vertical: 15 ,
432- horizontal: 20 ,
433- ),
434- margin: const EdgeInsets .only (bottom: 8 ),
435- child: Column (children: [
436- if (text case final text? ) MarkdownBody (data: text),
437- if (image case final image? ) image,
438- ]))),
524+ child: Container (
525+ constraints: const BoxConstraints (maxWidth: 600 ),
526+ decoration: BoxDecoration (
527+ color: isFromUser
528+ ? Theme .of (context).colorScheme.primaryContainer
529+ : Theme .of (context).colorScheme.surfaceContainerHighest,
530+ borderRadius: BorderRadius .circular (18 ),
531+ ),
532+ padding: const EdgeInsets .symmetric (
533+ vertical: 15 ,
534+ horizontal: 20 ,
535+ ),
536+ margin: const EdgeInsets .only (bottom: 8 ),
537+ child: Column (
538+ children: [
539+ if (text case final text? ) MarkdownBody (data: text),
540+ if (image case final image? ) image,
541+ ],
542+ ),
543+ ),
544+ ),
439545 ],
440546 );
441547 }
0 commit comments