-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit f36c5d6
Showing
11 changed files
with
517 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
NODE_ENV=development | ||
PORT=4040 | ||
WSURL=http://localhost:4040 | ||
APIAI_CLIENT_TOKEN=YOUR_API_AI_TOKEN |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/client | ||
/node_modules | ||
|
||
*.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Date Bot | ||
|
||
A simple Date bot that answers date related questions like: | ||
- how many days between today and November 21st | ||
- Is it Monday today | ||
- How many days until December | ||
- etc. | ||
|
||
Also API.AI's small talk agent included, which enables the bot to answers questions, well... related to small talk. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
const dotenv = require('dotenv').config({ | ||
path: process.env.NODE_ENV === 'test' ? 'test.env' : | ||
(process.env.NODE_ENV === 'production' ? 'production.env' : '.env') | ||
}); | ||
const server = require('./server'); | ||
const app = require('./server/express'); | ||
const socket = require('./server/websocket'); | ||
|
||
server.on('request', app); | ||
|
||
server.listen(process.env.PORT || 3000, () => { | ||
console.info(`server/ws started on port ${process.env.PORT}`); // eslint-disable-line no-console | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"name": "ws-chat-bot", | ||
"version": "0.1.0", | ||
"description": "Rxjs Websockets", | ||
"main": "index.js", | ||
"scripts": { | ||
"start": "node index.js", | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"author": "Vanco Stojkov <[email protected]>", | ||
"license": "ISC", | ||
"dependencies": { | ||
"apiai": "^4.0.2", | ||
"dotenv": "^4.0.0", | ||
"express": "^4.15.3", | ||
"moment": "^2.18.1", | ||
"rxjs": "^5.4.2", | ||
"uuid": "^3.1.0", | ||
"ws": "^3.0.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
const express = require('express'); | ||
|
||
const app = express(); | ||
const router = express.Router(); | ||
|
||
router.use('/*', function(req, res){ | ||
return res.sendFile('index.html', { | ||
root: 'client/dist/' | ||
}); | ||
}); | ||
app.use(router); | ||
|
||
module.exports = app; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
const http = require('http'); | ||
const server = http.createServer(); | ||
|
||
module.exports = server; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
const moment = require('moment'); | ||
|
||
const daysOfWeekByDay = { | ||
'Sunday': 0, | ||
'Monday': 1, | ||
'Tuesday': 2, | ||
'Wednesday': 3, | ||
'Thursday': 4, | ||
'Friday': 5, | ||
'Saturday': 6 | ||
}; | ||
|
||
const daysOfWeekByIndex = Object.keys(daysOfWeekByDay) | ||
.reduce((acc, d, ix) => { | ||
acc[ix] = d; | ||
return acc; | ||
}, {}); | ||
|
||
const plural = (num, unit) => num + ' ' + unit + (+num !== 1 ? 's' : ''); | ||
|
||
module.exports = { | ||
"date.between": (pars) => { | ||
const date1 = moment(pars['date-1']); | ||
const date2 = moment(pars['date-2']); | ||
const unit = pars.unit; | ||
const diff = Math.abs(date1.diff(date2, unit)); | ||
|
||
return `There are ${plural(diff, unit)} between ` + date1.format('MMMM Do YYYY') + ' and ' + date2.format('MMMM Do YYYY'); | ||
}, | ||
"date.check": (pars) => { | ||
const { location } = pars; | ||
const date = moment(pars.date); | ||
const now = moment(); | ||
|
||
return now.format("MM-DD-YYYY") === date.format("MM-DD-YYYY") | ||
? 'Yes' : 'No'; | ||
}, | ||
"date.day_of_week": (pars) => { | ||
const { date, location } = pars; | ||
|
||
return daysOfWeekByIndex[moment(date).format('e')]; | ||
}, | ||
"date.day_of_week.check": (pars) => { | ||
const { dayofweek, location } = pars; | ||
const date = moment(pars.date); | ||
const realDayOfWeek = date.format('e'); | ||
|
||
return +daysOfWeekByDay[dayofweek] === +realDayOfWeek | ||
? `Yes, it's ${daysOfWeekByIndex[realDayOfWeek]}` | ||
: `No, it's ${daysOfWeekByIndex[realDayOfWeek]}`; | ||
}, | ||
"date.get": (pars) => { | ||
const date = pars.date ? moment(date) : moment(); | ||
|
||
return date.format('MMMM Do YYYY'); | ||
}, | ||
"date.month.check": (pars) => { | ||
const [start, end] = pars['date-period'].split("/"); | ||
const now = moment(); | ||
const month = +moment(start).format('M'); | ||
|
||
return +now.format('M') === month | ||
? 'Yes, it\'s ' + now.format('MMMM') | ||
: 'No, it\'s ' + now.format('MMMM'); | ||
}, | ||
"date.month.get": () =>'It\'s ' + moment().format('MMMM'), | ||
"date.since": (pars) => { | ||
const { unit } = pars; | ||
const date = moment(pars.date); | ||
const now = moment(); | ||
const diff = Math.abs(now.diff(date, unit)); | ||
|
||
return `${plural(diff, unit)} since ` + date.format('MMMM Do YYYY'); | ||
}, | ||
"date.until": (pars) => { | ||
const now = moment(); | ||
const date = moment(pars['date']); | ||
const unit = pars.unit; | ||
const diff = Math.abs(now.diff(date, unit)); | ||
|
||
return `${plural(diff, unit)} until ${date.format('MMMM Do YYYY')}`; | ||
}, | ||
"date.year.check": (pars) => { | ||
const [start, end] = pars['date-period'].split("/"); | ||
const now = moment(); | ||
const year = +moment(start).format('YYYY'); | ||
|
||
return +now.format('YYYY') === year | ||
? 'Yes, it\'s ' + now.format('YYYY') | ||
: 'No, it\'s ' + now.format('YYYY'); | ||
}, | ||
"date.year.get": () => 'The current year is ' + moment().format('YYYY'), | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
const date = require('./date'); | ||
|
||
// merge all intent actions | ||
const intents = Object.assign({}, date); | ||
|
||
function doIntent(action, pars) { | ||
const unrecognizedActionMsg = 'I don\t understand that. Can you try again?'; | ||
|
||
return intents[action] ? intents[action](pars) : unrecognizedActionMsg; | ||
} | ||
|
||
module.exports = doIntent; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
const server = require('./'); | ||
const doIntent = require('./intents'); | ||
const WebSocket = require('ws'); | ||
const apiai = require("apiai")(process.env.APIAI_CLIENT_TOKEN); | ||
const uuidv4 = require('uuid/v4'); | ||
const util = require('util') | ||
|
||
const wss = new WebSocket.Server({server: server}); | ||
|
||
wss.on('connection', (ws) => { | ||
ws.on('message', (msg) => { | ||
try { | ||
const input = JSON.parse(msg); | ||
|
||
if (input.type === 'user' && input.msg) { | ||
const sessionId = input.sessionId || uuidv4(); | ||
|
||
callApiAi(input.msg, sessionId) | ||
.then((response) => { | ||
const { parameters, action, fulfillment } = response.result; | ||
const output = doIntent(action, parameters); | ||
|
||
return ws.send(JSON.stringify({type: 'bot', msg: output})); | ||
}) | ||
.catch(error => | ||
ws.send(JSON.stringify({type: 'bot', msg: 'Didn\'t quite get that?'})) | ||
); | ||
} | ||
} catch (err) { | ||
// TODO: handle JSON.parse error | ||
ws.send(JSON.stringify({type: 'bot', msg: 'Didn\'t quite get that?'})) | ||
} | ||
}); | ||
|
||
// TODO: generate ws session ids w/ uuid or sth. | ||
ws.send(JSON.stringify({type: 'sessionId', msg: uuidv4()})); | ||
// ws.send(JSON.stringify({type: 'bot', msg: 'Hi there!'})); | ||
ws.send(JSON.stringify({type: 'bot', msg: '⏰ I\'m a date bot — ask me something about date!'})); | ||
}); | ||
|
||
function callApiAi(text, sessionId) { | ||
return new Promise((resolve, reject) => { | ||
try { | ||
// TODO: generate ws session ids w/ uuid or sth. | ||
const request = apiai.textRequest(text, { sessionId: sessionId }); | ||
|
||
request.on('response', response => resolve(response)); | ||
request.on('error', error => reject(error)); | ||
request.end(); | ||
} catch (err) { | ||
reject(err); | ||
} | ||
}); | ||
} | ||
|
||
module.exports = wss; |
Oops, something went wrong.