Skip to content

Commit c9d285e

Browse files
authored
chore(vertexai): update sample for developer api and fix the instance key for FirebaseVertexAI (#17319)
1 parent 73e4064 commit c9d285e

File tree

6 files changed

+245
-123
lines changed

6 files changed

+245
-123
lines changed

packages/firebase_vertexai/firebase_vertexai/example/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,4 @@ app.*.map.json
4848
firebase_options.dart
4949
google-services.json
5050
GoogleService-Info.plist
51+
firebase.json

packages/firebase_vertexai/firebase_vertexai/example/android/settings.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ pluginManagement {
1919
plugins {
2020
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
2121
id "com.android.application" version "7.3.0" apply false
22+
// START: FlutterFire Configuration
23+
id "com.google.gms.google-services" version "4.3.15" apply false
24+
// END: FlutterFire Configuration
2225
id "org.jetbrains.kotlin.android" version "1.9.22" apply false
2326
}
2427

packages/firebase_vertexai/firebase_vertexai/example/lib/main.dart

Lines changed: 206 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -38,161 +38,283 @@ void main() async {
3838
// await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
3939
await Firebase.initializeApp();
4040
await FirebaseAuth.instance.signInAnonymously();
41+
runApp(const GenerativeAISample());
42+
}
4143

42-
var vertexInstance =
43-
FirebaseVertexAI.instanceFor(auth: FirebaseAuth.instance);
44-
final model = vertexInstance.generativeModel(model: 'gemini-1.5-flash');
44+
class GenerativeAISample extends StatefulWidget {
45+
const GenerativeAISample({super.key});
4546

46-
runApp(GenerativeAISample(model: model));
47+
@override
48+
State<GenerativeAISample> createState() => _GenerativeAISampleState();
4749
}
4850

49-
class GenerativeAISample extends StatelessWidget {
50-
final GenerativeModel model;
51+
class _GenerativeAISampleState extends State<GenerativeAISample> {
52+
bool _useVertexBackend = false;
53+
late GenerativeModel _currentModel;
54+
late ImagenModel _currentImagenModel;
55+
int _currentBottomNavIndex = 0;
56+
57+
@override
58+
void initState() {
59+
super.initState();
60+
61+
_initializeModel(_useVertexBackend);
62+
}
5163

52-
const GenerativeAISample({super.key, required this.model});
64+
void _initializeModel(bool useVertexBackend) {
65+
if (useVertexBackend) {
66+
final vertexInstance =
67+
FirebaseVertexAI.instanceFor(auth: FirebaseAuth.instance);
68+
_currentModel = vertexInstance.generativeModel(model: 'gemini-1.5-flash');
69+
_currentImagenModel = _initializeImagenModel(vertexInstance);
70+
} else {
71+
final googleAI = FirebaseVertexAI.googleAI(auth: FirebaseAuth.instance);
72+
_currentModel = googleAI.generativeModel(model: 'gemini-2.0-flash');
73+
_currentImagenModel = _initializeImagenModel(googleAI);
74+
}
75+
}
76+
77+
ImagenModel _initializeImagenModel(FirebaseVertexAI instance) {
78+
var generationConfig = ImagenGenerationConfig(
79+
negativePrompt: 'frog',
80+
numberOfImages: 1,
81+
aspectRatio: ImagenAspectRatio.square1x1,
82+
imageFormat: ImagenFormat.jpeg(compressionQuality: 75),
83+
);
84+
return instance.imagenModel(
85+
model: 'imagen-3.0-generate-001',
86+
generationConfig: generationConfig,
87+
safetySettings: ImagenSafetySettings(
88+
ImagenSafetyFilterLevel.blockLowAndAbove,
89+
ImagenPersonFilterLevel.allowAdult,
90+
),
91+
);
92+
}
93+
94+
void _toggleBackend(bool value) {
95+
setState(() {
96+
_useVertexBackend = value;
97+
});
98+
_initializeModel(_useVertexBackend);
99+
}
100+
101+
void _onBottomNavTapped(int index) {
102+
setState(() {
103+
_currentBottomNavIndex = index;
104+
});
105+
}
53106

54107
@override
55108
Widget build(BuildContext context) {
56109
return MaterialApp(
57-
title: 'Flutter + Vertex AI',
110+
title: 'Flutter + ${_useVertexBackend ? 'Vertex AI' : 'Google AI'}',
111+
debugShowCheckedModeBanner: false,
112+
themeMode: ThemeMode.dark,
58113
theme: ThemeData(
59114
colorScheme: ColorScheme.fromSeed(
60115
brightness: Brightness.dark,
61116
seedColor: const Color.fromARGB(255, 171, 222, 244),
62117
),
63118
useMaterial3: true,
64119
),
65-
home: HomeScreen(model: model),
120+
home: HomeScreen(
121+
key: ValueKey(
122+
'${_useVertexBackend}_${_currentModel.hashCode}',
123+
),
124+
model: _currentModel,
125+
imagenModel: _currentImagenModel,
126+
useVertexBackend: _useVertexBackend,
127+
onBackendChanged: _toggleBackend,
128+
selectedIndex: _currentBottomNavIndex,
129+
onSelectedIndexChanged: _onBottomNavTapped,
130+
),
66131
);
67132
}
68133
}
69134

70135
class HomeScreen extends StatefulWidget {
71136
final GenerativeModel model;
72-
const HomeScreen({super.key, required this.model});
137+
final ImagenModel imagenModel;
138+
final bool useVertexBackend;
139+
final ValueChanged<bool> onBackendChanged;
140+
final int selectedIndex;
141+
final ValueChanged<int> onSelectedIndexChanged;
142+
143+
const HomeScreen({
144+
super.key,
145+
required this.model,
146+
required this.imagenModel,
147+
required this.useVertexBackend,
148+
required this.onBackendChanged,
149+
required this.selectedIndex,
150+
required this.onSelectedIndexChanged,
151+
});
73152

74153
@override
75154
State<HomeScreen> createState() => _HomeScreenState();
76155
}
77156

78157
class _HomeScreenState extends State<HomeScreen> {
79-
int _selectedIndex = 0;
80-
81-
List<Widget> get _pages => <Widget>[
82-
// Build _pages dynamically
83-
ChatPage(title: 'Chat', model: widget.model),
84-
AudioPage(title: 'Audio', model: widget.model),
85-
TokenCountPage(title: 'Token Count', model: widget.model),
86-
const FunctionCallingPage(
87-
title: 'Function Calling',
88-
), // function calling will initial its own model
89-
ImagePromptPage(title: 'Image Prompt', model: widget.model),
90-
ImagenPage(title: 'Imagen Model', model: widget.model),
91-
SchemaPromptPage(title: 'Schema Prompt', model: widget.model),
92-
DocumentPage(title: 'Document Prompt', model: widget.model),
93-
VideoPage(title: 'Video Prompt', model: widget.model),
94-
BidiPage(title: 'Bidi Stream', model: widget.model),
95-
];
96-
97158
void _onItemTapped(int index) {
98-
setState(() {
99-
_selectedIndex = index;
100-
});
159+
widget.onSelectedIndexChanged(index);
160+
}
161+
162+
// Method to build the selected page on demand
163+
Widget _buildSelectedPage(
164+
int index,
165+
GenerativeModel currentModel,
166+
ImagenModel currentImagenModel,
167+
bool useVertexBackend,
168+
) {
169+
switch (index) {
170+
case 0:
171+
return ChatPage(title: 'Chat', model: currentModel);
172+
case 1:
173+
return AudioPage(title: 'Audio', model: currentModel);
174+
case 2:
175+
return TokenCountPage(title: 'Token Count', model: currentModel);
176+
case 3:
177+
// FunctionCallingPage initializes its own model as per original design
178+
return FunctionCallingPage(
179+
title: 'Function Calling',
180+
useVertexBackend: useVertexBackend,
181+
);
182+
case 4:
183+
return ImagePromptPage(title: 'Image Prompt', model: currentModel);
184+
case 5:
185+
return ImagenPage(title: 'Imagen Model', model: currentImagenModel);
186+
case 6:
187+
return SchemaPromptPage(title: 'Schema Prompt', model: currentModel);
188+
case 7:
189+
return DocumentPage(title: 'Document Prompt', model: currentModel);
190+
case 8:
191+
return VideoPage(title: 'Video Prompt', model: currentModel);
192+
case 9:
193+
return BidiPage(title: 'Bidi Stream', model: currentModel);
194+
default:
195+
// Fallback to the first page in case of an unexpected index
196+
return ChatPage(title: 'Chat', model: currentModel);
197+
}
101198
}
102199

103200
@override
104201
Widget build(BuildContext context) {
105202
return Scaffold(
106203
appBar: AppBar(
107-
title: const Text('Flutter + Vertex AI'),
204+
title: Text(
205+
'Flutter + ${widget.useVertexBackend ? 'Vertex AI' : 'Google AI'}',
206+
),
207+
actions: <Widget>[
208+
Padding(
209+
padding: const EdgeInsets.symmetric(horizontal: 16),
210+
child: Row(
211+
mainAxisSize: MainAxisSize.min,
212+
children: <Widget>[
213+
Text(
214+
'Google AI',
215+
style: TextStyle(
216+
fontSize: 12,
217+
color: widget.useVertexBackend
218+
? Theme.of(context)
219+
.colorScheme
220+
.onSurface
221+
.withValues(alpha: 0.7)
222+
: Theme.of(context).colorScheme.primary,
223+
),
224+
),
225+
Switch(
226+
value: widget.useVertexBackend,
227+
onChanged: widget.onBackendChanged,
228+
activeTrackColor: Colors.green.withValues(alpha: 0.5),
229+
inactiveTrackColor: Colors.blueGrey.withValues(alpha: 0.5),
230+
activeColor: Colors.green,
231+
inactiveThumbColor: Colors.blueGrey,
232+
),
233+
Text(
234+
'Vertex AI',
235+
style: TextStyle(
236+
fontSize: 12,
237+
color: widget.useVertexBackend
238+
? Theme.of(context).colorScheme.primary
239+
: Theme.of(context)
240+
.colorScheme
241+
.onSurface
242+
.withValues(alpha: 0.7),
243+
),
244+
),
245+
],
246+
),
247+
),
248+
],
108249
),
109250
body: Center(
110-
child: _pages.elementAt(_selectedIndex),
251+
child: _buildSelectedPage(
252+
widget.selectedIndex,
253+
widget.model,
254+
widget.imagenModel,
255+
widget.useVertexBackend,
256+
),
111257
),
112258
bottomNavigationBar: BottomNavigationBar(
113-
items: <BottomNavigationBarItem>[
259+
type: BottomNavigationBarType.fixed,
260+
selectedFontSize: 10,
261+
unselectedFontSize: 9,
262+
selectedItemColor: Theme.of(context).colorScheme.primary,
263+
unselectedItemColor:
264+
Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.7),
265+
items: const <BottomNavigationBarItem>[
114266
BottomNavigationBarItem(
115-
icon: Icon(
116-
Icons.chat,
117-
color: Theme.of(context).colorScheme.primary,
118-
),
267+
icon: Icon(Icons.chat),
119268
label: 'Chat',
120269
tooltip: 'Chat',
121270
),
122271
BottomNavigationBarItem(
123-
icon: Icon(
124-
Icons.mic,
125-
color: Theme.of(context).colorScheme.primary,
126-
),
127-
label: 'Audio Prompt',
272+
icon: Icon(Icons.mic),
273+
label: 'Audio',
128274
tooltip: 'Audio Prompt',
129275
),
130276
BottomNavigationBarItem(
131-
icon: Icon(
132-
Icons.numbers,
133-
color: Theme.of(context).colorScheme.primary,
134-
),
135-
label: 'Token Count',
277+
icon: Icon(Icons.numbers),
278+
label: 'Tokens',
136279
tooltip: 'Token Count',
137280
),
138281
BottomNavigationBarItem(
139-
icon: Icon(
140-
Icons.functions,
141-
color: Theme.of(context).colorScheme.primary,
142-
),
143-
label: 'Function Calling',
282+
icon: Icon(Icons.functions),
283+
label: 'Functions',
144284
tooltip: 'Function Calling',
145285
),
146286
BottomNavigationBarItem(
147-
icon: Icon(
148-
Icons.image,
149-
color: Theme.of(context).colorScheme.primary,
150-
),
151-
label: 'Image Prompt',
287+
icon: Icon(Icons.image),
288+
label: 'Image',
152289
tooltip: 'Image Prompt',
153290
),
154291
BottomNavigationBarItem(
155-
icon: Icon(
156-
Icons.image_search,
157-
color: Theme.of(context).colorScheme.primary,
158-
),
159-
label: 'Imagen Model',
292+
icon: Icon(Icons.image_search),
293+
label: 'Imagen',
160294
tooltip: 'Imagen Model',
161295
),
162296
BottomNavigationBarItem(
163-
icon: Icon(
164-
Icons.schema,
165-
color: Theme.of(context).colorScheme.primary,
166-
),
167-
label: 'Schema Prompt',
297+
icon: Icon(Icons.schema),
298+
label: 'Schema',
168299
tooltip: 'Schema Prompt',
169300
),
170301
BottomNavigationBarItem(
171-
icon: Icon(
172-
Icons.edit_document,
173-
color: Theme.of(context).colorScheme.primary,
174-
),
175-
label: 'Document Prompt',
302+
icon: Icon(Icons.edit_document),
303+
label: 'Document',
176304
tooltip: 'Document Prompt',
177305
),
178306
BottomNavigationBarItem(
179-
icon: Icon(
180-
Icons.video_collection,
181-
color: Theme.of(context).colorScheme.primary,
182-
),
183-
label: 'Video Prompt',
307+
icon: Icon(Icons.video_collection),
308+
label: 'Video',
184309
tooltip: 'Video Prompt',
185310
),
186311
BottomNavigationBarItem(
187-
icon: Icon(
188-
Icons.stream,
189-
color: Theme.of(context).colorScheme.primary,
190-
),
191-
label: 'Bidi Stream',
312+
icon: Icon(Icons.stream),
313+
label: 'Bidi',
192314
tooltip: 'Bidi Stream',
193315
),
194316
],
195-
currentIndex: _selectedIndex,
317+
currentIndex: widget.selectedIndex,
196318
onTap: _onItemTapped,
197319
),
198320
);

0 commit comments

Comments
 (0)