├── bot.gif
├── .gitignore
├── server
└── db
│ └── TextMessage.js
├── package.json
├── seed.js
├── createData.js
├── index.js
├── README.md
└── functions.js
/bot.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dorcheng/dorisbot/HEAD/bot.gif
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | data
3 | messagePairs.json
4 | .DS_Store
5 | npm-debug.log
6 |
--------------------------------------------------------------------------------
/server/db/TextMessage.js:
--------------------------------------------------------------------------------
1 | const Sequelize = require('sequelize');
2 | const db = new Sequelize(
3 | process.env.DATABASE_URL || 'postgres://localhost:5432/dorisbot', {
4 | logging: false
5 | }
6 | );
7 |
8 | const TextMessage = db.define('textMessage', {
9 | message: {
10 | type: Sequelize.TEXT
11 | },
12 | response: {
13 | type: Sequelize.TEXT
14 | }
15 | });
16 |
17 | module.exports = TextMessage;
18 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dorisbot",
3 | "version": "1.0.0",
4 | "description": "An intelligent chatbot",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "node server",
8 | "test": "echo \"Error: no test specified\" && exit 1",
9 | "seed": "node seed.js"
10 | },
11 | "author": "Doris Cheng",
12 | "license": "ISC",
13 | "dependencies": {
14 | "axios": "^0.16.2",
15 | "body-parser": "^1.18.2",
16 | "express": "^4.15.4",
17 | "fast-levenshtein": "^2.0.6",
18 | "js-yaml": "^3.10.0",
19 | "node-wit": "^4.3.0",
20 | "pg": "^7.3.0",
21 | "pg-hstore": "^2.3.2",
22 | "request": "^2.82.0",
23 | "sequelize": "^4.10.3"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/seed.js:
--------------------------------------------------------------------------------
1 | const TextMessage = require('./server/db/TextMessage.js');
2 | const messagePairs = require('./messagePairs.json');
3 |
4 | let rows = [];
5 |
6 | const keys = Object.keys(messagePairs);
7 | for (var i = 0; i < keys.length; i++) {
8 | let entry = {
9 | message: keys[i],
10 | response: messagePairs[keys[i]]
11 | };
12 | rows.push(entry);
13 | }
14 |
15 | const seed = () =>
16 | Promise.all(rows.map(row => TextMessage.create(row)));
17 |
18 | TextMessage.sync({force: true})
19 | .then(() => {
20 | return seed();
21 | })
22 | .then(() => {
23 | process.exit(0);
24 | })
25 | .catch(err => {
26 | console.error(err.stack);
27 | process.exit(1);
28 | });
29 |
--------------------------------------------------------------------------------
/createData.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | var yaml = require('js-yaml');
3 | var levenshtein = require('fast-levenshtein');
4 |
5 | // Declare document and messagePairs
6 | let doc;
7 | let messagePairs = {};
8 |
9 | // Parse yaml document of 30309 text messages (896249 words; two years of data) and convert into json object
10 | try {
11 | doc = yaml.safeLoad(fs.readFileSync('./data/textData.yaml', 'utf8'));
12 | doc = doc.sms.slice(0, 30309);
13 | } catch (e) {
14 | console.log(e);
15 | }
16 |
17 | let newKey = ''; // key is the message
18 | let newValue = ''; // value is response
19 | let prevType = 0;
20 |
21 | // Get rid of strings that are similar to size down data set
22 | for (var i = 0; i < doc.length; i++) {
23 | let currType = doc[i]._type;
24 | let currBody = doc[i]._body;
25 |
26 | if (currType === 1) {
27 | //if doris just finished replying
28 | if (prevType === 2) {
29 | //add key + value to your dict
30 | let add = true;
31 | let keys = Object.keys(messagePairs);
32 | for (var j = 0; j < keys.length; j++) {
33 | let distance = levenshtein.get(keys[j], newKey);
34 | let level = distance / Math.max(keys[j].length, newKey.length);
35 | if (level < 0.25) {
36 | add = false;
37 | break;
38 | }
39 | }
40 | if (add) {
41 | messagePairs[newKey] = newValue;
42 | }
43 | //reset newKey and value
44 | newKey = '';
45 | newValue = '';
46 | }
47 | newKey = `${newKey} ${currBody}`;
48 | }
49 | if (currType === 2) {
50 | newValue = `${newValue} ${currBody}`;
51 | }
52 | prevType = currType;
53 | }
54 |
55 | // write results into file with json format
56 | fs.writeFile('./data/messagePairs.json', JSON.stringify(messagePairs, null, 4), (err) => {
57 | if (err) {
58 | console.error(err);
59 | return;
60 | }
61 | console.log('Yay! Successfully created file');
62 | });
63 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const express = require('express');
4 | const bodyParser = require('body-parser');
5 | const handleMessage = require('./functions.js').handleMessage;
6 | const sendTextMessage = require('./functions.js').sendTextMessage;
7 | const app = express();
8 |
9 | app.set('port', (process.env.PORT || 5000));
10 | app.use(bodyParser.urlencoded({extended: false}));
11 | app.use(bodyParser.json());
12 |
13 | app.get('/', function (req, res) {
14 | res.send('Hello world, I am DorisBot');
15 | });
16 |
17 | // Facebook verification
18 | app.get('/webhook/', function (req, res) {
19 | if (req.query['hub.verify_token'] === process.env.FB_VERIFY_TOKEN) {
20 | res.send(req.query['hub.challenge']);
21 | }
22 | res.send('Error, wrong token');
23 | });
24 |
25 | app.post('/webhook', function (req, res) {
26 | var data = req.body;
27 |
28 | // Make sure this is a page subscription
29 | if (data.object === 'page') {
30 |
31 | // Iterate over each entry
32 | data.entry.forEach(function(entry) {
33 |
34 | // Iterate over each messaging event
35 | entry.messaging.forEach(function(event) {
36 | if (event.message) {
37 | receivedMessage(event);
38 | } else {
39 | console.log('Webhook received unknown event: ', event);
40 | }
41 | });
42 | });
43 |
44 | res.sendStatus(200);
45 | }
46 | });
47 |
48 | function receivedMessage(event) {
49 | var senderID = event.sender.id;
50 | var message = event.message;
51 | var nlp = message.nlp.entities;
52 |
53 | var messageText = message.text;
54 | var messageAttachments = message.attachments;
55 |
56 | if (messageText) {
57 | handleMessage(senderID, messageText, nlp);
58 |
59 | } else if (messageAttachments) {
60 | sendTextMessage(senderID, 'Message with attachment received');
61 | }
62 | }
63 |
64 | // Start server
65 | app.listen(app.get('port'), function() {
66 | console.log('running on port', app.get('port'));
67 | });
68 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Meet DorisBot
2 |
3 | DorisBot is a smart chatbot that was built with Wit.ai and Messenger Platform. To make things more interesting, she was built with the goal of speaking like Doris Cheng (me!).
4 |
5 |
6 |
7 |
8 |