Skip to content

Instantly share code, notes, and snippets.

@hidesakai
Last active May 9, 2017 05:57
Show Gist options
  • Save hidesakai/cbe54b0e2f6396596987a23afcf935a5 to your computer and use it in GitHub Desktop.
Save hidesakai/cbe54b0e2f6396596987a23afcf935a5 to your computer and use it in GitHub Desktop.
Pythonサーバーレスフレームワーク Chalice と Twilio で簡易的な受付システムを作ってみる ref: http://qiita.com/hidesakai/items/5bd86240ee042b13139f
import os, json
from urlparse import parse_qs
from chalice import Chalice, Response
from twilio.jwt.client import ClientCapabilityToken
from twilio.twiml.voice_response import VoiceResponse
app = Chalice(app_name='EmployeeCaller')
# 音声通話のEndpoint、TwiMLを生成する
@app.route('/voice', methods=['POST'], content_types=['application/x-www-form-urlencoded'], cors=True)
def voice():
parsed = parse_qs(app.current_request.raw_body)
dest_number = parsed.get('PhoneNumber', [])
resp = VoiceResponse()
resp.dial(dest_number[0], caller_id=os.environ['TWILIO_CALLER_ID'])
return Response(body=str(resp), status_code=200, headers={'Content-Type': 'application/xml'})
# トークンを発行する
@app.route('/client', methods=['GET'])
def client():
request = app.current_request
account_sid = os.environ['TWILIO_ACCOUNT_SID']
auth_token = os.environ['TWILIO_AUTH_TOKEN']
application_sid = os.environ['TWILIO_TWIML_APP_SID']
capability = ClientCapabilityToken(account_sid, auth_token)
capability.allow_client_outgoing(application_sid)
capability.allow_client_incoming(os.environ['DEFAULT_CLIENT'])
token = capability.to_jwt()
callback = request.query_params['callback']
return str(callback) + "(" + json.dumps({"token": token}) + ")"
<html>
<head>
<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://media.twiliocdn.com/sdk/js/client/v1.4/twilio.min.js"></script>
<script type="text/javascript">
Twilio.Device.ready(function (device) {
console.log("Ready");
});
Twilio.Device.error(function (error) {
console.log("Error: " + error.message);
});
Twilio.Device.connect(function (conn) {
console.log("Successfully established call");
});
Twilio.Device.disconnect(function (conn) {
console.log("Call ended");
$('.employee-hangup').addClass('disabled').prop('disabled', true);
$('.employee-call').removeClass('disabled').prop('disabled', false);
});
Twilio.Device.incoming(function (conn) {
console.log("Incoming connection from " + conn.parameters.From);
conn.accept();
});
function twilioReadyAsync(phoneNumber) {
return new Promise(function(resolve){
(function ready(){
if (Twilio.Device.status() == 'ready') {
resolve({"PhoneNumber": phoneNumber});
}
setTimeout(ready, 1000);
})();
});
}
$(function() {
$('.employee-hangup').addClass('disabled').prop('disabled', true);
$('.employee-call').click(function(){
var employeePhoneNumber = $(this).attr('data-phone-number');
$(this).next().removeClass('disabled').prop('disabled', false);
$('.employee-call').addClass('disabled').prop('disabled', true);
$.ajax({
url: 'https://******.execute-api.ap-northeast-1.amazonaws.com/dev/client',
dataType: 'jsonp',
jsonCallback: 'callback'
})
.done(function(data) {
Twilio.Device.setup(data.token);
twilioReadyAsync(employeePhoneNumber).then(Twilio.Device.connect);
});
});
$('.employee-hangup').click(function(){
Twilio.Device.disconnectAll();
$(this).addClass('disabled').prop('disabled', true);
$('.employee-call').removeClass('disabled').prop('disabled', false);
});
});
</script>
<style>
.container {width: auto;}
</style>
</head>
<body>
<div class="container">
<h1>受付</h1>
<div class="card-deck">
<div class="card text-center" id="employee-1">
<img class="card-img-top img-fluid" src="hidesakai.png" alt="Card image cap">
<div class="card-block">
<h4 class="card-title">hidesakai</h4>
<p class="card-text">
<p>Development: Engineer</p>
御用の際は内線にてご連絡ください。
</p>
<button class="btn btn-primary employee-call" data-phone-number="+8190-****-****">Call</button>
<button class="btn btn-danger employee-hangup">Hangup</button>
</div>
</div>
<div class="card text-center" id="employee-2">
<img class="card-img-top img-fluid" src="spam.jpg" alt="Card image cap">
<div class="card-block">
<h4 class="card-title">Spam さん</h4>
<p class="card-text">
<p>Design: Designer</p>
受付よりご連絡をお願いします。
</p>
<button class="btn btn-primary employee-call" data-phone-number="+8190-****-****">Call</button>
<button class="btn btn-danger employee-hangup">Hangup</button>
</div>
</div>
<div class="card text-center" id="employee-3">
<img class="card-img-top img-fluid" src="egg.png" alt="Card image cap">
<div class="card-block">
<h4 class="card-title">Egg さん</h4>
<p class="card-text">
<p>Sales: Marketer</p>
</p>
<button class="btn btn-primary employee-call" data-phone-number="+8190-****-****">Call</button>
<button class="btn btn-danger employee-hangup">Hangup</button>
</div>
</div>
<div class="card text-center" id="employee-4">
<div class="card-block">
<h4 class="card-title">受付</h4>
<p class="card-text">
こちらは受付となります。
</p>
<button class="btn btn-primary employee-call" data-phone-number="+8180-****-****">Call</button>
<button class="btn btn-danger employee-hangup">Hangup</button>
</div>
</div>
</div>
</div>
</body>
</html>
$ pip install chalice
$ mkdir ~/.aws
$ vim ~/.aws/credentials
.....
"app_name": "EmployeeCaller",
// 以下の項目を追加
"environment_variables": {
"TWILIO_ACCOUNT_SID": "*******************",
"TWILIO_AUTH_TOKEN": "*******************",
"TWILIO_TWIML_APP_SID": "*******************",
"TWILIO_CALLER_ID": "+81********",
"DEFAULT_CLIENT": "reception"
}
$ chalice deploy
$ vim employee.html
[default]
aws_access_key_id=YOUR_ACCESS_KEY_HERE
aws_secret_access_key=YOUR_SECRET_ACCESS_KEY
region=YOUR_REGION (such as us-west-2, us-west-1, etc)
$ chalice new-project EmployeeCaller
$ cd EmployeeCaller
$ vim requirements.txt
twilio==6.0.0
@app.route('/client', methods=['GET'])
@app.route('/voice', methods=['POST'], content_types=['application/x-www-form-urlencoded'], cors=True)
$ chalice deploy
Updating IAM policy.
Updating lambda function...
Regen deployment package...
Sending changes to lambda.
API Gateway rest API already found.
Deploying to: dev
https://********.execute-api.ap-northeast-1.amazonaws.com/dev/
$ vim .chalice/config.json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment