Building in minutes a Django application that is using IBM Watson APIs to analyse comments.

Introduction

IBM, under the general brand of "Watson", is offering a banch of cloud, Artificial Inteligence services that you can use in two ways:

Give to your applications the power of cognitive computing Analysing structured/unstructure data, comming to conclussions about your business

This article will stay on technical level, demonstrating how you can get started in a few minutes bulding a web application that is using one of those services.

Article's concept

The concept is to build a web application with just one form. The user is writting a comment and submits the form. Then the application is using "Alchemy API" to identify the positive or negative sentiment of user's comment, reporting it to the user with a simple json.

This will only use one of the following 13 functions of the API:

Entity Extraction

Sentiment Analysis (this is what we are using)

Emotion Analysis

Keyword Extraction

Concept Tagging

Relation Extraction

Taxonomy Classification

Author Extraction

Language Detection

Text Extraction

Microformats Parsing

Feed Detection

Linked Data Support

You can check each one of the links to get informed about the possibilities.

Bluemix registration and your apikey

The first thing you need to do is to create an account . Then you have to login , click on "Watson" and then on "Get started now!" icon.

Click "AlchemyAPI" and create your Credentials with the free pricing plan selected.

You will end up with a JSON like this bellow:

{

"credentials":{

"url":"https://gateway-a.watsonplatform.net/calls",

"note":"It may take up to 5 minutes for this key to become active",

"apikey":"28ab5b1a1a080b13v130c0145a65f565723fefe6"

}

}

For our API calls in our demo we will only need the "apikey".

Our environment

This will be a rapid development of a basic Django project you may be familiar with. We will describe the process in detail in order to use it for other demonstrations in the future.

Specifically we assoume that you have a linux machine (we are using just a raspberry pi) with python 3 and virtualenv installed.

Create a python virtual environment and activate it:

username@hostname ~$ virtualenv watson_env -p python3

Running virtualenv with interpreter /usr/local/bin/python3

Using base prefix '/usr/local'

New python executable in /home/username/watson_env/bin/python3

Also creating executable in /home/username/watson_env/bin/python

Installing setuptools, pip, wheel...done.

username@hostname ~$ source watson_env/bin/activate

(watson_env) username@hostname ~$

Install watson-developer-cloud library with dependencies:

(watson_env) username@hostname ~$ pip install watson-developer-cloud

Collecting watson-developer-cloud

Collecting pysolr<4.0,>=3.3 (from watson-developer-cloud)

Using cached pysolr-3.5.0-py2.py3-none-any.whl

Collecting requests<3.0,>=2.0 (from watson-developer-cloud)

Using cached requests-2.10.0-py2.py3-none-any.whl

Installing collected packages: requests, pysolr, watson-developer-cloud

Successfully installed pysolr-3.5.0 requests-2.10.0 watson-developer-cloud-0.18.0

Install Django:

(watson_env) username@hostname ~$ pip install Django

Collecting Django

Downloading Django-1.9.8-py2.py3-none-any.whl (6.6MB)

100% |--------------------------------| 6.6MB 25kB/s

Installing collected packages: Django

Successfully installed Django-1.9.8

Creating the project

Start a new django project:

(watson_env) username@hostname ~$ django-admin startproject watson_project

Make database migrations:

(watson_env) username@hostname ~/watson_project$ python manage.py migrate

Operations to perform:

Apply all migrations: contenttypes, sessions, admin, auth

Running migrations:

Rendering model states... DONE

Applying contenttypes.0001_initial... OK

Applying auth.0001_initial... OK

Applying admin.0001_initial... OK

Applying admin.0002_logentry_remove_auto_add... OK

Applying contenttypes.0002_remove_content_type_name... OK

Applying auth.0002_alter_permission_name_max_length... OK

Applying auth.0003_alter_user_email_max_length... OK

Applying auth.0004_alter_user_username_opts... OK

Applying auth.0005_alter_user_last_login_null... OK

Applying auth.0006_require_contenttypes_0002... OK

Applying auth.0007_alter_validators_add_error_messages... OK

Applying sessions.0001_initial... OK

Run your development server (ignore the IP:port that fits to my envorinment):

(watson_env) username@hostname ~/watson_project$ python manage.py runserver 192.168.25.1:8080

...and point your browser to this url:

http://192.168.25.1:8080

Bulding the App

Now it is time for some real work. Create a new django application:

(watson_env) username@hostname ~/watson_project$ python manage.py startapp watson_app

Go to your settings.py file and add the new application and the apikey as a setting:

~/watson_project/watson_project/settings.py

# ... # Application definition INSTALLED_APPS = [ 'django.contrib.admin' , 'django.contrib.auth' , 'django.contrib.contenttypes' , 'django.contrib.sessions' , 'django.contrib.messages' , 'django.contrib.staticfiles' , 'watson_app' , ] # APIKEY = '28ab5b1a1a080b13v130c0145a65f565723fefe6'

Now create the form:

~/watson_project/watson_app/forms.py

from django import forms from django.http import HttpResponse from django.conf import settings # Watson dependencies import json from os.path import join , dirname from watson_developer_cloud import AlchemyLanguageV1 # Getting APIKEY variable from settings APIKEY = getattr ( settings , "APIKEY" , None ) # Watson authentication alchemy_language = AlchemyLanguageV1 ( api_key = APIKEY ) class CommentForm ( forms . Form ): comment = forms . CharField ( label = "Comment" , widget = forms . Textarea ( attrs = { 'rows' : 10 }), required = True ) def ask_watson ( self ): text = self . cleaned_data [ 'comment' ] combined_operations = [ 'doc-sentiment' ] return alchemy_language . combined ( text = text , extract = combined_operations )

...the view:

~/watson_project/watson_app/views.py

from django.shortcuts import render from django.http import HttpResponse import json # Create your views here. from django.views.generic.edit import FormView from watson_app.forms import CommentForm class CommentView ( FormView ): template_name = 'comment.html' form_class = CommentForm success_url = '.' def form_valid ( self , form ): serialized_json = json . dumps ( form . ask_watson () , sort_keys = True , indent = 4 ) return HttpResponse ( serialized_json , content_type = "application/json" )

...the html template:

~/watson_project/watson_app/templates/comment.html

<div class= "row" > <div class= "col s12" > <h3> Comment </h3> <form action= "" method= "post" > { % csrf_token % } { { form.as_p } } <button class= "btn waves-effect waves-light" type= "submit" name= "action" > Submit <i class= "mdi-content-send right" ></i> </button> </form> </div> </div>

...and add to your urls.py the pattern for your view:

~/watson_project/watson_project/urls.py

# .... urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^watson/', CommentView.as_view(), name='comment'), ]

Testing

The application is ready to go. Run your server (again ignore the IP:port):

(watson_env) username@hostname ~/watson_project$ python manage.py runserver 192.168.16.12:8080

... and give the url http://192.168.16.12:8080/watson to your users for some testing.

For example this comment:

...gives the following answer:

{ "docSentiment": { "mixed": "1", "score": "-0.492867", "type": "negative" }, "language": "english", "status": "OK", "usage": "By accessing AlchemyAPI or using information generated by AlchemyAPI, you are agreeing to be bound by the AlchemyAPI Terms of Use: http://www.alchemyapi.com/company/terms.html" }

This comment though:

...gives another answer:

{ "docSentiment": { "score": "0.697192", "type": "positive" }, "language": "english", "status": "OK", "usage": "By accessing AlchemyAPI or using information generated by AlchemyAPI, you are agreeing to be bound by the AlchemyAPI Terms of Use: http://www.alchemyapi.com/company/terms.html" }

Beautify

Now lets use Google Charts to beautify the response.

Edit your view to extract the score from Watson response and add it as 'score' variable to the context dictionary:

~/watson_project/watson_app/views.py

from django.template.response import TemplateResponse from django.shortcuts import render from django.http import HttpResponse , HttpResponseNotFound from django.http import JsonResponse import json # Create your views here. from django.views.generic.edit import FormView from watson_app.forms import CommentForm class CommentView ( FormView ): template_name = 'comment.html' form_class = CommentForm success_url = '.' def form_valid ( self , form ): watsonresponse = form . ask_watson () score = float ( watsonresponse [ 'docSentiment' ][ 'score' ]) * 100 context = self . get_context_data () context [ 'score' ] = score return render ( self . request , 'comment.html' , context )

Your new template:

~/watson_project/watson_app/templates/comment.html

<html> <body> <div class= "row" > <div class= "col s12" > <h3> Comment </h3> <form action= "" method= "post" > { % csrf_token % } { { form.as_p } } <button class= "btn waves-effect waves-light" type= "submit" name= "action" > Submit <i class= "mdi-content-send right" ></i> </button> </form> </div> </div> <script type= "text/javascript" src= "https://www.gstatic.com/charts/loader.js" ></script> <div id= "chart_div" style= "width: 400px; height: 120px;" ></div> <script> google . charts . load ( 'current' , { 'packages' : [ 'gauge' ]}); google . charts . setOnLoadCallback ( drawChart ); function drawChart () { var score = { { score } } var data = google . visualization . arrayToDataTable ([ [ 'Label' , 'Value' ], [ 'Score' , score ] ]); var options = { width : 400 , height : 120 , redFrom : - 100 , redTo : - 50 , yellowFrom :- 50 , yellowTo : 0 , minorTicks : 5 , min : - 100 }; var chart = new google . visualization . Gauge ( document . getElementById ( 'chart_div' )); chart . draw ( data , options ); } </script> </body> </html>

Enjoy:

Trying to fool it:

Keep in mind that Watson is getting smarter every day. ;)