
Partager:
Ancien développeur .NET Advocate @Vonage, ingénieur logiciel polyglotte full-stack, AI/ML
Compréhension du langage SMS avec LUIS et .NET
Comment obtenez-vous les données de l'utilisateur ? Je parie que si vous créez une application web ou une interface graphique, vous utiliserez probablement un formulaire que l'utilisateur pourra remplir et soumettre. Si vous écrivez une application console, vous aurez une série codée d'entrées et de drapeaux que l'utilisateur vous donnera. Et si vous vouliez recevoir un message, disons un SMS, d'un utilisateur et en extraire des informations exploitables ?
Prenons l'exemple de cette phrase :
I'd like to have one cheese pizza from Joe's Pizza delivered to 21 Jump Street, Melbourne, FL 32940.Imaginez que ces informations soient collectées dans un formulaire web.
Quantity: 1
Item: Pizza
Toppings: cheese
Restaurant: Joe's Pizza
Method: Delivery
street-number: 21
street-name: Jump Street
City: Melbourne
State: FL
Zip: 32940Mais bien sûr, comme cette phrase n'est pas structurée, il est impossible d'en extraire ces informations. C'est là que l'outil de compréhension du langage de Microsoft (LUIS) de Microsoft. Avec LUIS, nous pouvons construire des robots qui nous permettent d'utiliser le langage naturel comme entrée et de comprendre l'intention de l'utilisateur même à partir de ces phrases. Et c'est ce que nous allons apprendre dans ce billet - comment construire une compréhension du langage naturel à l'aide de LUIS et utiliser cette reconnaissance du langage pour traiter les entrées provenant de SMS.
Conditions préalables
Visual Studio ou Rider (j'utilise Visual Studio 2019)
Le moteur d'exécution .NET Core 3.1
Facultatif : ngrok pour tester
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.
Quelques concepts importants dans LUIS AI
LUIS considère toutes les entrées comme des "énoncés", c'est-à-dire des choses que vous pourriez dire. Il y a deux concepts clés que vous devez comprendre pour démarrer avec LUIS. Le premier est l'intention. L'intention est l'objectif de l'énoncé - ainsi, dans notre exemple, vous pourriez appeler cette intention "OrderFood" Le second concept est celui des entités, qui sont des éléments d'information spécifiques transmis par nos énoncés, qui pourraient correspondre aux données d'un formulaire.
En utilisant ces concepts de base, vous pouvez détecter l'intention de votre utilisateur, presque comme si vous acheminiez la demande vers un point final. Vous pouvez ensuite extraire les informations fournies par l'utilisateur pour les utiliser dans votre application.
Construire des applications LUIS
Commençons par aller sur la page d'application de LUIS la page de l'application LUIS.
A partir de là, créez une application en cliquant sur Créer une application. Nommons-la DeliverySample.

Après avoir créé votre application, vous serez redirigé vers le tableau de bord de votre application. Cliquez sur Construire dans la barre d'onglets en haut :

Vous accéderez ainsi à l'interface du constructeur. Il y a deux façons de construire votre application Luis : via l'API ou avec l'interface graphique. Nous allons apprendre à le faire avec l'interface graphique.
Ajouter des entités
Adresse Entité
Pour ajouter des entités à notre application, nous allons dans la section Actifs de l'application -> Entités. Nous commencerons par créer une entité Adresse. Comme une adresse se décompose en plusieurs composants, nous commencerons par ajouter les types d'entités des composants. Cliquez d'abord sur Créer une nouvelle entité et créez un type simple appelé StreetNumber. Répétez cette opération pour StreetName, City, State et ZipCode. Enfin, nous pouvons créer l'entité composite. Cliquez sur Créer une nouvelle entité sélectionnez le type compositeet ajoutez chacun des types que nous venons de créer en tant qu'enfant de ce type.

Méthode Entité
Il est désormais possible de créer d'autres entités, par exemple une entité "Méthode" décrivant la manière dont l'utilisateur va se procurer la nourriture. À l'ère du COVID-19, nous n'avons que deux options : la vente à emporter ou la livraison. Nous créerons donc Method en tant qu'entité List (une entité avec une liste de valeurs énumérées), et ces valeurs peuvent être accompagnées de synonymes, par exemple "à emporter" ou "déposé".

Ajout d'une entité alimentaire
Nous pouvons également ajouter une entité alimentaire. Pour cela, ajoutons une autre entité simple et l'appelons food.
Introduire une entité simple du domaine
La dernière entité que nous ajouterons sera l'entité PlaceName Domain-Simple. Cliquez sur Ajouter une entité de domaine préconstruite et trouvez RestaurantReservation.PlaceName. Ces entités préconstruites sont accompagnées de centaines d'énoncés pré-entraînés. Elles permettent donc de comprendre assez bien à quoi ressemble un nom de lieu dans son contexte. Quoi qu'il en soit, nous devrons entraîner LUIS à les comprendre un peu mieux, car il examinera les noms de restaurants d'un point de vue différent.
Ajouter notre intention
Les intentions dans LUIS sont ce que l'énoncé que vous lui fournissez demande ou dit. Ainsi, dans notre exemple, nous pouvons lire l'intention de la phrase comme étant `OrderFood`. C'est ce que nous allons faire. Allez à App Assets -> Intents. Cette page contient la liste des intentions que votre application recherche. Chaque application LUIS comprend l'intention "None", qui est l'intention "I don't know" (je ne sais pas) qu'elle enregistre lorsqu'elle ne peut pas comprendre ce que dit l'énoncé. Ajoutons notre exemple d'intention 'OrderFood'.
Ajouter des énoncés à l'intention de OrderFood
Une fois notre intention créée, nous devons la remplir d'énoncés. L'ajout de ces énoncés permet à LUIS de reconnaître l'intention et d'en extraire les données. Selon les recommandations de Microsoft, toute intention du monde réel doit comporter au moins 15 énoncés de longueurs, de structures et de temps différents avant que LUIS puisse commencer à prédire et à extraire des informations avec précision.
Pour ajouter des énoncés à une intention, cliquez sur l'intention, ce qui vous amènera à la page de l'intention. Sur cette page, il y a une section qui dit "Entrez un exemple de ce qu'un utilisateur pourrait dire et appuyez sur Entrée" Suivez ces instructions pour entrer un énoncé. En voici quelques-unes avec lesquelles j'ai commencé :
Je souhaite recevoir une commande de frites disco au 14 Seventh Ave, New York New York, 10001
Puis-je me faire livrer un burrito au poulet de Chipotle au 15 Yemen Road, Cedar Rapids Iowa, 52227 ?
J'aimerais acheter un poulet General Tsao's Chicken chez Hop Bo's.
Entités d'étiquetage
Ce que nous venons de faire permettra à LUIS d'extraire l'intention de l'utilisateur à partir de ces phrases. Mais ce n'est que la moitié de la puissance de LUIS. Là où LUIS devient puissant, c'est qu'il vous permet d'extraire des données directement à partir des énoncés de l'utilisateur en utilisant les entités que nous avons définies plus tôt. Mais pour ce faire, vous devez d'abord étiqueter les entités dans les énoncés afin de les identifier. Pour ce faire, cliquez sur les mots de l'énoncé qui correspondent à l'entité. Voyez comment j'ai procédé dans le GIF ci-dessous.

Tester nos intentions
Avec les quelque 3 entités que nous avons saisies et marquées jusqu'à présent, nous pouvons maintenant jouer avec LUIS pour voir comment il se comporte (indice : il ne se débrouillera pas très bien avec seulement 3 énoncés). Cliquez sur le bouton Train dans le coin supérieur droit de l'écran. LUIS s'entraîne alors avec toutes les entités/intensités/exprimées que vous lui avez fournies jusqu'à présent.
Lorsque Luis a terminé sa formation, vous pouvez le tester dans l'interface web. Cliquez sur l'icône Test qui fait apparaître la fenêtre de chat. Cliquez sur la flèche en haut à droite pour développer le panneau des détails. Nous pouvons maintenant entrer des phrases et voir ce que LUIS fait. Je commencerai par "Envoyer des ailes de poulet au 7287 North Cottage Ave. Camden, NJ 08105 de Popeye's". Cette phrase ne donnera pas de bons résultats parce que LUIS n'a encore jamais rien vu de structuré de la sorte. Nous pouvons donc ouvrir le panneau des détails et modifier l'intention pour qu'elle corresponde à ce qu'elle aurait dû être. La définition de l'intention dans le panneau des détails fait apparaître l'énoncé dans la liste des énoncés correspondant à cette intention. A partir de là, nous pouvons marquer les différentes entités de l'intention.

Ajout de motifs
Si vous regardez la phrase "Envoyer des ailes de poulet au 7287 North Cottage Ave. Camden, NJ 08105 de Popeye's" avec toutes les entités en surbrillance, cela donne ceci :

Cela forme ce que l'on appelle un motif, qui est presque comme une expression rationnelle pour LUIS. Vous pouvez l'ajouter en tant que modèle en cochant la case à côté de l'énoncé et en cliquant sur "add as pattern" (ajouter comme modèle) en haut de la page. Après avoir effectué cette opération, cliquez à nouveau sur Train pour que LUIS intègre le nouvel énoncé et le motif à son modèle.
Extraction d'entités à partir de requêtes
Maintenant que nous avons un peu mieux entraîné LUIS, passons-lui à nouveau "Envoyer des ailes de poulet au 7287 North Cottage Ave. Camden, NJ 08105 de Popeye's". Ce résultat sera très différent. D'une part, il est désormais certain à 100 % que l'intention était de commander de la nourriture. D'autre part, et de manière plus significative, en plus de déterminer l'intention de l'énoncé, il a extrait des informations utiles de l'énoncé. Par exemple, nous savons que la méthode est "Envoyer", qui fait partie de la sous-liste de livraison, et nous savons donc que le client veut se faire livrer des ailes de poulet. Nous savons qu'ils veulent des ailes de poulet de Popeye's et nous savons où les livrer ! Lorsque nous interrogerons cette liste plus tard à partir de notre application C#, nous verrons que les données nous reviendront sous la forme d'un objet JSON que nous pourrons analyser facilement.

Publier la démo
Pour publier votre application LUIS, il suffit de cliquer sur le bouton "Publier" en haut à droite de l'écran, puis de sélectionner l'onglet "Production". Production et de suivre les instructions. Vous pouvez activer la vérification orthographique de Bing ou même l'analyse des sentiments si vous souhaitez extraire les sentiments des demandes. L'application sera alors publiée sur un point de terminaison Azure. Primary Key, du Endpoint Urlet, bien sûr, de votre AppId dans les pages d'information sur les ressources et les applications Azure. Vous en aurez besoin plus tard.
Construire notre application .NET
Pour cette démo, nous allons créer une simple application API SMS entrante/sortante en ASP.NET Core. Lançons donc Visual Studio :
Cliquez sur Créer un nouveau
Application Web ASP.NET Core
Le nommer
LuisVonageDemoCliquez sur Créer
Sélectionnez API pour le type
Cliquez sur Créer
Ajouter une nouvelle classe
LuisQueryCliquez avec le bouton droit de la souris sur le répertoire des contrôleurs et cliquez sur Ajouter -> ContrôleurCréez un nouveau contrôleur API -> Vide
SmsControllerAjoutez une nouvelle classe appelée
Dispatcherau projet
Ajouter des paquets
Ajoutez les paquets suivants au projet :
Microsoft.Azure.CognitiveServices.Language.LUIS.Runtime (j'utilise 3.0.0)
Nexmo.Csharp.Client (j'utilise la version 4.3.1)
Ajouter des variables d'environnement
Vous pouvez décider de la manière dont vous allez introduire vos informations d'identification dans votre application. J'aime utiliser soit l'injection de dépendance de configuration soit les variables d'environnement. L'utilisation des variables d'environnement est un peu plus simple dans ce cas, nous allons donc l'utiliser pour la démo. Faites un clic droit sur le projet et allez dans propriétés. Dans la section Débogage faites défiler jusqu'aux variables d'environnement et ajoutez ce qui suit :
| 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 |
Requête Luis
Nous allons maintenant interroger le point de terminaison LUIS à partir de notre application. Ouvrez la classe LuisQuery et ajoutez les instructions d'utilisation suivantes en haut de la page :
using Microsoft.Azure.CognitiveServices.Language.LUIS.Runtime;
using Microsoft.Azure.CognitiveServices.Language.LUIS.Runtime.Models;
using System;
using System.Threading.Tasks;Ensuite, à l'intérieur de la classe, ajoutez les champs suivants :
// 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");Ensuite, nous allons créer le client en générant un ensemble d'informations d'identification à partir de notre clé de prédiction, et en utilisant ces informations d'identification avec notre point de terminaison. Nous allons créer un client dans une méthode statique.
private static LUISRuntimeClient CreateClient()
{
var credentials = new ApiKeyServiceClientCredentials(_predictionKey);
return new LUISRuntimeClient(credentials, new System.Net.Http.DelegatingHandler[] { })
{
Endpoint = _predictionEndpoint
};
}La dernière chose à faire ici est de créer une méthode qui utilise notre client de prédiction pour créer une prédiction. Cette méthode prend une chaîne queryelle obtient un client de prédiction et ajoute notre requête à notre point d'arrivée de prédiction.
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);
}
}
Ajouter un code de dispatcher
Notre Dispatcher va gérer la logique commerciale de ce que nous voulons faire avec nos intentions. La première chose à faire est donc d'établir l'enum pour nos intentions. Ajoutez ce qui suit à votre Dispatcher classe :
public enum Intent
{
None,
OrderFood
}Ensuite, ajoutez les instructions d'utilisation suivantes au fichier Dispatcher les instructions d'utilisation suivantes.
using Newtonsoft.Json.Linq;
using Nexmo.Api;
using System;Ensuite, nous allons ajouter une fonction, ExecuteQuerypour exécuter la requête, créer un message de réponse à partir du résultat de la requête, et renvoyer ce message au point de terminaison. Cette fonction va prendre notre message SMS entrant à partir de notre contrôleur (que nous construirons ensuite), extraire le message et l'envoyer à travers notre classe LuisQuery à l'intérieur de notre classe. Si la requête détecte une intention None, elle crée un message disant "Je n'ai pas tout à fait compris. Sinon, elle extrait le nom du plat et du restaurant du message et répond au client que son plat est en route.
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());
}
} Réception et envoi de SMS
Nous allons recevoir des SMS sur notre point de terminaison SmsController nous allons recevoir des SMS sur notre point de terminaison, interroger LUIS et répondre aux SMS entrants. Pour ce faire, entrons dans notre classe SmsController classe. La première chose que nous allons faire est de supprimer l'attribut Route de l'attribut SmsController. Ensuite, ajoutons une méthode :
[HttpGet("webhooks/inbound")]
public IActionResult Get([FromQuery]SMS.SMSInbound inbound)
{
Dispatcher.ExecuteQuery(inbound);
return NoContent();
}Pour ce faire, vous devez importer l'espace de noms Nexmo.Api pour cela.
Et c'est tout le code dont nous aurons besoin !
Test avec IIS Express et ngrok
Nous allons juste tester ceci dans IIS Express, donc allons dans l'onglet debug de la page des propriétés du projet. Je vais désactiver SSL sur IIS Express et noter le numéro de port sur lequel il est hébergé. Ensuite, je vais exécuter la commande suivante dans l'invite de commande :
Cela lancera ngrok et produira quelque chose comme :

Prenez note de l'identifiant unique qui précède ngrok.io dans l'URL. Laissez cela et démarrez l'application en mode débogage dans IIS Express.
Configurer les Webhooks
Il ne reste plus qu'à aller sur la page des paramètres dans le tableau de bord et de changer l'URL des messages entrants en http://UNIQUE_NGROK_ENDPOINT.ngrok.io/webhooks/inbound. Remplacer UNIQUE_NGROK_ENDPOINT par l'ensemble aléatoire de caractères produit par ngrok. Dans l'exemple ci-dessus, le point de terminaison serait http://dc0feb1d.ngrok.io/webhooks/inbound. Ceci pointe Vonage vers notre serveur IIS Express et nous permet de recevoir des messages sur notre point de terminaison SMS.
Le moment de tester
Il ne reste plus qu'à faire un test. L'application devrait être opérationnelle ; tout ce que vous avez à faire est d'envoyer un message texte avec votre commande de livraison à n'importe quel numéro compatible SMS que vous avez acquis par le biais du tableau de bord de l tableau de bord API de Vonageet la commande sera traitée pour vous.
Prochaines étapes
Cette démo est un exemple basique de la façon de travailler avec LUIS. LUIS est une plateforme robuste et très flexible. Cependant, comme vous l'avez sans doute remarqué, elle nécessite une réflexion approfondie sur la manière dont vous allez construire la base de connaissances pour qu'elle soit vraiment utile.
Les API de Vonage vous permettent d'utiliser un grand nombre de canaux pour communiquer avec LUIS. Vous pouvez utiliser l Messages APIqui prend en charge Facebook Messenger, WhatsApp et Viber en plus des SMS. LUIS vous permet également de travailler directement avec la parole, de sorte que vous pourriez potentiellement construire un robot qui écoute la parole d'un appel RTPC via l'API Websocket API de Vonage.
Ressources
Vous pouvez trouver le code complet de l'exemple dans GitHub
Si vous souhaitez ignorer la construction du modèle et importer celui que j'ai construit à des fins de démonstration, il est disponible ici.
Il y a beaucoup d'excellents documents sur la façon de travailler avec Luis sur le site docs de Microsoft. de Microsoft.
