Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added basic REST API to command center #175

Merged
merged 31 commits into from
Jun 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d7bafd0
Added basic REST API to command center
KamalGalrani May 6, 2017
fef3656
Added API for learning and querying knowledge. Removed duplicate code…
KamalGalrani May 9, 2017
b219f5b
Formatting fixes in README
KamalGalrani May 9, 2017
9b4280e
Merge branch 'master' into command-center-rest-api
KamalGalrani May 12, 2017
6999f20
Merge remote-tracking branch 'upstream/master' into command-center-re…
KamalGalrani May 17, 2017
20d80ac
Fixes
KamalGalrani May 17, 2017
5fc869c
Merged with upstream/master
KamalGalrani May 17, 2017
188b882
Update interface.js
KamalGalrani May 18, 2017
8899dfd
Automating set endpoint and adding config.sh
KamalGalrani May 22, 2017
35d4cca
Fixes
KamalGalrani May 22, 2017
eb25b28
Fixes
KamalGalrani May 22, 2017
d7de1f7
Added phantomjs to dependency
KamalGalrani May 22, 2017
fb26ba2
Fixes
KamalGalrani May 23, 2017
5f5b8db
Fixes
KamalGalrani May 23, 2017
b1c6eaa
Fixes
KamalGalrani May 23, 2017
ddb253e
Made automatic update of endpoint optional
KamalGalrani May 24, 2017
2b073af
README fixes
KamalGalrani May 24, 2017
8fff334
README fixes
KamalGalrani May 24, 2017
fe5bb43
Merge remote-tracking branch 'upstream/master' into command-center-re…
KamalGalrani May 24, 2017
3ce2727
Fixes
KamalGalrani May 24, 2017
285f09f
Fixes for Ubuntu 14.04
KamalGalrani May 25, 2017
6207218
Removed country dependent urls
KamalGalrani May 25, 2017
099f28f
Fixes for Ubuntu 14.04
KamalGalrani May 26, 2017
664c56a
Fixed README
KamalGalrani May 26, 2017
4c29ba4
Fixes Makefile
KamalGalrani May 26, 2017
eaf800e
Fixes Makefile
KamalGalrani May 26, 2017
4901111
Fixes Makefile
KamalGalrani May 26, 2017
fc6138b
Minor fixes
KamalGalrani May 26, 2017
7ba8f29
Merge remote-tracking branch 'upstream/master' into command-center-re…
KamalGalrani May 26, 2017
1d23ccc
Updated README
KamalGalrani May 26, 2017
3ed1ee7
Fixes
KamalGalrani Jun 2, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ see [CONTRIBUTING](CONTRIBUTING.md) for more details.

- Once done, check out the [`tutorial`](tutorial.pdf) for usage and sample questions.

## REST API for command center

The REST API is in active development and may change drastically. It currently supports only infer and learn. Other features may be added later.
An [example client](lucida/botframework-interface) for botframework is available. Information on how to use the API can be found in the [wiki](https://github.com/claritylab/lucida/wiki/REST-API)

## Design Notes -- How to Add Your Own Service into Lucida?

### Back-end Communication
Expand Down
2 changes: 1 addition & 1 deletion lucida/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
SUBDIRS=commandcenter imagematching questionanswering calendar djinntonic weather musicservice # TODO add back in if using kaldi. speechrecognition
SUBDIRS=commandcenter imagematching questionanswering calendar djinntonic weather botframework-interface musicservice # TODO add back in if using kaldi. speechrecognition

include ../Makefile.common
8 changes: 8 additions & 0 deletions lucida/botframework-interface/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
*.bak
credentials.js
config.sh
config.tmp
phantom.out
last_pushed_host
node_modules/
deps/downloads/
20 changes: 20 additions & 0 deletions lucida/botframework-interface/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.PHONY: all start_server clean

all:
ngrok version 2>/dev/null | grep -Pe "ngrok version 2\." 2>&1 1>/dev/null || sudo ./install_ngrok.sh
phantomjs -v 2>/dev/null | grep -Pe "^2\." 2>&1 1>/dev/null || sudo ./deps/install_phantomjs.sh
which node || sudo ./deps/install_node.sh
which npm || sudo ./deps/install_node.sh
npm install

start_server:
bash start_interface.sh

clean:
rm -rf node_modules
rm -f config.tmp
rm -f phantom.out
rm -f credentials.js
rm -f last_pushed_host
rm -rf deps/downloads
mv config.sh config.bak 2>/dev/null && echo "Backed up old config to config.bak" || :
55 changes: 55 additions & 0 deletions lucida/botframework-interface/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
Microsoft BotFramework interface to Lucida
==========================================

This interaface allows accessing Lucida services from BotFramework supported channels like Facebook, Skype, messaging etc. Currently only text infer queries are supported.

## Installation
* Change directory to $LUCIDAROOT/botframework-interface and run `make all`
* Create a new bot at https://dev.botframework.com/bots/new
- Fill in the name, bot handle and description for your bot.
- Click on 'Create Microsoft App ID and password. Then click on generate password. Copy your App ID and password and keep them in a safe place.
- Leave all other fields blank unless you know what you are doing.
- Agree to the terms and click on 'Register' to finish registering your bot.
* You may want to add channels on the bot page. Follow the instructions on https://dev.botframework.com/bots.

## Start Interface
* Change directory to $LUCIDAROOT/botframework-interface and run `make start_server`
* First run will ask some questions. These can be modified later by editing 'config.sh'.

## Add User
* Add the bot to your channel. This can be done using 'Add to Skype' button for Skype channel and adding yourself as developer for corresponding Facebook bot for Facebook Messenger channel.
* Connect your Lucida user to channel user
- Sign in to the web interface of Lucida and click on your username.
- Copy the verification message (Verify <token>) and send it using the channel you want to verify.

## Setting Message Endpoint Manually
While most users should be able to set endpoint automatically, some may face network problems. Automatic update of endpoint will also break if Microsoft updates its website. For such scenarios you can
set the endpoint manually by logging into https://dev.botframework.com/bots, selecting your bot, going to settings and following one of the following methods.

#### If the BotFramework interface for Lucida is running on a https server
* Type the address of the server followed port on which the interface is running and '/api/messages' ( e.g. `https://example.com:3728/api/message` ) and save the changes.
#### If you don't have a server
* Type `ngrok http 3728` to start ngrok. The port 3728 should be changed if interface is running on a different port.
* You'll see a `https://*.ngrok.io` address when ngrok goes online. Copy this appended with '/api/messages' to Messaging endpoint field and save the changes.
* The endpoint will change everytime you restart ngrok. You'll need to change endpoint on https://dev.botframework.com/bots every time you restart ngrok.

## Troubleshooting
#### First one or two messages not being received by command center
This is more of a bug. This happens because the change in endpoint doesn't propagate as it should. I have mailed Microsoft team about this and am waiting for their reply. Don't expect this to be fixed soon as Microsoft doesn't encourage changing endpoint frequently.
#### Microsoft needs additional information to sign you in
This error usually occurs when you run interface on a remote server. Microsoft detects that you are signing in from a different region/PC and asks the interface questions that it cannot currently answer. To fix the error:
* SSH into your remote server with `-D 8888` option passed to openssh (e.g. `ssh -D 8888 user@remote_host` ).
* Open Firefox (not a private window) on your local machine and go to Edit->Preferences->Advanced->Network->Connection->Settings.
* Fill the details as shown below
![proxy_configuration.png](proxy_configuration.png)
* Old versions of Firefox do not have an option to 'Proxy DNS when using SOCKS v5'. If you are using one of those versions
- Navigate to 'about:config'
- Click on 'I accept the risk!'
- Type 'socks' in the search box
- Double click 'network.proxy.socks_remote_dns' to toggle it to true.
* Navigate to 'https://dev.botframework.com/bots/' and sign in
* Run `make start_server` in botframework directory of your remote host
* If everything works fine undo the changes you made to your Firefox. Otherwise create an issue on the git repository.

NOTE: The bot won't be available in bot directory unless you publish it. Till then only the people with 'Add to Skype' link (in case of Skype) and ones listed as developers/testers (in case of Facebook)
will be able to send messages to the bot.
18 changes: 18 additions & 0 deletions lucida/botframework-interface/deps/install_ngrok.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash

mkdir -p deps/downloads
cd deps/downloads
uname -a | grep "x86_64" > /dev/null
if [ $? -eq 0 ]; then
wget -c "https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip" \
&& unzip -o ngrok-stable-linux-amd64.zip \
&& sudo killall ngrok || : \
&& sudo cp ngrok /usr/bin/ngrok
if [ $? -ne 0 ]; then exit 1; fi
else
wget -c "https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-386.zip" \
&& unzip ngrok-stable-linux-386.zip \
&& sudo killall ngrok || : \
&& sudo cp ngrok /usr/bin/ngrok
if [ $? -ne 0 ]; then exit 1; fi
fi
3 changes: 3 additions & 0 deletions lucida/botframework-interface/deps/install_node.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

sudo apt-get install npm && sudo npm install -g n && sudo n lts
18 changes: 18 additions & 0 deletions lucida/botframework-interface/deps/install_phantomjs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash

mkdir -p deps/downloads
cd deps/downloads
uname -a | grep "x86_64" > /dev/null
if [ $? -eq 0 ]; then
wget -c "https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2" \
&& tar -xf phantomjs-2.1.1-linux-x86_64.tar.bz2 \
&& sudo killall phantomjs || : \
&& sudo cp phantomjs-2.1.1-linux-x86_64/bin/phantomjs /usr/bin/phantomjs
if [ $? -ne 0 ]; then exit 1; fi
else
wget -c "https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-i686.tar.bz2" \
&& tar -xf phantomjs-2.1.1-linux-i686.tar.bz2 \
&& sudo killall phantomjs || : \
&& sudo cp phantomjs-2.1.1-linux-i686/bin/phantomjs /usr/bin/phantomjs
if [ $? -ne 0 ]; then exit 1; fi
fi
145 changes: 145 additions & 0 deletions lucida/botframework-interface/interface.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*-----------------------------------------------------------------------------
Filename : interface.js
Author : Kamal Galrani
Description : This file handles dialogs from bot framework, forwards messages
to Lucida and forwards response to users
-----------------------------------------------------------------------------*/

var restify = require('restify')
var server = restify.createServer()
var builder = require('botbuilder')
var request = require('request')
var credentials = require('./credentials')
var url = require("url")
var bfw_port
var cc_host

//=========================================================
// Bot Setup
//=========================================================

function check_bfw_port(str_port) {
port = parseInt(str_port)
if ( ! isNaN(port) && port.toString() === str_port ) {
if ( port < 1 || port > 65535 ) {
console.log("[ERROR] Port should be a number between 1 and 65535")
return false
}
// Setup Restify Server
server.listen(port, function () {
console.log("[INFO] Listening to bot channels on port " + port + "...")
})
return true
}
return false
}

function check_cc_host(host) {
match = host.match(/^((\d+\.\d+\.\d+\.\d+)|localhost)(:\d+)?(.*)?$/)
if ( match != null ) {
cc_host = "http://" + host.replace(/\/$/, "")
console.log("[INFO] Remote command center host is set to " + cc_host)
return true
} else if ( url.parse(host)['host'] != null ) {
cc_host = host.replace(/\/$/, "")
console.log("[INFO] Remote command center host is set to " + cc_host)
return true
} else {
return false
}
}

function check_args() {
args = process.argv.slice(2)
if (args.length == 0) {
console.log("[WARN] Neither interface port nor command center host specified. Using defaults...")
check_bfw_port("3728")
check_cc_host("http://localhost:3000")
} else if (args.length == 1) {
if ( check_bfw_port(args[0]) ) {
console.log("[WARN] No command center host specified. Using default...")
check_cc_host("http://localhost:3000")
} else if ( check_cc_host(args[0]) ) {
console.log("[WARN] No interface port specified. Using default...")
check_bfw_port("3728")
} else {
console.log("[ERROR] Argument provided is neither a valid interface port nor a valid command center host.")
process.exit()
}
} else if (args.length == 2) {
if ( ! ( ( check_bfw_port(args[0]) && check_cc_host(args[1]) ) || ( check_bfw_port(args[1]) && check_cc_host(args[0]) ) ) ) {
console.log("[ERROR] Either an invalid interface port or an invalid command center host is provided.")
process.exit()
}
} else {
console.log("[ERROR] Usage: node interface.js <interface_port> <command_center_host>")
process.exit()
}
}
check_args()

// Create chat bot
var connector = new builder.ChatConnector(credentials.credentials)
var bot = new builder.UniversalBot(connector)
server.post('/api/messages', connector.listen())

//=========================================================
// Bots Dialogs
//=========================================================

var addresses = {}

bot.dialog('/', [
function (session) {
var address = session.message.address
addresses[address.channelId] = {channelId: address.channelId, bot: {id: address.bot.id, name: address.bot.name}, serviceUrl: address.serviceUrl, useAuth: address.useAuth}
request.post({
headers: {'content-type' : 'application/x-www-form-urlencoded'},
form: { interface: session.message.address.channelId, username: session.message.address.user.id, text_input: session.message.text },
url: cc_host + '/api/infer',
form: { interface: session.message.address.channelId, username: session.message.address.user.id, speech_input: session.message.text }
}, function(error, response, body){
address = addresses[session.message.address.channelId]
address['user'] = { id: session.message.address.user.id }
if (error) {
text = "Error occured '" + error.code + "'!!! Is command center running?"
} else if ( response.statusCode == 200 ) {
body = JSON.parse(body)
text = body.result
} else if ( response.statusCode == 403 ) {
var regex = /^Verify ([0-9a-zA-Z-_\.]*)$/
var result = session.message.text.match(regex)
if ( result ) {
request.post({
headers: {'content-type' : 'application/x-www-form-urlencoded'},
url: cc_host + '/api/add_interface',
form: { interface: session.message.address.channelId, token: result[1], username: session.message.address.user.id }
}, function(error, response, body){
if (error) {
text = "Error occured '" + error.code + "'!!! Is command center running?"
} else if ( response.statusCode == 200 ) {
text = body
} else if ( response.statusCode == 401 ) {
text = "Token expired... Please regenerate token on the web interface"
} else if ( response.statusCode == 403 ) {
text = "You must be kidding me"
} else {
text = response.statusCode + " " + response.statusMessage + " received. Go through the logs and figure. Otherwise create an issue on github with logs attached."
}
var reply = new builder.Message().address(address).text(text)
bot.send(reply)
})
return
} else {
text = "You are not authorized on this interface. Log on to the web interface, click on your email id and follow the instructions there."
}
} else if ( response.statusCode == 500 ) {
text = "Internal server error occured!!! Are all required microservices running?"
} else {
text = response.statusCode + " " + response.statusMessage + " received. Go through the logs and figure. Otherwise create an issue on github with logs attached."
}
var reply = new builder.Message().address(address).text(text)
bot.send(reply)
})
}
])
16 changes: 16 additions & 0 deletions lucida/botframework-interface/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "lucida-botframework-interface",
"version": "1.0.0",
"description": "Microsoft BotFramework interface for LUCIDA AI",
"main": "interface.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"botbuilder": "^3.5.4",
"botbuilder-calling": "^3.0.1",
"request": "^2.81.0",
"restify": "^4.3.0",
"url": "^0.11.0"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading