Créons un système de réception simple avec le framework sans serveur Python Chalice et Twilio

Chose que tu veux faire

J'ai écrit sur le système de réception, mais ce que je veux faire est essentiellement une extension du démarrage rapide suivant.

Démarrage rapide de PYTHON: passer un appel depuis votre navigateur

employee-call.png

Quand je me suis demandé si je pouvais faire quelque chose avec WebRTC du client Twilio, j'ai pensé que je pourrais implémenter le téléphone de réception qui est commun dans l'entreprise de manière plus sans serveur en utilisant un navigateur Web tel qu'une tablette.

Twilio a officiellement un exemple de code pour les appels de navigateur utilisant Flask, mais les informations sur twilio-python et twilio.js sont un peu anciennes, donc cela ne fonctionnait pas tel quel, donc cela fonctionne avec le dernier code. J'essaye de le faire.

Au lieu d'utiliser un téléphone supplémentaire, vous pouvez passer un appel directement sur votre smartphone personnel. L'avantage est que vous n'avez pas besoin d'un téléphone fixe et que vous n'avez pas besoin de donner votre numéro de téléphone personnel. De plus, comme il est implémenté sans serveur, il est sans entretien et peu coûteux. (Des frais d'appel seront facturés ...)

environnement

Les choses nécessaires

Cette fois, je voulais créer rapidement un environnement AWS Lambda + API GateWay, j'ai donc utilisé AWS Chalice.

Installation des bibliothèques requises

$ pip install chalice

Ensuite, définissez les informations d'identification AWS. Si vous l'avez déjà configuré en utilisant boto3 etc., vous n'en avez probablement pas besoin.

$ mkdir ~/.aws
$ vim ~/.aws/credentials
[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)

Créer une fonction Lambda

Créez un projet dans Chalice.

$ chalice new-project EmployeeCaller
$ cd EmployeeCaller

Lorsque vous exécutez la commande ci-dessus, un fichier sera créé sous le répertoire, alors modifiez ce fichier.

Tout d'abord, écrivez la bibliothèque à déployer dans requirements.txt.

$ vim requirements.txt
twilio==6.0.0

Ensuite, modifiez app.py et insérez le code.

app.py


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')

#Générer TwiML, Endpoint pour les appels vocaux
@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'})

#Émettre un jeton
@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}) + ")"

Petit complément à Chalice, Chalice est basé sur un microframework appelé Flask. Je pense donc que vous devriez consulter la documentation Flask pour le routage, etc.

À propos du routage

Tout d'abord, concernant le routage suivant

@app.route('/client', methods=['GET'])

Vous devrez recevoir un jeton de capacité, qui est nécessaire pour passer un appel avec le client Twilio. Appuyez sur / client pour générer ce jeton et le renvoyer avec json. On a l'impression que la face avant l'utilise pour passer un appel.

Pour plus d'informations sur les jetons, consultez TWILIO Client Capability Tokens.

Puis le routage suivant

@app.route('/voice', methods=['POST'], content_types=['application/x-www-form-urlencoded'], cors=True)

Ce / voice recevra une demande du serveur Twilio comprenant le numéro de téléphone de la destination de connexion. Puisqu'il est envoyé par POST, il est nécessaire de spécifier ʻapplication / x-www-form-urlencoded` pour Content-Type.

À propos des variables d'environnement

La partie de os.environ ['---'] dans le code est l'endroit où lire la variable d'environnement, qui est écrite dans le fichier de configuration Chalice, mais elle est définie après un déploiement unique et la configuration de Twilio.

Déployer

Déployez le code ci-dessus. Exécutez la commande suivante dans le répertoire du projet.

$ 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/

Lorsque vous l'exécutez, vous devriez voir un résultat comme celui ci-dessus. Notez la dernière URL de sortie car elle sera utilisée plus tard dans l'URL de destination de l'appel APIGateWay.

Créer une application TwiML avec Twilio

Compte SID et jeton d'authentification

Connectez-vous à Twilio et notez les "ACCOUNT SID" et "AUTH TOKEN" de la console Dash Board.

Créer une application TwiML

Créez une nouvelle APP TwiML à partir de "Numéro de téléphone" -> "Outils". Entrez le nom de l'application en fonction du nom convivial.

Entrez l'URL + / voice que vous avez noté lorsque vous avez déployé le calice 'plus tôt dans "Request URL" de "Voice call" et enregistrez-le. (https: // ********. execute-api.ap-northeast-1.amazonaws.com / dev / voice`)

Lorsque vous créez une application TwiML, l'application apparaît dans la liste, affichez donc les détails, vérifiez le "SID" (SID de l'application TwiML) et notez-le.

Acheter un numéro de téléphone

Achetez un numéro de téléphone à partir de «Numéro de téléphone» avec «Acheter un numéro». Notez votre numéro de téléphone.

Comment acheter un numéro de téléphone [article précédemment écrit](http://qiita.com/hidesakai/items/20873fa354cb49911608#twilio%E3%81%A7%E9%9B%BB%E8%A9%B1%E7%95 % AA% E5% 8F% B7% E8% B3% BC% E5% 85% A5% E8% AA% B2% E9% 87% 91), donc si vous ne savez pas, veuillez vous y référer.

Définir des variables d'environnement dans la fonction Lambda

Après avoir créé l'application TwiML, revenez au projet calice et modifiez les fichiers suivants.

$ vim .chalice/config.json

Ajoutez un élément appelé ʻenviroment_variables` au fichier config.json. Définissez le SID et le jeton que vous avez noté précédemment ici. Ce sera une variable d'environnement sur AWS Lambda.

.....
"app_name": "EmployeeCaller",
//Ajout des éléments suivants
"environment_variables": {
    "TWILIO_ACCOUNT_SID": "*******************",
    "TWILIO_AUTH_TOKEN": "*******************",
    "TWILIO_TWIML_APP_SID": "*******************",
    "TWILIO_CALLER_ID": "+81********",
    "DEFAULT_CLIENT": "reception"
}

Après avoir modifié config.json, déployez à nouveau.

$ chalice deploy

Créer un écran de réception, télécharger sur S3

Ensuite, créez un écran de réception.

Création d'écran

$ vim employee.html

employee_call.html


<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>accueil</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>
Veuillez nous contacter par extension lorsque vous en avez besoin.
                        </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>
Merci de nous contacter à la réception.
                        </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">Oeuf</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">accueil</h4>
                        <p class="card-text">
C'est la réception.
                        </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>

$ .ajax () ʻurl: 'https: // ******. execute-api.ap-northeast-1.amazonaws.com / dev / client'` URL lorsque charis est déployé plus tôt Est inséré comme il convient

Entrez ensuite le numéro de téléphone commençant par le code du pays (+81) dans data-phone-number.

Télécharger vers S3

Créez un compartiment approprié sur S3 et téléchargez le fichier html.

Appeler depuis l'écran

Après avoir téléchargé sur S3, accédez à la page et appuyez sur le bouton Appeler. C'est OK si vous pouvez envoyer au numéro de téléphone défini.

スクリーンショット 2017-05-09 1.50.01.png

Point de défis

À ce rythme, vous pouvez y accéder de n'importe où et vous pouvez jouer avec.

Après cela, j'ai mis le numéro de téléphone directement sur le html, mais j'aimerais obtenir les données de Lambda telles que DynamoDB.

Recommended Posts

Créons un système de réception simple avec le framework sans serveur Python Chalice et Twilio
Touchez AWS avec Serverless Framework et Python
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 1 ~
Créer une fonction Lambda de version Python (+ couche Lambda) avec Serverless Framework
Essayez de créer une application Todo avec le framework Django REST
Essayez de créer un jeu simple avec Python 3 et iPhone
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 2 ~
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 3 ~
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 4 ~
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 5 ~
Facilement sans serveur avec Python en utilisant Calice
Créer un répertoire avec python
Probablement le moyen le plus simple de créer un pdf avec Python 3
Créons un diagramme PRML avec Python, Numpy et matplotlib.
Créez un Twitter BOT avec le SDK GoogleAppEngine pour Python
Créez un outil d'analyse vidéo simple avec python wxpython + openCV
Créez un environnement de développement Python simple avec VSCode et Docker Desktop
Créez un environnement virtuel avec Python!
Créer un système de recommandation avec python
Créer un framework de décorateur à usage général pour Python
Créez une illusion rayée avec correction gamma pour Python3 et openCV3
Créez un sélecteur de couleurs pour la roue chromatique avec Python + Qt (PySide)
Créez un simple OMR (lecteur de feuille de marque) avec Python et OpenCV
Spécifiez ou créez un dossier python, puis enregistrez la capture d'écran.
Créez un lot planifié simple à l'aide de l'image Python de Docker et de parse-crontab
Résolvez le problème du sac à dos Python avec la méthode de branche et liée
Créer une API REST pour faire fonctionner dynamodb avec le Framework Django REST
Créer et renvoyer un fichier CSV CP932 pour Excel avec Chalice
Créez un programme de jugement de compatibilité avec le module aléatoire de python.
Créer un décorateur de fonction Python avec Class
Créer un fichier power simple avec Python
Calculer l'itinéraire le plus court d'un graphe avec la méthode Dyxtra et Python
Installer Python en tant que Framework avec pyenv
[AWS] Créez un environnement Python Lambda avec CodeStar et faites Hello World
Créez une image factice avec Python + PIL.
Créer une application GUI simple en Python
[Python] Créez un environnement virtuel avec Anaconda
Créons un groupe gratuit avec Python
Un mémo contenant Python2.7 et Python3 dans CentOS
Rechercher le labyrinthe avec l'algorithme python A *
Créer et décrypter du code César avec python
Créez un système stellaire avec le script Blender 2.80
Créez une application Web simple avec Flask
Obtenez et convertissez l'heure actuelle dans le fuseau horaire local du système avec python
Créer un compteur de fréquence de mots avec Python 3.4
Créer un enregistrement avec des pièces jointes dans KINTONE à l'aide du module de requêtes Python
Créez un framework Web avec Python! (1)
Créez un environnement Python 3 avec pyenv sur Mac et affichez des graphiques Network X
Créez un arbre de décision à partir de 0 avec Python et comprenez-le (5. Entropie des informations)
Créez un framework Web avec Python! (2)
J'ai fait un simple blackjack avec Python
Implémentez une application simple avec Python full scratch sans utiliser de framework web.
Créer en Python sans fichier image factice dans Django et tester le téléchargement de l'image
Mettez Docker dans Windows Home et exécutez un serveur Web simple avec Python
Créons-le en appliquant Protocol Buffer à l'API avec Serverless Framework.
Utilisez la commande [shell] pour compresser par zip n'importe quel fichier pour créer un fichier et supprimer le fichier d'origine.
J'ai essayé de créer facilement un système de présence entièrement automatique avec Selenium + Python