One place for hosting & domains

      construire

      Comment construire un bot Discord avec Node.js


      L’auteur a choisi le Free and Open Source Fund comme récipiendaire d’un don dans le cadre du programme Write for DOnations.

      Introduction

      Discord est une application de chat qui permet à des millions d’utilisateurs à travers le monde d’échanger des messages et de s’appeler en ligne au sein de communautés appelées guildes ou serveurs. Discord fournit également une API complète que les développeurs peuvent utiliser pour créer de puissants bots Discord. Les bots peuvent effectuer diverses actions telles que l’envoi de messages aux serveurs, le DM-ing des utilisateurs, la modération des serveurs et la lecture audio dans les chats vocaux. Cela permet aux développeurs de créer des bots puissants qui comprennent des fonctionnalités avancées et complexes comme des outils de modération ou même des jeux. Par exemple, le bot utilitaire Dyno sert des millions de guildes et contient des fonctions utiles telles que la protection contre le spam, un lecteur de musique et d’autres fonctions utilitaires. Apprendre à créer des bots Discord vous permet d’implémenter de nombreuses choses, avec lesquelles des milliers de personnes pourront interagir chaque jour.

      Dans ce tutoriel, vous allez construire un bot Discord à partir de zéro, en utilisant Node.js et la bibliothèque Discord.js, qui permet aux utilisateurs d’interagir directement avec l’API Discord. Vous allez créer un profil pour un bot Discord, obtenir des jetons d’authentification pour le bot, et programmer le bot pour lui donner la capacité de traiter les commandes des utilisateurs avec des arguments.

      Conditions préalables

      Avant de commencer, vous aurez besoin des éléments suivants :

      Étape 1 — Configuration d’un bot Discord

      Au cours de cette étape, vous utiliserez l’interface graphique des développeurs Discord pour mettre en place un bot Discord et obtenir le jeton du bot, que vous passerez dans votre programme.

      Pour enregistrer un bot sur la plate-forme Discord, utilisez le tableau de bord de l’application Discord. Les développeurs peuvent y créer des applications Discord, y compris des bots Discord.

      Image du tableau de bord de l'application Discord après une première visite sur https://discord.com/developers/applications

      Pour commencer, cliquez sur New Application (Nouvelle Application). Discord vous demandera d’entrer un nom pour votre nouvelle application. Cliquez ensuite sur Create (Créer) pour créer l’application.

      Image de l'invite à créer une application, avec "Test Node.js Bot" saisi comme nom de l'application

      Note : le nom de votre application est indépendant du nom du bot, et le bot n’a pas besoin d’avoir le même nom que l’application.

      Ouvrez maintenant le tableau de bord de votre application. Pour ajouter un bot à l’application, naviguez dans l’onglet Bot de la barre de navigation, à gauche.

      Image de l'onglet bot du tableau de bord de l'application

      Cliquez sur le bouton Add Bot (Ajouter un Bot) pour ajouter un bot à l’application. Cliquez sur le bouton Yes, do it! (C’est parti !) lorsqu’il vous demande une confirmation. Vous vous retrouverez alors sur un tableau de bord contenant les détails du nom de votre bot, son jeton d’authentification et sa photo de profil.

      Tableau de bord contenant les détails de votre bot

      Vous pouvez modifier le nom ou la photo de profil de votre bot ici, sur le tableau de bord. Vous devez également copier le jeton d’authentification du bot en cliquant sur Click to Reveal Token (Cliquer pour révéler le jeton) et en copiant le jeton qui apparaît.

      Warning : ne partagez pas, ne téléchargez pas votre jeton de bot, car il permet à n’importe qui de se connecter à votre bot.

      Vous devez maintenant créer une invitation qui vous permette d’ajouter les guildes Discord de bots où vous pouvez tester le robot. Tout d’abord, naviguez vers l’onglet OAuth2 du tableau de bord de l’application. Pour créer une invitation, faites défiler l’écran vers le bas et sélectionnez bot sous scopes. Vous devez également définir des autorisations pour contrôler les actions que votre bot peut effectuer dans les guildes. Pour les besoins de ce tutoriel, sélectionnez Administrator (Administrateur), ce qui donnera à votre bot la permission d’effectuer presque toutes les actions dans les guildes. Copiez le lien à l’aide du bouton Copy (Copier).

      Onglet OAuth2, avec scope définie sur

      Ensuite, ajoutez le bot à un serveur. Suivez le lien d’invitation que vous venez de créer. Vous pouvez ajouter le bot à n’importe lequel des serveurs que vous possédez, ou pour lequel vous avez des autorisations d’administrateur, à partir du menu déroulant.

      Page suivant le lien d'invitation, permettant aux utilisateurs d'ajouter le bot aux serveurs

      Cliquez maintenant sur** Continue** (Continuer). Vérifiez que vous avez coché la case située à côté de Administrator – cela donnera au bot des autorisations d’administrateur. Ensuite, cliquez sur Authorize (Autoriser). Discord vous demandera de résoudre un CAPTCHA avant que le bot ne rejoigne le serveur. Votre bot Discord se trouvera désormais sur la liste des membres du serveur à laquelle vous l’avez ajouté, sous offline.

      Liste des membres d'un serveur Discord avec le bot nouvellement créé sous la section "offline" de la liste des membres

      Vous avez créé avec succès un robot Discord et l’avez ajouté à un serveur. Ensuite, vous allez écrire un programme pour vous connecter au bot.

      Étape 2 — Création de votre projet

      Au cours de cette étape, vous allez configurer l’environnement de codage de base dans lequel vous allez construire votre bot et vous connecter au bot par programmation.

      Tout d’abord, vous devez créer un dossier de projet et les fichiers de projet nécessaires pour le bot.

      Créez votre dossier de projet :

      Rendez-vous dans le dossier de projet que vous venez de créer :

      Ensuite, utilisez votre éditeur de texte pour créer un fichier nommé config.json, afin de stocker le jeton d’authentification de votre bot :

      Ajoutez ensuite le code suivant au fichier de configuration, en remplaçant le texte surligné par le jeton d’authentification de votre bot :

      config.json

      {
          "BOT_TOKEN": "YOUR BOT TOKEN"
      }
      

      Enregistrez et quittez le fichier.

      Ensuite, vous créerez un fichier package.json, qui stockera les détails de votre projet et des informations sur les dépendances que vous utiliserez pour le projet. Vous allez créer un fichier package.json en exécutant la commande npm suivante :

      npm vous demandera différentes informations sur votre projet. Si vous souhaitez obtenir des conseils sur la manière de remplir ces invites, vous trouverez plus d’informations dans la section Comment utiliser les modules Node.js avec npm et package.json.

      Vous allez maintenant installer le paquet discord.js que vous utiliserez pour interagir avec l’API Discord. Vous pouvez installer discord.js par le biais de npm avec la commande suivante :

      Maintenant que vous avez configuré le fichier de configuration et installé la dépendance nécessaire, vous êtes prêt à commencer à construire votre bot. Dans une application réelle, un gros bot serait réparti sur plusieurs fichiers, mais pour les besoins de ce tutoriel, le code de votre bot se trouvera dans un seul fichier.

      Tout d’abord, créez un fichier nommé index.js dans le dossier discord-bot pour le code :

      Commencez à coder le bot en demandant la dépendance discord.js et le fichier de configuration avec le jeton du bot :

      index.js

      const Discord = require("discord.js");
      const config = require("./config.json");
      

      Ensuite, ajoutez les deux lignes de code suivantes :

      index.js

      ...
      const client = new Discord.Client();
      
      client.login(config.BOT_TOKEN);
      

      Enregistrez et fermez votre fichier

      La première ligne de code crée un nouveau Discord.Client et l’attribue au client constant. Ce client permet en partie d’interagir avec l’API Discord et de vous informer des événements tels que l’arrivée de nouveaux messages. Le client, en effet, représente le bot Discord.

      La deuxième ligne de code utilise la méthode login sur le client pour se connecter au bot Discord que vous avez créé, en utilisant le jeton du fichier config.json comme mot de passe. Le jeton permet à l’API Discord de savoir à quel bot le programme est destiné et que vous avez été authentifié pour utiliser le bot.

      Maintenant, exécutez le fichier index.js en utilisant Node :

      Le statut de votre bot passera à online (en ligne) dans le serveur Discord auquel vous l’avez ajouté.

      Image du bot en ligne

      Vous avez configuré avec succès un environnement de codage et créé le code de base pour vous connecter à un bot Discord. Dans l’étape suivante, vous allez gérer les commandes utilisateur et demander à votre bot d’effectuer des actions, comme l’envoi de messages.

      Étape 3 — Traitement de votre première commande utilisateur

      Dans cette étape, vous allez créer un bot qui peut gérer les commandes de l’utilisateur. Vous commencerez par configurer votre première commande ping, qui répondra par "pong" et indiquera le temps nécessaire pour répondre à la commande.

      Tout d’abord, vous devez détecter et recevoir tout message envoyé par les utilisateurs afin de pouvoir traiter toute commande. En utilisant la méthode on sur le client Discord, Discord vous enverra une notification sur les nouveaux événements. La méthode on prend deux arguments : le nom d’un événement à attendre et une fonction à exécuter chaque fois que cet événement se produit. Avec cette méthode, vous pouvez attendre le message de l’événement – cela se produit chaque fois qu’un message est envoyé à une guilde où le bot a la permission de voir les messages. C’est pourquoi nous allons créer une fonction, qui s’exécute à chaque fois qu’un message est envoyé, pour traiter les commandes.

      Tout d’abord, ouvrez votre fichier :

      Ajoutez le code suivant à votre fichier :

      index.js

      ...
      const client = new Discord.Client();
      
      
      client.on("message", function(message) { 
                                               
      });                                      
      
      client.login(config.BOT_TOKEN);
      

      Cette fonction, qui s’exécute sur l’événement message, prend message comme paramètre. message aura la valeur d’une instance de message Discord.js, qui contient des informations sur le message envoyé et des méthodes pour aider le bot à répondre.

      Ajoutez maintenant la ligne de code suivante à votre fonction de traitement des commandes :

      index.js

      ...
      client.on("message", function(message) {
        if (message.author.bot) return;
      });
      ...
      

      Cette ligne vérifie si l’auteur du message est un bot, et si c’est le cas, arrête le traitement de la commande. C’est important car, en général, vous ne voulez pas traiter les messages des bots ou y répondre. Les bots n’ont généralement pas besoin ou ne veulent pas utiliser notre bot. Ignorer leurs messages permet donc d’économiser de la puissance de traitement et d’éviter les réponses accidentelles.

      Maintenant vous allez écrire un gestionnaire de commandes. Pour ce faire, il est bon de comprendre le format habituel d’une commande Discord. En général, la structure d’une commande Discord contient trois parties dans l’ordre suivant : un préfixe, un nom de commande et (parfois) des arguments de commande.

      Une image d'une commande Discord indiquant "! add12"

      • Préfixe : le préfixe peut être de toute nature, mais il s’agit généralement d’un morceau de ponctuation ou d’une phrase abstraite qui ne se trouverait normalement pas au début d’un message. Cela signifie que lorsque vous incluez le préfixe au début du message, le bot saura que l’intention de cette commande est qu’un bot la traite.

      • Nom de la commande : le nom de la commande que l’utilisateur veut utiliser. Cela signifie que le bot peut prendre en charge plusieurs commandes avec des fonctionnalités différentes et permettre aux utilisateurs de choisir entre elles en fournissant un nom de commande différent.

      • Arguments : parfois, si la commande nécessite ou utilise des informations supplémentaires de la part de l’utilisateur, celui-ci peut fournir des arguments après le nom de la commande, chaque argument étant séparé par un espace.

      Note : ll n’y a pas de structure de commandes imposée et les bots peuvent traiter les commandes comme ils le souhaitent, mais la structure présentée ici est une structure efficace, que la grande majorité des bots utilise.

      Pour commencer à créer un analyseur de commandes qui gère ce format, ajoutez les lignes de code suivantes à la fonction de traitement des messages :

      index.js

      ...
      const prefix = "!";
      
      client.on("message", function(message) {
        if (message.author.bot) return;
        if (!message.content.startsWith(prefix)) return;
      });
      ...
      

      Vous ajoutez la première ligne de code pour attribuer la valeur "!" au prefix de la constante, que vous utiliserez comme préfixe du bot.

      La deuxième ligne de code que vous ajoutez vérifie si le contenu du message que le bot traite commence par le préfixe que vous avez défini, et si ce n’est pas le cas, elle empêche la poursuite du traitement du message.

      Vous devez maintenant convertir le reste du message en un nom de commande et en arguments qui peuvent exister dans le message. Ajoutez les lignes surlignées suivantes :

      index.js

      ...
      client.on("message", function(message) {
        if (message.author.bot) return;
        if (!message.content.startsWith(prefix)) return;
      
        const commandBody = message.content.slice(prefix.length);
        const args = commandBody.split(' ');
        const command = args.shift().toLowerCase();
      });
      ...
      

      Ici, vous utilisez la première ligne pour supprimer le préfixe du contenu du message et attribuer le résultat à la constante commandBody. Cette action est nécessaire, car vous ne voulez pas inclure le préfixe dans le nom de la commande analysée.

      La deuxième ligne prend le message dont le préfixe a été supprimé et utilise la méthode split, avec une espace comme séparateur. Cette méthode entraîne la division du message en une série de sous-chaînes de caractères, ce qui fait qu’elle se divise partout où il y a un espace. Cela donne lieu à un tableau contenant le nom de la commande et les arguments, s’ils sont inclus dans le message. Vous assignez ce tableau à la constante args.

      La troisième ligne supprime le premier élément du tableau args (qui sera le nom de la commande fournie), le convertit en minuscules, puis l’affecte à la constante command. Cela vous permet d’isoler le nom de la commande et de ne laisser que les arguments dans le tableau. Vous utilisez également la méthode toLowerCase car les commandes sont généralement insensibles à la casse dans les bots Discord.

      Vous avez terminé la construction d’un analyseur de commandes, l’implémentation d’un préfixe requis et l’obtention du nom de la commande et des arguments des messages. Vous allez maintenant implémenter et créer le code pour les commandes spécifiques.

      Ajoutez le code suivant pour commencer à implémenter la commande ping :

      index.js

      ...
        const args = commandBody.split(' ');
        const command = args.shift().toLowerCase();
      
        if (command === "ping") {
                                 
        }                        
      });
      ...
      

      Cet énoncé if vérifie si le nom de commande que vous avez analysé (attribué à la constante command) correspond à "ping". Si c’est le cas, cela indique que l’utilisateur veut utiliser la commande "ping". Vous allez imbriquer le code de la commande spécifique à l’intérieur du bloc if. Vous allez répéter ce schéma pour les autres commandes que vous souhaitez implémenter.

      Maintenant, vous pouvez implémenter le code pour la commande "ping" :

      index.js

      ...
        if (command === "ping") {
          const timeTaken = Date.now() - message.createdTimestamp;
          message.reply(`Pong! This message had a latency of ${timeTaken}ms.`);
        }
      ...
      

      Enregistrez et fermez votre fichier

      Vous ajoutez le bloc de commande "ping" qui calcule la différence entre l’heure actuelle – trouvée en utilisant la méthode now sur l’objet Date – et l’heure de création du message en millisecondes. Cela permet de calculer le temps de traitement du message et le "ping" du bot.

      La deuxième ligne répond à la commande de l’utilisateur en utilisant la méthode reply sur la constante message. La méthode reply envoie un ping à l’utilisateur qui a invoqué la commande (ce qui avertit l’utilisateur et met en évidence le message pour l’utilisateur spécifié), suivi du contenu fourni comme premier argument de la méthode. Vous fournissez un modèle littéral contenant un message et le ping calculé comme réponse que la méthode reply utilisera.

      Ceci conclut l’implémentation de la commande "ping".

      Exécutez votre bot en utilisant la commande suivante (dans le même dossier que index.js) :

      Vous pouvez maintenant utiliser la commande "! ping" dans n’importe quel canal que le robot peut visualiser et dans lequel il peut envoyer un message, ce qui donne lieu à une réponse.

      Image du bot répondant dans Discord à

      Vous avez créé avec succès un bot capable de gérer les commandes des utilisateurs et vous avez implémenté votre première commande. Dans l’étape suivante, vous continuerez à développer votre bot en implémentant une commande sum.

      Étape 4 — Implémentation de la commande sum

      Vous allez maintenant étendre votre programme en implémentant la commande "! sum". La commande prendra un nombre quelconque d’arguments et les additionnera, avant de renvoyer la somme de tous les arguments à l’utilisateur.

      Si votre bot Discord fonctionne toujours, vous pouvez arrêter son processus avec CTRL + C.

      Ouvrez à nouveau votre fichier index.js :

      Pour commencer à implémenter la commande "!sum” vous utiliserez le bloc else-if. Après avoir vérifié le nom de la commande ping, il vérifiera si le nom de la commande est égal à "sum". Nous utilisons un bloc “else-if” car une seule commande sera traitée à la fois, donc si le programme correspond au nom de commande "ping", il n’a pas besoin de vérifier la commande "sum". Ajoutez les lignes surlignées suivantes à votre fichier :

      index.js

      ...
        if (command === "ping") {
          const timeTaken = Date.now() - message.createdTimestamp;
          message.reply(`Ping! This message had a latency of ${timeTaken}ms.`);
        }
      
        else if (command === "sum") {
                                     
        }                            
      });
      ...
      

      Vous pouvez commencer à implémenter le code pour la commande "sum". Le code de la commande "sum" ira dans le bloc else-if que vous venez de créer. Maintenant, ajoutez le code suivant :

      index.js

      ...
        else if (command === "sum") {
          const numArgs = args.map(x => parseFloat(x));
          const sum = numArgs.reduce((counter, x) => counter += x);
          message.reply(`The sum of all the arguments you provided is ${sum}!`);
        }
      ...
      

      Vous utilisez la méthode map sur la liste des arguments pour créer une nouvelle liste en utilisant la fonction parseFloat sur chaque élément du tableau args. Cela crée un nouveau tableau (attribué à la constante numArgs) dans lequel tous les éléments sont des nombres au lieu de chaînes de caractères. Cela signifie que vous pouvez ensuite trouver la somme des nombres en les additionnant.

      La deuxième ligne utilise la méthode reduce sur la constante numArgs, fournissant une fonction qui totalise tous les éléments de la liste. Vous attribuez la somme de tous les éléments de numArgs à la constante sum.

      Vous utilisez ensuite la méthode reply sur l’objet du message pour répondre à la commande de l’utilisateur avec un modèle littéral, qui contient la somme de tous les arguments que l’utilisateur envoie au bot.

      Ceci conclut l’implémentation de la commande "sum". Maintenant, exécutez le bot en utilisant la commande suivante (dans le même dossier que index.js) :

      Vous pouvez maintenant utiliser la commande "! sum" dans n’importe quel canal que le bot peut visualiser et dans lequel il peut envoyer des messages.

      Image du bot répondant

      Ce qui suit est une version complète du script du bot index.js :

      index.js

      const Discord = require("discord.js");
      const config = require("./config.json");
      
      const client = new Discord.Client();
      
      const prefix = "!";
      
      client.on("message", function(message) {
        if (message.author.bot) return;
        if (!message.content.startsWith(prefix)) return;
      
        const commandBody = message.content.slice(prefix.length);
        const args = commandBody.split(' ');
        const command = args.shift().toLowerCase();
      
        if (command === "ping") {
          const timeTaken = Date.now() - message.createdTimestamp;
          message.reply(`Pong! This message had a latency of ${timeTaken}ms.`);
        }
      
        else if (command === "sum") {
          const numArgs = args.map(x => parseFloat(x));
          const sum = numArgs.reduce((counter, x) => counter += x);
          message.reply(`The sum of all the arguments you provided is ${sum}!`);
        }
      });
      
      client.login(config.BOT_TOKEN);
      

      Au cours de cette étape, vous avez développé votre bot Discord en implémentant la commande sum.

      Conclusion

      Vous avez implémenté avec succès un bot Discord qui peut gérer plusieurs commandes utilisateur et arguments différents. Si vous souhaitez développer votre bot, vous pouvez implémenter plus de commandes ou essayer d’autres parties de l’API Discord pour créer un puissant bot Discord. Vous pouvez consulter la documentation de Discord.js ou celle de l’API Discord pour approfondir vos connaissances de l’API Discord.

      Lorsque vous créez des bots Discord, vous devez toujours garder à l’esprit les conditions d’utilisation de l’API Discord, qui décrivent comment les développeurs doivent utiliser l’API Discord. Vous pouvez également lire cet ensemble de lignes directrices qui indique la meilleure façon d’implémenter un bot Discord et fournit des conseils sur la façon de concevoir des bots Discord. Si vous souhaitez en savoir plus sur Node.js, consultez notre série Comment coder en Node.js.



      Source link

      Comment construire un slackbot en Python sur Ubuntu 20.04


      L’auteur a choisi le Tech Education Fund comme récipiendaire d’un don dans le cadre du programme Write for DOnations.

      Introduction

      Slack est une plate-forme de communication conçue pour la productivité sur le lieu de travail. Elle comprend des fonctionnalités telles que la messagerie directe, des chaînes publiques et privées, des appels vocaux et vidéo, et l’intégration de bots. Un Slackbot est un programme automatisé qui peut remplir diverses fonctions en Slack, de l’envoi de messages au déclenchement de tâches en passant par l’alerte sur certains événements.

      Dans ce tutoriel, vous allez construire un Slackbot en langage de programmation Python. Python est un langage populaire qui peut s’enorgueillir d’une grande simplicité et lisibilité. Slack fournit une riche API Python Slack qui s’intègre à Slack pour effectuer des tâches courantes telles que l’envoi de messages, l’ajout d’emojis aux messages, et bien plus encore. Slack fournit également une API Python Slack Events pour l’intégration des événements dans Slack, vous permettant d’effectuer des actions sur des événements tels que des messages et des mentions.

      Pour une démonstration amusante de la puissance de Python et de ses API Slack, vous construirez un CoinBot – un Slackbot qui surveille un canal et qui, une fois déclenché, tirera à pile ou face pour vous. Vous pouvez ensuite modifier votre CoinBot pour répondre à un certain nombre d’applications un peu plus pratiques.

      Notez que ce tutoriel utilise Python 3 et n’est pas compatible avec Python 2.

      Conditions préalables

      Pour suivre ce guide, vous aurez besoin :

      • Un espace de travail Slack dans lequel vous avez la possibilité d’installer des applications. Si vous avez créé l’espace de travail, vous avez cette capacité. Si vous n’en avez pas déjà un, vous pouvez en créer un sur le site web de Slack.

      • (Facultatif) Un serveur ou un ordinateur doté d’une adresse IP publique pour le développement. Nous recommandons une nouvelle installation d’Ubuntu 20.04, un utilisateur non root avec des privilèges sudo, et SSH activé.  Vous pouvez suivre ce guide pour initialiser votre serveur et effectuer ces étapes.

      Vous voudrez peut-être tester ce tutoriel sur un serveur qui a une adresse IP publique. Slack devra être capable d’envoyer des événements tels que des messages à votre bot. Si vous effectuez des tests sur une machine locale, vous devrez faire transiter le trafic par votre pare-feu vers votre système local. Si vous cherchez un moyen de développer sur un serveur cloud, consultez ce tutoriel Comment utiliser le code Visual Studio pour le développement à distance via le plugin Remote-SSH.

      Étape 1 – Création du slackbot dans l’interface utilisateur de Slack

      Créez d’abord votre application Slack dans le panneau de contrôle de l’API Slack. Connectez-vous à votre espace de travail dans Slack via un navigateur web et naviguez jusqu’au panneau de contrôle de l’API. Cliquez maintenant sur le bouton Create an App (Créer une application).

      Créez votre application Slack

      Ensuite, vous serez invité à indiquer le nom de votre application et à sélectionner un espace de travail Slack de développement. Pour ce tutoriel, nommez votre application CoinBot et sélectionnez un espace de travail auquel vous avez accès en tant qu’administrateur. Une fois que vous avez fait cela, cliquez sur le bouton Create App (Créer une application).

      Nommez votre application Slack et sélectionnez un espace de travail

      Une fois que votre application est créée, le tableau de bord par défaut suivant vous sera présenté. Ce tableau de bord vous permet de gérer votre application en définissant les autorisations, en vous inscrivant à des événements, en installant l’application dans les espaces de travail, etc.

      Tableau de bord par défaut de l'application Slack

      Pour que votre app puisse envoyer des messages sur un canal, vous devez lui attribuer des autorisations d’envoi de messages. Pour ce faire, cliquez sur le bouton Permissions dans le panneau de contrôle.

      Sélectionnez le bouton Permissions dans le panneau de contrôle

      Lorsque vous arrivez à la page OAuth & Permissions, faites défiler vers le bas jusqu’à ce que vous trouviez la section Scopes (Champs) de la page. Ensuite, trouvez la sous-section Bot Token Scopes dans le champ et cliquez sur le bouton Add an OAuth Scope.

      Sélectionnez le bouton Add an OAuth Scope (Ajouter un champ d'application OAuth)

      Cliquez sur ce bouton et tapez ensuite chat:write. Sélectionnez cette autorisation pour l’ajouter à votre bot. Cela permettra à l’application de poster des messages sur les canaux auxquels elle peut accéder. Pour plus d’informations sur les autorisations disponibles, consultez la documentation de Slack.

      Ajoutez la permission chat:write

      Maintenant que vous avez ajouté la permission appropriée, il est temps d’installer votre application dans votre espace de travail Slack. Faites défiler la page OAuth & Permissions vers le haut et cliquez sur le bouton Install App to Workspace (Installer l’application dans l’espace de travail) en haut.

      Installez l'application sur l'espace de travail

      Cliquez sur ce bouton et passez en revue les actions que l’app peut effectuer dans le canal. Une fois que vous êtes satisfait, cliquez sur le bouton Allow (Autoriser) pour terminer l’installation.

      Installez l'application sur l'espace de travail

      Une fois le bot installé, un jeton d’accès OAuth pour l’utilisateur du bot vous sera présenté afin que vous puissiez utiliser votre application pour effectuer des actions dans l’espace de travail. Poursuivez et copiez ce jeton ; vous en aurez besoin plus tard.

      Sauvegardez le jeton d'accès

      Enfin, ajoutez votre bot nouvellement installé dans un canal de votre espace de travail. Si vous n’avez pas encore créé de canal, vous pouvez utiliser le canal #general qui est créé par défaut dans votre espace de travail Slack. Localisez l’application dans la section Apps de la barre de navigation de votre client Slack et cliquez dessus. Une fois que vous avez fait cela, ouvrez le menu Details (Détails) en haut à droite. Si votre client Slack n’est pas en plein écran, cela ressemblera à un i dans un cercle.

      Cliquez sur l'icône Détails de l'application

      Pour terminer l’ajout de votre app à un canal, cliquez sur le bouton Plus représenté par trois points dans la page de détails et sélectionnez Add this app to a channel… (Ajouter cette app à un canal…) Tapez votre canal dans le modal qui apparaît et cliquez sur Add (Ajouter).

      Ajoutez une application à un canal

      Vous avez maintenant réussi à créer votre application et à l’ajouter à un canal dans votre espace de travail Slack. Une fois que vous aurez écrit le code de votre application, celle-ci sera en mesure d’afficher des messages sur ce canal. Dans la section suivante, vous commencerez à écrire le code Python qui fera fonctionner CoinBot.

      Étape 2 – Configuration de votre environnement de développement Python

      Commençons par configurer votre environnement Python pour que vous puissiez développer le Slackbot.

      Ouvrez un terminal et installez Python3 et les outils pertinents sur votre système :

      • sudo apt install python3 python3-venv

      Ensuite, vous allez créer un environnement virtuel pour isoler vos paquets Python de l’installation système de Python. Pour ce faire, créez d’abord un répertoire dans lequel vous créerez votre environnement virtuel. Créez un nouveau répertoire à ~/.venvs :

      Créez maintenant votre environnement virtuel Python :

      • python3 -m venv ~/.venvs/slackbot

      Ensuite, activez votre environnement virtuel afin de pouvoir utiliser son installation Python et installer des paquets :

      • source ~/.venvs/slackbot/bin/activate

      L’invite de commande de votre shell affichera désormais l’environnement virtuel entre parenthèses. Elle ressemblera à cela :

      Utilisez maintenant pip pour installer les paquets Python nécessaires dans votre environnement virtuel :

      • pip install slackclient slackeventsapi Flask

      slackclient et slackeventsapi facilitent l’interaction de Python avec les API de Slack. Flask est un micro-cadre web populaire que vous utiliserez pour déployer votre application  :

      Maintenant que vous avez mis en place votre environnement de développement, vous pouvez commencer à écrire votre Slackbot Python :

      Étape 3 – Création de la classe de message Slackbot en Python

      Dans Slack, les messages sont envoyés via une charge utile JSON spécifiquement formatée. Voici un exemple de JSON que votre Slackbot va élaborer et envoyer comme message :

      {
         "channel":"channel",
         "blocks":[
            {
               "type":"section",
               "text":{
                  "type":"mrkdwn",
                  "text":"Sure! Flipping a coin....nn"
               }
            },
            {
               "type":"section",
               "text":{
                  "type":"mrkdwn",
                  "text":"*flips coin* The result is Tails."
               }
            }
         ]
      }
      

      Vous pourriez fabriquer manuellement ce JSON et l’envoyer, mais à la place, construisons une classe Python qui non seulement fabrique cette charge utile, mais simule aussi un tirage au sort.

      Utilisez d’abord la commande touch pour créer un fichier nommé coinbot.py :

      Ensuite, ouvrez le fichier avec nano ou votre éditeur de texte favori :

      Ajoutez maintenant les lignes de code suivantes pour importer les bibliothèques pertinentes pour votre application. La seule bibliothèque dont vous avez besoin pour cette classe est la bibliothèque aléatoire de la Python Standard Library. Cette bibliothèque nous permettra de simuler un tirage au sort.

      Ajoutez les lignes suivantes à coinbot.py pour importer toutes les bibliothèques nécessaires :

      coinbot.py

      # import the random library to help us generate the random numbers
      import random
      

      Ensuite, créez votre classe CoinBot et une instance de cette classe pour élaborer la charge utile du message. Ajoutez les lignes suivantes au site coinbot.py pour créer la classe CoinBot :

      coinbot.py

      ...
      class CoinBot:
      

      Maintenant, faites un retrait d’une unité et créez les constantes, les constructeurs et les méthodes nécessaires à votre classe. Commençons par créer la constante qui constituera la base de la charge utile de votre message. Cette section précise que cette constante est du type section et que le texte est formaté via la démarque. Il précise également le texte que vous souhaitez afficher. Vous pouvez en savoir plus sur les différentes options de charge utile dans la documentation officielle de Slack à propos de la charge utile des messages.

      Ajoutez les lignes suivantes à coinbot.py pour créer le modèle de base de la charge utile :

      coinbot.py

      ...
          # Create a constant that contains the default text for the message
          COIN_BLOCK = {
              "type": "section",
              "text": {
                  "type": "mrkdwn",
                  "text": (
                      "Sure! Flipping a coin....nn"
                  ),
              },
          }
      

      Ensuite, créez un constructeur pour votre classe afin de pouvoir créer une instance distincte de votre bot pour chaque requête. Ne vous préoccupez pas de la mémoire ici ; le ramasseur d’ordures Python nettoiera ces instances une fois qu’elles ne seront plus nécessaires. Ce code définit le canal destinataire en fonction d’un paramètre transmis au constructeur.

      Ajoutez les lignes suivantes à coinbot.py pour créer le constructeur :

      coinbot.py

      ...
          # The constructor for the class. It takes the channel name as the a
          # parameter and sets it as an instance variable.
          def __init__(self, channel):
              self.channel = channel
      

      Maintenant, écrivez le code qui simule le tirage à pile ou face. Nous allons générer aléatoirement un un ou un zéro, représentant respectivement pile ou face.

      Ajoutez les lignes suivantes au site coinbot.py pour simuler le tirage au sort et renvoyer la charge utile fabriquée :

      coinbot.py

      ...
          # Generate a random number to simulate flipping a coin. Then return the
          # crafted slack payload with the coin flip message.
          def _flip_coin(self):
              rand_int =  random.randint(0,1)
              if rand_int == 0:
                  results = "Heads"
              else:
                  results = "Tails"
      
              text = f"The result is {results}"
      
              return {"type": "section", "text": {"type": "mrkdwn", "text": text}},
      

      Enfin, créez une méthode qui fabrique et renvoie la totalité de la charge utile du message, y compris les données de votre constructeur, en appelant votre méthode _flip_coin.

      Ajoutez les lignes suivantes au site coinbot.py pour créer la méthode qui générera la charge utile finie :

      coinbot.py

      ...
          # Craft and return the entire message payload as a dictionary.
          def get_message_payload(self):
              return {
                  "channel": self.channel,
                  "blocks": [
                      self.COIN_BLOCK,
                      *self._flip_coin(),
                  ],
              }
      

      Vous avez maintenant terminé la classe CoinBot et elle est prête à être testée. Avant de continuer, vérifiez que votre fichier fini, coinbot.py, contient les éléments suivants :

      coinbot.py

      # import the random library to help us generate the random numbers
      import random
      
      # Create the CoinBot Class
      class CoinBot:
      
          # Create a constant that contains the default text for the message
          COIN_BLOCK = {
              "type": "section",
              "text": {
                  "type": "mrkdwn",
                  "text": (
                      "Sure! Flipping a coin....nn"
                  ),
              },
          }
      
          # The constructor for the class. It takes the channel name as the a
          # parameter and then sets it as an instance variable
          def __init__(self, channel):
              self.channel = channel
      
          # Generate a random number to simulate flipping a coin. Then return the
          # crafted slack payload with the coin flip message.
          def _flip_coin(self):
              rand_int =  random.randint(0,1)
              if rand_int == 0:
                  results = "Heads"
              else:
                  results = "Tails"
      
              text = f"The result is {results}"
      
              return {"type": "section", "text": {"type": "mrkdwn", "text": text}},
      
          # Craft and return the entire message payload as a dictionary.
          def get_message_payload(self):
              return {
                  "channel": self.channel,
                  "blocks": [
                      self.COIN_BLOCK,
                      *self._flip_coin(),
                  ],
              }
      

      Enregistrez et fermez le fichier.

      Maintenant que vous avez une classe Python prête à faire le travail pour votre Slackbot, faisons en sorte que cette classe produise une charge utile de messages et que vous puissiez l’envoyer à votre espace de travail.

      Étape 4 – Test de votre message

      Maintenant, vérifions que cette classe produit une charge utile adéquate. Créez un fichier nommé coinbot_test.py :

      Maintenant ajoutez le code suivant : Assurez-vous de changer le nom du canal dans l’instanciation de la classe coinbot coin_bot = coinbot("#YOUR_CHANNEL_HERE"). Ce code créera un client Slack en Python qui enverra un message au canal que vous aurez spécifié et dans lequel vous aurez déjà installé l’application :

      coinbot_test.py

      from slack import WebClient
      from coinbot import CoinBot
      import os
      
      # Create a slack client
      slack_web_client = WebClient(token=os.environ.get("SLACK_TOKEN"))
      
      # Get a new CoinBot
      coin_bot = CoinBot("#YOUR_CHANNEL_HERE")
      
      # Get the onboarding message payload
      message = coin_bot.get_message_payload()
      
      # Post the onboarding message in Slack
      slack_web_client.chat_postMessage(**message)
      

      Enregistrez et fermez le fichier.

      Avant de pouvoir exécuter ce fichier, vous devrez exporter le jeton Slack que vous avez enregistré à l’étape 1 en tant que variable d’environnement :

      • export SLACK_TOKEN="your_bot_user_token"

      Maintenant, testez ce fichier et vérifiez que la charge utile est produite et envoyée en exécutant le script suivant dans votre terminal. Assurez-vous que votre environnement virtuel est activé. Vous pouvez vérifier cela en voyant le texte (slackbot) au début de l’invite de votre bash. Exécutez cette commande, vous recevrez un message de votre Slackbot avec les résultats d’un tirage au sort :

      Vérifiez le canal dans lequel vous avez installé votre application et vérifiez que votre bot a bien envoyé le message de tirage au sort. Votre résultat sera pile ou face.

      Test de tirage au sort

      Maintenant que vous avez vérifié que votre Slackbot peut tirer à pile ou face, créer un message et le diffuser, créons un Flask pour faire fonctionner cette app en permanence et faisons en sorte qu’elle simule un tirage à pile ou face et partage les résultats chaque fois qu’elle voit un certain texte dans les messages envoyés dans le canal.

      Étape 5 – Création d’une application Flask pour exécuter votre slackbot

      Maintenant que vous avez une application fonctionnelle qui peut envoyer des messages à votre espace de travail Slack, vous devez créer un processus de longue durée pour que votre bot puisse écouter les messages envoyés dans le canal et y répondre si le texte répond à certains critères. Vous allez utiliser le Flask, le framework web de Python, pour exécuter ce processus et écouter les événements de votre canal.

      Dans cette section, vous allez exécuter votre application Flask à partir d’un serveur doté d’une adresse IP publique afin que l’API Slack puisse vous envoyer des événements. Si vous l’exécutez localement sur votre poste de travail personnel, vous devrez transférer le port de votre pare-feu personnel vers le port qui sera exécuté sur votre poste de travail. Ces ports peuvent être les mêmes, et ce tutoriel sera configuré pour utiliser le port 3000.

      Réglez d’abord les paramètres de votre pare-feu pour autoriser le trafic par le port 3000 :

      Vérifiez maintenant le statut de ufw :

      Vous verrez un résultat similaire à ce qui suit :

      Output

      Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere 3000 ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) 3000 (v6) ALLOW Anywhere (v6)

      Créez maintenant le fichier pour votre application Flask. Nommez ce fichier app.py :

      Ensuite, ouvrez ce fichier dans votre éditeur de texte préféré :

      Ajoutez maintenant les déclarations d’importation suivantes. Vous importerez les bibliothèques ci-après pour les raisons suivantes :

      • import os – Pour accéder aux variables d’environnement
      • import logging – Pour enregistrer les événements de l’application
      • from flask import Flask – Pour créer une application Flask
      • from slack import WebClient – Pour envoyer des messages via Slack
      • from slackeventsapi import SlackEventAdapter – Pour recevoir les événements de Slack et les traiter
      • from coinbot import CoinBot – Pour créer une instance de votre CoinBot et générer la charge utile du message.

      Ajoutez les lignes suivantes à app.py pour importer toutes les bibliothèques nécessaires :

      app.py

      import os
      import logging
      from flask import Flask
      from slack import WebClient
      from slackeventsapi import SlackEventAdapter
      from coinbot import CoinBot
      

      Créez maintenant votre application Flask et enregistrez un adaptateur Slack Event dans votre application Slack sur le point de terminaison /slack/events. Cela créera un itinéraire dans votre app Slack où les événements Slack seront envoyés et ingérés. Pour ce faire, vous devrez obtenir un autre jeton de votre application Slack, ce que vous ferez plus tard dans le tutoriel. Une fois que vous aurez obtenu cette variable, vous l’exporterez en tant que variable d’environnement nommée SLACK_EVENTS_TOKEN. Procédez et écrivez votre code pour le lire lors de la création du SlackEventAdapter, même si vous n’avez pas encore défini le jeton.

      Ajoutez les lignes suivantes à app.py pour créer l’application Flask et enregistrez l’adaptateur d’événements dans cette application :

      app.py

      ...
      # Initialize a Flask app to host the events adapter
      app = Flask(__name__)
      
      # Create an events adapter and register it to an endpoint in the slack app for event ingestion.
      slack_events_adapter = SlackEventAdapter(os.environ.get("SLACK_EVENTS_TOKEN"), "/slack/events", app)
      

      Ensuite, créez un objet client web qui permettra à votre application d’effectuer des actions dans l’espace de travail, notamment pour envoyer des messages. Le processus est similaire à ce que vous avez fait lorsque vous avez testé votre fichier coinbot.py précédemment.

      Ajoutez la ligne suivante à app.py pour créer ce slack_web_client :

      app.py

      ...
      # Initialize a Web API client
      slack_web_client = WebClient(token=os.environ.get("SLACK_TOKEN"))
      

      Créez maintenant une fonction qui peut être appelée et qui créera une instance de CoinBot, puis utilisez cette instance pour créer une charge utile de message et transmettre cette charge utile au client web Slack pour livraison. Cette fonction ne prendra en compte qu’un seul paramètre, channel, qui spécifiera quel canal reçoit le message.

      Ajoutez la ligne suivante à app.py pour créer cette fonction :

      app.py

      ...
      def flip_coin(channel):
          """Craft the CoinBot, flip the coin and send the message to the channel
          """
          # Create a new CoinBot
          coin_bot = CoinBot(channel)
      
          # Get the onboarding message payload
          message = coin_bot.get_message_payload()
      
          # Post the onboarding message in Slack
          slack_web_client.chat_postMessage(**message)
      

      Maintenant que vous avez créé une fonction pour gérer les aspects de messagerie de votre application, créez-en une qui surveille les événements Slack pour une certaine action et qui exécute ensuite votre bot. Vous allez configurer votre application pour qu’elle réponde avec les résultats d’une simulation de pile ou face lorsqu’elle voit la phrase “Hey Sammy, Flip a coin”. Vous allez accepter que n’importe quelle version de ce cas n’empêche pas l’app de répondre.

      Décorez d’abord votre fonction avec la syntaxe @slack_events_adapter.on qui permet à votre fonction de recevoir des événements. Précisez que vous voulez uniquement les événements du message et que votre fonction doit accepter un paramètre de charge utile contenant toutes les informations Slack nécessaires. Une fois que vous aurez cette charge utile, vous analyserez le texte. Ensuite, si elle reçoit la phrase d’activation, votre application enverra les résultats d’un tirage au sort simulé.

      Ajoutez le code suivant à app.py pour recevoir, analyser et agir sur les messages entrants :

      app.py

      # When a 'message' event is detected by the events adapter, forward that payload
      # to this function.
      @slack_events_adapter.on("message")
      def message(payload):
          """Parse the message event, and if the activation string is in the text,
          simulate a coin flip and send the result.
          """
      
          # Get the event data from the payload
          event = payload.get("event", {})
      
          # Get the text from the event that came through
          text = event.get("text")
      
          # Check and see if the activation phrase was in the text of the message.
          # If so, execute the code to flip a coin.
          if "hey sammy, flip a coin" in text.lower():
              # Since the activation phrase was met, get the channel ID that the event
              # was executed on
              channel_id = event.get("channel")
      
              # Execute the flip_coin function and send the results of
              # flipping a coin to the channel
              return flip_coin(channel_id)
      

      Enfin, créez une section main qui créera un logger afin que vous puissiez voir les éléments internes de votre application ainsi que lancer l’application sur votre adresse IP externe sur le port 3000. Afin d’ingérer les événements de Slack, comme par exemple lorsqu’un nouveau message est envoyé, vous devez tester votre application sur une adresse IP publique.

      Ajoutez les lignes suivantes à app.py pour mettre en place votre section main :

      app.py

      if __name__ == "__main__":
          # Create the logging object
          logger = logging.getLogger()
      
          # Set the log level to DEBUG. This will increase verbosity of logging messages
          logger.setLevel(logging.DEBUG)
      
          # Add the StreamHandler as a logging handler
          logger.addHandler(logging.StreamHandler())
      
          # Run your app on your externally facing IP address on port 3000 instead of
          # running it on localhost, which is traditional for development.
          app.run(host="0.0.0.0", port=3000)
      

      Vous avez maintenant terminé l’application Flask et elle est prête à être testée. Avant de continuer, vérifiez que votre fichier terminé, app.py contient ce qui suit :

      app.py

      import os
      import logging
      from flask import Flask
      from slack import WebClient
      from slackeventsapi import SlackEventAdapter
      from coinbot import CoinBot
      
      # Initialize a Flask app to host the events adapter
      app = Flask(__name__)
      # Create an events adapter and register it to an endpoint in the slack app for event injestion.
      slack_events_adapter = SlackEventAdapter(os.environ.get("SLACK_EVENTS_TOKEN"), "/slack/events", app)
      
      # Initialize a Web API client
      slack_web_client = WebClient(token=os.environ.get("SLACK_TOKEN"))
      
      def flip_coin(channel):
          """Craft the CoinBot, flip the coin and send the message to the channel
          """
          # Create a new CoinBot
          coin_bot = CoinBot(channel)
      
          # Get the onboarding message payload
          message = coin_bot.get_message_payload()
      
          # Post the onboarding message in Slack
          slack_web_client.chat_postMessage(**message)
      
      
      # When a 'message' event is detected by the events adapter, forward that payload
      # to this function.
      @slack_events_adapter.on("message")
      def message(payload):
          """Parse the message event, and if the activation string is in the text,
          simulate a coin flip and send the result.
          """
      
          # Get the event data from the payload
          event = payload.get("event", {})
      
          # Get the text from the event that came through
          text = event.get("text")
      
          # Check and see if the activation phrase was in the text of the message.
          # If so, execute the code to flip a coin.
          if "hey sammy, flip a coin" in text.lower():
              # Since the activation phrase was met, get the channel ID that the event
              # was executed on
              channel_id = event.get("channel")
      
              # Execute the flip_coin function and send the results of
              # flipping a coin to the channel
              return flip_coin(channel_id)
      
      if __name__ == "__main__":
          # Create the logging object
          logger = logging.getLogger()
      
          # Set the log level to DEBUG. This will increase verbosity of logging messages
          logger.setLevel(logging.DEBUG)
      
          # Add the StreamHandler as a logging handler
          logger.addHandler(logging.StreamHandler())
      
          # Run our app on our externally facing IP address on port 3000 instead of
          # running it on localhost, which is traditional for development.
          app.run(host="0.0.0.0", port=3000)
      

      Enregistrez et fermez le fichier.

      Maintenant que votre application Flask est prête à servir votre application, testons-la.

      Étape 6 – Exécution de votre application Flask

      Enfin, assemblez tout et exécutez votre application.

      Premièrement, ajoutez votre application en cours d’exécution en tant que gestionnaire autorisé de votre Slackbot.

      Accédez à la section Basic Information (Informations de base) de votre application dans le Slack UI. Faites défiler la page vers le bas jusqu’à ce que vous trouviez la section App Credentials (Identifiants d’application).

      Signature Secrète Slack

      Copiez la signature secrète et exportez-la en tant que variable d’environnement SLACK_EVENTS_TOKEN :

      • export SLACK_EVENTS_TOKEN="MY_SIGNING_SECRET_TOKEN"

      Vous disposez ainsi de tous les jetons d’API nécessaires pour exécuter votre application. Reportez-vous à l’étape 1 si vous avez besoin d’un rafraîchissement sur la façon d’exporter votre SLACK_TOKEN. Vous pouvez maintenant lancer votre application et vérifier qu’elle fonctionne bien. Assurez-vous que votre environnement virtuel est activé et exécutez la commande suivante pour lancer votre application Flask :

      Vous verrez un résultat similaire à ce qui suit :

      (slackbot) [20:04:03] sammy:coinbot$ python app.py
       * Serving Flask app "app" (lazy loading)
       * Environment: production
         WARNING: This is a development server. Do not use it in a production deployment.
         Use a production WSGI server instead.
       * Debug mode: off
       * Running on http://0.0.0.0:3000/ (Press CTRL+C to quit)
      

      Pour vérifier que votre application est bien configurée, ouvrez une nouvelle fenêtre de terminal et curl l’adresse IP de votre serveur avec le bon port sur /slack/events :

      • curl http://YOUR_IP_ADDRESS:3000/slack/events

      curl renverra ce qui suit :

      Output

      These are not the slackbots you're looking for.

      La réception du message These are not the slackbots you're looking for. (Ce ne sont pas les slackbots que vous recherchez), indique que votre app est opérationnelle.

      Maintenant, laissez cette application Flask tourner pendant que vous finissez de configurer votre application dans l’interface utilisateur Slack.

      Donnez d’abord à votre application les permissions nécessaires pour qu’elle puisse écouter les messages et répondre en conséquence. Cliquez sur Event Subscriptions (Abonnements aux événements) dans la barre latérale de l’interface utilisateur et activez le bouton radio Enable Events (Activer les événements).

      Activez le bouton Events

      Une fois que vous avez fait cela, tapez votre adresse IP, le port et le point final /slack/events dans le champ Request URL. N’oubliez pas le préfixe du protocole HTTP. Slack fera une tentative de connexion à votre terminal. Une fois qu’il l’aura fait avec succès, vous verrez une coche verte avec le mot Verified à côté.

      Demande d'abonnements aux événements URL

      Ensuite, développez la rubrique Subscribe to bot events (S’abonner aux événements du bot) et ajoutez la permission message.channels à votre application. Cela permettra à votre app de recevoir des messages de votre canal et de les traiter.

      S'abonner aux permissions pour les événements du bot

      Une fois que vous aurez fait cela, vous verrez l’événement répertorié dans votre section Subscribe to bot events (S’abonner aux événements du bot). Cliquez ensuite sur le bouton vert Save Changes (Enregistrer les modifications) dans le coin inférieur droit.

      Confirmer et enregistrer les modifications

      Une fois que vous aurez fait cela, vous verrez une bannière jaune en haut de l’écran vous informant que vous devez réinstaller votre application pour que les changements suivants soient appliqués. Chaque fois que vous modifiez les autorisations, vous devez réinstaller votre application. Cliquez sur le lien reinstall your app (réinstaller votre application) dans cette bannière pour réinstaller votre application.

      Bannière Reinstaller votre application

      Un écran de confirmation vous sera présenté, résumant les autorisations dont disposera votre bot et vous demandant si vous souhaitez autoriser son installation. Cliquez sur le bouton vert Allow (Autoriser) pour terminer le processus d’installation.

      Confirmation de réinstallation

      Maintenant que vous avez fait cela, votre application devrait être prête. Retournez sur le canal où vous avez installé CoinBot et envoyez un message contenant la phrase Hey Sammy, Flip a coin. Votre bot tirera à pile ou face et répondra avec les résultats. Félicitations ! Vous avez créé un Slackbot !

      Hey Sammy, Flip a coin

      Conclusion

      Une fois que vous avez terminé le développement de votre application et que vous êtes prêt à la mettre en production, vous devez la déployer sur un serveur. C’est nécessaire, car le serveur de développement de Flask n’est pas un environnement de production sécurisé. Vous serez mieux servi si vous déployez votre application en utilisant un WSGI et peut-être même en sécurisant un nom de domaine et en donnant à votre serveur un enregistrement DNS. Il existe de nombreuses options pour déployer les applications Flask, dont certaines sont énumérées ci-dessous :

      Il existe bien d’autres façons de déployer votre application. Comme toujours, lorsqu’il s’agit de déploiements et d’infrastructures, faites ce qui fonctionne le mieux pour vous.

      En tout cas, vous disposez maintenant d’un Slackbot que vous pouvez utiliser pour tirer à pile ou face afin de vous aider à prendre des décisions, par exemple sur ce qu’il faut manger pour le déjeuner.

      Vous pouvez également prendre ce code de base et le modifier pour l’adapter à vos besoins, qu’il s’agisse de support automatisé, de gestion des ressources, d’images de chats, ou de tout ce à quoi vous pouvez penser. Vous pouvez consulter la documentation complète de l’API Python Slack ici.



      Source link

      Comment construire un réseau neuronal pour traduire la langue des signes en anglais


      L’auteur a choisi Code Org ​​ pour recevoir un don dans le cadre du programme Write for DOnations.

      Introduction

      La vision par ordinateur est un sous-domaine de l’informatique qui vise à extraire une compréhension supérieure des choses à partir d’images et de vidéos. On la retrouve dans les technologies comme les filtres de chat vidéo amusants, l’authentification de visage sur votre appareil mobile et les voitures autonomes.

      Dans ce tutoriel, vous utiliserez la vision par ordinateur pour créer un traducteur de la langue des signes américaine pour votre webcam. Au cours de ce tutoriel, vous utiliserez OpenCV, une bibliothèque de vision par ordinateur, PyTorch pour créer un réseau neuronal profond et onnx pour exporter votre réseau neuronal. Vous appliquerez également les concepts suivants lors de la création d’une application de vision par ordinateur :

      • Vous utiliserez la même méthode en trois étapes qui est utilisée dans le tutoriel Comment appliquer la vision par ordinateur pour créer un filtre pour chiens basé sur les émotions : pré-traiter un ensemble de données, former un modèle et évaluer le modèle.
      • Vous allez également aller plus loin dans chacune de ces étapes : utiliser l’augmentation des données pour traiter les aiguilles tournées ou non centrées, modifier les horaires de fréquence d’apprentissage pour améliorer la précision du modèle et exporter des modèles pour une vitesse d’inférence plus rapide.
      • En cours de route, vous explorerez également les concepts liés à l’apprentissage automatique.

      À la fin de ce tutoriel, vous aurez à la fois un traducteur de la langue des signes américaine et le savoir-faire fondamental sur l’apprentissage profond. Vous pouvez également accéder au code source complet de ce projet.

      Conditions préalables

      Pour terminer ce tutoriel, vous aurez besoin des éléments suivants :

      Étape 1 – Création du projet et installation des dépendances

      Créons un espace de travail pour ce projet et installons les dépendances dont nous aurons besoin.

      Sur les distributions Linux, commencez par préparer votre gestionnaire de packages système et installez le package virtualenv de Python3. Utilisez :

      • apt-get update
      • apt-get upgrade
      • apt-get install python3-venv

      Nous allons appeler notre espace de travail SignLanguage :

      Naviguez jusqu’au répertoire SignLanguage :

      Ensuite, créez un nouvel environnement virtuel pour le projet :

      • python3 -m venv signlanguage

      Activez votre environnement :

      • source signlanguage/bin/activate

      Installez ensuite PyTorch, un framework d’apprentissage profond pour Python que nous utiliserons au cours de ce tutoriel.

      Sous macOS, installez Pytorch avec la commande suivante :

      • python -m pip install torch==1.2.0 torchvision==0.4.0

      Sous Linux et Windows, utilisez les commandes suivantes pour une construction du CPU uniquement :

      • pip install torch==1.2.0+cpu torchvision==0.4.0+cpu -f https://download.pytorch.org/whl/torch_stable.html
      • pip install torchvision

      Installez maintenant les binaires préfilmés pour OpenCV, numpy et onnx, des bibliothèques destinée à la vision par ordinateur, l’algèbre linéaire, l’exportation de modèle AI et l’exécution de modèle AI, respectivement. OpenCV propose des utilitaires tels que les rotations d’images et numpy fournit des utilitaires d’algèbre linéaire comme l’inversion d’une matrice :

      • python -m pip install opencv-python==3.4.3.18 numpy==1.14.5 onnx==1.6.0 onnxruntime==1.0.0

      Sur les distributions Linux, vous devrez installer libSM.so :

      • apt-get install libsm6 libxext6 libxrender-dev

      Une fois les dépendances installées, construisons la première version de notre traducteur de la langue des signes : un système de classification de la langue des signes.

      Étape 2 – Préparation de l’ensemble de données de classification de la langue des signes

      Au cours des trois prochaines sections, vous allez construire un système de classification de la langue des signes à l’aide d’un réseau neuronal. Votre objectif est de produire un modèle qui accepte une image d’une main en entrée et génère une lettre.

      Vous devez suivre les trois étapes suivantes pour créer un modèle de classification d’apprentissage automatique :

      1. Pré-traitez les données : appliquez one-hot encoding​​​​​​ à vos étiquettes et sauvegardez vos données dans PyTorch Tensors. Entraînez votre modèle sur des données augmentées pour le préparer à une saisie “inhabituelle”, comme une main sur le côté ou tournée.
      2. Spécifiez et entraînez le modèle : configurez un réseau neuronal à l’aide de PyTorch. Définissez les hyper-paramètres d’entraînement (comme la durée d’entraînement) et exécutez la descente de gradient stochastique. Vous modifierez également un hyper-paramètre d’entraînement spécifique, qui correspond au calendrier de fréquence d’apprentissage. Ils optimisent la précision du modèle.
      3. Exécutez une prédiction à l’aide du modèle : évaluez le réseau neuronal sur vos données de validation pour comprendre sa précision. Ensuite, exportez le modèle dans un format appelé ONNX pour avoir des vitesses d’inférence plus rapides.

      Dans cette section du tutoriel, vous allez effectuer l’étape 1 sur 3. Vous allez télécharger les données, créer un objet Dataset pour itérer sur vos données et enfin appliquer l’augmentation des données. À la fin de cette étape, vous aurez un moyen d’accéder par programme aux images et aux étiquettes de votre ensemble de données qui viendront alimenter votre modèle.

      Tout d’abord, téléchargez l’ensemble de données dans votre répertoire de travail actuel :

      Note : sous macOS, par défaut, wget n’est pas disponible. Pour qu’il le soit, installez Homebrew en suivant ce tutoriel de DigitalOcean. Ensuite, exécutez brew install wget.

      • wget https://assets.digitalocean.com/articles/signlanguage_data/sign-language-mnist.tar.gz

      Décompressez le fichier zip, qui contient un répertoire data/ :

      • tar -xzf sign-language-mnist.tar.gz

      Créez un nouveau fichier que vous nommerez step_2_dataset.py :

      Comme précédemment, importez les utilitaires nécessaires et créez la classe qui contiendra vos données. Ici, pour le traitement des données, vous allez créer des ensembles de données d’entraînement et de test. Vous allez implémenter l’interface de Dataset de PyTorch, qui vous permettra de charger et d’utiliser le pipeline de données intégré de PyTorch pour votre ensemble de données de classification de la langue des signes :

      step_2_dataset.py

      from torch.utils.data import Dataset
      from torch.autograd import Variable
      import torch.nn as nn
      import numpy as np
      import torch
      
      import csv
      
      
      class SignLanguageMNIST(Dataset):
          """Sign Language classification dataset.
      
          Utility for loading Sign Language dataset into PyTorch. Dataset posted on
          Kaggle in 2017, by an unnamed author with username `tecperson`:
          Sign Language MNIST
      
          Each sample is 1 x 1 x 28 x 28, and each label is a scalar.
          """
          pass
      

      Supprimez l’espace réservé pass dans la catégorie SignLanguageMNIST. À sa place, ajoutez une méthode pour générer un mappage d’étiquette :

      step_2_dataset.py

          @staticmethod
          def get_label_mapping():
              """
              We map all labels to [0, 23]. This mapping from dataset labels [0, 23]
              to letter indices [0, 25] is returned below.
              """
              mapping = list(range(25))
              mapping.pop(9)
              return mapping
      

      Les étiquettes vont de 0 à 25. Cependant, les lettres J (9) et Z (25) sont exclues. Cela signifie qu’il n’existe que 24 valeurs d’étiquette valables. Pour que l’ensemble de toutes les valeurs d’étiquette à partir de 0 soit contigu, nous mappons toutes les étiquettes de [0 à 23]. Ce mappage des étiquettes de [0 à 23] et des indices de lettre de [0 à 25] de l’ensemble de données est fourni par cette méthode get_label_mapping.

      Ensuite, ajoutez une méthode pour extraire les étiquettes et les échantillons d’un fichier CSV. Ce qui suit suppose que chaque ligne commence par l’étiquette, ensuite suivie des valeurs 784 pixels. Ces valeurs 784 pixels représentent une image 28x28 :

      step_2_dataset.py

          @staticmethod
          def read_label_samples_from_csv(path: str):
              """
              Assumes first column in CSV is the label and subsequent 28^2 values
              are image pixel values 0-255.
              """
              mapping = SignLanguageMNIST.get_label_mapping()
              labels, samples = [], []
              with open(path) as f:
                  _ = next(f)  # skip header
                  for line in csv.reader(f):
                      label = int(line[0])
                      labels.append(mapping.index(label))
                      samples.append(list(map(int, line[1:])))
              return labels, samples
      

      Pour avoir une explication sur la façon dont ces 784 valeurs représentent une image, voir Créer un filtre pour chien basé sur les émotions, étape 4.

      Notez que chaque ligne de l’itérable csv.reader est une liste de chaînes. Les invocations int et map (int, ...) transforment toutes les chaînes en entiers. Juste en dessous de notre méthode statique, ajoutez une fonction qui initialisera notre support de données :

      step_2_dataset.py

          def __init__(self,
                  path: str="data/sign_mnist_train.csv",
                  mean: List[float]=[0.485],
                  std: List[float]=[0.229]):
              """
              Args:
                  path: Path to `.csv` file containing `label`, `pixel0`, `pixel1`...
              """
              labels, samples = SignLanguageMNIST.read_label_samples_from_csv(path)
              self._samples = np.array(samples, dtype=np.uint8).reshape((-1, 28, 28, 1))
              self._labels = np.array(labels, dtype=np.uint8).reshape((-1, 1))
      
              self._mean = mean
              self._std = std
      

      Cette fonction commence par charger les échantillons et les étiquettes. Ensuite, elle sauvegarde les données dans des tableaux NumPy. Les informations sur l’écart moyen et l’écart-type seront expliquées sous peu, dans la section __getitem__ suivante.

      Juste après la fonction __init__, ajoutez une fonction __len__ Le Dataset requiert cette méthode pour déterminer à quel moment arrêter l’itération sur les données :

      step_2_dataset.py

      ...
          def __len__(self):
              return len(self._labels)
      

      Enfin, ajoutez une méthode __getitem__, qui renvoie un dictionnaire qui contient l’échantillon et l’étiquette :

      step_2_dataset.py

          def __getitem__(self, idx):
              transform = transforms.Compose([
                  transforms.ToPILImage(),
                  transforms.RandomResizedCrop(28, scale=(0.8, 1.2)),
                  transforms.ToTensor(),
                  transforms.Normalize(mean=self._mean, std=self._std)])
      
              return {
                  'image': transform(self._samples[idx]).float(),
                  'label': torch.from_numpy(self._labels[idx]).float()
              }
      

      Vous utilisez la technique que l’on appelle data augmentation, dans laquelle les échantillons sont perturbés pendant l’entraînement, pour augmenter la robustesse du modèle face à ces perturbations. En particulier, zoomez de façon aléatoire sur l’image en variant les quantités et sur différents emplacements, via RandomResizedCrop. Notez que le zoom avant ne devrait pas affecter la catégorie finale de la langue des signes. Ainsi, l’étiquette n’est pas transformée. Vous normalisez encore plus les entrées de sorte que les valeurs d’image soient remises à l’échelle dans la plage [0 à 1] dans les valeurs attendues, au lieu de [0 à 25]5. Pour ce faire, utilisez l’ensemble de données _mean et _std lors de la normalisation.

      La catégorie SignLanguageMNIST que vous venez de terminer ressemblera à ce qui suit :

      step_2_dataset.py

      from torch.utils.data import Dataset
      from torch.autograd import Variable
      import torchvision.transforms as transforms
      import torch.nn as nn
      import numpy as np
      import torch
      
      from typing import List
      
      import csv
      
      
      class SignLanguageMNIST(Dataset):
          """Sign Language classification dataset.
      
          Utility for loading Sign Language dataset into PyTorch. Dataset posted on
          Kaggle in 2017, by an unnamed author with username `tecperson`:
          Sign Language MNIST
      
          Each sample is 1 x 1 x 28 x 28, and each label is a scalar.
          """
      
          @staticmethod
          def get_label_mapping():
              """
              We map all labels to [0, 23]. This mapping from dataset labels [0, 23]
              to letter indices [0, 25] is returned below.
              """
              mapping = list(range(25))
              mapping.pop(9)
              return mapping
      
          @staticmethod
          def read_label_samples_from_csv(path: str):
              """
              Assumes first column in CSV is the label and subsequent 28^2 values
              are image pixel values 0-255.
              """
              mapping = SignLanguageMNIST.get_label_mapping()
              labels, samples = [], []
              with open(path) as f:
                  _ = next(f)  # skip header
                  for line in csv.reader(f):
                      label = int(line[0])
                      labels.append(mapping.index(label))
                      samples.append(list(map(int, line[1:])))
              return labels, samples
      
          def __init__(self,
                  path: str="data/sign_mnist_train.csv",
                  mean: List[float]=[0.485],
                  std: List[float]=[0.229]):
              """
              Args:
                  path: Path to `.csv` file containing `label`, `pixel0`, `pixel1`...
              """
              labels, samples = SignLanguageMNIST.read_label_samples_from_csv(path)
              self._samples = np.array(samples, dtype=np.uint8).reshape((-1, 28, 28, 1))
              self._labels = np.array(labels, dtype=np.uint8).reshape((-1, 1))
      
              self._mean = mean
              self._std = std
      
          def __len__(self):
              return len(self._labels)
      
          def __getitem__(self, idx):
              transform = transforms.Compose([
                  transforms.ToPILImage(),
                  transforms.RandomResizedCrop(28, scale=(0.8, 1.2)),
                  transforms.ToTensor(),
                  transforms.Normalize(mean=self._mean, std=self._std)])
      
              return {
                  'image': transform(self._samples[idx]).float(),
                  'label': torch.from_numpy(self._labels[idx]).float()
              }
      

      Comme précédemment, vous allez maintenant vérifier les fonctions de notre utilitaire d’ensemble de données en chargeant l’ensemble de données SignLanguageMNIST. Ajoutez le code suivant à la fin de votre fichier après la catégorie SignLanguageMNIST :

      step_2_dataset.py

      def get_train_test_loaders(batch_size=32):
          trainset = SignLanguageMNIST('data/sign_mnist_train.csv')
          trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size, shuffle=True)
      
          testset = SignLanguageMNIST('data/sign_mnist_test.csv')
          testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size, shuffle=False)
          return trainloader, testloader
      

      Ce code initialise l’ensemble de données avec la catégorie SignLanguageMNIST. Ensuite, pour les ensembles d’entraînement et de validation, il sauvegarde l’ensemble de données dans un DataLoader. Cela traduira l’ensemble de données en un itérable à utiliser plus tard.

      Vous allez maintenant vérifier que les utilitaires d’ensemble de données fonctionnent bien. Créez un exemple de chargeur de jeu de données à l’aide DataLoader et imprimez le premier élément de ce chargeur. Ajoutez ce qui suit à la fin de votre fichier :

      step_2_dataset.py

      if __name__ == '__main__':
          loader, _ = get_train_test_loaders(2)
          print(next(iter(loader)))
      

      Vous pouvez vérifier si votre fichier correspond au fichier step_2_dataset dans ce (référentiel). Quittez votre éditeur et exécutez le script avec les éléments suivants :

      Cela génère la paire de vecteurs contravariants suivante. Notre pipeline de données génère deux échantillons et deux étiquettes. Cela indique que notre pipeline de données est opérationnel et prêt à être utilisé :

      Output

      {'image': tensor([[[[ 0.4337, 0.5022, 0.5707, ..., 0.9988, 0.9646, 0.9646], [ 0.4851, 0.5536, 0.6049, ..., 1.0502, 1.0159, 0.9988], [ 0.5364, 0.6049, 0.6392, ..., 1.0844, 1.0844, 1.0673], ..., [-0.5253, -0.4739, -0.4054, ..., 0.9474, 1.2557, 1.2385], [-0.3369, -0.3369, -0.3369, ..., 0.0569, 1.3584, 1.3242], [-0.3712, -0.3369, -0.3198, ..., 0.5364, 0.5364, 1.4783]]], [[[ 0.2111, 0.2796, 0.3481, ..., 0.2453, -0.1314, -0.2342], [ 0.2624, 0.3309, 0.3652, ..., -0.3883, -0.0629, -0.4568], [ 0.3309, 0.3823, 0.4337, ..., -0.4054, -0.0458, -1.0048], ..., [ 1.3242, 1.3584, 1.3927, ..., -0.4054, -0.4568, 0.0227], [ 1.3242, 1.3927, 1.4612, ..., -0.1657, -0.6281, -0.0287], [ 1.3242, 1.3927, 1.4440, ..., -0.4397, -0.6452, -0.2856]]]]), 'label': tensor([[24.], [11.]])}

      Vous avez maintenant vérifié si votre pipeline de données fonctionne bien. Ceci conclut la première étape, le prétraitement de vos données, qui comprend désormais une augmentation des données pour un module plus robuste. Vous allez ensuite définir le réseau neuronal et l’optimiseur.

      Étape 3 – Création et formation du un système de classification de la langue des signes à l’aide de l’apprentissage profond

      Maintenant que vous avez un pipeline de données fonctionnel, vous allez définir un modèle et le former sur les données. Vous allez tout particulièrement construire un réseau neuronal à six couches, définir une perte, un optimiseur et enfin optimiser la fonction de perte pour les prédictions de votre réseau neuronal. À la fin de cette étape, vous disposerez d’un système de classification de la langue des signes fonctionnel.

      Créez un nouveau fichier appelé step_3_train.py :

      Importez les utilitaires dont vous avez besoin :

      step_3_train.py

      from torch.utils.data import Dataset
      from torch.autograd import Variable
      import torch.nn as nn
      import torch.nn.functional as F
      import torch.optim as optim
      import torch
      
      from step_2_dataset import get_train_test_loaders
      

      Définissez un réseau neuronal PyTorch comprenant trois couches convolutives, suivies de trois couches entièrement connectées. Ajoutez ce qui suit à la fin de votre script existant :

      step_3_train.py

      class Net(nn.Module):
          def __init__(self):
              super(Net, self).__init__()
              self.conv1 = nn.Conv2d(1, 6, 3)
              self.pool = nn.MaxPool2d(2, 2)
              self.conv2 = nn.Conv2d(6, 6, 3)
              self.conv3 = nn.Conv2d(6, 16, 3)
              self.fc1 = nn.Linear(16 * 5 * 5, 120)
              self.fc2 = nn.Linear(120, 48)
              self.fc3 = nn.Linear(48, 24)
      
          def forward(self, x):
              x = F.relu(self.conv1(x))
              x = self.pool(F.relu(self.conv2(x)))
              x = self.pool(F.relu(self.conv3(x)))
              x = x.view(-1, 16 * 5 * 5)
              x = F.relu(self.fc1(x))
              x = F.relu(self.fc2(x))
              x = self.fc3(x)
              return x
      

      Maintenant, initialisez le réseau neuronal, définissez une fonction de perte et configurez les hyperparamètres d’optimisation en ajoutant le code suivant à la fin du script :

      step_3_train.py

      def main():
          net = Net().float()
          criterion = nn.CrossEntropyLoss()
          optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9)
      

      Enfin, vous vous entraînerez sur deux epochs :

      step_3_train.py

      def main():
          net = Net().float()
          criterion = nn.CrossEntropyLoss()
          optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9)
      
          trainloader, _ = get_train_test_loaders()
          for epoch in range(2):  # loop over the dataset multiple times
              train(net, criterion, optimizer, trainloader, epoch)
          torch.save(net.state_dict(), "checkpoint.pth")
      

      Vous configurez une epoch comme une itération de l’entraînement au cours de laquelle chaque échantillon d’entraînement a été utilisé exactement une fois. À la fin de la fonction principale, les paramètres du modèle seront enregistrés dans un fichier nommé "checkpoint.pth".

      Ajoutez le code suivant à la fin de votre script pour extraire l’image et l'étiquette du chargeur d’ensemble de données, puis sauvegardez-les tous dans une variable PyTorch :

      step_3_train.py

      def train(net, criterion, optimizer, trainloader, epoch):
          running_loss = 0.0
          for i, data in enumerate(trainloader, 0):
              inputs = Variable(data['image'].float())
              labels = Variable(data['label'].long())
              optimizer.zero_grad()
      
              # forward + backward + optimize
              outputs = net(inputs)
              loss = criterion(outputs, labels[:, 0])
              loss.backward()
              optimizer.step()
      
              # print statistics
              running_loss += loss.item()
              if i % 100 == 0:
                  print('[%d, %5d] loss: %.6f' % (epoch, i, running_loss / (i + 1)))
      

      Ce code exécutera également la passe avant, puis la rétropropagera à travers le réseau de perte et neuronal.

      À la fin de votre fichier, ajoutez ce qui suit pour appeler la fonction main :

      step_3_train.py

      if __name__ == '__main__':
          main()
      

      Vérifiez que les éléments de votre fichier correspondent à ce qui suit :

      step_3_train.py

      from torch.utils.data import Dataset
      from torch.autograd import Variable
      import torch.nn as nn
      import torch.nn.functional as F
      import torch.optim as optim
      import torch
      
      from step_2_dataset import get_train_test_loaders
      
      
      class Net(nn.Module):
          def __init__(self):
              super(Net, self).__init__()
              self.conv1 = nn.Conv2d(1, 6, 3)
              self.pool = nn.MaxPool2d(2, 2)
              self.conv2 = nn.Conv2d(6, 6, 3)
              self.conv3 = nn.Conv2d(6, 16, 3)
              self.fc1 = nn.Linear(16 * 5 * 5, 120)
              self.fc2 = nn.Linear(120, 48)
              self.fc3 = nn.Linear(48, 25)
      
          def forward(self, x):
              x = F.relu(self.conv1(x))
              x = self.pool(F.relu(self.conv2(x)))
              x = self.pool(F.relu(self.conv3(x)))
              x = x.view(-1, 16 * 5 * 5)
              x = F.relu(self.fc1(x))
              x = F.relu(self.fc2(x))
              x = self.fc3(x)
              return x
      
      
      def main():
          net = Net().float()
          criterion = nn.CrossEntropyLoss()
          optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9)
      
          trainloader, _ = get_train_test_loaders()
          for epoch in range(2):  # loop over the dataset multiple times
              train(net, criterion, optimizer, trainloader, epoch)
          torch.save(net.state_dict(), "checkpoint.pth")
      
      
      def train(net, criterion, optimizer, trainloader, epoch):
          running_loss = 0.0
          for i, data in enumerate(trainloader, 0):
              inputs = Variable(data['image'].float())
              labels = Variable(data['label'].long())
              optimizer.zero_grad()
      
              # forward + backward + optimize
              outputs = net(inputs)
              loss = criterion(outputs, labels[:, 0])
              loss.backward()
              optimizer.step()
      
              # print statistics
              running_loss += loss.item()
              if i % 100 == 0:
                  print('[%d, %5d] loss: %.6f' % (epoch, i, running_loss / (i + 1)))
      
      
      if __name__ == '__main__':
          main()
      

      Sauvegardez et fermez. Ensuite, lancez notre entraînement de validation de concept en exécutant :

      Lorsque votre réseau neuronal s’entraîne, vous aurez un résultat semblable à ce qui suit :

      Output

      [0, 0] loss: 3.208171 [0, 100] loss: 3.211070 [0, 200] loss: 3.192235 [0, 300] loss: 2.943867 [0, 400] loss: 2.569440 [0, 500] loss: 2.243283 [0, 600] loss: 1.986425 [0, 700] loss: 1.768090 [0, 800] loss: 1.587308 [1, 0] loss: 0.254097 [1, 100] loss: 0.208116 [1, 200] loss: 0.196270 [1, 300] loss: 0.183676 [1, 400] loss: 0.169824 [1, 500] loss: 0.157704 [1, 600] loss: 0.151408 [1, 700] loss: 0.136470 [1, 800] loss: 0.123326

      Pour obtenir une perte plus faible, vous pouvez augmenter le nombre d’époques de 5 à 10 ou même 20. Cependant, après une certaine période d’entraînement, la perte de réseau ne pourra plus diminuer avec l’augmentation du temps d’entraînement. Pour contourner ce problème, à mesure que le temps d’entraînement augmente, vous introduirez un calendrier de taux d’apprentissage, qui viendra faire baisser le taux d’apprentissage au fil du temps. Pour comprendre pourquoi cela fonctionne, voir la présentation de Distill “Pourquoi Momentum fonctionne réellement”

      Modifiez votre fonction main avec les deux lignes suivantes, configurant un scheduler et invoquant scheduler.step. De plus, configurez le nombre d’époques sur 12 :

      step_3_train.py

      def main():
          net = Net().float()
          criterion = nn.CrossEntropyLoss()
          optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9)
          scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)
      
          trainloader, _ = get_train_test_loaders()
          for epoch in range(12):  # loop over the dataset multiple times
              train(net, criterion, optimizer, trainloader, epoch)
              scheduler.step()
          torch.save(net.state_dict(), "checkpoint.pth")
      

      Vérifiez que votre fichier correspond au fichier de l’étape 3 dans ce référentiel. L’entraînement durera environ 5 minutes. Votre résultat ressemblera à ce qui suit:

      Output

      [0, 0] loss: 3.208171 [0, 100] loss: 3.211070 [0, 200] loss: 3.192235 [0, 300] loss: 2.943867 [0, 400] loss: 2.569440 [0, 500] loss: 2.243283 [0, 600] loss: 1.986425 [0, 700] loss: 1.768090 [0, 800] loss: 1.587308 ... [11, 0] loss: 0.000302 [11, 100] loss: 0.007548 [11, 200] loss: 0.009005 [11, 300] loss: 0.008193 [11, 400] loss: 0.007694 [11, 500] loss: 0.008509 [11, 600] loss: 0.008039 [11, 700] loss: 0.007524 [11, 800] loss: 0.007608

      La perte finale obtenue est de 0.007608, soit 3 ordres de grandeur plus petite que la perte de départ de 3.20. Ceci conclut la deuxième étape de notre flux de travail, au cours duquel nous configurons et entraînons le réseau neuronal. Cela dit, aussi petite que soit cette valeur de perte, elle n’a que peu de sens. Pour mettre les performances du modèle en perspective, nous calculerons sa précision, c’est à dire le pourcentage d’images correctement classées par le modèle.

      Étape 4 – Évaluation du système de classification de la langue des signes

      Vous allez maintenant évaluer votre système de classification de la langue des signes en calculant sa précision sur le validation set, un ensemble d’images que le modèle n’a pas vu pendant l’entraînement. Cela vous donnera une meilleure idée des performances du modèle que la valeur de perte finale. De plus, vous ajouterez des utilitaires pour enregistrer notre modèle entraîné à la fin de l’entraînement et charger notre modèle pré-formé lors de l’inférence.

      Créez un nouveau fichier que vous appellerez step_4_evaluate.py.

      Importez les utilitaires dont vous avez besoin :

      step_4_evaluate.py

      from torch.utils.data import Dataset
      from torch.autograd import Variable
      import torch.nn as nn
      import torch.nn.functional as F
      import torch.optim as optim
      import torch
      import numpy as np
      
      import onnx
      import onnxruntime as ort
      
      from step_2_dataset import get_train_test_loaders
      from step_3_train import Net
      

      Ensuite, configurer un utilitaire pour évaluer les performances du réseau neuronal. La fonction suivante compare la lettre prédite par le réseau neuronal avec la vraie lettre, pour une seule image :

      step_4_evaluate.py

      def evaluate(outputs: Variable, labels: Variable) -> float:
          """Evaluate neural network outputs against non-one-hotted labels."""
          Y = labels.numpy()
          Yhat = np.argmax(outputs, axis=1)
          return float(np.sum(Yhat == Y))
      

      outputs liste les catégories probables pour chaque échantillon. Par exemple, les outputs pour un seul échantillon peuvent être [0.1, 0.3, 0.4, 0.2]. labels est une liste de catégories d’étiquettes. Par exemple, la catégorie d’étiquette peut être 3.

      Y = ... convertit les étiquettes en un tableau NumPy. Ensuite, Yhat = np.argmax (...) convertit les catégories probables des outputs en prédictions de catégories. Par exemple, la liste de catégories probables [0.1, 0.3, 0.4, 0.2] donnerait la prédiction de catégorie 2 prédite, car la valeur d’indice 2 de 0,4 est la plus grande valeur.

      Maintenant que Y et Yhat sont des catégories, vous pouvez les comparer. Yhat == Y vérifie si la prédiction de catégorie correspond à la catégorie d’étiquette, et np.sum (...) est une astuce qui calcule le nombre de valeurs de truth-y. En d’autres termes, np.sum affichera le nombre d’échantillons correctement classés.

      Ajoutez la deuxième fonction batch_evaluate, qui applique la première fonction evaluate à toutes les images :

      step_4_evaluate.py

      def batch_evaluate(
              net: Net,
              dataloader: torch.utils.data.DataLoader) -> float:
          """Evaluate neural network in batches, if dataset is too large."""
          score = n = 0.0
          for batch in dataloader:
              n += len(batch['image'])
              outputs = net(batch['image'])
              if isinstance(outputs, torch.Tensor):
                  outputs = outputs.detach().numpy()
              score += evaluate(outputs, batch['label'][:, 0])
          return score / n
      

      batch est un groupe d’images stockées comme un seul vecteur contravariant. Tout d’abord, vous devez augmenter le nombre total d’images à évaluer (n) en fonction du nombre d’images de ce lot. Ensuite, exécutez l’inférence sur le réseau neuronal avec ce lot d’images, outputs = net(...). La vérification type if isinstance (...) convertit les sorties dans un tableau NumPy au besoin. Enfin, utilisez evaluate pour calculer le nombre d’échantillons correctement classés. À la fin de la fonction, vous calculez le pourcentage d’échantillons que vous avez correctement classés, score / n.

      Enfin, ajoutez le script suivant pour tirer parti des utilitaires précédents :

      step_4_evaluate.py

      def validate():
          trainloader, testloader = get_train_test_loaders()
          net = Net().float()
      
          pretrained_model = torch.load("checkpoint.pth")
          net.load_state_dict(pretrained_model)
      
          print('=' * 10, 'PyTorch', '=' * 10)
          train_acc = batch_evaluate(net, trainloader) * 100.
          print('Training accuracy: %.1f' % train_acc)
          test_acc = batch_evaluate(net, testloader) * 100.
          print('Validation accuracy: %.1f' % test_acc)
      
      
      if __name__ == '__main__':
          validate()
      

      Cela charge un réseau neuronal pré-entraîné et évalue ses performances sur l’ensemble de données en langue des signes fourni. Plus précisément, le script donne ici une précision sur les images que vous avez utilisées pour la formation et un ensemble distinct d’images que vous mettez de côté à des fins de test, appelé validation set.

      Vous allez ensuite exporter le modèle PyTorch vers un fichier binaire ONNX. Ce fichier binaire peut ensuite être utilisé en production pour exécuter l’inférence avec votre modèle. Plus important encore, le code exécutant ce binaire n’a pas besoin d’une copie de la configuration du réseau d’origine. À la fin de la fonction de valide, ajoutez ce qui suit :

      step_4_evaluate.py

          trainloader, testloader = get_train_test_loaders(1)
      
          # export to onnx
          fname = "signlanguage.onnx"
          dummy = torch.randn(1, 1, 28, 28)
          torch.onnx.export(net, dummy, fname, input_names=['input'])
      
          # check exported model
          model = onnx.load(fname)
          onnx.checker.check_model(model)  # check model is well-formed
      
          # create runnable session with exported model
          ort_session = ort.InferenceSession(fname)
          net = lambda inp: ort_session.run(None, {'input': inp.data.numpy()})[0]
      
          print('=' * 10, 'ONNX', '=' * 10)
          train_acc = batch_evaluate(net, trainloader) * 100.
          print('Training accuracy: %.1f' % train_acc)
          test_acc = batch_evaluate(net, testloader) * 100.
          print('Validation accuracy: %.1f' % test_acc)
      

      Cela exporte le modèle ONNX, vérifie le modèle exporté, puis exécute l’inférence avec le modèle exporté. Vérifiez que votre fichier correspond au fichier de l’étape 4 dans ce référentiel :

      step_4_evaluate.py

      from torch.utils.data import Dataset
      from torch.autograd import Variable
      import torch.nn as nn
      import torch.nn.functional as F
      import torch.optim as optim
      import torch
      import numpy as np
      
      import onnx
      import onnxruntime as ort
      
      from step_2_dataset import get_train_test_loaders
      from step_3_train import Net
      
      
      def evaluate(outputs: Variable, labels: Variable) -> float:
          """Evaluate neural network outputs against non-one-hotted labels."""
          Y = labels.numpy()
          Yhat = np.argmax(outputs, axis=1)
          return float(np.sum(Yhat == Y))
      
      
      def batch_evaluate(
              net: Net,
              dataloader: torch.utils.data.DataLoader) -> float:
          """Evaluate neural network in batches, if dataset is too large."""
          score = n = 0.0
          for batch in dataloader:
              n += len(batch['image'])
              outputs = net(batch['image'])
              if isinstance(outputs, torch.Tensor):
                  outputs = outputs.detach().numpy()
              score += evaluate(outputs, batch['label'][:, 0])
          return score / n
      
      
      def validate():
          trainloader, testloader = get_train_test_loaders()
          net = Net().float().eval()
      
          pretrained_model = torch.load("checkpoint.pth")
          net.load_state_dict(pretrained_model)
      
          print('=' * 10, 'PyTorch', '=' * 10)
          train_acc = batch_evaluate(net, trainloader) * 100.
          print('Training accuracy: %.1f' % train_acc)
          test_acc = batch_evaluate(net, testloader) * 100.
          print('Validation accuracy: %.1f' % test_acc)
      
          trainloader, testloader = get_train_test_loaders(1)
      
          # export to onnx
          fname = "signlanguage.onnx"
          dummy = torch.randn(1, 1, 28, 28)
          torch.onnx.export(net, dummy, fname, input_names=['input'])
      
          # check exported model
          model = onnx.load(fname)
          onnx.checker.check_model(model)  # check model is well-formed
      
          # create runnable session with exported model
          ort_session = ort.InferenceSession(fname)
          net = lambda inp: ort_session.run(None, {'input': inp.data.numpy()})[0]
      
          print('=' * 10, 'ONNX', '=' * 10)
          train_acc = batch_evaluate(net, trainloader) * 100.
          print('Training accuracy: %.1f' % train_acc)
          test_acc = batch_evaluate(net, testloader) * 100.
          print('Validation accuracy: %.1f' % test_acc)
      
      
      if __name__ == '__main__':
          validate()
      

      Pour utiliser et évaluer le point de contrôle de la dernière étape, exécutez ce qui suit :

      • python step_4_evaluate.py

      Cela générera une sortie similaire à la suivante, affirmant que votre modèle exporté non seulement fonctionne, mais le fait également en accord avec votre modèle PyTorch d’origine :

      Output

      ========== PyTorch ========== Training accuracy: 99.9 Validation accuracy: 97.4 ========== ONNX ========== Training accuracy: 99.9 Validation accuracy: 97.4

      Votre réseau neuronal atteint une précision d’entraînement de 99,9 % et une précision de validation de 97,4 %. Cet écart entre la précision d’entraînement et de la validation indique que votre modèle souffre d’un ajustement excessif. Cela signifie qu’au lieu d’apprendre des modèles généralisables, votre modèle a mémorisé les données d’entraînement. Pour comprendre les implications et les causes du sur-ajustement, consultez Comprendre les compromis entre le biais et la variance.

      À ce stade, nous avons terminé de concevoir un système de classification de la langue des signes En substance, notre modèle peut correctement lever une ambiguïté entre les signes presque tout le temps. Nous avons un modèle plutôt acceptable, nous pouvons donc passer à l’étape finale de notre application. Nous utiliserons ce système de classification de la langue des signes dans une application webcam en temps réel.

      Étape 5 – Liaison du flux de la caméra

      Votre prochain objectif est de relier l’appareil photo de l’ordinateur à votre système de classification de la langue des signes. Vous allez collecter les entrées de la caméra, classer la langue des signes affichée, puis signaler le signe classifié à l’utilisateur.

      Créez maintenant un script Python pour le détecteur de visages. Créez le fichier step_6_camera.py en utilisant nano ou votre éditeur de texte favori :

      Ajoutez le code suivant dans le fichier :

      step_5_camera.py

      """Test for sign language classification"""
      import cv2
      import numpy as np
      import onnxruntime as ort
      
      def main():
          pass
      
      if __name__ == '__main__':
          main()
      

      Ce code importe OpenCV, qui contient vos utilitaires d’image, et le runtime ONNX, tout ce dont vous avez besoin pour exécuter l’inférence avec votre modèle. Le reste du code est un texte standard type du programme Python.

      Remplacez maintenant pass dans la fonction main par le code suivant, qui initialise un système de classification de la langue des signes en utilisant les paramètres que vous avez précédemment entraînés. Ajoutez également un mappage des index aux lettres et aux statistiques d’images :

      step_5_camera.py

      def main():
          # constants
          index_to_letter = list('ABCDEFGHIKLMNOPQRSTUVWXY')
          mean = 0.485 * 255.
          std = 0.229 * 255.
      
          # create runnable session with exported model
          ort_session = ort.InferenceSession("signlanguage.onnx")
      

      Vous utiliserez des éléments de ce test script de la documentation officielle d’OpenCV. Plus précisément, vous mettrez à jour le corps de la fonction main. Commencez par initialiser un objet VideoCapture configuré pour capturer le flux en direct à partir de la caméra de votre ordinateur. Placez-le à la fin de la fonction main :

      step_5_camera.py

      def main():
          ...
          # create runnable session with exported model
          ort_session = ort.InferenceSession("signlanguage.onnx")
      
          cap = cv2.VideoCapture(0)
      

      Ajoutez ensuite une boucle while pour que la lecture se fasse à partir de la caméra à chaque intervalle de temps :

      step_5_camera.py

      def main():
          ...
          cap = cv2.VideoCapture(0)
          while True:
              # Capture frame-by-frame
              ret, frame = cap.read()
      

      Écrivez une fonction utilitaire qui prend le recadrage central comme cadre de caméra. Placez cette fonction avant main :

      step_5_camera.py

      def center_crop(frame):
          h, w, _ = frame.shape
          start = abs(h - w) // 2
          if h > w:
              frame = frame[start: start + w]
          else:
              frame = frame[:, start: start + h]
          return frame
      

      Ensuite, prenez le recadrage central comme cadre de la caméra, convertissez-le en niveaux de gris, normalisez -le et redimensionnez-le en 28x28. Placez-le dans la boucle while de la fonction main :

      step_5_camera.py

      def main():
          ...
          while True:
              # Capture frame-by-frame
              ret, frame = cap.read()
      
              # preprocess data
              frame = center_crop(frame)
              frame = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
              x = cv2.resize(frame, (28, 28))
              x = (frame - mean) / std
      

      Toujours dans la boucle while, exécutez l’inférence avec le runtime ONNX. Convertissez les sorties en un index de catégorie, puis en une lettre :

      step_5_camera.py

              ...
              x = (frame - mean) / std
      
              x = x.reshape(1, 1, 28, 28).astype(np.float32)
              y = ort_session.run(None, {'input': x})[0]
      
              index = np.argmax(y, axis=1)
              letter = index_to_letter[int(index)]
      

      Affichez la lettre prédite à l’intérieur du cadre et affichez le cadre à l’utilisateur :

      step_5_camera.py

              ...
              letter = index_to_letter[int(index)]
      
              cv2.putText(frame, letter, (100, 100), cv2.FONT_HERSHEY_SIMPLEX, 2.0, (0, 255, 0), thickness=2)
              cv2.imshow("Sign Language Translator", frame)
      

      À la fin de la boucle while, ajoutez ce code pour vérifier si lorsque l’utilisateur frappe le caractère q il quitte bien l’application. Cette ligne arrête le programme pendant 1 milliseconde. Ajoutez ce qui suit :

      step_5_camera.py

              ...
              cv2.imshow("Sign Language Translator", frame)
      
              if cv2.waitKey(1) & 0xFF == ord('q'):
                  break
      

      Enfin, relâchez la capture et fermez toutes les fenêtres. Placez-la en dehors de la boucle while pour terminer la fonction main.

      step_5_camera.py

      ...
      
          while True:
              ...
              if cv2.waitKey(1) & 0xFF == ord('q'):
                  break
      
      
          cap.release()
          cv2.destroyAllWindows()
      

      Vérifiez que votre fichier correspond à ce qui suit ou à ce référentiel :

      step_5_camera.py

      import cv2
      import numpy as np
      import onnxruntime as ort
      
      
      def center_crop(frame):
          h, w, _ = frame.shape
          start = abs(h - w) // 2
          if h > w:
              return frame[start: start + w]
          return frame[:, start: start + h]
      
      
      def main():
          # constants
          index_to_letter = list('ABCDEFGHIKLMNOPQRSTUVWXY')
          mean = 0.485 * 255.
          std = 0.229 * 255.
      
          # create runnable session with exported model
          ort_session = ort.InferenceSession("signlanguage.onnx")
      
          cap = cv2.VideoCapture(0)
          while True:
              # Capture frame-by-frame
              ret, frame = cap.read()
      
              # preprocess data
              frame = center_crop(frame)
              frame = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
              x = cv2.resize(frame, (28, 28))
              x = (x - mean) / std
      
              x = x.reshape(1, 1, 28, 28).astype(np.float32)
              y = ort_session.run(None, {'input': x})[0]
      
              index = np.argmax(y, axis=1)
              letter = index_to_letter[int(index)]
      
              cv2.putText(frame, letter, (100, 100), cv2.FONT_HERSHEY_SIMPLEX, 2.0, (0, 255, 0), thickness=2)
              cv2.imshow("Sign Language Translator", frame)
      
              if cv2.waitKey(1) & 0xFF == ord('q'):
                  break
      
          cap.release()
          cv2.destroyAllWindows()
      
      if __name__ == '__main__':
          main()
      

      Quittez votre fichier et exécutez le script.

      Une fois le script exécuté, une fenêtre apparaîtra avec votre flux de webcam en direct. La lettre de la langue des signes prédite s’affichera en haut à gauche. Levez la main et faites votre signe favori pour voir votre classeur en action. Voici quelques exemples de résultats avec la lettre L et D.

      Capture d'écran de votre programme OpenCV échantillon, pour la langue des signes « L » 
       Capture d'écran de votre programme OpenCV échantillon, pour la langue des signes « D »

      Lorsque vous réalisez les tests, notez que l’arrière-plan doit être assez clair pour que ce traducteur fonctionne. C’est une conséquence malheureuse de la propreté de l’ensemble de données. Si l’ensemble de données comprenait des images de signes de la main avec des arrière-plans divers, le réseau pourrait résister aux arrière-plans bruyants. Cependant, dans cet ensemble de données, les arrière-plans sont vierges et les mains bien centrées. Par conséquent, ce traducteur de webcam fonctionne mieux lorsque vous centrez votre main et la placez sur un fond vierge.

      Ceci conclut l’application du traducteur de la langue des signes.

      Conclusion

      Dans ce tutoriel, vous avez créé un traducteur de la langue des signes américaine à l’aide de la vision par ordinateur et d’un modèle d’apprentissage automatique. Vous avez tout particulièrement abordé de nouveaux aspects de l’entraînement d’un modèle d’apprentissage automatique, notamment l’augmentation des données pour veiller à la robustesse du modèle, les calendriers de fréquence d’apprentissage pour réduire les pertes et l’exportation de modèles d’IA à l’aide d’ONNX pour la production. Vous avez ensuite obtenu une application de vision par ordinateur en temps réel, qui traduit le langage des signes en lettres à l’aide d’un pipeline que vous avez créé. Il convient de noter vous pouvez lutter contre la fragilité du classificateur final en utilisant l’une des méthodes suivantes (ou l’ensemble d’entre elles). Pour explorer le sujet plus profondément, essayez les rubriques suivantes pour améliorer votre application :

      • Généralisation : il ne s’agit d’un sous-thème de la vision par ordinateur, mais plutôt d’un problème constant tout au long de l’apprentissage automatique. Voir Comprendre les compromis entre le biais et la variance.
      • Adaptation du domaine : supposons que votre modèle soit formé dans le domaine A (par exemple, des environnements ensoleillés). Pouvez-vous rapidement adapter le modèle au domaine B (par exemple, des environnements nuageux) ?
      • Exemples contradictoires : Supposons qu’un adversaire conçoit intentionnellement des images pour tromper votre modèle. Comment pouvez-vous concevoir de telles images ? Que pouvez-vous faire pour combattre de telles images ?



      Source link