HOW TO TEST ROBOMATIC REST API WITH FLUTTER?
(Build a chat app — chat interface — with Flutter to communicate with RoboMatic)
In recent years, new tools have been designed to improve the interactions between human and machine. These are chatbots or virtual assistants. Even if the concept of chatbot goes back to the beginning of computers and human-machine interaction, it is only from 2016 onwards that they will be increasingly popular thanks to the involvement of large companies such as Google and Facebook.
A chatbot is a software designed to conduct conversations with human users using their natural languages. Conversations often require full understanding of words, sentences and contexts. There are :
Rule-based chatbots that have been designed for a specific need with predefined responses and limited interactions;
AI chatbots which use natural language processing (NLP) technologies to identify the user’s intent and translate the meaning to a machine in which it replies back with a suitable response or action.
Natural Language Processing (NLP) is a field of computer science, artificial intelligence and computational linguistics concerned with the interactions between computers and human (natural) languages.
Chatbots can be used in almost every field from marketing to medicine, social interaction (disrupted especially in this time of pandemic), entertainment …etc.
Too much talking !!!,
What is the main subject of this article?
To have some fun, I propose to test the integration of the RoboMatic.AI chatbot in a small Flutter application.
RoboMatic is a chatbot built by InfraDrive and under improvements since 2003. It’s based on a custom NLP engine built from scratch which can be integrated in desktop, web, mobile or IoT applications to be used in businesses or personal purposes.
You can build your own chatbot using this platform, then integrate it with your application using: embedded script, POST requests or Websocket connections.
We will use RapidAPI to access RoboMatic’s RestAPI. You will need to register and obtain your own x-rapidapi-host and x-rapidapi-key.
Here are the links:
Pre-requisites:
- Register on RapidAPI and subscribe to RoboMatic API :
- Make sure you have your x-rapidapi-host and x-rapidapi-key.
Here’s what you get:
- Project setup and dependencies: Flutter SDK, version 1.22.5,
- Packages
We will use:
Animated Splash Screen to build our splash screen. Learn more here.
http to make HTTP requests. Learn more here.
intl to format and parse date. Learn more here,
toast to display message toast. Learn more here.
So, let’s code. Just follow me along the steps.
1. Create a splash screen
Replace the code in main.dart with the following code:
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:robomatic/ChatScreen.dart';
import 'package:animated_splash_screen/animated_splash_screen.dart';
import 'package:page_transition/page_transition.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: "RoboMatic.AI Chatbot",
//home: new SplashScreen(),
home: AnimatedSplashScreen(
duration: 20500,
//image or logo
splash: "assets/images/roboHead.jpg",
splashIconSize: 500,
nextScreen: new MyChatScreen(),
splashTransition: SplashTransition.sizeTransition,
pageTransitionType: PageTransitionType.leftToRight,
backgroundColor: Colors.white70
)
);
}
}
As I told you before, for the splash screen, I used: Animated Splash Screen package. Learn more here.
2. Create a UI for displaying messages
We need a widget to display user’ chat message or RoboMatic response. A widget that represents a single chat message.
Create a StatelessWidget
called MessageBox
as follows:
MessageBox.dart
import 'package:flutter/material.dart';
class MessageBox extends StatelessWidget {
MessageBox({this.sender, this.message, this.side, this.datetime});
final String sender;
final String message;
final String side;
final String datetime;
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: side == 'leftside'//if sender is robomatic
? Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
//datetime
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 6.0),
decoration: BoxDecoration(
color:Color.fromRGBO(85,75,200, 1.0),
border: Border.all(
color:Color.fromRGBO(85,75,200, 1.0),
width: .25,
style: BorderStyle.solid),
borderRadius: BorderRadius.only(
topRight: Radius.circular(0.0),
topLeft: Radius.circular(0.0),
bottomRight: Radius.circular(5.0),
bottomLeft: Radius.circular(5.0),
),
),
alignment: Alignment.bottomLeft,
padding: const EdgeInsets.only(
top: 0.0, bottom: 8.0, left: 8.0, right: 8.0),
child: Text(
datetime,
style: TextStyle(
fontSize: 12.0,
color: Colors.white,
),
),
width: 180.0,
),
],
),
//message
Stack(
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 6.0),
decoration: new BoxDecoration(
color:Colors.white,
border: new Border.all(
color:Colors.white,
width: .25,
style: BorderStyle.solid),
borderRadius: BorderRadius.only(
topRight: Radius.circular(5.0),
topLeft: Radius.circular(5.0),
bottomRight: Radius.circular(0.0),
bottomLeft: Radius.circular(0.0),
),
),
alignment: Alignment.bottomLeft,
padding: const EdgeInsets.all(8.0),
child: new Text(
message,
style:TextStyle(
fontFamily: 'Roboto',
fontSize: 20.0,
color: Colors.black,
),
),
width: 180.0,
),
],
),
//sender
Container(
margin: EdgeInsets.only(left: 6.0),
decoration: BoxDecoration(
color: Colors.white70,
border: Border.all(
color: Colors.white70,
width: .25,
style: BorderStyle.solid),
borderRadius: BorderRadius.only(
topRight: Radius.circular(0.0),
topLeft: Radius.circular(0.0),
bottomRight: Radius.circular(5.0),
bottomLeft: Radius.circular(5.0),
),
),
alignment: Alignment.bottomLeft,
padding: const EdgeInsets.only(
top: 0.0, bottom: 8.0, left: 8.0, right: 8.0),
child: Text(
sender,
style: TextStyle(
fontSize: 12.0,
color: Colors.black54,
),
),
width: 180.0,
),
],
),
],
))
: Row( //if sender is user
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
//datetime
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.only(right: 6.0),
decoration: BoxDecoration(
color:Color.fromRGBO(85,75,200, 1.0),
border: Border.all(
color:Color.fromRGBO(85,75,200, 1.0),
width: .25,
style: BorderStyle.solid),
borderRadius: BorderRadius.only(
topRight: Radius.circular(0.0),
topLeft: Radius.circular(0.0),
bottomRight: Radius.circular(5.0),
bottomLeft: Radius.circular(5.0),
),
),
alignment: Alignment.bottomRight,
padding: const EdgeInsets.only(
top: 0.0, bottom: 8.0, left: 8.0, right: 8.0),
child: Text(
datetime,
style: TextStyle(
fontSize: 12.0,
color: Colors.white,
),
),
width: 180.0,
),
],
),
//message
Stack(
alignment: Alignment.topRight,
children: <Widget>[
Container(
margin: EdgeInsets.only(right: 6.0),
decoration: BoxDecoration(
color: Color.fromRGBO(127, 124, 255, 1.0),
border: Border.all(
color: Color.fromRGBO(127, 124, 255, 1.0),
width: .25,
style: BorderStyle.solid),
borderRadius: BorderRadius.only(
topRight: Radius.circular(5.0),
topLeft: Radius.circular(5.0),
bottomRight: Radius.circular(0.0),
bottomLeft: Radius.circular(0.0),
),
),
alignment: Alignment.bottomRight,
padding: const EdgeInsets.all(8.0),
child: Text(
message,
style: TextStyle(
fontFamily: 'Roboto',
fontSize: 22.0,
color: Color(0xffffffff),
),
),
width: 180.0,
),
],
),
//sender
Container(
margin: EdgeInsets.only(right: 6.0),
decoration: BoxDecoration(
color: Colors.white70,
border: Border.all(
color: Colors.white70,
width: .25,
style: BorderStyle.solid),
borderRadius: BorderRadius.only(
topRight: Radius.circular(0.0),
topLeft: Radius.circular(0.0),
bottomRight: Radius.circular(5.0),
bottomLeft: Radius.circular(5.0),
),
),
alignment: Alignment.bottomRight,
padding: const EdgeInsets.only(
top: 0.0, bottom: 8.0, left: 8.0, right: 8.0),
child: Text(
sender,
style: TextStyle(
fontSize: 12.0,
color: Colors.black54,
),
),
width: 180.0,
),
],
),
],
),
);
}
}
The widget in question is composed of a Row
which display a Container
containing (oh la la ça pique les yeux) the date and the time the message was sent, a Container
containing the message itself and a Container
containing the sender’s name.
Depending on the sender of the message(user or RoboMatic), the widget containing the message will appear on the left or right side of the screen. This is why the variable side
exists.
For this UI, I was inspired by:
*this codelab:
https://codelabs.flutter-io.cn/codelabs/flutter/index.html#0
*and this repository:
3. Build the chat screen
Create a file called MyChatScreen.dart
import 'dart:core';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:intl/intl.dart';
import 'package:robomatic/Message.dart';
import 'dart:convert';
import 'dart:convert' as convert;
import 'package:toast/toast.dart';
class MyChatScreen extends StatefulWidget {
const MyChatScreen({Key key, this.title}) : super(key: key);
final String title;
@override
_MyChatState createState() => new _MyChatState();
}
class _MyChatState extends State<MyChatScreen> {
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Chat with RoboMatic' ,style: TextStyle(
//color: Colors.amber,
color:Colors.white,
fontSize: 19.0,
fontFamily: "Roboto",
fontStyle: FontStyle.normal,
fontWeight: FontWeight.bold,
),),
//backgroundColor: Colors.black,
backgroundColor: Color.fromRGBO(54,54,154,1.0),
centerTitle: true,
shadowColor: Colors.black12,
bottomOpacity: 0.5,
toolbarOpacity: 0.8,
),
);
}
}
— Add a UI for composing messages
First of all, let’s add a body
to our Scaffold:
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Chat with RoboMatic' ,style: TextStyle(
//color: Colors.amber,
color:Colors.white,
fontSize: 19.0,
fontFamily: "Roboto",
fontStyle: FontStyle.normal,
fontWeight: FontWeight.bold,
),),
//backgroundColor: Colors.black,
backgroundColor: Color.fromRGBO(54,54,154,1.0),
centerTitle: true,
shadowColor: Colors.black12,
bottomOpacity: 0.5,
toolbarOpacity: 0.8,
),
//new
//Add body to our Scaffold
body: Container( //New
width: double.infinity,
height: double.infinity,
color:Color.fromRGBO(85,75,200, 1.0),
child: Container(
child: Column(
children: <Widget>[
Container(
decoration:
BoxDecoration(color: Theme.of(context).cardColor),
child: IconTheme(
data: IconThemeData(
color: Theme.of(context).accentColor),
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 2.0),
child: Row(
children: <Widget>[
//child widgets (input field and scrolling list) will be added here
],
),
))),
],
),
)),
);
Roughly speaking, our body
consists of a large Container
whose child
is another Container
which, in turn, contains a Column
widget. The Column
widget which lays out its direct children vertically will take child widgets, a scrolling list and a row for an input field.
Widget for composing messages
We need that widget to allows users to enter chat messages by typing a non-empty string and send their typed messages by pressing the graphical Send button next to the input field.
We use a TextEditingController
object to manage interactions with the field:
- Read contents of the input field,
- Clear the text typed once submitted,
class _MyChatState extends State<MyChatScreen> {
final _textController = TextEditingController();//new
@override
void initState() {
super.initState();
}
//Override dispose method
@override
void dispose() {
_textController.dispose();//new
super.dispose();
}
Add an interactive text input field:
Our body
become:
Add a new method to _MyChatState()
class:
The callback method _handleSubmit()
allows to notify when the user submits a message. _handleSubmit()
returns a future that completes some operations. Future is a core Dart class for working with asynchronous operations. Because it doesn’t return a usable value,_handleSubmit()
has the type Future<void>.
The Send button onPressed
property, use an anonymous function to invoke the _handleSubmit()
method. This callback method first allows to notify when the user submits a message. The message is passed by using _textController
. The values of the parameters side
and datetime
are passed also (they will be need later).
— Implement a chat message list
We can use a List
member called _messages
to get the list of chat messages and show it in the UI. This list must be scrollable so that users can view the chat history. Each list item is a MessageBox
instance.
In _MyChatState()
class:
Once the message is sent by the user, the application adds the new message to the list of messages thanks to setState()
call.
The _handleSubmit() method’s new face is set out as follows:
Place the message list
We will need a ListView
widget to display the list of messages. Modify the build()
method as follows:
For more explanations on all the widgets used for all these UIs please refer to this link:
— Get response from RoboMatic
Remember, the _handleSubmit() method allows to add the message entered by the user to the messages list. This same method should allow to send the user’s message to the API for a response. So modify the _handleSubmit()
method as follows :
In setState()
, we called a new method, botMaticApiRequest(),
that will allow us to :
- Send the user’s message to RoboMatic;
- Retrieve the response from RoboMatic;
- Add RoboMatic’s response to the messages list;
This is botMaticApiRequest()
:
The documentation of RoboMatic.AI has all the details on the parameters you can insert and how you can use them. There is the link for the documentation: https://robomatic.ai/#
4. Get full source code
Sorry for the length of this article. But all in all you can clone the project from my GitHub. Please give it a star while cloning.
Thanks for reading this article ❤
And if something went wrong, let me know in the comments section.