
Partager:
Aaron était défenseur des développeurs chez Nexmo. Ingénieur logiciel chevronné et artiste numérique en herbe, Aaron est souvent amené à créer des choses avec du code ou de l'électronique, parfois les deux. On peut généralement savoir qu'il travaille sur quelque chose de nouveau grâce à l'odeur de composants brûlés qui flotte dans l'air.
Passer un appel téléphonique en synthèse vocale avec Django
Temps de lecture : 5 minutes
Parmi les notifications incessantes que les gens reçoivent chaque jour, une sonnerie de téléphone est encore plus difficile à ignorer ou à négliger.

Il crée un sentiment d'urgence, ce qui en fait le moyen idéal pour transmettre des messages critiques ou sensibles au facteur temps, tels que codes d'authentification à deux facteurs ou notifications de services importants.
Dans ce tutoriel, nous verrons comment vous pouvez utiliser l'API de synthèse vocale de Nexmo. l'API de synthèse vocale de Nexmo de Nexmo pour passer des appels sortants avec Python et Django.
Conditions préalables
Vonage API Account
To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.
This tutorial also uses a virtual phone number. To purchase one, go to Numbers > Buy Numbers and search for one that meets your needs.
Votre serveur Django devra être accessible par l'API Nexmo. Si vous l'exécutez localement, alors vous devrez utiliser un outil tel que ngrok pour l'exposer à l'internet public.
Applications Nexmo
Une dernière chose avant de commencer à écrire notre code Python/Django, nous devons comprendre ce qui suit Les applications Nexmo. Lorsque nous créons une nouvelle application Nexmo, nous l'utilisons non seulement pour stocker des données de configuration telles que l'URL de notre Nexmo call control object (NCCO)ou l'endroit où Nexmo doit envoyer des informations sur les événements ; nous pouvons également l'utiliser pour générer notre paire de clés publiques/privées.
La sécurité est essentielle pour nous, et nous ne voulons pas que quelqu'un puisse usurper votre identité ou celle de votre application en passant des appels à partir de votre numéro. Pour sécuriser notre Voice API, nous utilisons votre clé privée pour créer un jeton Web JSON (JWT).
Avant de commencer, nous allons donc créons une nouvelle application Nexmoattachons-la à un numéro virtuel, puis générons et téléchargeons notre clé privée.

N'oubliez pas de conserver votre clé privée en lieu sûr ; je vous recommande d'utiliser quelque chose comme Vault. Si vous pensez, pour quelque raison que ce soit, que quelqu'un a compromis votre clé privée, vous devez cesser de l'utiliser immédiatement et générer une nouvelle paire de clés publique/privée.
Création d'un BCN de base
L'API Voice API pour les appels sortants vocale sortante nécessite un answer_url. Lorsque quelqu'un répond à notre appel, Nexmo récupère notre fichier NCCO à partir de cette URL et exécute toutes les actions définies dans ce fichier. Créons une application Django afin de pouvoir servir notre fichier JSON NCCO.
Nous allons installer nos dépendances via pip. Je recommande toujours de garder chaque projet Python et ses dépendances dans leur propre environnement virtuel.
pip install django nexmo
django-admin startproject ttsUne fois que nous avons notre projet Django, nous devons créer une nouvelle application, c'est là que se déroulera l'essentiel de notre développement.
cd tts
python manage.py startapp outboundAprès avoir créé votre nouvelle application, n'oubliez pas de l'ajouter à votre base de données. tts/settings.pyVous devriez probablement éditer votre ALLOWED_HOSTS pendant que vous modifiez vos paramètres.
INSTALLED_APPS = [
…
'outbound'
]
ALLOWED_HOSTS = ["*"] # Never do this in production!Notre première vue sera un fichier JSON statique. Nous allons créer un répertoire templates dans le dossier de notre nouvelle application et y ajouter notre fichier JSON.
mkdir -p outbound/templates/outbound
touch outbound/templates/outbound/hello.jsonModifiez votre fichier hello.json et ajoutez la première action pour votre NCCO
[
{
"action": "talk",
"text": "Hello World from Nexmo"
}
]Dans le code ci-dessus, nous définissons une nouvelle liste qui contient une seule action talk qui utilisera la synthèse vocale pour lire la chaîne de caractères text à notre interlocuteur chaque fois qu'il répondra à notre appel sortant. Nous devons encore rendre ce fichier chaque fois que nous recevons une requête GET sur la route spécifiée, la fonction générique TemplateView de Django est parfait pour cela. Comme nous n'étendons pas la classe TemplateViewnous pouvons l'importer directement dans notre tts/urls.py
from django.conf.urls import url
from django.views.generic import TemplateView
urlpatterns = [
url(r'^hello/', TemplateView.as_view(
template_name='outbound/hello.json',
content_type='application/json'
)),
]Une fois que vous avez édité votre urls.py démarrez votre serveur Django et vérifiez que tout fonctionne en visitant http://127.0.0.1:8000/hello/
python manage.py runserverAvec un peu de chance, vous voyez le fichier NCCO que nous avons créé ci-dessus. Si ce n'est pas le cas, vérifiez l'écran de débogage du navigateur ou votre terminal pour voir s'il y a des erreurs.
Avant de pouvoir effectuer notre appel sortant, nous avons besoin que notre serveur Django soit joignable par l'API Nexmo. Nous recommandons d'utiliser ngrok pour cela si vous avez des problèmes lisez notre article de blog sur la connexion de votre serveur de développement local à l'API Nexmo à l'aide d'un tunnel ngrok.
ngrok http 8000Nous aurons besoin de plusieurs terminaux pour la suite, vous pouvez donc utiliser screen ou tmux. Assurez-vous que votre serveur Django tourne toujours dans un terminal et que ngrok est actif dans un autre. Nous allons faire notre premier appel sortant via la REPL de Python, donc lancez python dans une autre fenêtre de terminal, mais n'oubliez pas d'activer d'abord votre environnement virtuel !
import nexmo
client = nexmo.Client(application_id='<VOICE APP ID>', private_key='private.key')
to_number = [{'type': 'phone', 'number': '<YOUR NUMBER>'}]
from_number = {'type': 'phone', 'number': '<NEXMO VIRTUAL NUMBER>'}
answer_url = ['https://<NGROK URL>/hello/']
client.create_call({'to': to_number, 'from': from_number, 'answer_url': answer_url})
Après avoir exécuté les commandes ci-dessus, regardez votre terminal ngrok et vous devriez voir Nexmo demander votre NCCO ! C'était un exemple assez simple, essayons d'envoyer un message plus excitant.

Appel sortant avec données dynamiques
Cette fois-ci, nous allons créer notre NCCO de manière dynamique en utilisant les informations de l'API Marvel API. Avant de commencer la partie suivante, vous devez vous inscrire pour obtenir un compte développeur Marvel gratuitAprès m'être enregistré, j'ai ajouté mes informations d'identification Marvel en tant que variables d'environnement.
export MARVEL_API_KEY='<YOUR API KEY>'
export MARVEL_PRIVATE_KEY='<YOUR PRIVATE KEY>'
Ces commandes créent les variables d'environnement dans un système UNIX. Cependant, vous devrez les exporter à chaque fois que vous redémarrerez votre shell. Vous pouvez utiliser python-dotenv pour rendre cela automatique.
Créons une nouvelle route dans notre urls.py pour ce nouveau point de terminaison NCCO.
from django.conf.urls import url
from django.views.generic import TemplateView
from outbound.views import MarvelView
urlpatterns = [
url(r'^hello/', TemplateView.as_view(
template_name='outbound/hello.json',
content_type='application/json'
)),
url(r'^marvel/', MarvelView.as_view())
]Dans votre views.py nous allons importer et étendre le TemplateView.
import os
from hashlib import md5
from time import time
import random
import requests
from django.utils.html import strip_tags
from django.views.generic import TemplateView
class MarvelView(TemplateView):
template_name = 'outbound/marvel.json'
content_type = 'application/json'
@staticmethod
def get_marvel_data():
marvel_api_url = 'https://gateway.marvel.com:443/v1/public/characters'
private_key = os.environ['MARVEL_PRIVATE_KEY']
api_key = os.environ['MARVEL_API_KEY']
# Create Marvel API request params
timestamp = str(time())
hashed_key = md5(
str(timestamp + private_key + api_key).encode('utf-8')
)
# Fetch Avengers data from Marvel API
response = requests.get(
marvel_api_url,
params={
'series': '22547', # Avengers (2016 - Present)
'apikey': api_key,
'ts': timestamp,
'hash': hashed_key.hexdigest()
},
headers={
'Accept': 'application/json'
}
)
marvel_response_data = response.json()
# Some characters don't have descriptions, ignore those characters
return [{
'name': x['name'],
'description': x['description']
} for x in marvel_response_data['data']['results'] if x['description']]
@staticmethod
def random_voice_name():
# https://developer.nexmo.com/api/voice/ncco#voice-names
return random.choice([
'Salli', 'Joey', 'Nicole', 'Russell', 'Amy', 'Brian', 'Emma',
'Gwyneth', 'Geraint', 'Raveena', 'Chipmunk', 'Eric', 'Ivy',
'Jennifer', 'Justin', 'Kendra', 'Kimberly',
])
# Add our Marvel data to the templete context
def get_context_data(self, **kwargs):
marvel_data = self.get_marvel_data()
random_character = random.choice(marvel_data)
kwargs['voice_name'] = self.random_voice_name()
# Concat our character name & bio together to act as our voice message
# Also remove any errant HTML tags from Marvel text
kwargs['marvel_message'] = "{name} - {description}".format(
name=strip_tags(random_character['name']),
description=strip_tags(random_character['description'])
)
return super(MarvelView, self).get_context_data(**kwargs)
A propos de notre vue personnalisée

Passons en revue ce qui se passe dans notre nouveau ... MarvelView. Nous devons ajouter deux éléments de données disponibles dans notre contexte lors du rendu de notre marvel.json lors du rendu de notre modèle, voice_name et marvel_message. Le voice_name est simple ; c'est le nom d'une voix synthétisée aléatoire en langue anglaise à partir de la sélection de sélection proposée par l'API de synthèse vocale Nexmo. Pour le marvel_message nous interrogeons l'API Marvel pour tous les personnages de la série Avengers (2016 - présent). Après avoir légèrement nettoyé les données, en supprimant toutes les balises HTML erronées et en ignorant les caractères avec des informations manquantes, nous concaténons le nom du personnage et sa description en une seule chaîne. Nous concaténons le nom du personnage et sa description en une seule chaîne ; c'est notre marvel_message.
Si nous essayons d'accéder à http://127.0.0.1:8000/marvel/ maintenant, nous obtiendrons une TemplateDoesNotExist exception. Dans notre dossier de modèles, nous devons créer un fichier marvel.json
[
{
"action": "talk",
"text": "{{ marvel_message|safe }}",
"voiceName": "{{ voice_name }}"
}
]Nous pouvons maintenant tester notre nouveau point de terminaison, et avec un peu de chance, nous devrions voir des informations sur un personnage aléatoire des Avengers ! Données fournies par Marvel. 2014 Marvel
[
{
"action": "talk",
"text": "Taskmaster - Taskmaster first exhibited his unusual ability, called 'photographic reflexes,' which allowed him to mimic the motion of anyone he saw, when he was a young boy.",
"voiceName": "Emma"
}
]
Passer notre appel sortant Avengers en synthèse vocale
Cette fois-ci, au lieu d'utiliser la REPL Python pour passer notre appel, nous allons l'intégrer dans une commande de gestion afin de pouvoir passer rapidement un appel Marvel sortant vers n'importe quel numéro. Les commandes de gestion de Django nécessitent une structure de répertoire particulière, créons-la d'abord.
mkdir -p outbound/management/commands
touch outbound/management/__init__.py
touch outbound/management/commands/__init__.py
touch outbound/management/commands/marvel.pyMaintenant que les fichiers sont en place, nous pouvons écrire notre marvel.py
import nexmo
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = 'Random Avenger character as a TTS phonecall'
def add_arguments(self, parser):
parser.add_argument('to_number', type=str)
parser.add_argument('from_number', type=str)
def handle(self, *args, **options):
client = nexmo.Client(
application_id='<YOUR NEXMO VOICE APP ID>',
private_key='private.key'
)
to_number = [{'type': 'phone', 'number': options['to_number']}]
from_number = {'type': 'phone', 'number': options['from_number']}
answer_url = ['https://<NGROK URL>/marvel/']
response = client.create_call({
'to': to_number,
'from': from_number,
'answer_url': answer_url
})
self.stdout.write(str(response))
Ce code est essentiellement le même que celui que nous avons fait précédemment sur la REPL, mais nous l'avons maintenant enveloppé dans une commande de gestion de Django. La nouvelle commande marvel prend deux arguments : le numéro que nous voulons appeler et le numéro virtuel Nexmo d'où l'appel doit provenir.

Quelle est la prochaine étape ?

Lorsque vous avez une alerte urgenteLes appels en synthèse vocale sont parfaits, mais parfois il ne suffit pas de savoir que quelqu'un a répondu à l'appel. Combinez la synthèse vocale sortante avec le SVI pour s'assurer que la personne a bien reçu le message.
Partager:
Aaron était défenseur des développeurs chez Nexmo. Ingénieur logiciel chevronné et artiste numérique en herbe, Aaron est souvent amené à créer des choses avec du code ou de l'électronique, parfois les deux. On peut généralement savoir qu'il travaille sur quelque chose de nouveau grâce à l'odeur de composants brûlés qui flotte dans l'air.
