
Teilen Sie:
Mark war nominell für die Client-Bibliotheken von Nexmo verantwortlich (obwohl er nur die Python- und Java-Bibliotheken schreibt). Er war ursprünglich Java-Entwickler, ist seit 18 Jahren Python-Entwickler und beschäftigt sich zunehmend mit Go und Rust. Er liebt es, Programmiersprachen bis an ihre Grenzen zu treiben und diese Techniken dann anderen Programmierern beizubringen. Er trägt einen Wikingerhut, ist aber kein Wikinger, und aus Gründen, die er nicht näher erläutern möchte, ist er Judy2k auf Twitter.
Einrichtung einer Familien-Hotline mit Vonage
Lesedauer: 15 Minuten
Jedes Unternehmen, das ich anrufe, hat immer eines dieser automatischen Anrufbeantworter, die mir Fragen stellen, bevor ich mit einem echten Menschen spreche, und weil ich ein bisschen komisch bin, habe ich immer gedacht: "Warum kann ich nicht I so etwas haben?"
Meine Tochter wurde vor ein paar Monaten in die Sekundarschule eingeschult, und das Formular, das wir ausfüllen sollten, enthielt nur ein Feld für die nur ein Feld für eine Kontakttelefonnummer. Was passiert, wenn wir ihnen meine Daten geben und ich nicht erreichbar bin? Zum Glück arbeite ich für Vonage und weiß, wie ich eine Telefonnummer einrichten kann, die Anrufe an einen von uns beiden weiterleitet - oder an beide! Vonage als Retter in der Not!
Was wir bauen werden
Die Schule erhält eine Vonage-Nummer als Kontaktnummer.
Wenn sie die Nummer anrufen, erhalten sie eine automatische Nachricht mit den folgenden Optionen:
Führen Sie die Namen der Eltern auf, mit einer Ziffer, die Sie drücken müssen, um sie an die Eltern weiterzuleiten.
Wenn der Anrufer nichts tut, wird an das erste Elternteil in der Liste weitergeleitet.
Drücken Sie '*', wenn es sich um einen Notfall handelt. Dadurch wird eine Telefonkonferenz eingerichtet und beide Elternteile werden eingewählt.
Ich hatte noch ein paar andere Anforderungen:
Einfach und praktisch kostenlos zu hosten und zu betreiben sein.
Es muss keine Datenbank verwaltet werden, was die Sache noch einfacher macht.
Wie wir es aufbauen werden
Ich habe mich für ein paar Technologien entschieden, mit denen ich am besten vertraut bin - Python 3.6 und Flask. Ich habe mich für Python 3.6 entschieden, weil dies die Version war, die mit f-strings und die sind großartig! Ich verwende außerdem pipenv um meine Python-Abhängigkeiten zu verwalten.
Diese Kombination ermöglicht es uns, ein großartiges IVR-System (Interactive Voice Response) in nur 100 Codezeilen zu erstellen!
Vonage API-Konto
Um dieses Tutorial durchzuführen, benötigen Sie ein Vonage API-Konto. Wenn Sie noch keines haben, können Sie sich noch heute anmelden und mit einem kostenlosen Guthaben beginnen. Sobald Sie ein Konto haben, finden Sie Ihren API-Schlüssel und Ihr API-Geheimnis oben auf dem Vonage-API-Dashboard.
Los geht's!
Richten wir zunächst unsere Entwicklungsumgebung ein.
Da Vonage den Server anrufen muss, den Sie schreiben werden, und Ihr Laptop hinter einer sicheren Firewall sitzt, werden Sie wahrscheinlich ngrok für die lokale Entwicklung verwenden - ich empfehle den ausgezeichneten Blogbeitrag meines Kollegen Aaron ausgezeichneten Blog-Post über die Verwendung von ngrok.
Sie werden wahrscheinlich Folgendes installieren wollen pipenv global installieren, und von da an werden wir es verwenden, um die virtuelle Umgebung unseres Projekts zu verwalten:
Installieren wir nun die Abhängigkeiten, die wir für dieses Projekt benötigen, und aktivieren wir unsere virtuelle Umgebung. Führen Sie die folgenden Befehle im Verzeichnis Ihres neuen Projekts aus - ich habe meines so genannt hotline:
Beginnen wir nun mit dem Schreiben unseres Flask-Servers.
Öffnen Sie eine Datei namens hotline.pyund geben Sie Folgendes ein:
from flask import Flask, jsonify, url_for as url_for_, request
app = Flask(__name__)
@app.route("/incoming/", methods=["GET", "POST"])
def incoming():
"""
An HTTP endpoint which handles incoming calls.
:return: A JSON HTTP response containing the main menu NCCO actions.
"""
return jsonify(
[
{
"action": "talk",
"text": "Welcome to the Brockman family hotline",
"voiceName": "Amy",
}
]
)Jetzt, in separaten Terminalfenstern die folgenden Befehle gleichzeitig aus:
Wenn Sie ngrokausführen, gibt es den generierten Domänennamen aus, den es an Ihren Server weiterleitet. Es wird ungefähr so aussehen: https://abcde1234.ngrok.io -> localhost:5000. Jetzt können Sie Ihre Flask-Applikation testen unter https://abcde1234.ngrok.io/incoming (ersetzen Sie abcde1234 mit dem, was auf Ihrem Terminal ausgegeben wurde).
Sie sollten etwa so aussehen:
First Test
Telefonieren Sie mit Ihrem Server
Jetzt müssen Sie eine Virtuelle Vonage-Nummer um Ihren Server anzurufen, wenn jemand Ihre Nummer anruft. Sie brauchen also 3 Dinge:
Eine konfigurierte Voice-Anwendung
Eine konfigurierte virtuelle Vonage-Nummer.
Vonage-Account erstellen
Vonage API-Konto
Um dieses Tutorial durchzuführen, benötigen Sie ein Vonage API-Konto. Wenn Sie noch keines haben, können Sie sich noch heute anmelden und mit einem kostenlosen Guthaben beginnen. Sobald Sie ein Konto haben, finden Sie Ihren API-Schlüssel und Ihr API-Geheimnis oben auf dem Vonage-API-Dashboard.
In diesem Lernprogramm wird auch eine virtuelle Telefonnummer verwendet. Um eine zu erwerben, gehen Sie zu Rufnummern > Rufnummern kaufen und suchen Sie nach einer Nummer, die Ihren Anforderungen entspricht.
Installieren Sie die Vonage CLI
Installieren Sie die Vonage CLI global mit diesem Befehl:
npm install @vonage/cli -gAls nächstes konfigurieren Sie die CLI mit Ihrem Vonage-API-Schlüssel und -Geheimnis. Sie finden diese Informationen im Entwickler-Dashboard.
vonage config:set --apiKey=VONAGE_API_KEY --apiSecret=VONAGE_API_SECRET Erstellen einer Voice-Applikation
Erstellen Sie ein neues Verzeichnis für Ihr Projekt und legen Sie eine CD darin ab:
mkdir my_project
CD my_projectVerwenden Sie nun die CLI, um eine Vonage-Anwendung zu erstellen.
Sie sollten den Ausweis, der nach dem Ausfüllen des Formulars ausgedruckt wird, speichern. Application created:. Sie werden sie im nächsten Schritt benötigen.
Kaufen Sie eine Numbers und verknüpfen Sie sie mit Ihrer Voice App
Jetzt brauchen Sie eine Nummer, damit Sie Anrufe empfangen können. Sie können eine Nummer mieten, indem Sie den folgenden Befehl verwenden (ersetzen Sie die Landesvorwahl durch Ihre Vorwahl). Wenn Sie sich zum Beispiel in den USA befinden, ersetzen Sie GB durch US:
Verknüpfen Sie nun die Nummer mit Ihrer App:
vonage apps:link --number=VONAGE_NUMBER APP_IDOkay!
Jetzt können Sie das alles testen, indem Sie die soeben gekaufte Telefonnummer anrufen. Sie sollten hören, wie Amy die Nachricht "Willkommen bei der Brockman-Familienhotline" vorliest. Wenn Sie eine Meldung hören, dass die Nummer nicht erkannt wurde, oder die Dinge nicht funktionieren, öffnen Sie die ngrok-Debug-Seite unter http://127.0.0.1:4040/ in Ihrem Browser, damit Sie sehen können, welche Anfragen eingegangen sind und ob der Server korrekt geantwortet hat.
Reagieren auf INPUT
Ändern wir die Nachricht und fügen wir eine Eingabeaktion zu unserem Menü NCCO hinzu, damit der Anrufer die Person auswählen kann, mit der er sprechen möchte:
@app.route("/incoming/", methods=["POST", "GET"])
def incoming():
"""
An HTTP endpoint which handles incoming calls.
"""
return jsonify(
[
{
"action": "talk",
"text": """
Welcome to the Brockman family hotline.
To speak to Pete Brockman, please press 1.
To speak to Sue Brockman, please press 2.
""",
"voiceName": "Amy",
"bargeIn": True,
},
{
"action": "input",
"eventUrl": [url_for("family_selection")],
"maxDigits": 1,
},
]
)
@app.route("/family-selection/", methods=["POST"])
def family_selection():
"""
An HTTP endpoint which handles the DTMF input from the main menu.
"""
postdata = request.json
if postdata["timed_out"]:
index = 0
else:
index = int(postdata["dtmf"]) - 1
return jsonify([{
"action": "talk",
"text": f"You selected the {index} option",
}])Noch ist es nicht so weit! Wir sind noch nicht ganz so weit ... aber lassen Sie mich erklären, was dies bewirkt:
Ich habe folgendes zur talk Aktion hinzugefügt:
"bargeIn": True,Das bedeutet, dass der Anrufer eine Nummer auf seinem Telefon drücken kann, während die talk Aktion noch die Nachricht vorliest. Dadurch wird automatisch die folgende input Aktion. Ich habe auch die folgende Aktion hinzugefügt:
{
"action": "input",
"eventUrl": [url_for("family_selection")],
"maxDigits": 1,
},Diese input Aktion weist Vonage an, die family_selection Funktion aufzurufen, die wir ebenfalls gerade hinzugefügt haben. Die Funktion von Flask url_for Funktion liefert die URL für den angegebenen Funktionsnamen.
Eine saubere Verwendung vonpartial
url_for erzeugt standardmäßig eine relative URL. Relative URLs werden von Vonage Voice nicht unterstützt - daher habe ich das Folgende am Anfang der Datei hinzugefügt:
from functools import partial
from flask import url_for as url_for_
# We don't have any use for relative URLs, so hard-code this param:
url_for = partial(url_for_, _external=True)Diese Verwendung von partial setzt die url_for Funktion auf etwas Nützlicheres - es ist eine Kopie von Flask's url_for Funktion, aber mit dem Standardwert des _external Parameters auf True. (Ich habe vergessen, diesen Parameter zu setzen so viele Male bevor ich es hiermit behoben habe).
Sobald Sie das zu Ihrer Datei hinzugefügt und sichergestellt haben, dass Ihr Server neu geladen wurde, ist es an der Zeit, Ihre Nummer erneut anzurufen. Es sollte Ihnen die Nachricht vorlesen, Ihnen die Möglichkeit geben, eine Nummer auf Ihrem Telefon zu wählen, und Ihnen dann diese Nummer vorlesen, wobei eine Nummer abgezogen wird. Wenn Sie ein paar Sekunden warten, sollte es Ihnen mitteilen, dass Sie die Nummer zero.
Warum ziehe ich 1 von der eingegebenen Zahl ab? Damit wir eine Person aus einer Liste auswählen können! Wenn der Test oben gut gelaufen ist, können wir die Personen in eine Liste aufnehmen und das Menü etwas dynamischer gestalten.
Weiterleitung von Anrufen
Das erste, was wir wirklich brauchen, ist eine bessere Möglichkeit, unsere "Eltern" zu konfigurieren. Es ist gut, eine Liste der Personen zu haben, an die wir Anrufe weiterleiten wollen. Für den Moment legen wir ihre Details in der Python-Datei fest. Bitte machen Sie das nicht mit echten Telefonnummern und stellen Sie sie nicht in ein öffentliches Repository!
import attr
@attr.s
class Endpoint:
""" A data class containing a potential callee's details. """
name = attr.ib()
phone_number = attr.ib()
ENDPOINTS = [
Endpoint(name="Pete Brockman", phone_number="447700900123"),
Endpoint(name="Sue Brockman", phone_number="447700900456"),
]
VONAGE_NUMBER = "447700900847"Im obigen Code verwende ich die erstaunliche attrs Bibliothek, um eine einfache Klasse zu definieren, Endpointzu definieren, die den Namen und die Telefonnummer einer Person enthält. Ich erstelle dann eine Liste von Endpoints für die Personen, an die wir Anrufe weiterleiten wollen.
Jetzt füge ich eine einfache Hilfsfunktion zur Erzeugung von talk Aktionen. Das macht den Code lesbarer und bedeutet, dass wir standardmäßig die Amy Stimme. Eine Liste aller Stimmen, die Vonage unterstützt, finden Sie hier
def talk(message, voice="Amy", barge_in=None):
""" Utility function to generate a `talk` NCCO action. """
response = {"action": "talk", "text": message, "voiceName": voice}
if barge_in is not None:
response["bargeIn"] = barge_in
return responseUnd jetzt Ich habe den Code für die Generierung der Hauptmenünachricht ausgeklammert:
def make_answer_message(message, endpoints):
"""
Generate a script to be read to the caller, informing them of their options.
"""
endpoint_options = [
f"To speak to {endpoint.name}, please press {code}."
for code, endpoint in enumerate(endpoints, start=1)
]
return " ".join([message, *endpoint_options, "If you're not sure, please hold."])Sie sehen das *endpoint_options in der letzten Zeile des obigen Codes? Wussten Sie, dass Sie in Python 3 eine Liste in eine andere Liste erweitern können? In diesem Fall ist das Ergebnis eine Liste von Zeichenketten, die wir mit Leerzeichen zusammenfügen können.
Sie können nun die talk Aktion in der incoming Methode durch den folgenden Aufruf der talk Funktion ersetzen:
talk(
make_answer_message(
"Welcome to the Brockman family hotline.", ENDPOINTS
),
barge_in=True,
),Und schließlich können Sie die Funktion family_selection Funktion so ändern, dass sie den Anruf tatsächlich an eine Telefonnummer weiterleitet:
@app.route("/family-selection/", methods=["POST"])
def family_selection():
"""
An HTTP endpoint which handles the DTMF input from the main menu.
"""
postdata = request.json
try:
if postdata["timed_out"]:
index = 0
else:
index = int(postdata["dtmf"]) - 1
if index < len(ENDPOINTS):
# They elected to speak to an individual
endpoint = ENDPOINTS[index]
return jsonify(
[
talk(f"Connecting to {endpoint.name}"),
{
"action": "connect",
"from": VONAGE_NUMBER,
"endpoint": [{"type": "phone", "number": endpoint.phone_number}],
},
]
)
except ValueError:
pass # This is raised by `int`, and can be ignored - we just forward on to the following error message...
return jsonify([talk("I didn't understand that option.")])
Der obige Code sieht viel komplizierter aus als vorher, aber das liegt daran, dass wir jetzt eine Fehlerprüfung durchführen und dem Anrufer mitteilen, wenn er eine Taste gedrückt hat, die wir nicht erwartet haben. Wenn der Benutzer die Taste 1 oder 2 drückt, wird ihm eine Nachricht vorgelesen, die besagt, dass er verbunden wird, und dann wird er mit der Nummer des Endpunkts verbunden.
Okay, was haben wir bis jetzt gemacht?
Die Schule kann meine Nummer anrufen und bekommt eine Liste von Personen, mit denen sie Kontakt aufnehmen kann.
Wenn sie die 1 oder 2 drücken, werden sie mit dieser Person verbunden. (Übrigens kann keine der beiden Seiten des Anrufs die Telefonnummer des anderen sehen, so dass dies eine großartige Möglichkeit ist, Anrufe zu anonymisieren).
Wenn der Anrufer wartet, wird er mit dem ersten Endpunkt in der konfigurierten Liste verbunden.
Wir könnten hier aufhören, wenn wir wollen, aber ich hatte eine dritte Forderung: Im Falle eines Notfalls könnte der Anrufer auf stardrücken, um uns beide anzurufen und uns alle in eine Telefonkonferenz einzuwählen.
Hinzufügen einer Konferenzgesprächsoption
Eine Telefonkonferenz wird mit einer conversation Aktion erstellt und endet (standardmäßig), wenn keine weiteren Personen an der Konferenz teilnehmen. Das einzige, was wir brauchen, um eine Person mit einer Telefonkonferenz zu verbinden, ist der Name, den wir der Telefonkonferenz mit der ersten conversation Aktion gegeben haben.
Initialisieren eines Client-Objekts
Wir brauchen ein Vonage Client Objekt, um ausgehende Anrufe zu den Eltern zu erzeugen. Zum Glück haben wir die Vonage Python-Bibliothek zu Beginn dieses Tutorials installiert, oder? Fügen Sie die folgenden Zeilen ganz oben in Ihre Datei ein. Wenn Sie möchten möchten, können Sie Ihre application_id und private_key Werte direkt in die Datei einfügen, aber ich denke, es ist besser, sie stattdessen aus Umgebungsvariablen zu laden. Es ist zu einfach, sie an ein öffentliches Repository zu übergeben, und jeder, der sie hat, kann Ihr Vonage-Guthaben ausgeben!
import vonage
vonage_client = vonage.Client(
application_id=os.getenv('VONAGE_APPLICATION_ID'),
private_key=os.getenv('VONAGE_PRIVATE_KEY')
) Sagen Sie dem Benutzer, dass er "*" drücken kann.
Bevor wir das tun, fügen wir die Nachricht "If this is an emergency, please press star." in die Zeichenkette ein, die von unserer make_answer_message Funktion zurückgegeben wird. Ich habe sie direkt nach dem message Element in der Liste.
Erstellen einer Telefonkonferenz
Lassen Sie uns nun unsere Telefonkonferenz erstellen. Atmen Sie tief durch; es ist ein ziemlich großer Codeblock.
Wir benötigen einen neuen HTTP-Endpunkt mit der Bezeichnung conference_nccoder NCCO-Aktionen für jeden der Elternteile, die sich in die Telefonkonferenz einwählen, bereitstellt.
Ich habe den gesamten Code für die Anwahl der Eltern und die Generierung von NCCO-Aktionen für den Anrufer in eine Funktion namens create_conference_call.
Ich füge die beiden Funktionen zusammen ein, damit Sie sehen können, wie der Parameter conference_id, der in create_conference_call generiert wird, in den URL-Pfad zum conference_ncco Endpunkt eingebettet wird, so dass er den Namen der Telefonkonferenz kennt und in die conversation NCCO-Aktion einzubetten.
@app.route("/conference/<conference_id>/ncco", methods=["GET", "POST"])
def conference_ncco(conference_id: str):
"""
An HTTP endpoint which generates the NCCO actions to connect a callee to
a conference call.
"""
return jsonify(
[
talk("You are being connected to a family hotline conference call."),
{"action": "conversation", "name": conference_id},
]
)
def create_conference_call(endpoints):
"""
Generate an NCCO response to connect the caller to all the provided
`endpoints` in a single conference call.
"""
# Generate a unique name for our conference:
conference_name = str(uuid.uuid4())
# Loop through the endpoints and dial them into the conference call:
for endpoint in endpoints:
vonage_client.create_call(
{
"to": [{"type": "phone", "number": endpoint.phone_number}],
"from": {"type": "phone", "number": VONAGE_NUMBER},
"answer_url": [
url_for("conference_ncco", conference_id=conference_name)
],
}
)
print(f"Dialing {endpoint.phone_number} into {conference_name}")
# Connect the inbound leg to the conference call we're creating:
return jsonify(
[
talk("Connecting all parties."),
{
"action": "conversation",
"name": conference_name,
},
]
) Umgang mit einer Sterneingabe
Jetzt müssen wir nur noch die family_selection so modifizieren, dass sie weiß, was sie mit einem * dtmf-Code zu tun hat, indem wir dies an den Anfang der Funktion setzen:
if postdata["dtmf"] == "*":
return create_conference_call(ENDPOINTS) Testen Sie es!
Rufen Sie Ihre Vonage-Nummer an und folgen Sie den Anweisungen im Hauptmenü, um zu überprüfen, ob sie funktionieren! Wenn alles funktioniert, ist es an der Zeit, es einzurichten!
Einsetzen!
Wenn Sie sich das Git-Repository für dieses Projekt ansehen, werden Sie sehen, dass ich einige kleinere Änderungen daran vorgenommen habe, darunter das Laden aller Konfigurationen aus Umgebungsvariablen und das Hinzufügen eines Procfiles. Dies sollte bedeuten, dass die Bereitstellung auf Heroku relativ einfach ist - aber ich überlasse das als Übung für Sie! Vergessen Sie nicht, die Konfiguration Ihrer Vonage-Anwendung so zu aktualisieren, dass sie auf die neue Heroku-URL statt auf die ngrok-URL verweist, die Sie für die Entwicklung verwendet haben.
Sobald es eingesetzt wird, ist es an der Zeit, mit der Schule Ihres Kindes zu sprechen und sie zu bitten, Ihre Kontaktdaten zu aktualisieren!
Was haben wir getan?
Wir haben ein komplettes IVR-System entwickelt, damit die Schule uns kontaktieren kann! Es kann Anrufe an einzelne Numbers weiterleiten oder alle zu einer Telefonkonferenz zusammenschalten!
Weitere Kredite
Einige weitere Dinge, die ich mit diesem Server machen wollte, sind:
Weiterleitung der an die Nummer gesendeten SMS-Nachrichten an beide Elternteile.
Senden von Textnachrichten, um Eltern zu informieren, wenn sie einen Anruf von der Schule verpasst haben.
Erstellen eines "Wettanrufs", bei dem beide Elternteile angerufen werden und der erste, der sich meldet, den Anruf entgegennimmt. Der zweite Anruf wird unterbrochen und erhält eine SMS, dass der andere Elternteil den Anruf entgegengenommen hat.
Wenn kein Elternteil abnimmt, kann die Schule eine Nachricht aufzeichnen, die dann von beiden Elternteilen abgeholt werden kann.
Integration mit einem Familien-Slack, mit Warnungen für eingehende Anrufe, Weiterleitung von SMS-Nachrichten an das Slack und sogar das Posten von aufgezeichneten Nachrichten, die im Slack abgespielt werden!
Wie Sie sehen können, gibt es viele Möglichkeiten, wenn Sie erst einmal angefangen haben. Ich hoffe, Sie hatten viel Spaß mit diesem Tutorial. Ich bin @judy2k auf Twitter - folgen Sie mir, oder stellen Sie mir Fragen zu diesem Tutorial!
Teilen Sie:
Mark war nominell für die Client-Bibliotheken von Nexmo verantwortlich (obwohl er nur die Python- und Java-Bibliotheken schreibt). Er war ursprünglich Java-Entwickler, ist seit 18 Jahren Python-Entwickler und beschäftigt sich zunehmend mit Go und Rust. Er liebt es, Programmiersprachen bis an ihre Grenzen zu treiben und diese Techniken dann anderen Programmierern beizubringen. Er trägt einen Wikingerhut, ist aber kein Wikinger, und aus Gründen, die er nicht näher erläutern möchte, ist er Judy2k auf Twitter.
