The app will allow users to enter ingredients in the textbox and they will get the personalized recipe recommendation based on their inputs through the capabilities of OpenAI .
Step 1: Create a new Flutter project
Step 2: Add Dependencies
dependencies:
http: ^0.13.0
Step 3: Design the App UI and Integrate OpenAI API with Flutter UI
In this technical blog post, we will walk through the process of creating a travel itinerary app using Flutter and integrating the OpenAI ChatGPT API. By leveraging the cross-platform capabilities of Flutter and the conversational intelligence of ChatGPT, we can develop an app that assists users in planning their trips and generates personalized itineraries based on their preferences.
Step 1: Setting Up the Development Environment
Install Flutter: Follow the official Flutter installation guide for your operating system.
Set Up an Editor: Choose an IDE or text editor for Flutter development, such as Visual Studio Code or Android Studio, and install the necessary plugins and extensions.
Step 2: Creating a New Flutter Project
Open your terminal or command prompt and run the command flutter create your_app_name to create a new Flutter project.
Step 3: Adding Dependencies
chat_gpt_sdk: ^2.1.7
Step 4: Designing the User Interface and Integrating OpenAI ChatGPT API
I developed a basic user interface using the Dart language to gather user input. The input will be used as a variable in the prompt for Chat GPT. Upon submission, the UI will generate a travel itinerary based on the provided user data.
OpenAI ChatGPT API:
Create an OpenAI account and obtain an API key for authentication.You can find the API key at here.
Note: No free version of Chat GPT API is available now. However, you can start for free with $5 in free credit that can be used during your first 3 months. Check details here
Chat GPT SDK
There is a SDK wrapper for OpenAI's APIs in Flutter, which assists in seamlessly integrating ChatGPT into your Flutter applications.
Add Chat GPT SDK and import it in your file and use following code to request and get response from Open AI's Chat GPT.
Business logic components (BLoC) allow you to separate the business logic from the UI. Using Bloc, we can easily separate the application into multiple layers, first we would have the presentation layer which would contain the UI/Views/widgets, then the business logic layer (Bloc) which will take care about the state changes and will have a dependency on the data access layer which contains a repository class which will act as an abstract class above the data access object classes.
class Recipe {
Recipe({
required this.publisher,
required this.title,
required this.sourceUrl,
required this.recipeId,
required this.imageUrl,
required this.socialRank,
required this.publisherUrl,
});
String publisher;
String title;
String sourceUrl;
String recipeId;
String imageUrl;
double socialRank;
String publisherUrl;
factory Recipe.fromJson(Map<String, dynamic> json) => Recipe(
publisher: json["publisher"],
title: json["title"],
sourceUrl: json["source_url"],
recipeId: json["recipe_id"],
imageUrl: json["image_url"],
socialRank: json["social_rank"]?.toDouble(),
publisherUrl: json["publisher_url"],
);
Map<String, dynamic> toJson() => {
"publisher": publisher,
"title": title,
"source_url": sourceUrl,
"recipe_id": recipeId,
"image_url": imageUrl,
"social_rank": socialRank,
"publisher_url": publisherUrl,
};
}
import 'package:searchscreen/data/model/pizza.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
abstract class SearchRepository{
Future<List<Recipe>> searchPizza(String query);
}
class SearchRepositoryImpl implements SearchRepository{
List<Recipe> recipes=[];
@override
Future<List<Recipe>> searchPizza(query) async{
try{
var response= await http.get( Uri.parse('https://forkify-api.herokuapp.com/api/search?q=$query' ));
if (response.statusCode == 200) {
var data = json.decode(response.body);
recipes = Pizza
.fromJson(data)
.recipes;
return recipes;
} else
{
return recipes;
}
}
catch(error){
throw (error.toString());
}
}
}
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:searchscreen/bloc/search/search_event.dart';
import 'package:searchscreen/bloc/search/search_state.dart';
import 'package:searchscreen/data/model/pizza.dart';
import 'package:searchscreen/data/repositories/search_repository.dart';
class SearchBloc extends Bloc<SearchEvent,SearchState> {
final SearchRepository repository;
SearchBloc(this.repository) : super(SearchUninitialized()) {
on<Search>(
(event, emit) async {
try {
emit(SearchLoadingState());
final List<Recipe> recipes = await repository.searchPizza(event.query);
emit(SearchLoaded(recipes: recipes));
} catch (e,stackTrace) {
emit(SearchErrorState(message: e.toString()));
}
});
}
}
bloc/search_event.dart
import 'package:equatable/equatable.dart';
abstract class SearchEvent extends Equatable{
const SearchEvent();
}
class Search extends SearchEvent{
late String query;
Search({required this.query});
@override
List<Object> get props => [];
}
bloc/search_state.dart
import 'package:equatable/equatable.dart';
import 'package:searchscreen/data/model/pizza.dart';
abstract class SearchState extends Equatable{
}
class SearchUninitialized extends SearchState{
@override
List<Object?> get props =>[];
}
class SearchLoadingState extends SearchState{
@override
List<Object?> get props => [];
}
class SearchLoaded extends SearchState{
final List<Recipe> recipes;
SearchLoaded({required this.recipes});
@override
List<Object?> get props => [];
}
class SearchErrorState extends SearchState{
final String message;
SearchErrorState({required this.message});
@override
List<Object?> get props => [];
}
main.dart
import 'package:flutter/material.dart';
import 'package:searchscreen/bloc/search/search_bloc.dart';
import 'package:searchscreen/data/repositories/search_repository.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:searchscreen/ui/search_view.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return
RepositoryProvider(
create: (context) =>PizzaRepositoryImpl() ,
child: MultiBlocProvider(
providers: [
BlocProvider<PizzaBloc>(
create: (context) => PizzaBloc(PizzaRepositoryImpl()
)..add(FetchPizzaEvent()),lazy: false,),
BlocProvider<SearchBloc>(
create: (context) => SearchBloc(SearchRepositoryImpl()
))
],
child: MaterialApp(
title: 'Recipe Search App',
home: SearchView(),
)),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:searchscreen/bloc/search/search_bloc.dart';
import 'package:searchscreen/bloc/search/search_event.dart';
import 'package:searchscreen/bloc/search/search_state.dart';
import 'package:searchscreen/ui/list.dart';
import 'package:searchscreen/widgets/search_text_field.dart';
class SearchView extends StatefulWidget {
const SearchView({super.key});
@override
SearchViewState createState() => SearchViewState();
}
class SearchViewState extends State<SearchView> {
final TextEditingController _controller = TextEditingController();
@override
void initState() {
super.initState();
_controller.addListener(
() => context
.read<SearchBloc>()
.add(Search(query: _controller.text))
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocConsumer<SearchBloc, SearchState>(
listener: (context, state) {
if (state is SearchErrorState) {
ScaffoldMessenger.of(context)
..hideCurrentSnackBar()
..showSnackBar(
const SnackBar(content: Text("Failed to Load")),
);
}
},
builder: (context, state) {
return Scaffold(appBar: AppBar(
title: const Text(
'Recipes'
)
),body:ListView(
shrinkWrap: true,
children: [
Card (child: SearchTextField(
key: const Key('searchPage_searchTextField'),
controller: _controller,
),),
const Divider(),
if(state is SearchLoaded)
buildHintsList(state.recipes)
],
));
},
);
}
}
|
|
|
Firebase is using the same storage infrastructure as google cloud .
1. Go to https://console.cloud.google.com and select the dashboard of the project that contains the firebase storage.
2. On the top right, there will be a button named "Activate Cloud Shell", click on it, a terminal will open on the bottom of the page
Click on Open Editor
Click on File, and New file.
3.Create new file with name cors.json, paste the following save.
[
{
"origin": ["*"],
"method": ["GET"],
"maxAgeSeconds": 3600
}
]
4.On your Firebase Console and select "Storage" and get your storage bucket URL (e.g gs://
)
5.Then open the terminal again and paste following
gsutil cors set cors.json gs://<your-cloud-storage-bucket>
The CORS error should be gone for Storage for which we added the configuration. It wont be applied to other storage bucket
You can automate Flutter Web Deployments to Firebase Hosting using GitHub. After the configuration and setup ,all you need to do is push your local code to GitHub and view your application on web using URL .
https://firebase.google.com/docs/hosting/quickstart#install-cli
Step 2 : Initialize your project
firebase init hosting:github
Step 3 : Follow the CLI prompts, and the command will automatically take care of setting up the GitHub Action
Once the configuration is complete, there will be two new files written:
- .firebaserc : Basic config for the project. It consist of your project name on firebase;
- firebase.json: Additional config. Tells Firebase about the public folder, which files/folders to ignore
Web App link for Invoice Portal Invoice Portal App lets an user view and create an Invoice. Features: View the list of Number of Invoices b...