Wolfram Alpha is a computational knowledge engine that allows users to submit a question, any question, and receive a comprehensive answer. It uses natural language understanding to parse user queries and retrieve answers from a highly curated data set. With Wolfram Alpha, you can give knowledge of geography, history, mathematics, earth science and many, many more subjects to your application.
They also provide an API that lets you build computational knowledge into your web, mobile, or enterprise app. And it was a perfect fit for PubNub BLOCKS. Our new Wolfram Alpha block enables users to submit a question via PubNub, and receive or publish the answer to any number of users in real time.
Intelligent Computation with Wolfram Alpha
In this article, we dive into a simple example of how to build question-and-answer functionality into a real-time AngularJS web application. In the past few years, there have been tremendous advances in natural language understanding and semantic representation. With Wolfram Alpha, we show how to give these knowledge capabilities to your real-time application.
As we prepare to explore our sample AngularJS web application with question-and-answer features, let's check out the underlying Wolfram Alpha API.
Wolfram Alpha API
Natural language understanding and semantic representation are notoriously difficult areas, and they requires substantial effort and engineering resources to maintain high quality results across the wide range of information available on the web.
Wolfram Alpha provides a solution to these issues with a friendly UI and easy-to-use API that “just works.” Through the API and user interface, it is possible to answer real-world queries and provide structured information in response to user messages in real time.
Getting Started with Wolfram Alpha API
The next thing you'll need to get started with natural language understanding services is a Wolfram Alpha account to take advantage of the Wolfram Alpha APIs.
- Step 1: Go to the Wolfram Alpha signup form.
- Step 2: Click the “get a new AppID” button and create a new AppID.
- Step 3: Make note of the AppID and use it in the appropriate code section below.
Setting up the BLOCK
With PubNub BLOCKS, it's really easy to create code to run in the network. Here's how to make it happen:
- Step 1: go to the application instance on the PubNub Admin Portal.
- Step 2: create a new block.
- Step 3: paste in the block code from the next section and update the credentials with the AppID from the previous steps above.
- Step 4: Start the block, and test it using the “publish message” button and payload on the left-hand side of the screen.
That's all it takes to create your serverless code running in the cloud!
Diving into the Code – the BLOCK
You'll want to grab the 25 lines of BLOCK JavaScript and save them to a file, say, pubnub_wolfram_block.js
. It's available as a Gist on GitHub for your convenience.
First up, we declare our dependencies: xhr
and query
(for HTTP requests).
const xhr = require('xhr'); const query = require('codec/query_string');
Next, we create a method to handle incoming messages, declare the AppID for accessing the Wolfram Alpha service, and set up the base URL for talking to the remote web service.
export default (request) => { const appId = 'YOUR_WOLFRAM_ALPHA_APP_ID'; const spoken = 'http://www.wolframalpha.com/api/v1/spoken-json.jsp';
Next, we set up the HTTP options for the metrics API request. We use a GET request to retrieve the query answer. We use query parameters for the API, and post a queryParams
value with 2 parts: the AppID, and the user's query text.
const queryParams = { appid: appId, input: request.message.text }; const apiUrl = spoken + '?' + query.stringify(queryParams);
Finally, we call the query endpoint with the given user query, store the answer result in the message's answer
attribute, and catch any errors and log to the BLOCKS console. Pretty easy!
return xhr.fetch(apiUrl) .then((r) => { const body = JSON.parse(r.body || r); request.message.answer = body.result || body.error; return request.ok(); }) .catch((e) => { console.error(e); return request.ok(); }); };
All in all, it doesn't take a lot of code to add question-and-answer functionality to your application. We like that!
OK, let's move on to the UI!
Diving into the Code – the User Interface
You'll want to grab these 70 lines of HTML & JavaScript and save them to a file, say, pubnub_wolfram_ui.html
.
The first thing you should do after saving the code is to replace two values in the JavaScript:
- YOUR_PUB_KEY: with the PubNub publish key mentioned above.
- YOUR_SUB_KEY: with the PubNub subscribe key mentioned above.
If you don't, the UI will not be able to communicate with anything and probably clutter your console log with entirely too many errors.
For your convenience, this code is also available as a Gist on GitHub, and a Codepen as well. Enjoy!
Dependencies
First up, we have the JavaScript code & CSS dependencies of our application.
<!doctype html> <html> <head> <script src="https://code.jquery.com/jquery-1.10.1.min.js"></script> <script src="https://cdn.pubnub.com/pubnub-3.15.1.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script> <script src="https://cdn.pubnub.com/sdk/pubnub-angular/pubnub-angular-3.2.1.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css" /> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" /> </head> <body>
For folks who have done front-end implementation with AngularJS before, these should be the usual suspects:
- JQuery : gives us the ability to use easy JQuery selectors.
- PubNub JavaScript client: to connect to our data stream integration channel.
- AngularJS: were you expecting a niftier front-end framework? Impossible!
- PubNub Angular JavaScript client: provides PubNub services in AngularJS quite nicely indeed.
- Underscore.js: we could avoid using Underscore.JS, but then our code would be less awesome.
In addition, we bring in 2 CSS features:
- Bootstrap: in this app, we use it just for vanilla UI presentation.
- Font-Awesome: we love Font Awesome because it lets us use truetype font characters instead of image-based icons. Pretty sweet!
Overall, we were pretty pleased that we could build a nifty UI with so few dependencies. And with that… on to the UI!
The User Interface
Here's what we intend the UI to look like:
The UI is pretty straightforward – everything is inside a div
tag that is managed by a single controller that we'll set up in the AngularJS code.
<div class="container" ng-app="PubNubAngularApp" ng-controller="MyQandACtrl"> <pre> NOTE: make sure to update the PubNub keys below with your keys, and ensure that the Q&A BLOCK is configured properly! </pre> <h3>MyApp Questions & Answers</h3>
We provide a simple text input for a user question to send to the PubNub channel as well as a button to perform the publish()
action.
<input ng-model="toSend" /> <input type="button" ng-click="publish()" value="Send!" />
Our UI consists of a simple list of questions and answers. We iterate over the messages in the controller scope using a trusty ng-repeat
. Each message includes the question and answer (or error message if the question could not be understood).
<ul> <li ng-repeat="message in messages track by $index"> Q: {{message.text}} <br /> A: {{message.answer}} </li> </ul>
And that's it – a functioning real-time UI in just a handful of code (thanks, AngularJS)!
The AngularJS Code
Right on! Now we're ready to dive into the AngularJS code. It's not a ton of JavaScript, so this should hopefully be pretty straightforward.
The first lines we encounter set up our application (with a necessary dependency on the PubNub AngularJS service) and a single controller (which we dub MyQandACtrl
). Both of these values correspond to the ng-app
and ng-controller
attributes from the preceding UI code.
<script> angular.module('PubNubAngularApp', ["pubnub.angular.service"]) .controller('MyQandACtrl', function($rootScope, $scope, Pubnub) {
Next up, we initialize a bunch of values. First is an array of message objects which starts out empty. After that, we set up the channel as the channel name where we will send and receive real-time structured data messages. NOTE: make sure this matches the channel specified by your BLOCK configuration!
$scope.messages = []; $scope.channel = 'wolfram-channel';
We initialize the Pubnub
object with our PubNub publish and subscribe keys mentioned above, and set a scope variable to make sure the initialization only occurs once. NOTE: this uses the v3 API syntax.
if (!$rootScope.initialized) { Pubnub.init({ publish_key: 'YOUR_PUB_KEY', subscribe_key: 'YOUR_SUB_KEY', ssl:true }); $rootScope.initialized = true; }
The next thing we'll need is a real-time message callback called msgCallback
; it takes care of all the real-time messages we need to handle from PubNub. In our case, we have only one scenario – an incoming message containing the question-and-answer values. We unshift the message object onto the scope array; that unshift()
operation should be in a $scope.$apply()
call so that AngularJS gets the idea that a change came in asynchronously.
var msgCallback = function(payload) { $scope.$apply(function() { $scope.messages.unshift(payload); }); };
The publish()
function takes the contents of the text input, publishes it as a structured data object to the PubNub channel, and resets the text box to empty.
$scope.publish = function() { Pubnub.publish({ channel: $scope.channel, message: {text:$scope.toSend} }); $scope.toSend = ""; };
In the main body of the controller, we subscribe()
to the message channel (using the JavaScript v3 API syntax) and bind the events to the callback function we just created.
Pubnub.subscribe({ channel: [$scope.channel], message: msgCallback });
We mustn't forget close out the HTML tags accordingly.
}); </script> </body> </html>
Not too shabby for seventy lines of HTML & JavaScript!
Conclusion
With that, we've built an intelligent Q&A application built right into your real-time streams of data via PubNub. Hopefully it's been a useful experience learning about natural-language-enabled technologies. In future articles, we'll dive deeper into additional web service APIs and use cases for other real-time web applications.