Introduction
To build your own ChatGPT Powered Mobile app using Flutter, you don't need to be an expert in programming. Flutter is a user-friendly framework that allows you to create mobile applications with ease. You can start developing your app quickly with the easy-to-use interface and helpful documentation. Whether you are new or experienced, Flutter makes it easy to create amazing mobile apps. Today you will learn how to integrate OpenAI's API in your application and make a helpful recipe generator app.
Users can type in the ingredients they have on hand, and the app with the power of OpenAI API generates a tasty recipe that uses those ingredients
Things You are going to learn today
- How to build your own ChatGPT-powered mobile app using Flutter.
- Setting up a Flutter project and creating a basic UI.
- Open AI key generation flow.
- Integrating OpenAI’s API into the app to generate recipe suggestions.
- Sending a POST request to OpenAI’s API with the necessary parameters.
- Displaying the AI-generated recipe on the app’s interface.
Things You Need
- OpenAPI Key
- Basic Understanding of Flutter Framework
- IDE like VSCODE or Android Studio
How to get your own OpenAI key?
OpenAI API is not freely available and comes with a price tag, which is based on tokens used and which model is used, you can access that information here: https://openai.com/pricing
You need to have an API Key in order to use it in your project, therefore first of all login to your OpenAI account by going to this website link:
https://platform.openai.com/api-keys
From this screen, you can obtain your personal key. Ensure it’s confidentiality as sharing it could lead to unauthorized usage, depleting your credits and incurring charges.
Getting Started
Set up your Flutter project:
First, make sure you have Flutter SDK installed and configured on your machine. If not, you can follow the official Flutter installation guide here: https://docs.flutter.dev/get-started/install
Create a new Flutter project using the following command in your VS code Terminal:
flutter create flutter_ai_recipe_app
In “main.dart” file, remove old code and replace with the below code:
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Magic AI Recipe App',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.green,
primary: Colors.black,
),
useMaterial3: true,
),
home: const RecipeScreen(),
);
}
}
In the above code we are basically just calling “RecipeScreen()” and setting the theme for our application.
Now, In your project create a new file named recipe_screen.dart
and Make the UI by pasting this code in your editor:
class RecipeScreen extends StatefulWidget {
const RecipeScreen({super.key});
@override
State createState() =>
_RecipeScreenState(); // Creating the state for this widget
}
class _RecipeScreenState extends State {
late final TextEditingController controller; // Controller for the text field
late final FocusNode focusNode; // Focus node for the text field
final List ingredients = []; // List to store the ingredients
String response = ''; // String to store the response from the AI
@override
void initState() {
super.initState();
controller = TextEditingController(); // Initializing the text controller
focusNode = FocusNode(); // Initializing the focus node
}
@override
void dispose() {
controller.dispose(); // Disposing the text controller when not needed
focusNode.dispose(); // Disposing the focus node when not needed
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Magic AI Recipe App'), // App bar title
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
const Text(
'Find your unique recipe! by typing your ingredients'), // Instruction text
const SizedBox(height: 16.0),
Row(
children: [
Flexible(
child: TextFormField(
controller: controller, // Assigning the controller
focusNode: focusNode, // Assigning the focus node
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Type Your Ingredients', // Placeholder text
),
onFieldSubmitted: (String value) {
// Action on submit
setState(() {
ingredients
.add(value); // Adding the ingredient to the list
controller.clear(); // Clearing the text field
focusNode
.requestFocus(); // Requesting focus for the text field
});
},
),
),
TextButton(
onPressed: () {
// Action on button press
setState(() {
ingredients.add(controller
.text); // Adding the ingredient to the list
controller.clear(); // Clearing the text field
focusNode
.requestFocus(); // Requesting focus for the text field
});
},
child: const Icon(Icons.add), // Button icon
),
],
),
const SizedBox(height: 5.0),
Wrap(
spacing: 8.0,
children: [
for (final String ingredient
in ingredients) // Looping through the ingredients list
Chip(
label: Text(ingredient), // Displaying the ingredient
onDeleted: () {
// Action on delete
setState(() {
ingredients.remove(
ingredient); // Removing the ingredient from the list
});
},
),
],
),
const SizedBox(height: 16.0),
Expanded(
child: SizedBox(
child: Text(response), // Displaying the response from the AI
)),
Align(
alignment: Alignment.bottomCenter,
child: ElevatedButton(
onPressed: () async {
// Action on button press
setState(() => response =
'Thinking'); // Updating the response to 'Thinking'
dynamic temp = await Response().askAi(ingredients.join(
ingredients
.toString())); // Asking the AI for a recipe
print(temp);
setState(() => response = temp
.toString()); // Updating the response with the AI's response
},
child: const Text('Create Recipe'), // Button text
)),
],
),
),
),
);
}
}
In recipe_screen.dart create a stateful class "RecipeScreen" and create basic variables:
late final TextEditingController controller; //for the formField (ingredients)
late final FocusNode focusNode; // focus node for the formField
final List ingredients = [ ];
String response = '';
Let’s Understand these Variables:
- final List<String> ingredients = <String>[]; – It’s a list that will hold the ingredients for the recipe and initializes as an empty list of strings.
- String response = ”; – This string will hold the response from the server.
This Dart code creates a user interface for a recipe app in Flutter. It includes a text field for ingredient input, an add button, and a display area for added ingredients. Ingredients can be submitted through the text field or the add button, and can be removed by clicking on the delete button on each ingredient chip.
Next, Add “http” package in the pubspec.yaml file and run pub get command in terminal The http package is used for making HTTP requests.
http: ^1.1.0
Integrating your chatGPT API
First of all, you need to create a separate dart file named response.dart, and write the following code:
Make sure you use your own key here.
// Importing required libraries
import 'dart:convert';
import 'package:flutter_ai_recipe_app/models/recipe_model.dart';
import 'package:http/http.dart' as http;
// Class to handle responses from the OpenAI API
class Response {
RecipeModel recipeModel = RecipeModel(); // Model to store the response
var choices = []; // List to store the choices from the response
String apiKey =
'sk-ilYnnPBMlp10ORNS8JMfT3BlbkFJF32312FASDED3DFFF3'; // API key for OpenAI(change it)
// Function to send a request to the OpenAI API and get a response
Future askAi(String prompt) async {
try {
// Sending a POST request to the OpenAI API
final response = await http.post(
Uri.parse('https://api.openai.com/v1/chat/completions'),
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer $apiKey',
},
body: jsonEncode(
{
"model": "gpt-3.5-turbo",
"temperature": 0,
"max_tokens": 100,
"top_p": 1,
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{
"role": "user",
"content":
"Create a recipe using the following ingredients: $prompt"
}
],
},
),
);
print(response.body); // Printing the response body
recipeModel = RecipeModel.fromJson(
jsonDecode(response.body)); // Parsing the response body to the model
choices = recipeModel.choices!; // Storing the choices from the response
return choices[0]
.message
.content; // Returning the content of the first choice
} catch (e) {
print('Error occurred: $e'); // Printing the error if any
rethrow;
}
}
}
This defines a Response class with a method askAi. This method sends a POST request to an OpenAI API, passing a prompt to create a recipe using provided ingredients, and uses an API key for authorization.
Now let’s understand this code:
HTTP: This package is used for making API requests in Dart applications.
Response class is responsible for communicating with the OpenAI API.It has three main properties:
recipeModel: An instance of RecipeModel used to store the response from the API.
choices: A list of Choice objects that store the different options provided by the API.
apiKey: The API key used to authenticate with the OpenAI API.
Now let’s talk about the askAi function:
Function askAi: 'askAi' takes a prompt as input and returns a Future, inside this function we are making “HTTP POST request” using the http.post method provided by the http package.Then we set the request headers, including content type and authorization using the API key
final response = await http.post(
Uri.parse('https://api.openai.com/v1/chat/completions'),
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer $apiKey',
},
body: jsonEncode(
{
"model": "gpt-3.5-turbo",
"temperature": 0,
"max_tokens": 100,
"top_p": 1,
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{
"role": "user",
"content":
"Create a recipe using the following ingredients: $prompt"
}
],
},
),
);
print(response.body); // Printing the response body
Let’s go to the body function and understand what's going on here.
This code will send POST request to the ‘OpenAI API’,
Uri.parse('https://api.openai.com/v1/chat/completions'),
Here is the URL where the request is sent.
headers: {
'content-type': 'application/json',
'Authorization': 'Bearer $apiKey',
},
This is the headers of the request. It tells the server that the content of the request is in JSON format and gives the API key for authorization.
body: jsonEncode(
{
"model": "gpt-3.5-turbo",// tells the API to use the "gpt-3.5-turbo" model.
"temperature": 0,// controls the randomness of the AI's output (0 means deterministic).
"max_tokens": 100,// sets the maximum length of the output to 100 tokens.
"top_p": 1,//It is the parameter related to the randomness of the output.
"messages": [
//This is an array of messages that set the context for the AI
. The first message tells the AI that it's a helpful assistant.
The second message is a user's request to create a recipe with the provided ingredients ($prompt).
{"role": "system", "content": "You are a helpful assistant."},
{
"role": "user",
"content":
"Create a recipe using the following ingredients: $prompt"
}
],
},
),
Here we have the body of request. It is converted to a JSON string using jsonEncode function, which commonly used to convert a Dart object into a JSON string.
Creating model
Now let’s create a model for the project.
RecipeModel class represents a response from the OpenAI API.
constructor that takes these six properties as optional parameters.
FactoryConstructor It has a factory constructor fromJson, which creates a RecipeModel instance from a JSON object.
toJson method converts a RecipeModel instance back into a JSON object.
class RecipeModel {
// The unique identifier of the response.
String? id;
// The type of the object in the response.
String? object;
// The time the response was created.
int? created;
// The model used to generate the response.
String? model;
// The choices in the response.
List? choices;
// The usage details of the API call.
Usage? usage;
RecipeModel({
this.id,
this.object,
this.created,
this.model,
this.choices,
this.usage,
});
factory RecipeModel.fromJson(Map json) => RecipeModel(
id: json["id"],
object: json["object"],
created: json["created"],
model: json["model"],
choices:
List.from(json["choices"].map((x) => Choice.fromJson(x))),
usage: Usage.fromJson(json["usage"]),
);
Map toJson() => {
"id": id,
"object": object,
"created": created,
"model": model,
"choices": List.from(choices!.map((x) => x.toJson())),
"usage": usage!.toJson(),
};
}
The Choice class represents a choice in our context.
index: It is the integer representing the index of the choice.
message: This is an instance of the Message class, which represents the message which is associated with the choice.
finishReason: It’s the string representing the reason why the generation of the choice was finished.
class Choice {
int index;
Message message;
String finishReason;
Choice({
required this.index,
required this.message,
required this.finishReason,
});
factory Choice.fromJson(Map json) => Choice(
index: json["index"],
message: Message.fromJson(json["message"]),
finishReason: json["finish_reason"],
);
Map toJson() => {
"index": index,
"message": message.toJson(),
"finish_reason": finishReason,
};
}
The Message class is a model that represents a message in the context.
role: It is the string that represents the role of the message sender. It could be "system", "user", or "assistant".
content: It is the string that represents the content of the message.
class Message {
String role;
String content;
Message({
required this.role,
required this.content,
});
factory Message.fromJson(Map json) => Message(
role: json["role"],
content: json["content"],
);
Map toJson() => {
"role": role,
"content": content,
};
}
Now, Let’s take a look at the UI of the application, you just built:
This is the main screen of the app where you will type the ingredients and hit enter, and then tap the create recipe button.
Type and enter all the ingredients you have in hand and press the create recipe button and see the magic of AI as it generates a recipe for you.
Finally, the app will show you a recipe based on your ingredients you provided, it nicely divides the ingredients and instructions for you, and gives you accurate measurements of ingredients as well. Now, go ahead an experiment with other ingredients and see what the AI has to offer!
Conclusion
Today you learned how easy it is to build your very own Flutter Application that has AI powers and generates a recipe for you based on the items you provide to it.
You first started out with a default flutter project, then you learned how to build a User Interface that is simple and clear.
You learned how to get the API key and learn using that API key how you can send a prompt to OpenAI and get a response in JSON and then made a model that helps with parsing of data and how to display the response to the screen.
If this article has helped in any way and you have learned something new today, Kindly consider sharing the article so others can also benefit and learn how to build simple AI applications.
Subscribe to our website for more interesting articles on AI and other interesting fields of IT.
You can find the code for this project here:
Repository Link:
- Repo link: github
Faheem Ahmed