Calling the PaLM 2 API with Dart and Flutter
Example
Prompt Template
To call the API with a prompt we can start by creating a template:
This post will talk about how to call the PaLM 2 API with pure Dart in Flutter.
Getting Started
Make sure you have the Flutter SDK installed and an API key for the PaLM API.
In a terminal window create a new directory and Flutter project:
mkdir flutter_ai_example
cd flutter_ai_example
flutter create .
Then run the following to add the required dependencies to you pubspec.yaml
:
flutter pub add flutter_dotenv mustache_template http
API Keys
Now create a .env
and the root of the project and add the API key you created earlier to the file:
GOOGLE_AI_API_KEY=[Your API Key Here]
Update lib/main.dart
main method to be async and load the .env
file on launch:
+ import 'package:flutter_dotenv/flutter_dotenv.dart';
- void main() {
+ Future<void> main() async {
+ await dotenv.load(fileName: ".env");
This example loads the API key into the bundle as plain text but for production apps you need to call the API from a server
Firebase has an extension for securely calling the API from your mobile app. 🎉
In addition you can help prevent abuse to your API by using App Check. 🔐

API Wrapper
Create a new file called lib/palm_api.dart
and add the following:
import 'dart:convert';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:mustache_template/mustache_template.dart';
import 'package:http/http.dart' as http;
class PalmApi {
final String template;
final String model;
PalmApi(
this.template, {
this.model = 'text-bison-001',
this.settings = const {
"temperature": 0.7,
"top_k": 40,
"top_p": 0.95,
"candidate_count": 1,
"max_output_tokens": 1024,
"stop_sequences": [],
"safety_settings": [
{"category": "HARM_CATEGORY_DEROGATORY", "threshold": 1},
{"category": "HARM_CATEGORY_TOXICITY", "threshold": 1},
{"category": "HARM_CATEGORY_VIOLENCE", "threshold": 2},
{"category": "HARM_CATEGORY_SEXUAL", "threshold": 2},
{"category": "HARM_CATEGORY_MEDICAL", "threshold": 2},
{"category": "HARM_CATEGORY_DANGEROUS", "threshold": 2}
]
},
});
Uri _createUrl(String apiKey) {
const domain = 'https://generativelanguage.googleapis.com';
final path = 'v1beta3/models/$model:generateText';
return Uri.parse('$domain/$path?key=$apiKey');
}
final Map<String, Object?> settings;
Future<List<String>> execute([Map<String, Object?> args = const {}]) async {
// Load the API key from .env
final apiKey = dotenv.env['GOOGLE_AI_API_KEY'];
if (apiKey == null) throw Exception('GOOGLE_AI_API_KEY Required in .env');
// Create the API url to call the correct model
final uri = _createUrl(apiKey);
// Render the prompt with the tokens
final text = Template(template).renderString(args);
// Call the API with the model settings and prompt template
final response = await http.post(
uri,
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
"prompt": {"text": text},
...settings
}),
);
// Check for a successful response and parse out the results
if (response.statusCode == 200) {
final body = response.body;
final json = jsonDecode(body) as Map<String, dynamic>;
final candidates = (json['candidates'] as List<dynamic>)
.map((e) => e as Map<String, dynamic>)
.toList();
return candidates.map((e) => e['output'] as String).toList();
}
// Default to empty result set
return [];
}
}
Here we are using Mustache to add tokens to our prompt that we pass to the API. This will feel familiar if you are used to working with MakerSuite and makes it easier to iterate on prompts and desired outputs.
You can also copy the config from MakerSuite if you want to change the model or other settings.
Example
Prompt Template
To call the API with a prompt we can start by creating a template:
const _template = '''
Generate a valid SVG that does not include animations based on the following UI description "{{description}}".
Make sure that the content is centered in the middle of the svg.
The width will be {{width}}.
The height will be {{height}}.
The viewbox will be 0 0 {{width}} {{height}}.
''';
Here we are adding tokens for description, width, and height that we will pass in later. Notice that the template is a const
since it will reuse this string at compile time.
Now we can create the API wrapper:
final api = PalmApi(_template);
Passing Tokens
To call the API we can pass in the tokens we defined earlier:
final results = await api.execute({
'description': 'Red rectangle with blue circle',
'width': 300,
'height': 600,
});
Since the API can return different results we can check for just the SVG code and extract it out:
final res = results.first;
var result = res.trim();
final startIdx = result.indexOf('```');
final endIdx = result.lastIndexOf('```');
result = result.substring(startIdx + 3, endIdx).trim();
if (result.startsWith('svg')) {
result = result.replaceFirst('svg', '').trim();
}
if (result.startsWith('xml')) {
result = result.replaceFirst('xml', '').trim();
}
result = result.trim();
If result
is not empty then we can work with it as an SVG string now 🎉
import 'package:flutter_svg/flutter_svg.dart';
...
SvgPicture(SvgStringLoader(result))
Conclusion
If you still want to explore PaLM 2 in Flutter further check out this codelab.