google_gemini 0.1.2 google_gemini: ^0.1.2 copied to clipboard
Google Gemini SDK for Flutter. This package provides a powerful bridge between your Flutter application and Google's revolutionary Gemini AI.
import 'package:flutter/material.dart';
import 'package:google_gemini/google_gemini.dart';
import 'dart:io';
import 'package:image_picker/image_picker.dart';
const apiKey = "--- Your Gemini Api Key ---";
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
useMaterial3: true,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({
super.key,
});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return DefaultTabController(
initialIndex: 0,
length: 2,
child: Scaffold(
appBar: AppBar(
title: const Text("Google Gemini"),
centerTitle: true,
bottom: const TabBar(
tabs: [
Tab(text: "Text Only"),
Tab(text: "Text with Image"),
],
),
),
body: const TabBarView(
children: [TextOnly(), TextWithImage()],
)));
}
}
// ------------------------------ Text Only ------------------------------
class TextOnly extends StatefulWidget {
const TextOnly({
super.key,
});
@override
State<TextOnly> createState() => _TextOnlyState();
}
class _TextOnlyState extends State<TextOnly> {
bool loading = false;
List textChat = [];
List textWithImageChat = [];
final TextEditingController _textController = TextEditingController();
final ScrollController _controller = ScrollController();
// Create Gemini Instance
final gemini = GoogleGemini(
apiKey: apiKey,
);
// Text only input
void fromText({required String query}) {
setState(() {
loading = true;
textChat.add({
"role": "User",
"text": query,
});
_textController.clear();
});
scrollToTheEnd();
gemini.generateFromText(query).then((value) {
setState(() {
loading = false;
textChat.add({
"role": "Gemini",
"text": value.text,
});
});
scrollToTheEnd();
}).onError((error, stackTrace) {
setState(() {
loading = false;
textChat.add({
"role": "Gemini",
"text": error.toString(),
});
});
scrollToTheEnd();
});
}
void scrollToTheEnd() {
_controller.jumpTo(_controller.position.maxScrollExtent);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: ListView.builder(
controller: _controller,
itemCount: textChat.length,
padding: const EdgeInsets.only(bottom: 20),
itemBuilder: (context, index) {
return ListTile(
isThreeLine: true,
leading: CircleAvatar(
child: Text(textChat[index]["role"].substring(0, 1)),
),
title: Text(textChat[index]["role"]),
subtitle: Text(textChat[index]["text"]),
);
},
),
),
Container(
alignment: Alignment.bottomRight,
margin: const EdgeInsets.all(20),
padding: const EdgeInsets.symmetric(horizontal: 15.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
border: Border.all(color: Colors.grey),
),
child: Row(
children: [
Expanded(
child: TextField(
controller: _textController,
decoration: InputDecoration(
hintText: "Type a message",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide.none),
fillColor: Colors.transparent,
),
maxLines: null,
keyboardType: TextInputType.multiline,
),
),
IconButton(
icon: loading
? const CircularProgressIndicator()
: const Icon(Icons.send),
onPressed: () {
fromText(query: _textController.text);
},
),
],
),
)
],
));
}
}
// ------------------------------ Text with Image ------------------------------
class TextWithImage extends StatefulWidget {
const TextWithImage({
super.key,
});
@override
State<TextWithImage> createState() => _TextWithImageState();
}
class _TextWithImageState extends State<TextWithImage> {
bool loading = false;
List textAndImageChat = [];
List textWithImageChat = [];
File? imageFile;
final ImagePicker picker = ImagePicker();
final TextEditingController _textController = TextEditingController();
final ScrollController _controller = ScrollController();
// Create Gemini Instance
final gemini = GoogleGemini(
apiKey: apiKey,
);
// Text only input
void fromTextAndImage({required String query, required File image}) {
setState(() {
loading = true;
textAndImageChat.add({
"role": "User",
"text": query,
"image": image,
});
_textController.clear();
imageFile = null;
});
scrollToTheEnd();
gemini.generateFromTextAndImages(query: query, image: image).then((value) {
setState(() {
loading = false;
textAndImageChat
.add({"role": "Gemini", "text": value.text, "image": ""});
});
scrollToTheEnd();
}).onError((error, stackTrace) {
setState(() {
loading = false;
textAndImageChat
.add({"role": "Gemini", "text": error.toString(), "image": ""});
});
scrollToTheEnd();
});
}
void scrollToTheEnd() {
_controller.jumpTo(_controller.position.maxScrollExtent);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: ListView.builder(
controller: _controller,
itemCount: textAndImageChat.length,
padding: const EdgeInsets.only(bottom: 20),
itemBuilder: (context, index) {
return ListTile(
isThreeLine: true,
leading: CircleAvatar(
child:
Text(textAndImageChat[index]["role"].substring(0, 1)),
),
title: Text(textAndImageChat[index]["role"]),
subtitle: Text(textAndImageChat[index]["text"]),
trailing: textAndImageChat[index]["image"] == ""
? null
: Image.file(
textAndImageChat[index]["image"],
width: 90,
),
);
},
),
),
Container(
alignment: Alignment.bottomRight,
margin: const EdgeInsets.all(20),
padding: const EdgeInsets.symmetric(horizontal: 15.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
border: Border.all(color: Colors.grey),
),
child: Row(
children: [
Expanded(
child: TextField(
controller: _textController,
decoration: InputDecoration(
hintText: "Write a message",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide.none),
fillColor: Colors.transparent,
),
maxLines: null,
keyboardType: TextInputType.multiline,
),
),
IconButton(
icon: const Icon(Icons.add_a_photo),
onPressed: () async {
final XFile? image =
await picker.pickImage(source: ImageSource.gallery);
setState(() {
imageFile = image != null ? File(image.path) : null;
});
},
),
IconButton(
icon: loading
? const CircularProgressIndicator()
: const Icon(Icons.send),
onPressed: () {
if (imageFile == null) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text("Please select an image")));
return;
}
fromTextAndImage(
query: _textController.text, image: imageFile!);
},
),
],
),
),
],
),
floatingActionButton: imageFile != null
? Container(
margin: const EdgeInsets.only(bottom: 80),
height: 150,
child: Image.file(imageFile ?? File("")),
)
: null,
);
}
}