我们将为我们的第一个项目建立一个方便的短信呼叫中心。
此呼叫中心将处理来自用户的传入 SMS 消息;它不会处理语音,只是短信。我们将在其他几章中讨论语音。
你想知道 Flybase 的一个美好之处吗?它很容易与其他服务集成。
在这一章中,我们将一起使用 Flybase 和 Twilio 来构建一个实时短信呼叫中心。
这可以用作客户帮助台,客户发送文本消息请求帮助,代理从他们的 web 浏览器发送回复。
实际的电话工作将由 Twilio 处理,Flybase 将存储数据并实时显示聊天内容。我们将使用 Node.js 来发送和接收文本消息,并使用 HTML 前端来处理实际的聊天。
我们将使用一些工具来构建这个应用。在继续之前,您需要设置好这些:
-
Twilio (
http://twilio.com):收发短信。没有 Twilio 帐户?免费报名(www.twilio.com/try-twilio)。 -
Flybase (
www.flybase.io/):一个实时数据库 API。我们将使用它来存储我们的传入和传出信息。 -
Node.js (
http://nodejs.org/):基于 Chrome 的 JavaScript 运行时构建的平台,用于轻松构建快速、可扩展的网络应用。
如果你还没有,现在就注册( https://app.flybase.io/signup )一个免费的 Flybase 帐户,然后创建一个新的应用。您将在呼叫中心使用您的应用。
我们首先需要设置我们的 Node.js 应用。
除了 Twilio 和 Flybase 模块,我们将使用 express 框架( http://expressjs.com/ )来设置我们的 Node web 服务器,以接收来自 Twilio 的 POST 请求,因此我们需要安装 Express 包。我们还将使用 body-parser 模块,所以我们也将安装它。
让我们创建我们的package.json文件:
javascript
{
"name": "sms-contact-center",
"version": "0.0.1",
"description": "SMS Contact Center powered by Flybase, Twilio and Node.js",
"main": "app.js",
"repository": "https://github.com/flybase/sms-contact",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"twilio",
"Flybase",
"sms"
],
"author": "Roger Stringer",
"license": "MIT",
"dependencies": {
"twilio": "~1.6.0",
"ejs": "~0.8.5",
"express": "~3.4.8",
"flybase": "~1.7.8",
"node-buzz": "~1.1.0",
"moment": "~2.5.1",
"less-middleware": "~0.2.1-beta",
"body-parser" : "~1.4.2",
"method-override" : "~2.0.2"
},
"engines": {
"node": "0.10.26"
}
}保存该文件,并从终端运行以下命令:
javascript
npm install这将创建一个包含我们想要使用的所有模块的node_modules文件夹。
让我们设置我们的文件夹结构;创建一个名为views的文件夹。这是我们将保持前端的地方。
现在,创建一个名为“public”的文件夹这将托管我们的静态文件。在该文件夹中,创建一个css文件夹和一个js文件夹;我们稍后将回到这些。
在 app.js 文件的开头,我们需要 require express 并将其初始化为一个名为 app 的变量。
我们还将使用 bodyParser 中间件( https://github.com/expressjs/body-parser )来方便地使用我们将在 POST 请求中获得的数据。
创建一个名为app.js的新文件,并需要 twilio、express 和 flybase 包:
javascript
var express = require('express');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var twilio = require('twilio');
var path = require('path');
var app = express();
app.set('views', path.join(process.cwd(), 'views'));
app.set('view engine', 'ejs');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(__dirname + '/public'));
var port = process.env.PORT || 8080; // set our port
var client = twilio('ACCOUNTSID', 'AUTHTOKEN');
var twilio_number = 'YOUR-NUMBER';
var api_key = "YOUR-API-KEY";
var appname = "YOUR-FLYBASE-APP";
var collection = "smscontact";
var messagesRef = require('flybase').init(appname, collection, api_key);
// backend routes =========================将ACCOUNTSID、AUTHTOKEN和YOUR-NUMBER替换为您将使用的 Twilio 凭证和 Twilio 帐户中的电话号码。
然后,用您的 Flybase API 键替换YOUR-API-KEY、YOUR-flybase-APP和smscontact,并创建一个集合来使用。如果您还没有创建收藏,当您第一次保存数据时,系统会自动为您创建一个收藏,因此如果您愿意,您可以将收藏名称设置为smscontact。
Flybase 使用集合来组织应用中的数据,因此一个应用可以有几个集合。如果您熟悉关系数据库,这相当于一个表。
这是我们应用的开始。接下来,我们将告诉它当新的短信进来和代理回复短信时该做什么。
Twilio 使用 webhooks ( https://en.wikipedia.org/wiki/Webhook )来让您的服务器知道何时有消息或电话进入我们的应用。我们需要设置一个端点,我们可以告诉 Twilio 将它用于消息传递 webhook。
我们将为/message添加一个用一些 TwiML (Twilio 标记语言, www.twilio.com/docs/api/twiml )响应的路由。TwiML 是一组基本指令,当你收到来电或短信时,你可以用它来告诉 Twilio 该做什么。我们的代码将如下所示:
javascript
app.post('/message', function (request, response) {
var d = new Date();
var date = d.toLocaleString();
messagesRef.push({
sid: request.param('MessageSid'),
type:'text',
direction: "inbound",
tstamp: date,
fromNumber:request.param('From'),
textMessage:request.param('Body'),
fromCity:request.param('FromCity'),
fromState:request.param('FromState'),
fromCountry:request.param('FromCountry')
});
var resp = new twilio.TwimlResponse();
resp.message('Thanks for the message, an agent will get back to you shortly.');
response.writeHead(200, {
'Content-Type':'text/xml'
});
response.end(resp.toString());
});这将监听任何传入的短信,并将它们存储在你的 Flybase 应用中。
一旦收到消息,我们使用 Twilio Node 库初始化一个新的TwimlResponse。然后我们使用消息关键字( www.twilio.com/docs/api/twiml/sms/message )来设置我们想要用什么来响应消息。在这种情况下,我们只需说“感谢您的消息,代理人会尽快回复您。”然后,我们将响应的内容类型设置为text/xml,并发送我们构建的 TwimlResponse 的字符串表示。
每当客户向我们设置的电话号码发送消息时,它都会向他们发送响应并将消息存储在 Flybase 中。如果代理正在监视客户端,那么他们会立即看到消息,并可以发送回复。
现在,让我们添加一条名为/reply的路线。当我们的代理想要回复一条消息时,我们将通过 AJAX 调用它:
javascript
app.post('/reply', function (request, response) {
var d = new Date();
var date = d.toLocaleString();
messagesRef.push({
type:'text',
direction: "outbound",
tstamp: date,
fromNumber:request.param('From'),
textMessage:request.param('Body'),
fromCity:'',
fromState:'',
fromCountry:''
});
client.sendMessage( {
to:request.param('To'),
from:twilio_number,
body:request.param('Body')
}, function( err, data ) {
console.log( data.body );
});
});这将在我们的 Flybase 应用中存储回复作为出站回复,并将消息发送给客户。
最后,让我们设置我们的服务器监听端口8080,并告诉它当我们从浏览器中查看它时该做什么:
javascript
// frontend routes =========================
// route to handle all angular requests
app.get('*', function(req, res) {
res.render('home', {
apikey:api_key,
appname:appname,
collection:collection
});
});
var server = app.listen(port, function() {
console.log('Listening on port %d', server.address().port);
});现在我们已经构建了我们的服务器,我们需要告诉 Twilio 使用这个消息 URL 作为我们的消息请求 URL。
向您的 Twilio 号码发送短信,您应该会收到回复。如果你不知道,看看 Twilio 应用监视器( www.twilio.com/user/account/developer-tools/app-monitor )来帮助确定哪里出了问题。
这是我们呼叫中心的后端部分;它监听传入的短信,将它们存储在我们的 Flybase 应用中,然后在代理回复时发送回复。
现在,我们需要构建我们的代理系统,在这里代理可以观察收到的消息并回复它们。
我们现在就来建造它。
我们让 Node.js 应用监听要发送和接收的消息。现在让我们设置我们的客户端,这是代理将从他们的 web 浏览器中看到的内容。
当有消息进来时,我们会显示一个显示消息的聊天框,然后发送回复。
首先,让我们创建视图。在/views文件夹中,创建名为home.ejs的文件:
HTML
<!doctype html>
<html>
<head>
<link href='http://fonts.googleapis.com/css?family=Lato:400,300italic,400italic&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
<link rel="stylesheet" type="text/css" href="http://angular-ui.github.com/ng-grid/css/ng-grid.css" />
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="/css/style.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="https://cdn.flybase.io/flybase.js?latest=1"></script>
<script src="/js/chat.js"></script>
<title>SMS Contact Center, powered by Flybase and Twilio</title>
</head>
<body>
<div class='container'>
<br />
<div class="well">
<p class='homefont'>Welcome to your SMS Contact Center</p>
<p class='homefont'>This call center is the start of a modern day call center.</p>
<p class='homefont'>Take a look around and give us a try.</p>
</div>
<hr/>
<h3>Incoming messages</h3>
<div id="templateContainer"></div>
</div>
<script>
$(function(){
// initializes our Flybase object
var flybaseRef = new flybase("<%= apikey %>", "<%= appname %>", "<%= collection %>");
// start our chatManager.
var myChatManager = new chatManager( flybaseRef );
myChatManager.updateChats();
});
</script>
</body>
</html>这个文件将作为我们的 HTML 文件,我们使用 EJS,所以我们可以传递我们的 Flybase 设置,而不必在多个地方配置它们。EJS 可以方便地将模板功能添加到 Node.js 应用中。
现在,让我们创建我们的 CSS。在我们之前创建的/public/css文件夹中,创建一个名为 style.css 的新文件:
css
body{font-size:12pt;font-family:helvetica}
.chatWindow{float:left;margin:20px;border:1px solid #000;width:300px;background:#e5e5e5;border-radius:5px}
.chatName{margin-bottom:10px;background:#666;color:#fff;padding:4px}
.messages{padding:4px}
.message_outbound{color:blue;text-align:right}
.tstamp{font-size:9px;padding:2px;margin-bottom:10px;border-bottom:1px dotted #666;color:#666}
.error{color:red;text-align:center}
.messageForm textarea{float:left;width:220px;margin:5px}最后,我们希望设置我们的应用的大脑。我们把最大的文件留到了最后。
在 public/js 文件夹中,新建一个名为 chat.js 的文件:
chat.js
var chatManager = function(flybaseRef) {
this.flybaseRef = flybaseRef;
};
chatManager.prototype = {
chats: [],
getChat: function(fromNumber) {
var foundChat = null;
for (c = 0; c < this.chats.length; c++) {
if (this.chats[c].from == fromNumber) {
foundChat = this.chats[c];
}
}
if (foundChat == null) {
foundChat = new chat( this.flybaseRef );
foundChat.init(fromNumber);
foundChat.displayTemplate();
this.chats.push(foundChat);
}
return foundChat;
},
updateChats: function() {
var _this = this;
this.flybaseRef.once('value', function (data) {
data.forEach( function(message){
var row = message.value();
_this.getChat( row.fromNumber ).addMessage(
row.textMessage,
row.tstamp,
row.direction
);
});
});
this.flybaseRef.on('added', function (data) {
var row = data.value();
_this.getChat( row.fromNumber ).addMessage(
row.textMessage,
row.tstamp,
row.direction
);
});
}
};
var chat = function(flybaseRef) {
this.flybaseRef = flybaseRef;
};
chat.prototype = {
init: function(name) {
this.from = name;
this.chatName = 'chat-' + this.from;
this.buttonName = 'submit-' + this.from;
this.textName = 'reply-' + this.from;
},
replyMessage: function(message) {
var _this = this;
$.ajax({
type: "POST",
url: "/reply",
data: {
'To': this.from,
'Body': message,
'From': this.from
},
dataType: "json",
success: function(data) {
// your message was sent
}
});
},
displayTemplate: function() {
var content = '<div class="chatName">Chat with ' + this.from + '</div> \
<div class="messages" id="' + this.chatName + '"></div> \
<div class="messageForm"><textarea id="' + this.textName + '"></textarea><button id="' + this.buttonName + '">Reply</button></div> \
</div>';
content = '<div class="chatWindow" id="' + this.tmplName + '">' + content + '</div>';
$('#templateContainer').append(content);
var _this = this;
$('#' + this.buttonName).click(function() {
_this.replyMessage($('#' + _this.textName).val());
$('#' + _this.textName).val('');
});
},
addMessage: function(message, tstamp, direction) {
$('#' + this.chatName).append("<div class='message_" + direction + "'>" + message + "<div class='tstamp'>" + tstamp + "</div></div>");
}
};我们的 chatManage 类是这样设置的,当它加载时,它首先使用value事件触发器获取一个保存的文本消息列表,并按照发送它们的电话号码显示它们。
我们将所有往来于同一号码的消息视为一个会话,因此对于每个聊天会话,我们会看到一个显示代理和客户之间消息的框,以及一个用于发送新消息的文本框。
然后,我们使用added事件触发器监听任何新消息,然后将它们显示在适当的聊天框中。
chat类告诉我们的应用如何显示聊天框,以及如何处理发送新的回复。
在这种情况下,当代理发送消息时,我们将它发布到我们的后端/reply路由,在那里它被保存到我们的 Flybase 应用,然后作为文本消息发送给客户。
我们还存储消息来自的方向,或者是inbound或者是outbound。这样,我们可以设计每条消息的样式,使其看起来与您在手机上查看聊天记录时相似。客户的文本将出现在左侧,代理的回复将出现在右侧。
现在让我们启动我们的应用:
javascript
node app.js我们已经告诉我们的应用在端口 8080 上运行,所以如果你去你的网络浏览器并输入http://localhost:8080/,你应该看到你的呼叫中心。
顺便说一句,如果你在本地运行这个,你需要确保在进入下一步之前已经运行了 ngrok。如果你以前没有用过 ngrok ( https://ngrok.com/ ),Twilio 的凯文·维尼里已经整理了一个很棒的教程( www.twilio.com/blog/2013/10/test-your-webhooks-locally-with-ngrok.html )来帮助你入门。
我们做到了!既然你已经构建了一个简单的短信呼叫中心应用( https://github.com/flybaseio/sms-contact ),那么你就有机会用它来创造一些东西了。
接下这个项目,继续做下去。一些想法是,你实际上可以完全删除/reply AJAX 调用,而是创建一个outbound文本队列来存储消息,然后向出站集合添加一个added侦听器,该侦听器既可以向客户发送回复,又可以将其添加到message集合中,这样它就会出现在聊天窗口中。
这将消除对 AJAX 调用的需要,并且在一次向几个客户发送多个回复的情况下增加一些队列支持。