Cross Platform NLP GUI on Flutter | by Doug Foo | Towards Data Science

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!
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:
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.
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.
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.
- <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
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).
Thanks for reading.
[1] Prior article on my Flutter NLP Chat Project— https://medium.com/flutter-community/nlp-chat-on-flutter-azure-676aa4768fbb
[2] Prior article on learning Flutter — https://codeburst.io/why-i-a-sr-manager-learned-flutter-8da9a05b2326?source=---------5------------------
[3] Nice article that inspired me — https://towardsdatascience.com/a-practitioners-guide-to-natural-language-processing-part-i-processing-understanding-text-9f4abfd13e72
[4] Some info on BERT and a few other NLP models— https://medium.com/swlh/bert-bidirectional-encoder-representations-from-transformers-c1ba3ef5e2f4