Watson api using node.js - node.js

I am trying to use this node.js code to use watson api which is in ibm cloud bluemix in our ios app. Can anybody tell me what this code is doing and provide us an answer how to use the watson service from our app.
var express = require('express');
var https = require('https');
var url = require('url');
// setup middleware
var app = express();
app.use(express.errorHandler());
app.use(express.urlencoded()); // to support URL-encoded bodies
app.use(app.router);
app.use(express.static(__dirname + '/public')); //setup static public directory
app.set('view engine', 'jade');
app.set('views', __dirname + '/views'); //optional since express defaults to CWD/views
// There are many useful environment variables available in process.env.
// VCAP_APPLICATION contains useful information about a deployed application.
var appInfo = JSON.parse(process.env.VCAP_APPLICATION || "{}");
// TODO: Get application information and use it in your app.
// defaults for dev outside bluemix
var service_url = '<service_url>';
var service_username = '<service_username>';
var service_password = '<service_password>';
// VCAP_SERVICES contains all the credentials of services bound to
// this application. For details of its content, please refer to
// the document or sample of each service.
if (process.env.VCAP_SERVICES) {
console.log('Parsing VCAP_SERVICES');
var services = JSON.parse(process.env.VCAP_SERVICES);
//service name, check the VCAP_SERVICES in bluemix to get the name of the services you have
var service_name = 'question_and_answer';
if (services[service_name]) {
var svc = services[service_name][0].credentials;
service_url = svc.url;
service_username = svc.username;
service_password = svc.password;
} else {
console.log('The service '+service_name+' is not in the VCAP_SERVICES, did you forget to bind it?');
}
} else {
console.log('No VCAP_SERVICES found in ENV, using defaults for local development');
}
console.log('service_url = ' + service_url);
console.log('service_username = ' + service_username);
console.log('service_password = ' + new Array(service_password.length).join("X"));
var auth = "Basic " + new Buffer(service_username + ":" + service_password).toString("base64");
// render index page
app.get('/', function(req, res){
res.render('index');
});
// Handle the form POST containing the question to ask Watson and reply with the answer
app.post('/', function(req, res){
// Select healthcare as endpoint
var parts = url.parse(service_url +'/v1/question/healthcare');
// create the request options to POST our question to Watson
var options = { host: parts.hostname,
port: parts.port,
path: parts.pathname,
method: 'POST',
headers: {
'Content-Type' :'application/json',
'Accept':'application/json',
'X-synctimeout' : '30',
'Authorization' : auth }
};
// Create a request to POST to Watson
var watson_req = https.request(options, function(result) {
result.setEncoding('utf-8');
var response_string = '';
result.on('data', function(chunk) {
response_string += chunk;
});
result.on('end', function() {
var answers_pipeline = JSON.parse(response_string),
answers = answers_pipeline[0];
return res.render('index',{'questionText': req.body.questionText, 'answers': answers})
})
});
watson_req.on('error', function(e) {
return res.render('index', {'error': e.message})
});
// create the question to Watson
var questionData = {
'question': {
'evidenceRequest': {
'items': 5 // the number of anwers
},
'questionText': req.body.questionText // the question
}
};
// Set the POST body and send to Watson
watson_req.write(JSON.stringify(questionData));
watson_req.end();
});
// The IP address of the Cloud Foundry DEA (Droplet Execution Agent) that hosts this application:
var host = (process.env.VCAP_APP_HOST || 'localhost');
// The port on the DEA for communication with the application:
var port = (process.env.VCAP_APP_PORT || 3000);
// Start server
app.listen(port, host);

Majority of this code is required for Node and for executing in the BlueMix environment. VCAP_SERVICES is the Bluemix environment variable that you use to obtain credentials for a given service that you are interested in using. In this case the service_name is set to "question_and_answer" to access the Question and Answer platform service.
In your Bluemix environment, you should have a Question and Answer service instance and an application. When the application is bound to the Question and Answer service it creates a service binding. The service binding has the application credentials to access the service instance. In this case, VCAP_SERVICES contains the URL, username and password of the binding used to communicated and authenticate with the service instance.
From your iOS app you will need a couple of things. First, you need a service binding and you have to, for now, create that in Bluemix. Once you have the credentials in Bluemix then you may use those in your iOS app. Or you could host an application on Bluemix and let that handle communication with Watson.
Next, you need the capability to invoke the Question and Answer service which is a RESTful service. In the code above, the variable options contains the necessary information to POST a question to the Watson service. Note that the service_url obtained from the credentials is appended with an additional path information to use the Watson For Healthcare domain.
From there you can create your question. Variable questionData contains the question in the code above. The question.questionText property is set to the question that you want to ask Watson, like, "Should I take aspirin on a daily basis?".
Then you can POST the question to Watson, as the following snippet does:
watson_req.write(JSON.stringify(questionData));
Node is asynchronous, so the response is handled in the http.request(...). The answer is sent back to the requesting application in
result.on('end', function() {
var answers_pipeline = JSON.parse(response_string),
answers = answers_pipeline[0];
return res.render('index',{'questionText': req.body.questionText, 'answers': answers})
})
Rest of the code is node specific. But I've outlined the basics that you need in your iOS application.

All the code is to handle a HTTPS request to the Watson Question and Answer service.
If you want to use the service in your IOs app you will have to:
Modify the nodejs code and add REST API capabilities.
For example, you should have an endpoint to receive a questions and return answers:
app.get('/api/question', function(req, res){
// Call the service with a question and get an array with the answers
var answers = watson.question(req.query);
// Send the answers and the question to the client in json
res.json({answers: answers, question: req.query.question});
});
Start your app in bluemix and save the URL, it will be something like:
http://my-cool-app.mybluemix.net
Call your API at http://my-cool-app.mybluemix.net/api/question?question=Watson
Notes:
For the IOs app you can use AFNetworking.
You should also read move about the question and answer service documentation here, and read the about the service API here

Related

Get my Action’s server URL in (JavaScript) fulfilment code

I am using actionssdk and I build my Action fulfilments using Javascript and node.js + Express.
I am looking for a way to get the url (protocol + host name + port) of the server where the fulfilment is hosted.
Is there a simple way to do this? E.g. in the MAIN intent? Is there some conv-property I can use? Can I get hold of a req-parameter in the MAIN-intent, from which I can deduct hostname etc?
const express = require('express');
const expressApp = express();
const { actionssdk, ... } = require('actions-on-google');
const app = actionssdk({
ordersv3: true,
clientId: ...
});
expressApp.post('/fulfilment', app);
app.intent('actions.intent.MAIN', (conv) => {
let myUrl: string = ... // ???????
...
});
(background: obviously I know myself to where I deployed my fulfilment code. But I have a reusable template for fulfilment code in which I want to refer to the host url, and I do not want to type that in manually each time I develop a new Action).
You can get access to the request object in a middleware via Framework Metadata which is by default of type BuiltinFrameworkMetadata which contains objects used by Express
For example, you can use it like this, which will be ran before each request:
app.middleware((conv, framework) => {
console.log(framework.express.request.headers.host)
})

Creating an API to wrap an... API?

This isn’t a specific issue question, but I’m trying to wrap my head around the concept of REST APIs and calling an API within your own API.
For example, if I develop an App called “BeesBees”, where users can buy bees, and I have a database of logins and passwords and obviously the bees, and how much each cost, I understand that I can used my own apps BeesBees API to get the list of bees (and if I make it open for other people, they can also use my GET /bees point to get, well, the bees)
But if I want to allow customers to buy the bees, and I don’t want to build a whole platform for doing so, so I integrate Stripe - could I have a POST /:users/charges/:priceOfBee API call that, in turn, called the Stripe API function somewhere somehow? For example, pointing to the URL of a Node.js project that will make the charge using Stripe’s Node.js SDK.
Or, in a case like this, would it be better to just implement the Stripe SDK for my device’s platform and make the charge using the device?
I have no code base so there’s nothing to pick apart, but I couldn’t think of anywhere else to ask, sorry y’all
You can certainly wrap APIs with other APIs, it's really just a form of composition, delegate to other services where it makes sense to do so.
Stripe integration might well be a good example of where it could make sense to follow this pattern. You certainly don't want to roll your own payment service.
Here's a trivial example of a local Express server making an API request:
const express = require("express");
const port = 3000;
const app = express();
const request = require('request');
app.get("/api/example", (req, res) => {
// Make external REST request here...
let options = {
url: 'https://httpbin.org/get',
qs: { parameter1: 42 },
json: true
}
request(options, (err, response, body) => {
if (err) {
res.status(500).send(err.message);
} else {
res.status(200).send(body);
}
});
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('running at http://' + host + ':' + port)
});
console.log(`Serving at http://localhost:${port}`);

Connecting Amazon Alexa to web_lirc, best practice?

I have successfully created demo project where i can control an infrared transmitter using the Amazon Echo Alexa.
Moving forward with my project I'm not sure what the best practices would be in relation to performance and mostly important security. I will explain the project below and elaborate on the issues:
Installed nodejs server on a Raspberry pi running on port 1234
Installed web_lirc to be able to have an nodejs api interface to LIRC
Created an AWS-lambda skill based on the HelloWorld nodejs template with my own simple "hack" working but not pretty :) See code snippet below:
var http = require('http');
var host = '12.34.56.78'; // (no http/https !)
var port = 3000;
var cmd = '';
function performMacroRequest(endpoint, data)
{
cmd = '/macros/' + endpoint;
//console.log('cmd: ' + cmd);
var options = {
host : host,
port : port,
path : cmd, // the rest of the url with parameters if needed
method : 'POST'
};
http.request(options, function(res)
{
console.log('performMacroRequest - STATUS: ' + res.statusCode);
res.on('data', function (chunk)
{
console.log(cmd + ': '+ chunk);
});
}).end();
}
//
var APP_ID = "protected by me"; // Amazon Alexa hardware ID
HelloWorld.prototype.intentHandlers = {
// register custom intent handlers
"HelloWorldIntent": function (intent, session, response)
{
response.tellWithCard("Hello World!", "Hello World", "Hello World!");
},
"IRIntent": function (intent, session, response)
{
performMacroRequest('TESTTV','');
},
"AMAZON.HelpIntent": function (intent, session, response) {
response.ask("You can say hello or cake to me!", "You can say hello or cake to me!");
}
};
The issues as i see them, but are not sure how to address:
The best and most secure way to control my Raspberry web service from AWS. What would be the best option to control external hardware, is that using a webservice and what about protection?
Currently i need to have the port open in my router, so basically everyone with access to my IP could control my raspberry using JSON POST/GET commands. What could be a potential solution, is that to add an overlaying web interface with password protection?
Is it possible to have Alexa talking directly with my hardware on LAN without going trough AWS Lambda?
Overall i think I'm asking for the best practices(technically/security) on having Alexa to access local nodejs server.
Please let me know if anything has to be elaborated or explained in more details.
/Thomas

Skype Bot responding with empty body

I'm trying to get a Skype bot up and running based off of the echo example but I'm struggling to make a successful POST to my app. When I send a post to /v1/chat I get back a status of 201 (successful creation), and nothing in the body. My console.log does not print anything either, which leads me to believe that the botService.on('personalMessage', ...) function is not being run. Does anyone have any insight into how these POST requests should be formatted? I cannot seem to find anything in the documentation.
My code:
const fs = require('fs');
const restify = require('restify');
const skype = require('skype-sdk');
const botService = new skype.BotService({
messaging: {
botId: '28:<bot’s id="ID176db9ab-e313-4d76-a60c-bc2a280e9825">',
serverUrl : "https://apis.skype.com",
requestTimeout : 15000,
appId: process.env.APP_ID,
appSecret: process.env.APP_SECRET
}
});
botService.on('contactAdded', (bot, data) => {
console.log('contact added');
bot.reply('Hello ${data.fromDisplayName}!', true);
});
botService.on('personalMessage', (bot, data) => {
console.log('message incoming');
console.log(data);
bot.reply('Hey ${data.from}. Thank you for your message: "${data.content}".', true);
});
const server = restify.createServer();
server.post('/v1/chat', skype.messagingHandler(botService));
const port = process.env.PORT || 8080;
server.listen(port);
console.log('Listening for incoming requests on port ' + port);
Final Edit & Solution: I think the problem caused by Heroku somehow(it could be something with their free tier ,1 dyno). After some effort, I uploaded the program to Azure, and it is now working perfectly.
Potential Solution: You need to change the server address in the server.post command. If you run your program in "https:\www.yourwebsite.com/v1/chat" , you need to modify this;
server.post('/v1/chat', skype.messagingHandler(botService));
to this;
server.post('https:\\www.yourwebsite.com/v1/chat', skype.messagingHandler(botService));
Of course, don't forget to specify your app id, bot id, and app secret. If you don't have one, you need to generate a password in your Skype application page.
I have the exact problem with the OP. I followed the tutorial, and it doesn't specify how to modify our code to comply with our server. So, after running the program it only returns this;
{"code":"ResourceNotFound","message":"/ does not exist"}
In the Echo example in the Skype Bot Webpage; it says;
"We'll assume the bot's URL for messaging was set to https://echobot.azurewebsites.net/v1/chat during registration."
Make sure that Procfile and worker processes are setup.
My bot is working fine on heroku itself

How to do an emit from different / another route?

I'm using express js & socket.io to built my simple app.
So, there is website "a" using PHP that will post some data to my app (built using express js). There are 2 routes defined in app.js, they are :
/send_voting_result -> Will receive POST data from website "a"
/voting_result -> Will be accessed by user & I want to make it to be realtime in updating the voting result data posted to /send_voting_result
What I did here are :
app.js
var app = require('express')()
, server = require('http').createServer(app)
, io = require('socket.io').listen(server);
...
// Receive POST data and do update the data to /voting_result route
app.post('/send_voting_result', function(req, res){
var result = JSON.parse(req.body.kandidat);
io.of('/voting_result').emit('getResult', {votingResult : result.data});
});
app.get('/voting_result', function(req, res){
res.render('voting_result', { title: 'Express', msg: 'This is Result page'});
});
voting_result.html
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect();
socket.on('getResult', function (data) {
console.log("Message from server : "+data);
});
</script>
However, the "emit" process in this script seems not working :
io.of('/voting_result').emit('getResult', {votingResult : result.data});
I'm unable to retrieve data posted to /send_voting_result in /voting_result
Actually, I'm new in using expressjs & socket.io, so I try my best to achieve it by referring to some related tutorial, but it's still not working.
Is there a proper way to do this?
Thanks in advance
The io.of() method you're using doesn't refer to the URL of the accessed webpage. It instead refers to a namespace that you can define when you create the socket:
// Client-side
var chat = io.connect('http://localhost/chat')
// Server-side
var chat = io
.of('/chat')
.on('connection', function (socket) { ... }) // will only apply to some connections
This feature is used for instance to multiplex multiple data streams on one WebSocket, see Socket.io's documentation, section Restricting yourself to a namespace.
There are then two solutions for your issue:
Don't use namespaces at all:
io.of('/voting_result').emit('getResult', {votingResult : result.data});
becomes
io.emit('getResult', {votingResult : result.data});
Define a namespace on the client, that you'll use on server-side:
var socket = io.connect('/voting_result');

Resources