Komplexe IVRs für ein CRM selbst erstellen

Nathalie
24.11.2021 0 7:33 min

Was ist sipgate.io?

sipgate.io ist eine Sammlung von APIs, die es den Kund:innen von sipgate
ermöglicht, flexible Integrationen für ihre individuellen Bedürfnisse zu
erstellen. Sie bietet unter anderem Schnittstellen zum Senden und Empfangen von Textnachrichten oder Faxen, zur Überwachung der Anrufhistorie sowie zum Initiieren und Manipulieren von Anrufen. In diesem Tutorial werden wir die Push-API von sipgate.io nutzen, um einen Anruf anzunehmen und einen IVR-Prozess zu starten. Die Anrufer:innen können dann mit Hilfe von DTMF-Tönen Informationen übermitteln. DTMF-Töne sind die Töne, die Sie hören, wenn Sie auf der Tastatur Ihres Telefons tippen.

In diesem Tutorial

Das Skript in diesem Projekt richtet einen einfachen Webserver ein, der auf Ihrem lokalen Rechner läuft. Wenn jemand versucht, Ihre sipgate-Nummer zu erreichen, nimmt dieser Webserver den Anruf entgegen und spielt den IVR-Prozess ab. Unser IVR-System besteht aus drei Phasen:

  1. Begrüßungsphase: Eine Audiodatei begrüßt Anrufer:innen und fragt sie nach deren Kundennummer.
  2. Anforderungsphase: Nachdem die Anrufer:innen die Nummer über ihre Tastatur eingegeben haben, fragt das System, ob sie ihr Guthaben abfragen (Tastennummer 1) oder mit dem Kundendienst sprechen möchten (Tastennummer 3).
  3. Endphase: Je nach Entscheidung der Anrufer:innen spielt das System abschließend wieder eine Audiodatei ab.

Voraussetzungen: Sie haben node.js and NPM auf ihrem Computer installiert.

Erste Schritte

Aufsetzen des Projekts

Wir nutzen Node.js, um die offizielle sipgate.io node Bibliothek zu benutzen. Zuerst erstellen wir ein neues Node.js Projekt, welches eine index.ts Datei enthält, in der das Skript geschrieben wird.

npm init -y
mkdir src
touch src/index.ts

Wir benötigen noch weitere Abhängigkeiten, die wir mit diesem Befehl installieren:

npm i sipgateio dotenv ts-node
npm i -D typescript
  • sipgateio: Eine von uns entwickelte Library, mit der wir einen Server aufbauen können und Antworten auf Webhooks entwerfen können.
  • dotenv: Hiermit können die in der .env-Datei gespeicherten Variablen gelesen werden.
  • ts-node &typescript: Das hilft uns, Typescript-Dateien ausführen zu können (typescript wird als dev dependency installiert).

Weitere Konfigurationen

Außerdem kommen noch zwei weitere Dateien dazu:

touch .env tsconfig.json

Die .env-Datei enthält die Server Adresse (die wir später noch hinzufügen werden) und den Port, auf den wir hören:

SIPGATE_WEBHOOK_SERVER_ADDRESS=
SIPGATE_WEBHOOK_SERVER_PORT=8080
  

Die Datei tsconfig.json gibt die root-Dateien und die Compileroptionen an, die zum Kompilieren eines Typescript-Projekts erforderlich sind:

{
    "compilerOptions": {
        "target": "es2017",
        "module": "commonjs",
        "lib": ["dom", "es6", "es2017", "esnext.asynciterable"],
        "skipLibCheck": true,
        "sourceMap": true,
        "outDir": "./dist",
        "moduleResolution": "node",
        "removeComments": true,
        "noImplicitAny": true,
        "strictNullChecks": true,
        "strictFunctionTypes": true,
        "noImplicitThis": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "noImplicitReturns": true,
        "noFallthroughCasesInSwitch": true,
        "allowSyntheticDefaultImports": true,
        "esModuleInterop": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "resolveJsonModule": true,
        "baseUrl": "."
    },
    "exclude": ["node_modules"],
    "include": ["./src/**/*.ts"]
}
  

Zuletzt müssen wir noch Änderungen an der automatisch generierten package.json vornehmen. Füge diese Zeilen für die Ausführung des Projekts hinzu:

"main": "src/index.ts",
"scripts": {
    "start": "ts-node ."
}
    

Aufbau des Skripts

Zunächst müssen die Dependencies, die wir zu Beginn installiert haben, importiert werden, damit wir sie für unser Skript verwenden können:

import * as dotenv from "dotenv";
import { createWebhookModule, WebhookResponse } from "sipgateio";
    

Als nächstes setzen wir die Umgebungsvariablen, wie sie in der .env-Datei definiert sind. Falls sie nicht gesetzt sind, werden Fehler geworfen und der Prozess beendet.

dotenv.config();

if (!process.env.SIPGATE_WEBHOOK_SERVER_ADDRESS) {
    console.error(
        "ERROR: You need to set a server address to receive webhook events!\n",
    );
    process.exit();
}
    
if (!process.env.SIPGATE_WEBHOOK_SERVER_PORT) {
    console.error(
        "ERROR: You need to set a server port to receive webhook events!\n",
    );
    process.exit();
}
    
const SERVER_ADDRESS = process.env.SIPGATE_WEBHOOK_SERVER_ADDRESS;
const PORT = process.env.SIPGATE_WEBHOOK_SERVER_PORT;
    

Im nächsten Schritt definieren wir die DTMF-Input-Länge für die verschiedenen IVR-Schritte. Die Konstanten geben an, welche DTMF-Input-Länge erwartet wird. Beispielsweise eine 8-stellige Kundennummer. Die Aufzählung „CallStage“ definiert die IVR-Schritte.

const MAX_WELCOME_DTMF_INPUT_LENGTH = 8;
const MAX_REQUEST_DTMF_INPUT_LENGTH = 1;

enum CallStage {
    WELCOMESTAGE,
    REQUESTSTAGE,
    ENDSTAGE,
}
    

Wir beginnen nun damit, unseren Server aufzubauen. Die Funktion createServer gibt ein Promise für einen WebhookServer zurück, der dann verwendet werden kann, um Callback-Funktionen für verschiedene Anrufereignisse zu registrieren:

createWebhookModule()
.createServer({
    port: PORT,
    serverAddress: SERVER_ADDRESS,
})
.then((webhookServer) => { /* TODO */ });
    

Die folgenden Inhalte werden in den geschweiften Klammern unter /* TODO */ hinzugefügt.

Zuerst mappen wir jeden Anruf (callId) auf den zugehörigen IVR-Schritt (CallStage).

In diesem Projekt muss unser Server auf newCall- und onData-Events reagieren. Dazu definieren wir eine Funktion, die aufgerufen werden soll, wenn ein neuer Anruf eingeht. Wir nutzen die WebhookResponse.gatherDTMF Funktion, um auf Webhooks mit einem passenden XML File zu antworten. Das XML File enthält folgende Attribute:

  • announcement: Hier kann die wav-Datei definiert werden, welche den Anrufer:innen vorgespielt wird.
  • timeout: Nach dem announcement wird ein Timer gestartet, der die maximale Zeit angibt, in der DTMF-Töne empfangen werden. Sobald neue DTMF-Töne empfangen werden (wenn die Anrufer:innen Tasteneingaben vornehmen), wird der Timer neu gestartet.
  • maxDigits: Die maximale Länge der Eingabe (DTMF-Töne) wird hier definiert.
const stage = new Map <string, CallStage>();
webhookServer.onNewCall((newCallEvent) => {
    stage.set(newCallEvent.callId, CallStage.WELCOMESTAGE);
    console.log(`New call from ${newCallEvent.from} to ${newCallEvent.to}`);
    return WebhookResponse.gatherDTMF({
        maxDigits: MAX_WELCOME_DTMF_INPUT_LENGTH,
        timeout: 5000,
        announcement:
        "https://github.com/sipgate-io/io-labs-complex-ivr/blob/main/static/welcome.wav?raw=true",
    });
});
    

Über das onData-Event erhalten wir die DTMF-Töne und die ID der Anrufer:innen. So können wir prüfen, ob die Anrufer:innen die korrekte Eingabe getätigt haben. Wenn das der Fall ist, wird in der nächsten Phase gefragt, ob die Anrufer:innen ihr Guthaben einsehen oder mit der Kundenbetreuung sprechen wollen. Wenn die Eingabe oder die CallStage inkorrekt war, wird der Anruf aufgelegt.

webhookServer.onData((dataEvent) => {
    const selection = dataEvent.dtmf;
    const callerId = dataEvent.callId;
    if (
        stage.get(callerId) === CallStage.WELCOMESTAGE &&
        selection.length === MAX_WELCOME_DTMF_INPUT_LENGTH
    ) {
        console.log(`The caller provided a valid id: ${selection} `);
        stage.set(callerId, CallStage.REQUESTSTAGE);
        return WebhookResponse.gatherDTMF({
        maxDigits: MAX_REQUEST_DTMF_INPUT_LENGTH,
        timeout: 5000,
        announcement:
            "https://github.com/sipgate-io/io-labs-complex-ivr/blob/main/static/request.wav?raw=true",
        });
    }

    //TODO
    
    return WebhookResponse.hangUpCall();
});
      

Das letzte //TODO, welches ergänzt werden muss, ist die Überprüfung, welche Option die Anrufer:innen gewählt haben (Tasteneingabe 1 oder 3). Dementsprechen werden wieder Audiofiles abgespielt, aber diesmal wird keine Eingabe erwartet und nach dem Abspielen eines announcement der Anruf beendet.

if (
  stage.get(callerId) === CallStage.REQUESTSTAGE &&
  selection.length === MAX_REQUEST_DTMF_INPUT_LENGTH
) {
stage.set(callerId, CallStage.ENDSTAGE);
switch (selection) {
    case "1":
    console.log("Ausgabe 1");
    return WebhookResponse.gatherDTMF({
        maxDigits: 1,
        timeout: 0,
        announcement:
        "https://github.com/sipgate-io/io-labs-complex-ivr/blob/main/static/credit.wav?raw=true",
    });
    case "3":
    console.log("Ausgabe 2");
    return WebhookResponse.gatherDTMF({
        maxDigits: 1,
        timeout: 0,
        announcement:
        "https://github.com/sipgate-io/io-labs-complex-ivr/blob/main/static/customerservice.wav?raw=true",
    });
    default:
    return WebhookResponse.hangUpCall();
  }
}
});
      

Ausführung des Projekts

Super, jetzt steht das Skript! Um alles auszuführen müssen Sie diese Schritte befolgen:

  1. Starten Sie Ihren lokalen Host mit ssh -R 80:localhost:8080 nokey@localhost.run. Es wird eine Ausgabe zu sehen sein, kopieren Sie davon die letzte URL.
  2. Fügen Sie die URL in ihrer .env-Datei neben SIPGATE_WEBHOOK_SERVER_ADDRESS ein.
  3. Gehen Sie zu Ihrem sipgate app-web account und setzen Sie sowohl die eingehende als auch die ausgehende Webhook-URL auf die URL aus den vorherigen Schritten.
  4. Führen Sie nun npm start im Terminal des root-Pakets des Projekts aus, um den Server zu starten.

Nun können Sie Ihre sipgate-Kontonummer anrufen, um den IVR-Prozess zu starten. Wenn der Anruf erfolgreich aufgebaut wurde, wird Ihr Terminal einige Informationen protokollieren.

Aussicht

Wenn Sie bis hierher durchgehalten haben, herzlichen Glückwunsch! In diesem Tutorial haben Sie gelernt, wie Sie automatisch einen Anruf annehmen und direkt einen IVR-Prozess starten. Es kann leicht erweitert werden, mit persönlichen IVR-Schritten und individuellen Audiofiles.

Das vollständige Projekt finden Sie in unserem GitHub-Repository.

Wenn Sie mehr über die Möglichkeiten unserer sipgate.io-Bibliothek erfahren möchten, schauen Sie sich unsere anderen Tutorials an, z.B. über die Erstellung aufschlussreicher Live-Statistiken.

Keine Kommentare


Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert