
Teilen Sie:
Ehemaliger .NET Developer Advocate @Vonage, polyglotter Software-Ingenieur, AI/ML
SMS Sprachverständnis mit LUIS und .NET
Wie gehen Sie vor, um Ihre Benutzereingaben zu erhalten? Ich wette, wenn Sie eine Webanwendung oder eine grafische Benutzeroberfläche entwickeln, werden Sie wahrscheinlich ein Formular verwenden, das der Benutzer ausfüllen und abschicken kann. Wenn Sie eine Konsolenanwendung schreiben, werden Sie eine Reihe von kodierten Eingaben und Flags haben, die Ihr Benutzer Ihnen geben wird. Was wäre, wenn Sie eine Nachricht, z. B. eine SMS, von einem Benutzer entgegennehmen und aus dieser SMS verwertbare Informationen auslesen wollten?
Nehmen wir diesen Satz als Beispiel:
I'd like to have one cheese pizza from Joe's Pizza delivered to 21 Jump Street, Melbourne, FL 32940.Stellen Sie sich vor, diese Informationen werden in einem Webformular erfasst.
Quantity: 1
Item: Pizza
Toppings: cheese
Restaurant: Joe's Pizza
Method: Delivery
street-number: 21
street-name: Jump Street
City: Melbourne
State: FL
Zip: 32940Da dieser Satz jedoch nicht strukturiert ist, ist es natürlich unmöglich, diese Informationen aus ihm zu extrahieren. An dieser Stelle kommt Microsofts Sprachverstehen (LUIS) ins Spiel. Mit LUIS können wir Bots erstellen, die natürliche Sprache als Eingabe verwenden und die Absicht des Benutzers sogar aus diesen Phrasen verstehen können. Und genau das werden wir in diesem Beitrag lernen - wie man mit LUIS ein natürliches Sprachverständnis aufbaut und diese Spracherkennung nutzt, um Eingaben per SMS zu verarbeiten.
Voraussetzungen
Visual Studio oder Rider (ich verwende Visual Studio 2019)
Die .NET Core 3.1 Laufzeitumgebung
Fakultativ: ngrok zum Testen
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.
Einige wichtige Concepts in LUIS AI
LUIS betrachtet alle Eingaben als "Äußerungen", oder Dinge, die Sie sagen könnten. Es gibt zwei wichtige Concepts, die Sie verstehen müssen, um mit LUIS loslegen zu können. Das erste ist die Intention. Der Intent ist das Ziel der Äußerung - in unserem Beispiel könnten Sie diesen Intent "OrderFood" nennen. Das zweite Konzept sind Entitäten, d. h. bestimmte Informationen, die durch unsere Äußerungen weitergegeben werden und den Daten in einem Formular entsprechen könnten.
Mithilfe dieser zentralen Concepts können Sie die Absicht Ihres Benutzers erkennen, fast so, als würden Sie die Anfrage an einen Endpunkt weiterleiten. Dann können Sie die Informationen, die Ihr Benutzer Ihnen gibt, für die Verwendung in Ihrer App herausziehen.
LUIS-Apps bauen
Beginnen wir mit dem Besuch der LUIS Anwendungsseite.
Erstellen Sie von hier aus eine App, indem Sie auf App erstellen. Nennen wir sie DeliverySample.

Nachdem Sie Ihre App erstellt haben, werden Sie zum Dashboard Ihrer App weitergeleitet. Klicken Sie auf . Erstellen in der Tab-Leiste oben:

Dadurch gelangen Sie zur Benutzeroberfläche des Builders. Es gibt nun zwei Möglichkeiten, Ihre Luis-App zu erstellen - über die API oder mit der grafischen Benutzeroberfläche. Wir werden nur lernen, wie man es mit der grafischen Benutzeroberfläche macht.
Einige Entitäten hinzufügen
Adresse Entität
Um einige Entitäten zu unserer App hinzuzufügen, gehen wir zu App-Assets -> Entitäten. Wir beginnen mit der Erstellung einer Adress-Entität. Da eine Adresse in mehrere Komponenten zerfällt, beginnen wir mit dem Hinzufügen der Komponenten-Entitätstypen. Klicken Sie zunächst auf Neue Entität erstellen und erstellen Sie einen simple Typ namens StreetNumber. Wiederholen Sie diesen Vorgang für StreetName, City, State und ZipCode. Schließlich können wir die zusammengesetzte Entität erstellen. Klicken Sie auf . Neue Entität erstellen erneut, wählen Sie Typ compositeaus, und fügen Sie jeden der soeben erstellten Typen als Kind dieses Typs hinzu.

Methode Entität
Sie können jetzt auch andere Entitäten erstellen, z. B. eine Entität "Methode", die beschreibt, wie der Benutzer das Essen bekommt. In diesem, dem Zeitalter von COVID-19, haben wir nur zwei Möglichkeiten: Abholung oder Lieferung. Daher erstellen wir "Methode" als eine List Entität (eine Entität mit einer Aufzählung von Werten), und diese Werte können wir mit Synonymen versehen, z. B. "zum Mitnehmen" oder "zum Abholen".

Hinzufügen einer Lebensmittel-Entität
Wir können auch eine Lebensmittel-Entität hinzufügen. Dazu fügen wir eine weitere simple Entität und nennen sie food.
Einbringen einer Domain-Simple-Entität
Die letzte Entität, die wir hinzufügen, ist die Entität PlaceName Domain-Simple. Klicken Sie auf Vorgefertigte Domain-Entität hinzufügen und finden Sie RestaurantReservation.PlaceName. Diese vorgefertigten Entitäten werden zusammen mit Hunderten von vorher trainierten Äußerungen geliefert. Sie sind also recht gut geeignet, um zu verstehen, wie ein Ortsname im Kontext aussieht. Trotzdem müssen wir LUIS trainieren, diese ein wenig besser zu verstehen, da es die Restaurantnamen aus einer anderen Perspektive betrachten wird.
Hinzufügen unseres Vorhabens
Intents in LUIS sind das, was die Äußerung, die Sie bereitstellen, verlangt oder sagt. In unserem Beispiel können wir also die "Absicht" des Satzes als "Lebensmittel bestellen" lesen. Lassen Sie uns also genau das tun. Gehen Sie zu App-Assets -> Beabsichtigungen. Diese Seite ist die Liste der Intents, nach denen Ihre Anwendung sucht. Jede LUIS-Applikation versteht einen "None"-Intent, d.h. den "Ich weiß nicht"-Intent, den sie registriert, wenn sie nicht erkennen kann, was die Äußerung bedeutet. Fügen wir unser Beispielintent 'OrderFood' hinzu.
Utterances zu OrderFood Intent hinzufügen
Nachdem wir unsere Absicht erstellt haben, müssen wir die Absicht mit Äußerungen auffüllen. Das Auffüllen dieser Äußerungen ermöglicht es LUIS, den Intent zu erkennen und die Daten aus ihm zu extrahieren. Die Empfehlung von Microsoft besagt, dass jede reale Absicht mindestens 15 Äußerungen unterschiedlicher Länge, Struktur und Zeitform benötigt, bevor LUIS beginnen kann, Informationen genau vorherzusagen und zu extrahieren.
Um Äußerungen zu einer Absicht hinzuzufügen, klicken Sie in die Absicht, wodurch Sie zur Seite der Absicht gelangen. Auf dieser Seite gibt es einen Abschnitt, in dem es heißt: "Geben Sie ein Beispiel dafür ein, was ein Benutzer sagen könnte, und drücken Sie die Eingabetaste". Folgen Sie diesen Anweisungen, um eine Äußerung einzugeben. Hier sind einige, mit denen ich angefangen habe:
Ich möchte eine Bestellung von Disco-Fritten an 14 Seventh Ave, New York New York, 10001 schicken.
Kann ich einen Chicken Burrito von Chipotle nach 15 Yemen Road, Cedar Rapids Iowa, 52227 liefern lassen?
Ich würde gerne ein General Tsao's Chicken von Hop Bo's kaufen.
Kennzeichnung von Entitäten
Was wir gerade getan haben, ermöglicht es LUIS, die Absicht des Benutzers aus diesen Phrasen zu extrahieren. Aber das ist nur die Hälfte dessen, was LUIS so mächtig macht. Die Stärke von LUIS liegt darin, dass es Ihnen ermöglicht, Daten direkt aus Benutzeräußerungen zu extrahieren, indem Sie die zuvor definierten Entitäten verwenden. Dazu müssen Sie jedoch zunächst die Entitäten in den Äußerungen kennzeichnen, damit sie identifiziert werden können. Klicken Sie dazu auf die einzelnen Wörter innerhalb der Äußerung, die für die Entität relevant sind. Im folgenden GIF sehen Sie, wie ich es gemacht habe.

Prüfung unserer Absichten
Mit den etwa 3 Entitäten, die wir bisher eingegeben und markiert haben, können wir nun mit LUIS spielen, um zu sehen, wie es funktioniert (Hinweis: es wird nicht gut abschneiden mit nur 3 Äußerungen). Klicken Sie auf die Schaltfläche train in der oberen rechten Ecke des Bildschirms. Dadurch wird LUIS mit allen Entitäten/Intentionen/Äußerungen trainiert, die Sie ihm bis jetzt zur Verfügung gestellt haben.
Wenn Luis das Training beendet hat, können Sie ihn in der Webschnittstelle testen. Klicken Sie auf die Schaltfläche Testen woraufhin sich das Chat-Fenster öffnet. Klicken Sie auf die Pfeilschaltfläche oben rechts, um den Detailbereich zu erweitern. Jetzt können wir Phrasen eingeben und sehen, was LUIS macht. Ich beginne mit "Sende Chicken Wings an 7287 North Cottage Ave. Camden, NJ 08105 von Popeye's". Das wird ziemlich schlecht funktionieren, weil LUIS noch nie etwas gesehen hat, das so strukturiert war. Wir können also das Detailfenster öffnen und die Absicht so bearbeiten, dass sie das widerspiegelt, was die Absicht hätte sein sollen. Durch das Setzen der Absicht im Detailbereich wird diese Äußerung in die Liste der Äußerungen für diese Absicht verschoben. Von dort aus können wir die verschiedenen Entitäten der Absicht markieren.

Hinzufügen von Mustern
Wenn Sie sich den Satz "Send chicken wings to 7287 North Cottage Ave. Camden, NJ 08105 von Popeye's" mit allen hervorgehobenen Einheiten sieht es so aus:

Dies bildet ein so genanntes Muster, das für LUIS fast wie ein Regex ist. Sie können dies als Muster hinzufügen, indem Sie das Kästchen neben der Äußerung markieren und oben auf "als Muster hinzufügen" klicken. Klicken Sie anschließend auf "train", damit LUIS die neue Äußerung und das Muster in sein Modell einbaut.
Extrahieren von Entitäten aus Abfragen
Nun, da wir LUIS etwas besser trainiert haben, geben wir ihm erneut die Aufgabe "Send chicken wings to 7287 North Cottage Ave. Camden, NJ 08105 von Popeye's." Dies wird ein wesentlich anderes Ergebnis liefern. Zum einen ist jetzt zu 100 % sicher, dass die Absicht darin bestand, Essen zu bestellen. Noch wichtiger ist, dass nicht nur die Absicht der Äußerung bestimmt wurde, sondern auch nützliche Informationen aus der Äußerung extrahiert wurden. So wissen wir beispielsweise, dass die Methode "Senden" Teil der Unterliste "Lieferung" ist und dass die Hähnchenflügel geliefert werden sollen. Wir wissen, dass das gewünschte Essen "Chicken Wings" ist, wir wissen, dass sie die Chicken Wings von Popeye's wollen, und wir wissen, wohin sie geliefert werden sollen! Wenn wir dies später von unserer C#-Anwendung aus abfragen, werden wir sehen, dass die Daten in einem JSON-Objekt zurückkommen, das wir leicht parsen können.

Veröffentlichung der Demo
Um Ihre LUIS-Anwendung zu veröffentlichen, klicken Sie einfach auf die Schaltfläche "Veröffentlichen" oben rechts auf dem Bildschirm, wählen Sie die Option Produktion und folgen Sie den Anweisungen. Möglicherweise möchten Sie die Bing-Rechtschreibprüfung oder sogar die Stimmungsanalyse aktivieren, wenn Sie die Stimmung der Anfragen auswerten möchten. Dadurch wird die App auf einem Azure-Endpunkt veröffentlicht - achten Sie auf das Symbol Primary Key, die Endpoint Urlund natürlich Ihre AppId in den Azure-Ressourcen und Anwendungsinformationsseiten. Sie werden sie später benötigen.
Aufbau unserer .NET-Anwendung
Für diese Demo werden wir eine einfache eingehende/ausgehende SMS API-App in ASP.NET Core erstellen. Starten wir also Visual Studio:
Klicken Sie auf . Neu erstellen
ASP.NET Core-Webanwendung
Name
LuisVonageDemoKlicken Sie auf erstellen.
Wählen Sie API für den Typ
Klicken Sie auf erstellen.
Eine neue Klasse hinzufügen
LuisQueryKlicken Sie mit der rechten Maustaste auf das Verzeichnis "Controller" und wählen Sie Hinzufügen -> Steuerungund erstellen Sie einen neuen API-Steuerung -> Leere
SmsControllerFügen Sie eine neue Klasse namens
Dispatcherzu dem Projekt
Pakete hinzufügen
Fügen Sie dem Projekt die folgenden Pakete hinzu:
Microsoft.Azure.CognitiveServices.Language.LUIS.Runtime (ich verwende 3.0.0)
Nexmo.Csharp.Client (ich verwende 4.3.1)
Umgebungsvariablen hinzufügen
Sie können selbst entscheiden, wie Sie Ihre Anmeldedaten in Ihre Anwendung übertragen wollen. Ich verwende gerne entweder Konfigurations-Abhängigkeitsinjektion oder Umgebungsvariablen. Die Verwendung von Umgebungsvariablen ist in diesem Fall etwas einfacher, daher werden wir sie für die Demo verwenden. Klicken Sie mit der rechten Maustaste auf das Projekt und gehen Sie zu Eigenschaften. Im Bereich Fehlersuche scrollen Sie nach unten zu den Umgebungsvariablen und fügen Sie Folgendes hinzu:
| Variable | Description |
|---|---|
| NEXMO_API_KEY | Your API Key from the dashboard |
| NEXMO_API_Secret | Your API Secret from the dashboard |
| LUIS_PREDICTION_KEY | This is the key from LUIS |
| LUIS_ENDPOINT_NAME | The endpoint URL from LUIS e.g. https://westus.api.cognitive.microsoft.com |
| LUIS_APP_ID | the Guid App ID from Luis |
Abfrage Luis
Jetzt werden wir also den LUIS-Endpunkt von unserer Anwendung aus abfragen. Öffnen Sie die LuisQuery Klasse und fügen Sie die folgenden using-Anweisungen am Anfang ein:
using Microsoft.Azure.CognitiveServices.Language.LUIS.Runtime;
using Microsoft.Azure.CognitiveServices.Language.LUIS.Runtime.Models;
using System;
using System.Threading.Tasks;Fügen Sie dann innerhalb der Klasse die folgenden Felder hinzu:
// Use Language Understanding (LUIS) prediction endpoint key
// to create authentication credentials
private static string _predictionKey = Environment.GetEnvironmentVariable("LUIS_PREDICTION_KEY");
// Endpoint URL example value = "https://YOUR-RESOURCE-NAME.api.cognitive.microsoft.com"
private static string _predictionEndpoint = Environment.GetEnvironmentVariable("LUIS_ENDPOINT_NAME");
// App Id example value e.g. "df67dcdb-c37d-46af-88e1-8b97951ca1c2"
private static string _appId = Environment.GetEnvironmentVariable("LUIS_APP_ID");Als Nächstes erstellen wir den Client, indem wir eine Reihe von Anmeldeinformationen aus unserem Vorhersageschlüssel generieren und diese Anmeldeinformationen zusammen mit unserem Endpunkt verwenden. Wir werden einen Client in einer statischen Methode erstellen.
private static LUISRuntimeClient CreateClient()
{
var credentials = new ApiKeyServiceClientCredentials(_predictionKey);
return new LUISRuntimeClient(credentials, new System.Net.Http.DelegatingHandler[] { })
{
Endpoint = _predictionEndpoint
};
}Als Letztes müssen wir eine Methode erstellen, die unseren Vorhersage-Client verwendet, um eine Vorhersage zu erstellen. Diese Methode nimmt eine Zeichenkette queryein, ruft einen Vorhersage-Client ab und fügt unsere Abfrage zu unserem Vorhersage-Endpunkt hinzu.
public static async Task<PredictionResponse> GetPredictionAsync(string query)
{
using (var luisClient = CreateClient())
{
var requestOptions = new PredictionRequestOptions
{
PreferExternalEntities = true
};
var predictionRequest = new PredictionRequest
{
Query = query,
Options = requestOptions
};
return await luisClient.Prediction.GetSlotPredictionAsync(
Guid.Parse(_appId),
slotName: "production",
predictionRequest,
verbose: true,
showAllIntents: true,
log: true);
}
}
Dispatcher-Code hinzufügen
Unser Dispatcher wird die Geschäftslogik dessen verwalten, was wir mit unseren Intents tun wollen. Das erste, was wir also einrichten müssen, ist das Enum für unsere Intents. Fügen Sie Folgendes zu Ihrer Dispatcher Klasse hinzu:
public enum Intent
{
None,
OrderFood
}Als nächstes fügen Sie die folgenden using-Anweisungen in die Dispatcher Datei hinzu.
using Newtonsoft.Json.Linq;
using Nexmo.Api;
using System;Als nächstes fügen wir eine Funktion hinzu, ExecuteQueryhinzufügen, um die Abfrage auszuführen, eine Antwortnachricht aus dem Ergebnis der Abfrage zu erstellen und diese Nachricht zurück an den Endpunkt zu senden. Sie wird unsere eingehende SMS-Nachricht von unserem Controller-Endpunkt (den wir als Nächstes erstellen werden) nehmen, die Nachricht herausziehen und sie durch unsere LuisQuery Klasse. Wenn die Abfrage eine Nicht-Absicht erkennt, erstellt sie eine Nachricht, die besagt: "Das habe ich nicht ganz verstanden. Andernfalls werden das Essen und der Name des Restaurants aus der Nachricht herausgezogen und dem Kunden geantwortet, dass sein Essen auf dem Weg ist.
public static async void ExecuteQuery(SMS.SMSInbound inbound)
{
try
{
var query = inbound.text;
var apiKey = Environment.GetEnvironmentVariable("NEXMO_API_KEY");
var apiSecret = Environment.GetEnvironmentVariable("NEXMO_API_SECRET");
var message = string.Empty;
//Get prediction
var pred = await LuisQuery.GetPredictionAsync(query);
var intent = Enum.Parse(typeof(Intent), pred.Prediction.TopIntent);
Console.WriteLine($"Top intent was {pred.Prediction.TopIntent}");
switch (intent)
{
case Intent.None:
message = "I didn't quite get that. Can you please specify what you would like to do?";
break;
case Intent.OrderFood:
var food = (pred.Prediction.Entities["Food"] as JArray)?[0];
var restaraunt = (pred.Prediction.Entities["RestaurantReservation.PlaceName"] as JArray)?[0];
message = $"We'll have that {food} from {restaraunt} send over straight away!";
break;
}
Console.WriteLine($"Message: {message}");
//Send the SMS back
var client = new Client(new Nexmo.Api.Request.Credentials { ApiKey = apiKey, ApiSecret = apiSecret });
client.SMS.Send(new SMS.SMSRequest { to = inbound.msisdn, from = inbound.to, text = message });
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
} Empfangen und Versenden von SMS
Wir werden SMS-Nachrichten an unserem SmsController Endpunkt empfangen, LUIS abfragen und auf die eingehenden SMS antworten. Um dies zu tun, gehen wir in unsere SmsController Klasse. Als erstes werden wir das Route Attribut aus der Klasse SmsController. Dann fügen wir hier eine Methode hinzu:
[HttpGet("webhooks/inbound")]
public IActionResult Get([FromQuery]SMS.SMSInbound inbound)
{
Dispatcher.ExecuteQuery(inbound);
return NoContent();
}Dazu müssen Sie den Nexmo.Api Namespace importieren.
Und das ist alles, was wir brauchen!
Testen mit IIS Express und ngrok
Wir werden dies nur in IIS Express testen, also gehen wir auf die Registerkarte Debug der Projekteigenschaften-Seite. Ich werde SSL auf IIS Express deaktivieren und mir die Portnummer notieren, auf der es gehostet wird. Als Nächstes werde ich den folgenden Befehl in der Eingabeaufforderung ausführen:
Das wird ngrok starten und etwas wie produzieren:

Achten Sie auf die eindeutige ID vor ngrok.io in der URL. Lassen Sie es dabei bewenden und starten Sie die Anwendung im Debug-Modus in IIS Express.
Webhooks konfigurieren
Jetzt müssen Sie nur noch auf die Einstellungsseite im Dashboard und die URL für eingehende Nachrichten in http://UNIQUE_NGROK_ENDPOINT.ngrok.io/webhooks/inbound. Ersetzen Sie UNIQUE_NGROK_ENDPOINT durch den von ngrok erzeugten zufälligen Satz von Zeichen zu ersetzen. Im obigen Beispiel würde der Endpunkt lauten http://dc0feb1d.ngrok.io/webhooks/inbound. Damit verweist Vonage auf unseren IIS-Express-Server und ermöglicht es uns, Nachrichten über unseren SMS-Endpunkt zu empfangen.
Zeit zum Testen
Jetzt müssen Sie nur noch einen Test machen. Die App sollte einsatzbereit sein. Sie müssen nur noch eine SMS mit Ihrem Lieferauftrag an eine beliebige SMS-aktivierte Nummer senden, die Sie über das Vonage API-Dashboarderhalten haben, und die Bestellung wird für Sie bearbeitet.
Nächste Schritte
Diese Demo war ein grundlegendes Beispiel dafür, wie man mit LUIS arbeitet. LUIS ist eine robuste Plattform mit viel Flexibilität. Wie Sie jedoch zweifellos bemerkt haben, muss man sich viele Gedanken darüber machen, wie man die Wissensbasis aufbaut, um wirklich nützlich zu sein.
Es gibt eine Vielzahl von Kanälen, die Sie über die APIs von Vonage nutzen können, um mit LUIS zu sprechen. Sie können die Messages APIverwenden, die neben SMS auch Facebook Messenger, WhatsApp und Viber unterstützt. LUIS ermöglicht es Ihnen auch, direkt mit Sprache zu arbeiten, so dass Sie möglicherweise einen Bot erstellen können, der auf Sprache von einem PSTN-Anruf über Vonage's Websocket-API.
