Cross Platform NLP GUI on Flutter
By: Doug Foo
Tags: Machine Learning, NLP, Sentiment Analysis, Flutter, Full Stack

Cross Platform NLP GUI on Flutter

Flutter for Android, Tablet, and Web (iOS as well !)

Objectives:

I started a project to build a Killer Chat App that leverages a NLP Sentiment Analyzer to perform realtime chat analysis in live chats as per my last article [2]. This article is the R&D phase of the project:

Backend REST service for Sentiment Analysis

Front end Visualizer to see what the model produces

While I could have done this easier in a Python notebook, I will eventually be building the Chat GUI in Flutter anyways so consider it good practice!

Backend Python Service

After pouring thru a lot of research on variants of NLP Sentiment Analyzers [4], I pulled out a few simple ones to cross-compare:

Vader

TextBlob

Azure Text Analytics (Cognitive Services)

Google Cloud Natural Language API

There are a dozen other libraries and I plan to build my own “Foo NLP”(for the experience) which I will detail in another blog. Eventually, I will add the holy grail BERT [5] but that requires some strategy on how to fine-tune and operate w/o costing me $$$ compute time on Azure.

My REST API has a simple interface:

Input: Text String

Output: Sentiment Score (-1 to +1, ie Negative to Positive scale)

The URL GET format is “http://nlp.foostack.ai/nlp/sa/all?textinput=I love you” which you can test live and see the REST JSON results:

REST service results

The Python implementation uses the Flask web framework and exposes a single REST API which in turn calls some NLP Sentiment Analyzer libraries or webservices and aggregates the results into the JSON response. Easy and cheap hosting on Azure.

Code for the REST service [1]

Flutter Cross Platform GUI

Most everyone knows Flutter is a great Android+iOS cross platform development system, but it also does Web as of mid-2019. The Web support works really well, though has its quirks:

Some 3rd party controls may not work. (Url Launcher, for example, did not work on web until a recent upgrade)

Copy-paste does not work in the Web. Text etc appear like unclickable images or something odd (I need to investigate further)

Dev cycle is a little clunky building & testing web separately

Adding custom web controls or HTML/JS appears difficult

In the end, the Flutter Web is more than enough for FooStack’s customers.

Structure of my App

Flutter nests everything in sub-Widgets. Ie, a Column widget to stack items vertically, Padding widgets to add space, Text widget for labels, etc. Makes for an easy lego-like interchangeable system. Just figure out the component to grab and stack it above, below, or inside another widget.

Abstract Structure of my Flutter App:

- <Widget build>

- Scaffold # shortcut with top,body,footer areas

- appBar:

- body:Center # centers all subcomponents

- Column # aligns subcomponents down the col

- Padding

- Text # title (Foo Sentiment Analyzer)

- ContrainedBox # width controlling container

- TextFormField # input box for text to analyze

- FlatButton # submit button

- Text # title (Results)

- Wrap # wrap n-results across and down

- Container

- Column # single column result table

- DataTable # formatted results table

- DataColumns # headers

- DataCells # rows

- floatingButton: # bottom right help button

Visualization of the same logical App:

Visual representation of Flutter code/layout

Actual Dart/Flutter code of the App

The other interesting bit of code is how we call the REST service from the GUI. On the Go button, we have an event handler “onPressed” which is mapped to the _submit function.

FlatButton (

child: Text('Go'),

color: Colors.blue,

textColor: Colors.white,

onPressed: _submit,

),

We define _submit() as a method that makes an HTTP request to our REST service which returns a JSON. The JSON is remapped to a List of Maps for the GUI to process. There is more to how GUI updates are done automatically that I won’t get into (StatefulWidgets etc).

void _submit() async {

// call REST service and extract JSON body

var host = 'http://flaskmli.azurewebsites.net/nlp/sa/alldata=';

var response = await http.get(host+inputController.text);

var resp = response.body; // extract JSON "results" array to a Map (dictionary)

// push it onto the new dataList array (list of Maps)

Map<String, dynamic> nlps = jsonDecode(resp);

List<dynamic> results = nlps['results'];

List<Map<String, dynamic>> dataList = [];

results.forEach((result) {

dataList.add(result);

}); // bit of hack here, add input text to _rawContentList

_rawContentList.insert(0,[dataList, inputController.text])

inputController.text = ''; // reset focus (clears keyboard on mobile devices)

FocusScope.of(context).requestFocus(FocusNode());

setState(() {}); // make GUI refresh from _rawContentList

}

All Done! I’m getting better at Flutter, this only took a few days to build.

I can build and publish my Android, Tablet and iPhone app thru Android Studio and Google Play Store [3]. To publish my Flutter Web app, I just run “flutter build web” and manually deploy the web/build artifacts to my webserver (literally copy them to an existing site, in my case to http://foostack.ai/nlp — feel free to test it out).

Live Foostack NLP try it out http://foostack.ai/nlp

Thanks for reading.