Skip to content

Instantly share code, notes, and snippets.

@romanejaquez
Last active June 26, 2024 22:43
Show Gist options
  • Save romanejaquez/d8dd3b36d39efce7f1c53a6db4969844 to your computer and use it in GitHub Desktop.
Save romanejaquez/d8dd3b36d39efce7f1c53a6db4969844 to your computer and use it in GitHub Desktop.
gemini_pictionary_fullcode.dart
// dependencies
import 'dart:convert';
import 'package:finger_painter/finger_painter.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_generative_ai/google_generative_ai.dart';
import 'dart:ui' as ui;
// root widget
void main() {
runApp(const ProviderScope(child: GeminiPictionaryApp()));
}
class GeminiPictionaryApp extends StatelessWidget {
const GeminiPictionaryApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: GeminiPictionaryHome(),
);
}
}
class GeminiPictionaryHome extends StatelessWidget {
const GeminiPictionaryHome({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
elevation: 0,
centerTitle: true,
title: const Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.collections, color: Colors.purple),
SizedBox(width: 16),
Text('Pictionary!', style: TextStyle(color: Colors.purple))
],
),
),
body: const Center(
child: Column(
children: [
PaintingSurface(),
PaintingValidationControls(),
PaintingValidator(),
],
)
)
);
}
}
class PaintingValidationControls extends ConsumerWidget {
const PaintingValidationControls({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return Padding(
padding: const EdgeInsets.all(24),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton.icon(
onPressed: () async {
await ref.read(paintingServiceProvider).validatePicture();
},
icon: const Icon(Icons.image),
label: const Text('Validate Picture')
),
const SizedBox(width: 24),
ElevatedButton.icon(
icon: const Icon(Icons.clear),
onPressed: () async {
ref.read(paintingServiceProvider).clear();
},
label: const Text('Clear')
)
],
),
);
}
}
class PaintingValidator extends ConsumerWidget {
const PaintingValidator({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final imgPayload = ref.watch(imageResultNotifier);
if (imgPayload == null) {
return const SizedBox.shrink();
}
return Container(
margin: const EdgeInsets.all(20),
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
),
child: Row(
children: [
Image.memory(imgPayload.imgBytes,
width: 200,
height: 200,
),
const SizedBox(width: 24),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Guessed Image:', style: TextStyle(fontSize: 20, color: Colors.purpleAccent),),
Text(imgPayload.name, style: const TextStyle(fontSize: 30, fontWeight: FontWeight.bold),),
],
),
)
],
),
).animate()
.slideY(
begin: 1, end: 0,
curve: Curves.easeInOut,
duration: 0.5.seconds,
);
}
}
class PaintingSurface extends ConsumerStatefulWidget {
const PaintingSurface({super.key});
@override
ConsumerState<PaintingSurface> createState() => _PaintingSurfaceState();
}
class _PaintingSurfaceState extends ConsumerState<PaintingSurface> {
late PainterController painterController;
@override
void initState() {
super.initState();
initializePainterController();
}
void initializePainterController() async {
painterController = ref.read(painterControllerProvider);
ByteData bgImg = await rootBundle.load('assets/bgimg.png');
painterController.setBackgroundImage(bgImg.buffer.asUint8List());
}
@override
Widget build(BuildContext context) {
return Painter(
controller: painterController,
backgroundColor: Colors.white,
size: Size(
MediaQuery.sizeOf(context).width, 300,
),
child: const ColoredBox(color: Colors.white),
);
}
}
final painterControllerProvider = Provider<PainterController>((ref) {
return PainterController()
..setPenType(PenType.paintbrush)
..setStrokeColor(Colors.black)
..setMinStrokeWidth(3)
..setMaxStrokeWidth(10)
..setBlurSigma(0.0)
..setBlendMode(ui.BlendMode.srcOver);
});
final paintingServiceProvider = Provider<GeminiPaintingService>((ref) {
return GeminiPaintingService(ref);
});
final imageResultNotifier = StateProvider<ImageResultPayload?>((ref) => null);
class GeminiPaintingService {
final Ref ref;
const GeminiPaintingService(this.ref);
Future<void> validatePicture() async {
try {
Uint8List imgBytes = ref.read(painterControllerProvider).getImageBytes()!;
var model = GenerativeModel(
model: 'gemini-1.5-pro',
apiKey: 'YOUR_API_KEY_HERE', // <- ADD YOUR API KEY HERE
generationConfig: GenerationConfig(
responseMimeType: 'application/json',
responseSchema: Schema.object(
properties: {
"guessedImage": Schema.string(),
}
)
)
);
final content = Content.multi([
TextPart('''
You are a pictionary player. Given the provided image, identify its contents
and reply in the form of a JSON payload response containing the following properties:
{
"guessedImage": the name of the image drawn
}
'''),
DataPart('image/png', imgBytes)
]);
var response = await model.generateContent([content]);
var jsonPayload = json.decode(response.text!);
ref.read(imageResultNotifier.notifier).state =
ImageResultPayload(
name: jsonPayload['guessedImage'],
imgBytes: imgBytes
);
}
on Exception {
rethrow;
}
}
void clear() {
ref.read(painterControllerProvider).clearContent(clearColor: Colors.white);
ref.read(imageResultNotifier.notifier).state = null;
}
}
class ImageResultPayload {
final String name;
final Uint8List imgBytes;
const ImageResultPayload({
required this.name,
required this.imgBytes,
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment