Open In App

How to Create a ChatBot Application using ChatGPT API in Flutter?

A ChatBot is a computer program that uses Artificial Intelligence (AI) and Natural Language Processing (NLP) to understand customers’ questions and give responses to them simulating human behavior. Building our own ChatBot from scratch requires us to train the Machine Learning (ML) model with rigorous amounts of text-based data, providing it with different contexts of real-world conversations. Now we don’t need to perform that meticulous task, as OpenAI already developed ChatGPT which was trained on billions of words of textual data which made it very powerful.

In this article, we will explain the total process of building a Mobile ChatBot Application using ChatGPT API and Flutter. We will be using Flutter Framework to build the application for Android. Flutter is an open-source framework developed and supported by Google to build and deploy hybrid applications quickly.



A sample video is given below to get an idea about what we are going to do in this article.

What is ChatGPT?

ChatGPT is a Large Language Model (LLM) developed by OpenAI that lets users enter prompts to receive textual information asked by the user. The language model can answer questions and assist you with tasks, such as composing emails, essays, and code. The “GPT” in ChatGPT refers to “Generative Pretrained Transformer”, in simple terms it uses Transformer architecture to respond to user’s prompts.



What is ChatGPT API?

API stands for Application Programming Interface. An API provides an interface to communicate with the resource/backend. Likewise, OpenAI had also created an API for developers to access this language model. The API is not totally free, OpenAI gives 5$ credit on signup which is more than enough for this project. We need to get an API key to proceed. Follow the below steps to continue!

Steps to Get API Key

To use the ChatGPT API, we need to create an account with OpenAI and generate an API key. If you have already used ChatGPT, you already have an account.

Note: You can skip this step if you already have an account.

Voila! you now have a brand new ChatGPT account to proceed with.

Generate API Key

Login to your account and head over to the OpenAI Platform.

In the top right corner of the screen, click on your account name and then select “API Keys” from the drop-down menu.

On the API Keys page, click the “Create new secret key” button, name your key (optional), and click on “Create secret key” to get your brand new key. Now copy the key and save it anywhere which we later need in this project.

Create an Application using Flutter

Tools Required

To build this app, you require the following tools on your machine :

  1. Visual Studio Code (Recommended IDE)
  2. Android Emulator / Original Device for testing.
  3. Flutter SDK
  4. Flutter Plugin for VS Code.

Create a New Project

Follow these steps to create a brand new project to make building the app.

Step-by-Step Implementation

Step 1:

After the initial setup of the project, you get a folder structure like this.

Open main.dart file from the lib folder.

Step 2:

Add the following required packages in the pubspec.yaml file just below the dependencies section which we are going to use in our app.

Step 3:

Create a new file named chat_screen.dart in the lib folder.

Step 4:

Import the material file using the following statement in the newly created file.

import 'package:flutter/material.dart';

Import the below files for the working of the application.

import 'package:http/http.dart' as http;
import 'package:chat_bubbles/chat_bubbles.dart';

Step 5:

Open the AndroidManifest.xml file which is available under the android/app/src/main folder. Add the following line above the <application> tag to give the app internet permission to communicate with the language model.

<uses-permission android:name="android.permission.INTERNET" />

Step 6:

Create a Stateful Widget named ChatScreen to code the UI and Logic of the app. You can also use the below template to create the widget.




class ChatScreen extends StatefulWidget {
  const ChatScreen({super.key});
 
  @override
  State<ChatScreen> createState() => _ChatScreenState();
}
 
class _ChatScreenState extends State<ChatScreen> {
  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}

Create a new file named message.dart in the lib folder. Below is the Dart code for it.




class Message {
  bool isSender;
  String msg;
  Message(this.isSender, this.msg);
}

Step 7:

Declare the following variables inside the ChatScreenState class i.e. above the build widget for future usage.




TextEditingController controller = TextEditingController();
ScrollController scrollController = ScrollController();
List<Message> msgs = [];
bool isTyping = false;

Usage of the above code

Dart Code for UI

Step 8:

Now, we need a chatbox at the bottom of the screen to type the text and a send button for sending the typed prompt to the chatbot for getting a response from it. Below is the Dart UI code for the same.




Row(
            children: [
              Expanded(
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Container(
                    width: double.infinity,
                    height: 40,
                    decoration: BoxDecoration(
                        color: Colors.grey[200],
                        borderRadius: BorderRadius.circular(10)),
                    child: Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 8),
                      child: TextField(
                        controller: controller,
                        textCapitalization: TextCapitalization.sentences,
                        onSubmitted: (value) {
                          sendMsg();
                        },
                        textInputAction: TextInputAction.send,
                        showCursor: true,
                        decoration: const InputDecoration(
                            border: InputBorder.none, hintText: "Enter text"),
                      ),
                    ),
                  ),
                ),
              ),
              InkWell(
                onTap: () {
                  sendMsg();
                },
                child: Container(
                  height: 40,
                  width: 40,
                  decoration: BoxDecoration(
                      color: Colors.blue,
                      borderRadius: BorderRadius.circular(30)),
                  child: const Icon(
                    Icons.send,
                    color: Colors.white,
                  ),
                ),
              ),
              const SizedBox(
                width: 8,
              )
            ],
          ),

Usage of the above code

Step 9:

Now we are remaining with adding chat bubbles (The individual rounded rectangular boxes that appear for each message). This can be achieved with the package that we imported previously – chat_bubbles. Below is the Dart UI code implementing it.




Expanded(
            child: ListView.builder(
                controller: scrollController,
                itemCount: msgs.length,
                shrinkWrap: true,
                reverse: true,
                itemBuilder: (context, index) {
                  return Padding(
                      padding: const EdgeInsets.symmetric(vertical: 4),
                      child: isTyping && index == 0
                          ? Column(
                              children: [
                                BubbleNormal(
                                  text: msgs[0].msg,
                                  isSender: true,
                                  color: Colors.blue.shade100,
                                ),
                                const Padding(
                                  padding: EdgeInsets.only(left: 16, top: 4),
                                  child: Align(
                                      alignment: Alignment.centerLeft,
                                      child: Text("Typing...")),
                                )
                              ],
                            )
                          : BubbleNormal(
                              text: msgs[index].msg,
                              isSender: msgs[index].isSender,
                              color: msgs[index].isSender
                                  ? Colors.blue.shade100
                                  : Colors.grey.shade200,
                            ));
                }),
          ),

Usage of the above code

Here is the final image of the UI that is coded up until now.

Dart Code for Functionality

Step 10:

The core function sendMsg() is implemented in this step. Add this function below the variables declared at the start. Below is the dart code for the same.

Note: Replace your-api-key with the API key that you generated and saved in past.




void sendMsg() async {
    String text = controller.text;
    String apiKey = "your-api-key";
    controller.clear();
    try {
      if (text.isNotEmpty) {
        setState(() {
          msgs.insert(0, Message(true, text));
          isTyping = true;
        });
        scrollController.animateTo(0.0,
            duration: const Duration(seconds: 1), curve: Curves.easeOut);
        var response = await http.post(
            Uri.parse("https://api.openai.com/v1/chat/completions"),
            headers: {
              "Authorization": "Bearer $apiKey",
              "Content-Type": "application/json"
            },
            body: jsonEncode({
              "model": "gpt-3.5-turbo",
              "messages": [
                {"role": "user", "content": text}
              ]
            }));
        if (response.statusCode == 200) {
          var json = jsonDecode(response.body);
          setState(() {
            isTyping = false;
            msgs.insert(
                0,
                Message(
                    false,
                    json["choices"][0]["message"]["content"]
                        .toString()
                        .trimLeft()));
          });
          scrollController.animateTo(0.0,
              duration: const Duration(seconds: 1), curve: Curves.easeOut);
        }
      }
    } on Exception {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
          content: Text("Some error occurred, please try again!")));
    }
  }

Usage of the above code

Step 11:

The final step remaining is to update the main.dart file where the application starts running the code. Add the following dart code in the main.dart file.




import 'package:chatbot/chat_screen.dart';
import 'package:flutter/material.dart';
 
void main() async {
  runApp(const MyApp());
}
 
class MyApp extends StatelessWidget {
  const MyApp({super.key});
 
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: ChatScreen(),
      debugShowCheckedModeBanner: false,
    );
  }
}

Complete Dart Code (Chat Screen)

Here is the total Dart code representing the chat screen.




import 'dart:convert';
import 'package:chatbot/message.dart';
import 'package:chat_bubbles/bubbles/bubble_normal.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
 
class ChatScreen extends StatefulWidget {
  const ChatScreen({super.key});
 
  @override
  State<ChatScreen> createState() => _ChatScreenState();
}
 
class _ChatScreenState extends State<ChatScreen> {
  TextEditingController controller = TextEditingController();
  ScrollController scrollController = ScrollController();
  List<Message> msgs = [];
  bool isTyping = false;
 
  void sendMsg() async {
    String text = controller.text;
    String apiKey = "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";
    controller.clear();
    try {
      if (text.isNotEmpty) {
        setState(() {
          msgs.insert(0, Message(true, text));
          isTyping = true;
        });
        scrollController.animateTo(0.0,
            duration: const Duration(seconds: 1), curve: Curves.easeOut);
        var response = await http.post(
            Uri.parse("https://api.openai.com/v1/chat/completions"),
            headers: {
              "Authorization": "Bearer $apiKey",
              "Content-Type": "application/json"
            },
            body: jsonEncode({
              "model": "gpt-3.5-turbo",
              "messages": [
                {"role": "user", "content": text}
              ]
            }));
        if (response.statusCode == 200) {
          var json = jsonDecode(response.body);
          setState(() {
            isTyping = false;
            msgs.insert(
                0,
                Message(
                    false,
                    json["choices"][0]["message"]["content"]
                        .toString()
                        .trimLeft()));
          });
          scrollController.animateTo(0.0,
              duration: const Duration(seconds: 1), curve: Curves.easeOut);
        }
      }
    } on Exception {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
          content: Text("Some error occurred, please try again!")));
    }
  }
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Chat Bot"),
      ),
      body: Column(
        children: [
          const SizedBox(
            height: 8,
          ),
          Expanded(
            child: ListView.builder(
                controller: scrollController,
                itemCount: msgs.length,
                shrinkWrap: true,
                reverse: true,
                itemBuilder: (context, index) {
                  return Padding(
                      padding: const EdgeInsets.symmetric(vertical: 4),
                      child: isTyping && index == 0
                          ? Column(
                              children: [
                                BubbleNormal(
                                  text: msgs[0].msg,
                                  isSender: true,
                                  color: Colors.blue.shade100,
                                ),
                                const Padding(
                                  padding: EdgeInsets.only(left: 16, top: 4),
                                  child: Align(
                                      alignment: Alignment.centerLeft,
                                      child: Text("Typing...")),
                                )
                              ],
                            )
                          : BubbleNormal(
                              text: msgs[index].msg,
                              isSender: msgs[index].isSender,
                              color: msgs[index].isSender
                                  ? Colors.blue.shade100
                                  : Colors.grey.shade200,
                            ));
                }),
          ),
          Row(
            children: [
              Expanded(
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Container(
                    width: double.infinity,
                    height: 40,
                    decoration: BoxDecoration(
                        color: Colors.grey[200],
                        borderRadius: BorderRadius.circular(10)),
                    child: Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 8),
                      child: TextField(
                        controller: controller,
                        textCapitalization: TextCapitalization.sentences,
                        onSubmitted: (value) {
                          sendMsg();
                        },
                        textInputAction: TextInputAction.send,
                        showCursor: true,
                        decoration: const InputDecoration(
                            border: InputBorder.none, hintText: "Enter text"),
                      ),
                    ),
                  ),
                ),
              ),
              InkWell(
                onTap: () {
                  sendMsg();
                },
                child: Container(
                  height: 40,
                  width: 40,
                  decoration: BoxDecoration(
                      color: Colors.blue,
                      borderRadius: BorderRadius.circular(30)),
                  child: const Icon(
                    Icons.send,
                    color: Colors.white,
                  ),
                ),
              ),
              const SizedBox(
                width: 8,
              )
            ],
          ),
        ],
      ),
    );
  }
}

Voila, your application is coded entirely and ready to be built, and run to get the output.

Step 12:

To run your app, select Run from the toolbar and click on Run Without Debugging or CTRL + F5 then select your preferred device to test the app. You can modify the code and update the UI as per your choice.

Output

Congratulations on building our chatbot. Here is the final output of the app.


Article Tags :