paint-brush
Créez un bot WhatsApp Trivia Quiz avec Twilio et ASP.NET Corepar@zadok
2,606 lectures
2,606 lectures

Créez un bot WhatsApp Trivia Quiz avec Twilio et ASP.NET Core

par Zadok J.15m2023/09/15
Read on Terminal Reader

Trop long; Pour lire

Dans ce guide didacticiel, vous apprendrez à créer un quiz à l'aide de Twilio pour WhatsApp, ASP.NET Core et l'API Trivia.
featured image - Créez un bot WhatsApp Trivia Quiz avec Twilio et ASP.NET Core
Zadok J. HackerNoon profile picture
0-item
1-item

Les jeux-questionnaires offrent une expérience engageante et éducative où vous pouvez apprendre de nouveaux faits et élargir vos connaissances sur divers sujets. De nos jours, les applications mobiles et Web Trivia quiz sont les domaines de prédilection les plus courants pour une telle activité. Que diriez-vous de jouer à un jeu-questionnaire sur WhatsApp ?


Dans ce guide didacticiel, vous apprendrez à créer une application de quiz à l'aide de Twilio pour WhatsApp, ASP.NET Core et L'API Trivia ( sous licence CC BY-NC 4.0 ). Le but de ce didacticiel est de créer une application de jeu-questionnaire qui permet aux utilisateurs de jouer et de répondre à des questions à choix multiples à l'aide de WhatsApp. Vous tirerez parti sessions dans ASP.NET Core pour stocker et récupérer la progression de l'utilisateur, suivre le score et maintenir l'état du jeu.


Pour récupérer ces questions, vous utiliserez l'API Trivia, une API REST, qui permet aux développeurs de créer facilement des applications de quiz en proposant des questions à choix multiples. Pour en savoir plus sur l'API Trivia, veuillez consulter la__ documentation de l'API Trivia __.


Conditions préalables

Pour réaliser ce tutoriel, vous aurez besoin de :


Le code source de ce tutoriel est disponible sur GitHub .


Configurer un nouveau projet ASP.NET Core

Pour commencer, en utilisant votre terminal shell dans un répertoire de travail préféré, exécutez les commandes suivantes pour créer un nouveau projet d'API Web :


 dotnet new webapi -n TwilioWhatsAppTriviaApp --no-openapi


La deuxième commande de l'extrait ci-dessus créera un nouveau projet d'API Web avec le nom spécifié et sans prise en charge d'OpenAPI (Swagger). Si vous souhaitez utiliser Swagger dans le projet, omettez simplement --no-openapi dans la commande ci-dessus.


Accédez au répertoire du projet en exécutant cette commande :


 cd TwilioWhatsAppTriviaApp


Installez le Bibliothèque Twilio Helper pour ASP.NET Core Forfait NuGet :


 dotnet add package Twilio.AspNet.Core


Cette bibliothèque simplifie l'utilisation des webhooks et des API Twilio dans une application ASP.NET Core.


Ouvrez le projet en utilisant votre IDE préféré. Dans le dossier Controllers , supprimez le fichier de contrôleur de modèle standard, WeatherForecastController.cs , et supprimez également WeatherForcast.cs dans le répertoire du projet.


Créez et exécutez votre projet pour vous assurer que tout ce que vous avez fait jusqu'à présent fonctionne bien à l'aide des commandes suivantes :


 dotnet build dotnet run


Après avoir exécuté le projet avec succès, notez toutes les URL localhost qui apparaissent dans la console de débogage. Vous pouvez utiliser n'importe laquelle de ces URL pour configurer un serveur Web local accessible au public à l'aide de ngrok.


URL d'hôte local


Mettre en œuvre des sessions

Les sessions sont l'une des nombreuses façons de stocker les données d'un utilisateur dans une application ASP.NET Core. Ceci est essentiel lorsque vous souhaitez conserver les données utilisateur entre les requêtes car par défaut, le protocole HTTP est sans état, ce qui signifie que les données ne sont pas conservées.

Ajoutez le fournisseur de session en mémoire en modifiant Program.cs , comme indiqué dans le code suivant :


 var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddDistributedMemoryCache(); builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromSeconds(40); options.Cookie.IsEssential = true; }); var app = builder.Build(); app.UseSession(); app.MapControllers(); app.Run();


AddDistributedMemoryCache() enregistre le service de cache de mémoire distribuée. Ce service fournit un cache en mémoire qui peut être utilisé pour stocker et récupérer des données sur plusieurs requêtes ou sessions.


AddSession() enregistre les services de session, permettant à l'application de maintenir l'état de session. Le paramètre options vous permet de configurer diverses options liées à la session. IdleTimeout est utilisé pour définir la durée d'inactivité après laquelle une session sera considérée comme inactive. Dans ce cas, elle est fixée à 40 secondes. Cookie.IsEssential garantit que l'état de la session reste fonctionnel et même dans les scénarios où le rejet des cookies est activé.


La prise en charge des sessions est activée en ajoutant le middleware UseSession au pipeline d'application, c'est-à-dire que votre application accède à un objet de session qui peut être utilisé pour stocker et récupérer des données.


Créer les modèles

Créez un nouveau dossier, Models, dans le répertoire de votre projet. Ajoutez deux fichiers de classe de modèle, TriviaApiResponse.cs et Question.cs avec les propriétés indiquées dans les exemples de code suivants :


 using Newtonsoft.Json; namespace TwilioWhatsAppTriviaApp.Models; public class TriviaApiResponse { [JsonProperty("category")] public string Category { get; set; } [JsonProperty("correctAnswer")] public string CorrectAnswer { get; set; } [JsonProperty("incorrectAnswers")] public List<string> IncorrectAnswers { get; set; } [JsonProperty("question")] public string Question { get; set; } [JsonProperty("type")] public string? Type { get; set; } [JsonProperty("difficulty")] public string Difficulty { get; set; } }


 namespace TwilioWhatsAppTriviaApp.Models; public class Question { public string QuestionText { get; set; } public List<(string option, bool isCorrect)> Options { get; set; } }


Le modèle TriviaApiResponse inclut des propriétés qui représentent les champs de la réponse de l'API Trivia. L'attribut JsonProperty garantit que chaque propriété est correctement renseignée avec les données JSON correspondantes.


Pour une manière simplifiée de gérer les questions triviales, la classe Question vient à la rescousse. Cette classe encapsule les informations nécessaires pour une question triviale, y compris le texte de la question et une liste d'options. Chaque option est représentée par un tuple contenant le texte de l'option et une valeur booléenne indiquant si c'est la bonne option.


Ajouter la classe de service Trivia

Créez un dossier Services dans le répertoire de votre projet et ajoutez un nouveau fichier de classe nommé TriviaService.cs . Modifiez son contenu, comme indiqué dans le code suivant :


 using Newtonsoft.Json; using TwilioWhatsAppTriviaApp.Models; namespace TwilioWhatsAppTriviaApp.Services; public class TriviaService { private const string TheTriviaApiUrl = @"https://the-trivia-api.com/api/questions?limit=3"; private HttpClient httpClient; public TriviaService(HttpClient httpClient) { this.httpClient = httpClient; } public async Task<IEnumerable<TriviaApiResponse>> GetTrivia() { var response = await httpClient.GetAsync(TheTriviaApiUrl); var triviaJson = await response.Content.ReadAsStringAsync(); var trivia = JsonConvert.DeserializeObject<IEnumerable<TriviaApiResponse>>(triviaJson); return trivia; } public List<Question> ConvertTriviaToQuestions(IEnumerable<TriviaApiResponse> questions) { List<Question> newQuestions = new(); foreach (var question in questions) { var options = new List<(string option, bool isCorrect)>() { (question.CorrectAnswer, true), (question.IncorrectAnswers[0], false), (question.IncorrectAnswers[1], false), (question.IncorrectAnswers[2], false) }; // Shuffle the options randomly Random random = new(); options = options.OrderBy(_ => random.Next()).ToList(); newQuestions.Add(new Question { QuestionText = question.Question, Options = options }); } return newQuestions; } }


La classe TriviaService contient deux méthodes : GetTrivia et ConvertTriviaToQuestions . La méthode GetTrivia envoie la requête HTTP GET à l'API Trivia avec un paramètre de requête, limit=3 , qui spécifie que seules 3 questions doivent être renvoyées. Sans le paramètre limit, l'API renvoie 10 questions par défaut.


La méthode ConvertTriviaToQuestions convertit la réponse de l'API de manière organisée. La méthode mélange également toutes les options de questions de manière aléatoire, de sorte qu'une seule option ne soit pas la réponse à toutes les questions.


Pour enregistrer TriviaService et le client HTTP dans le conteneur Dependency Injection (DI) de votre application, modifiez Program.cs comme indiqué dans le code suivant :


 using TwilioWhatsAppTriviaApp.Services; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddDistributedMemoryCache(); builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromSeconds(40); options.Cookie.IsEssential = true; }); builder.Services.AddHttpClient(); builder.Services.AddScoped<TriviaService>(); var app = builder.Build(); app.UseSession(); app.MapControllers(); app.Run();


Créer le contrôleur Trivia

Ajoutez une classe de contrôleur API vide dans un fichier nommé TriviaController.cs au dossier Controllers et modifiez son contenu comme indiqué dans le code suivant :


 using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using Twilio.AspNet.Core; using Twilio.TwiML; using Twilio.TwiML.Messaging; using TwilioWhatsAppTriviaApp.Models; using TwilioWhatsAppTriviaApp.Services; namespace WhatsappTrivia.Controllers; [Route("[controller]")] [ApiController] public class TriviaController : TwilioController { private const string SessionKeyIsGameOn = "IsGameOn"; private const string SessionKeyScore = "Score"; private const string SessionKeyCurrentQuestionIndex = "CurrentQuestionIndex"; private const string SessionKeyTotalQuestions = "TotalQuestions"; private const string SessionKeyQuestions = "Questions"; private static readonly string[] StartCommands = { "START", "S" }; private static readonly string[] OptionValues = { "A", "B", "C", "D" }; private readonly TriviaService triviaService; public TriviaController(TriviaService triviaService) { this.triviaService = triviaService; } [HttpPost] public async Task<IActionResult> Index() { var response = new MessagingResponse(); var form = await Request.ReadFormAsync(); var body = form["Body"].ToString().ToUpper().Trim(); await HttpContext.Session.LoadAsync(); var isGameOn = Convert.ToBoolean(HttpContext.Session.GetString(SessionKeyIsGameOn)); int currentQuestionIndex = HttpContext.Session.GetInt32(SessionKeyCurrentQuestionIndex) ?? 0; int totalQuestions = HttpContext.Session.GetInt32(SessionKeyTotalQuestions) ?? 0; if (StartCommands.Contains(body) && !isGameOn) { await StartGame(); HttpContext.Session.SetString(SessionKeyIsGameOn, "true"); response.Message(PresentQuestionWithOptions(currentQuestionIndex)); return TwiML(response); } if (OptionValues.Contains(body) && isGameOn) { var result = ProcessUserAnswer(body, currentQuestionIndex); response.Message(result); currentQuestionIndex++; if (currentQuestionIndex <= totalQuestions - 1) { HttpContext.Session.SetInt32(SessionKeyCurrentQuestionIndex, currentQuestionIndex); response.Append(new Message(PresentQuestionWithOptions(currentQuestionIndex))); } else { response.Append(new Message(EndTrivia())); } return TwiML(response); } response.Message(!isGameOn ? "*Hello! Send 'Start' or 'S' to play game*" : "*Invalid Input! Send a correct option 'A', 'B', 'C' or 'D'*"); return TwiML(response); } private async Task StartGame() { if (HttpContext.Session.GetString(SessionKeyQuestions) != null) { HttpContext.Session.Remove(SessionKeyQuestions); } var trivia = await this.triviaService.GetTrivia(); var questions = this.triviaService.ConvertTriviaToQuestions(trivia); AddNewQuestionsToSession(questions); HttpContext.Session.SetInt32(SessionKeyTotalQuestions, questions.Count); } private string ProcessUserAnswer(string userAnswer, int questionIndex) { bool optionIsCorrect = false; int score = HttpContext.Session.GetInt32(SessionKeyScore) ?? 0; var question = RetrieveQuestionFromSession(questionIndex); switch (userAnswer) { case "A": optionIsCorrect = question.Options[0].isCorrect; break; case "B": optionIsCorrect = question.Options[1].isCorrect; break; case "C": optionIsCorrect = question.Options[2].isCorrect; break; case "D": optionIsCorrect = question.Options[3].isCorrect; break; } if (optionIsCorrect) { score++; HttpContext.Session.SetInt32(SessionKeyScore, score); } return optionIsCorrect ? "_Correct ✅_" : $"_Incorrect ❌ Correct answer is {question.Options.Find(o => o.isCorrect).option.TrimEnd()}_"; } private string PresentQuestionWithOptions(int questionIndex) { var question = RetrieveQuestionFromSession(questionIndex); return $""" {questionIndex + 1}. {question.QuestionText} {OptionValues[0]}. {question.Options[0].option} {OptionValues[1]}. {question.Options[1].option} {OptionValues[2]}. {question.Options[2].option} {OptionValues[3]}. {question.Options[3].option} """; } private void AddNewQuestionsToSession(List<Question> questions) => HttpContext.Session.SetString(SessionKeyQuestions, JsonConvert.SerializeObject(questions)); private Question RetrieveQuestionFromSession(int questionIndex) { var questionsFromSession = HttpContext.Session.GetString(SessionKeyQuestions); return JsonConvert.DeserializeObject<List<Question>>(questionsFromSession)[questionIndex]; } private string EndTrivia() { var score = HttpContext.Session.GetInt32(SessionKeyScore) ?? 0; var totalQuestions = HttpContext.Session.GetInt32(SessionKeyTotalQuestions) ?? 0; var userResult = $""" Thanks for playing! 😊 You answered {score} out of {totalQuestions} questions correctly. To play again, send 'Start' or 'S' """; HttpContext.Session.Clear(); return userResult; } }


Cette classe de contrôleur est responsable du traitement des messages entrants, de la gestion de l'état de la session et de la génération des réponses. Il hérite de la classe TwilioController fournie par la bibliothèque Twilio.AspNet.Core, qui vous donne accès à la méthode TwiML . Vous pouvez utiliser cette méthode pour répondre avec TwiML, qui est le langage de balisage Twilio . La classe TriviaController utilise les méthodes HttpContext.Session pour interagir avec la session.

Les entrées valides sont des éléments des tableaux en lecture seule StartCommands et OptionValues . Le corps du message entrant est comparé à ces éléments pour garantir que l'utilisateur a envoyé une entrée appropriée. Dans le cas contraire, un message sera envoyé à l'utilisateur l'invitant à effectuer la bonne entrée en fonction de l'état actuel du jeu. D'autres champs avec le préfixe « SessionKey » sont utilisés pour définir des chaînes constantes privées pour les clés de session dans le programme.


La méthode Index est la méthode d'action principale qui gère les requêtes HTTP POST entrantes de WhatsApp via la route /Trivia . Il charge les données de session à l'aide de HttpContext.Session.LoadAsync() et récupère les données concernant l'état du jeu de la session à l'aide des méthodes HttpContext.Session.GetString() et HttpContext.Session.GetInt32() .


L'utilisation de traits de soulignement (_) et d'astérisques (*) au début et à la fin de certaines chaînes permet d'obtenir respectivement un formatage de texte en italique et en gras dans les messages WhatsApp rendus.


Chaque méthode d'assistance du TriviaController effectue une tâche spécifique qui prend en charge les fonctionnalités principales de la classe.

  • La méthode StartGame initialise le jeu en récupérant les questions triviales, en les convertissant dans un format adapté au jeu et en les stockant dans la session.
  • La méthode ProcessUserAnswer traite la réponse de l'utilisateur à une question et détermine si elle est correcte ou non.
  • La méthode PresentQuestionWithOptions est responsable du formatage et de la présentation d’une question avec ses options.
  • La méthode AddNewQuestionsToSession stocke une liste de questions dans la session. Il convertit les questions au format JSON et enregistre la chaîne JSON dans la session.
  • La méthode RetrieveQuestionFromSession récupère une question de la session à l’aide de l’index des questions.
  • La méthode EndTrivia génère un message pour terminer le jeu-questionnaire. Cette méthode supprime également les données de session liées au jeu. Basé sur la configuration du service de session dans Program.cs , cela se produit automatiquement lorsque la session est inactive pendant 40 secondes.


Testez l'application

Pour tester l'application, vous devez configurer Twilio Sandbox pour WhatsApp, rendre le point de terminaison de votre application accessible au public et ajouter l'URL du point de terminaison dans la configuration Sandbox en tant que webhook.

Configurer Twilio Sandbox pour WhatsApp

Allez au Console Twilio , accédez à Message > Essayez-le > Envoyer un message WhatsApp .


Console Twilio


Suivez les instructions sur la page pour vous connecter au bac à sable, en envoyant un message WhatsApp depuis votre appareil au numéro Twilio fourni afin de créer une connexion réussie avec le bac à sable WhatsApp. De même, les autres personnes souhaitant tester votre application avec leurs numéros respectifs devront suivre la même procédure.

Exposez votre webhook en utilisant ngrok pour les tests

Maintenant, ouvrez un terminal shell et exécutez la commande suivante pour démarrer ngrok et exposer votre application ASP.NET Core locale en remplaçant <localhost-url> par l'URL complète de votre hôte local que vous avez copié initialement :


 ngrok http <localhost-url>


ngrok générera une URL publique qui transmettra les requêtes à votre application ASP.NET locale. Recherchez l'URL de transfert intitulée Forwarding dans la fenêtre du terminal ngrok et copiez-la.


URL de transfert


Revenez à la page Twilio Try WhatsApp, cliquez sur Sandbox Settings et modifiez l'URL When a message comes in endpoint url avec l'URL de transfert générée par ngrok plus la route /Trivia et assurez-vous que la méthode est définie sur POST. Cliquez ensuite sur Enregistrer pour enregistrer la nouvelle configuration du bac à sable.


Bac à sable Twilio


Démo du projet

Exécutez votre projet ASP.NET Core à l'aide de la commande suivante :


 dotnet run


Maintenant, testez votre application en envoyant un message lors de la conversation initiale avec le numéro Twilio Sandbox.


Tester votre application dans WhatsApp


Conclusion

En tirant parti de la puissance de la plate-forme Twilio et de WhatsApp, vous avez créé une expérience de jeu-questionnaire immersive dont les utilisateurs peuvent profiter. Vous avez également appris à enregistrer et récupérer les données des sessions.


Il existe plusieurs façons d’améliorer ce projet. Vous pouvez encore améliorer ce projet en ajoutant une minuterie, en gérant les exceptions, en permettant aux utilisateurs de choisir la difficulté et en appliquant la difficulté choisie comme paramètre de requête via l'URL de l'API Trivia (par exemple https://the-trivia-api.com/api/questions?difficulty=hard ). De plus, vous pouvez explorer la possibilité de créer une solution permettant aux utilisateurs de répondre à des sondages via WhatsApp.