https://d226lax1qjow5r.cloudfront.net/blog/blogposts/real-time-call-transcription-ibm-watson-python-dr/Artboard-1-2.png

Transkription von Anrufen in Echtzeit mit IBM Watson und Python

Zuletzt aktualisiert am November 5, 2020

Lesedauer: 5 Minuten

Wir denken, dass unsere WebSocket-Funktion ziemlich genial ist; sie gibt Ihnen einen Echtzeit-Stream des Audios von Ihrem Telefonanruf (und erlaubt Ihnen, Audio zurück zu streamen), alles innerhalb Ihres Web-Frameworks.

Der Zugriff auf diesen Echtzeit-Stream eröffnet eine Vielzahl von Möglichkeiten, interessante Dinge mit dem Inhalt des Anrufs zu tun, nicht nur mit der Signalisierung. So können Sie zum Beispiel Zwei-Wege-Gespräche mit KI-Bots führen, oder vielleicht möchten Sie einfach nur das Audio des Anrufs an eine andere Plattform für eine Stimmungsanalyse in Echtzeit weiterleiten, oder vielleicht möchten Sie einfach nur nach Schlüsselwörtern innerhalb eines Anrufs suchen, damit Sie die Gespräche mit Ihren Kunden verfolgen können.

In den meisten dieser Beispiele müssen Sie zunächst die Audiodaten in Text umwandeln; dies wird als Spracherkennung oder Transkription bezeichnet. Normalerweise müssen die Dienste die Spracherkennung in Echtzeit durchführen, aber dazu müssen sie ihr Lexikon auf einige wenige vordefinierte Wörter oder Phrasen beschränken. Vielleicht haben Sie das schon einmal erlebt, als Sie bei Ihrer Bank angerufen haben und die automatische Vermittlung Sie fragte, was Sie tun wollen. Die Transkription kann das gesamte Gespräch verarbeiten, aber in der Vergangenheit war dies ein Offline-Batch-Prozess: Sie mussten den Ton des Anrufs aufzeichnen und dann, wenn der Anruf beendet war, die Aufnahme an einen Transkriptionsdienst weitergeben. Nachdem der Dienst die Aufnahme transkribiert hatte, wurden Sie über einen Rückruf benachrichtigt.

Mit den jüngsten Entwicklungen von KI-Plattformen sind wir nun in der Lage, das Beste aus beiden Welten zu erhalten: Volltexttranskription in Echtzeit. Eine der Plattformen, die dies besonders gut kann, ist IBM Watson. Watson stellt eine WebSocket-Schnittstelle zur Verfügung, über die Sie den Audiostrom des Anrufs einspeisen können. Das Format dieser Schnittstelle sieht der Nexmo WebSocket-Schnittstelle sehr ähnlich.

Verbinden mit Watson

IBM bietet die Watson Sprache-zu-Text-Dienst über verschiedene Kanäle an, z. B. REST, HTTP mit Webhook-Rückrufen und WebSockets. Im Großen und Ganzen funktionieren sie alle auf die gleiche Weise: Sie geben ein Stück Audio ein und Watson antwortet mit einer Transkription. Es gibt verschiedene Optionen, die Sie aktivieren können, wie z. B. Zwischenergebnisse die Ihnen eine Teiltranskription liefern, die dann aktualisiert werden kann, wenn Watson eine bessere Vorstellung von der Sprache mit mehr Kontext hat.

Sie müssen auch ein Sprachmodell angeben, das für die Transkription verwendet werden soll. Watson verfügt über Modelle für zahlreiche Sprachen, darunter separates britisches und amerikanisches Englisch. Wenn die Audioquelle aus einem Telefonat stammt, sollten Sie die Schmalbandmodelle verwenden, um die besten Ergebnisse zu erzielen.

Für diese Demo werden wir uns mit der WebSocket-Schnittstelle verbinden. Das bedeutet, dass wir die Audiodaten von Vonage direkt in Watson streamen können, ohne etwas wie eine Stilleerkennung durchführen zu müssen, um den Stream in Stücke zu zerlegen.

Da Watson mit den Transkriptionsdaten über die gleiche WebSocket-Verbindung antwortet, über die Sie die Audiodaten senden, können wir Nexmo nicht direkt mit IBM verbinden. Stattdessen müssen wir einen Relay-Server betreiben, der die Audiodaten von Nexmo empfängt und die Pakete an Watson weiterleitet; dann können wir die Transkriptionsnachrichten von Watson zurückerhalten und sie in unserer Anwendung verarbeiten.

The flow of the application featured in this articleThe flow of the application featured in this article

Sie finden den Code auf Github. Im Folgenden gehen wir die Vorgänge durch.

Bearbeitung des Anrufs

Wie alle Nexmo-Sprachanwendungen müssen wir eine Anwendung mit einer Antwort-URL einrichten, die ein NCCO zurückgibt. Wir werden diesen NCCO von unserem Web-App-Server aus bedienen. Dieser NCCO wird Nexmo anweisen, eine kurze Begrüßungsnachricht abzuspielen und dann den Anruf mit unserem WebSocket zu verbinden. Hier ist der NCCO:

[{
    "action": "talk",
    "text": "Please wait while we connect you to Watson"
},
{
    "action": "connect",
    "endpoint": [{
        "type": "websocket",
        "uri" : "ws://example.com/socket",
        "content-type": "audio/l16;rate=16000", 
        "headers": {}
    }]
}]

Wie Sie sehen können, handelt es sich um ein relativ einfaches NCCO. Wir begrüßen den Anrufer und verbinden ihn dann mit unserem WebSocket-Server.

Handhabung der Verbindung mit unserem WebSocket-Server

Wenn Vonage den Anruf mit unserem WebSocket-Server verbindet, müssen wir eine neue Verbindung zur Watson WebSocket-Schnittstelle herstellen. Um eine Verbindung zu Watson herzustellen, müssen wir ein Token mit unserem Benutzernamen und Passwort anfordern. Diese erhalten Sie, indem Sie sich für einen Satz von Watson [https://www.ibm.com/watson/developercloud/doc/common/getting-started-credentials.html]-Dienstanmeldeinformationen anmelden.

Diese Berechtigungsnachweise sehen in etwa so aus wie das folgende Objekt:

{
  "url": "https://stream.watsonplatform.net/speech-to-text/api",
  "username": "aaaaaaaa-1111-bbbb-2222-cccccccccccc",
  "password": "ABC123def456"

}

Mit diesem Objekt können wir dann eine Funktion erstellen, die ein Token anfordert und zurückgibt:

def gettoken():
    resp = requests.get('https://stream.watsonplatform.net/authorization/api/v1/token', auth=(d['username'], d['password']), params={'url' : d['url']})
    token = None
    if resp.status_code == 200:
        token = resp.content
    else:
        print resp.status_code
        print resp.content
    return token

Mit dieser Funktion können wir den URI für den Watson WebSocket-Dienst erstellen:

uri = 'wss://stream.watsonplatform.net/speech-to-text/api/v1/recognize?watson-token={}&model={}'.format(gettoken(), language_model)

Wir haben das language_model bereits zu Beginn des Codes in einer anderen Variablen angegeben.

Mit dieser URI erstellen wir dann eine neue WebSocket-Verbindung zu Watson und erstellen diese als Objekt innerhalb unserer eingehenden WebSocket-Verbindung. (self.watson_future)

Handhabung von Meldungen

Wenn eine Nachricht von Vonage auf dem WebSocket ankommt, werden wir sie mit der Funktion on_message in unserem WSHandler behandeln. Zuerst rufen wir yield auf unserem watson_future Objekt auf, damit wir einen Verweis auf die Watson-Verbindung haben, und analysieren dann die Nachricht.

Die erste Nachricht, die wir bei einer neuen Verbindung von Vonage erhalten, ist eine Textnachricht, die das Audioformat enthält. Wir müssen der Nachricht einige zusätzliche Parameter hinzufügen, um Watson mitzuteilen, wie der Stream transkribiert werden soll, und dann schreiben wir diese neue Nachricht an den Watson-Socket. Diese Nachricht wird etwa so aussehen:

{
	"interim_results": true,
	"action": "start",
	"content-type": "audio/l16;rate=16000"
}

Der Schlüsselparameter ist hier die "Aktion": "start"; er teilt Watson mit, dass dies der Beginn eines Transkriptionsstroms ist. Wir haben auch Zwischenergebnisse aktiviert. Das bedeutet, dass Watson Ihnen seine erste Vermutung zu einer Transkription sendet und diese dann möglicherweise in einer späteren Nachricht aktualisiert, wenn er eine bessere Antwort hat. Da Sie möglicherweise mehrere Nachrichten von Watson für eine einzige Transkription erhalten, müssen Sie sich die IDs ansehen, um Ihren Text zu konstruieren.

Antworten von Watson

Wenn die Socket-Verbindung zu Watson eine Nachricht erhält, wird der on_watson_message-Callback aufgerufen. Diese Funktion gibt im Moment nur die Nachricht auf dem Bildschirm aus, aber man könnte dieses Beispiel erweitern, um die Transkription nach Belieben zu behandeln.

Sobald Sie erfolgreich eine Verbindung zu Watson hergestellt haben, erhalten Sie eine Meldung wie die folgende:

{
   "state": "listening"
}

Wenn Sie dann Audio an Watson streamen, erhalten Sie folgende Transkriptionsmeldungen:

{
   "results": [
      {
         "alternatives": [
            {
               "confidence": 0.617, 
               "transcript": "hello this is the test "
            }
         ], 
         "final": true
      }
   ], 
   "result_index": 0
}

Die wichtigsten Punkte, auf die Sie bei diesen Antworten achten sollten, sind folgende:

Konfidenz-gibt an, wie sicher Watson ist, dass die Transkription korrekt ist; ein Wert von 1 steht für maximales Vertrauen. Wie Sie aus dem obigen Test ersehen können, habe ich "Hallo, dies ist ein Test" gesagt, aber Watson hat es leicht falsch verstanden. Der Konfidenzwert lag jedoch nur bei 0,617; die Antwort ergibt also immer noch Sinn und die wesentlichen Teile der Nachricht sind vorhanden.

Manchmal erhalten Sie sogar mehr als eine Transkriptionsoption mit zugehörigen Konfidenzwerten; es liegt an Ihnen, zu entscheiden, welche Sie verwenden möchten. Ebenso können Sie anhand des Konfidenzwerts entscheiden, wie Sie weiter vorgehen wollen; Sie könnten dem Benutzer beispielsweise die Frage erneut stellen.

Endgültig-bedeutet, dass dies der letzte Versuch ist, den Satz zu transkribieren. Manchmal erhalten Sie Zwischenergebnisse, bei denen Watson nur einen Teil der Nachricht transkribiert hat (siehe unten):

{
   "results": [
      {
         "alternatives": [
            {
               "transcript": "one two three four "
            }
         ], 
         "final": false
      }
   ], 
   "result_index": 3
}
{
   "results": [
      {
         "alternatives": [
            {
               "transcript": "one two three four five six seven eight "
            }
         ], 
         "final": false
      }
   ], 
   "result_index": 3
}
{
   "results": [
      {
         "alternatives": [
            {
               "confidence": 0.982, 
               "transcript": "one two three four five six seven eight nine ten "
            }
         ], 
         "final": true
      }
   ], 
   "result_index": 3
}

In diesem Beispiel habe ich relativ langsam bis 10 gezählt, so dass Watson ein Transkriptionsereignis nach einem Teil der Zählung gesendet hat. Wenn Sie sich den result_index-Wert ansehen, sehen Sie, dass er gleich ist, was darauf hinweist, dass es sich um mehrere Durchläufe desselben Sprachabschnitts handelt. Nur der letzte Durchgang hat final gesetzt auf true gesetzt und enthält die vollständige Zeichenfolge.

Beenden des Anrufs

Wenn der Benutzer auflegt, wird Nexmo die WebSocket-Verbindung schließen; wir können den on_close-Handler verwenden, um dieses Ereignis zu erfassen und eine Stop-Aktion an Watson zu senden, bevor die Verbindung geschlossen wird.

Teilen Sie:

https://a.storyblok.com/f/270183/384x384/7fbbc7293b/sammachin.png
Sam MachinVonage Ehemalige