Ajouter des commandes à votre application mobile à l'aide d'un agent Dialogflow

Ce tutoriel explique comment faire en sorte que votre application iOS réponde aux commandes vocales et textuelles traitées par un agent Dialogflow. L'application cliente de ce tutoriel capture la commande, l'envoie à l'agent et reçoit une réponse. L'agent traite la commande et la fait correspondre à un intent préconfiguré pour renvoyer une réponse appropriée. Ce tutoriel explique également comment récupérer des identifiants éphémères avec lesquels les applications clientes peuvent authentifier les appels d'API Google Cloud.

Présentation de la solution

La solution comprend les composants suivants :

Application cliente
Le composant client est une application iOS qui reçoit des commandes vocales et textuelles et les envoie à l'agent de chronométrage. L'application envoie la commande à l'aide d'une requête authentifiée qui inclut les identifiants obtenus à partir du service de jetons.
Service de jetons
Le service de jetons est mis en œuvre à l'aide de Cloud Functions for Firebase. Le service fournit des identifiants de courte durée que les applications clientes peuvent utiliser pour envoyer des requêtes authentifiées à l'agent de chronométrage. Le service de jetons récupère les identifiants de l'API IAM, les stocke dans une base de données Cloud Firestore et confirme la validité des identifiants.
Agent de chronométrage
Dialogflow héberge l'agent de chronométrage qui fournit les capacités de traitement du langage naturel, afin de traduire les commandes en instructions permettant de contrôler le chronomètre.

Le schéma suivant illustre l’interaction entre les composants :

Architecture de haut niveau de la solution

Coûts

Considérez les coûts éventuels suivants associés à l'exécution des exemples de ce tutoriel :

  • Firebase intègre un forfait d'utilisation gratuit. Si l'utilisation de ces services est inférieure aux limites spécifiées dans le forfait Spark, l’utilisation de Firebase est gratuite. Pour plus d'informations, consultez les formules Firebase.
  • Firebase définit des quotas pour l'utilisation de Cloud Functions, qui spécifient les limites de ressources, de durée et de débit. Pour plus d'informations, consultez la page sur les quotas et limites dans la documentation de Firebase.
  • L'utilisation de Dialogflow fait l'objet d'une facturation mensuelle basée sur l'édition de requêtes, le forfait associé, ainsi que le nombre et la durée des requêtes. Vous pouvez utiliser gratuitement un nombre limité de requêtes avec l'édition standard. Pour plus d'informations, consultez la page des tarifs de Dialogflow.

Vous pouvez également estimer les coûts à l'aide du simulateur de coût Google Cloud.

Avant de commencer

Pour suivre ce tutoriel, vous avez besoin des logiciels suivants :

L'exemple d'application a été testé avec Xcode 10.2.1, CocoaPods 1.5.2 et Node.js 8.16.1.

Cloner l'exemple de code

Clonez le code de l'application cliente :

git clone https://github.com/GoogleCloudPlatform/ios-docs-samples.git

Clonez le code du service de jetons :

git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

Créer un projet Firebase

  1. Créez un compte Firebase ou connectez-vous à un compte existant.

  2. Cliquez sur Ajouter un projet.

  3. Dans le champ Nom du projet, saisissez stopwatch. Notez l'ID de projet attribué à votre projet. Il est utilisé dans plusieurs étapes de ce tutoriel.

  4. Suivez les autres étapes d'installation, puis cliquez sur Créer un projet.

  5. Une fois que l'assistant a provisionné votre projet, cliquez sur Continuer.

  6. Sur la page Présentation de votre projet, cliquez sur l'icône Paramètres (en forme de roue dentée), puis sur Paramètres du projet.

  7. Cliquez sur Ajouter Firebase à votre application iOS.

  8. Dans le champ ID du groupe iOS, saisissez com.sample.dialogflow.

  9. Cliquez sur Enregistrer l'application.

  10. Suivez les étapes de la section Télécharger le fichier de configuration pour ajouter le fichier GoogleService-Info.plist au dossier ios-docs-samples/dialogflow/stopwatch/ dans votre projet.

  11. Cliquez sur Suivant dans la section Télécharger le fichier de configuration.

  12. Notez les instructions permettant d'utiliser CocoaPods afin d'installer et de gérer les dépendances du projet. Le gestionnaire de dépendances CocoaPods est déjà configuré dans l'exemple de code.

  13. Exécutez la commande suivante pour installer les dépendances. Celle-ci peut prendre un certain temps.

    cd ios-docs-samples/dialogflow/stopwatch/
    ./INSTALL-COCOAPODS
    

    Vous devrez peut-être exécuter la commande pod repo update si votre installation de CocoaPods ne trouve pas la dépendance Firebase.

    Après cette étape et pour tous les futurs développements sur l'application iOS, utilisez le fichier .xcworkspace nouvellement créé à la place du fichier .xcodeproj.

  14. Cliquez sur Suivant dans la section Ajouter le SDK Firebase.

  15. Notez le code requis pour initialiser Firebase dans votre projet.

  16. Cliquez sur Suivant dans la section Ajouter le code d'initialisation.

  17. Cliquez sur Ignorer cette étape dans la section Exécutez votre application pour vérifier l'installation.

  18. Remplacez l'espace réservé your-project-identifier dans le fichier ApplicationConstants.swift par l'ID de projet Firebase.

Créer un compte de service

Le service de jetons utilise l'API IAM pour demander des identifiants éphémères fournissant un accès client à l'API Dialogflow. Pour en savoir plus, consultez la page Créer des identifiants de compte de service éphémères.

Pour créer un compte de service disposant des autorisations requises, procédez comme suit :

  1. Dans le menu de gauche de la console Firebase, à côté de la page d'accueil du projet chronomètre, cliquez sur l'icône Paramètres (en forme de roue dentée), puis sur Paramètres du projet.

  2. Sélectionnez Comptes de service, puis Gérer les autorisations des comptes de service.

  3. Cliquez sur Créer un compte de service.

  4. Configurez les paramètres suivants :

    1. Dans le champ Nom du compte de service, saisissez dialogflow-client.
    2. Dans Rôle, sélectionnez Projet > Client de l'API Dialogflow.
  5. Cliquez sur Créer.

Ajouter des autorisations de créateur de jeton

La fonction Cloud pour Firebase s'exécute sous le compte de service par défaut App Engine, ce dernier nécessitant des autorisations pour créer des identifiants de courte durée. Pour ajouter les autorisations requises, ajoutez le rôle Créateur de jetons du compte de service au compte de service App Engine par défaut. Procédez comme suit :

  1. Accédez à la page IAM dans Cloud Console.

    Accéder à la page "IAM"

  2. Identifiez l'entrée qui affiche le compte de service App Engine par défaut dans la colonne Nom et cliquez sur le bouton Modifier le membre à la fin de la ligne.

  3. Cliquez sur Ajouter un autre rôle.

  4. Dans le menu Sélectionner un rôle, sélectionnez Comptes de service > Créateur de jetons de compte de service.

  5. Cliquez sur Enregistrer.

Activer la facturation et les API pour le projet Google Cloud

Ce tutoriel nécessite l’API Dialogflow. Pour activer l'API, procédez comme suit :

  1. Dans Google Cloud Console, sélectionnez le projet chronomètre.

    Accéder à la page "Projets"

  2. Assurez-vous que la facturation est activée pour votre projet Cloud. Découvrez comment vérifier que la facturation est activée pour votre projet.

  3. Activez l'API Dialogflow.

    Activer l'API

Construire et déployer le service de jetons

Pour créer et déployer le service de jetons, vous devez installer CLI Firebase, créer la structure de projet pour la fonction Cloud pour Firebase et remplacer la fonction par défaut par la fonction de service de jetons.

  1. Installez CLI Firebase.

    npm install -g firebase-tools
    
  2. Connectez-vous à Firebase.

    firebase login
    
  3. Créez la structure de projet pour la fonction.

    firebase init functions
    
  4. Remplacez le fichier par défaut index.js dans la structure du projet par le fichier index.js dans le dossier functions/tokenservice/functions du dépôt nodejs-docs-samples.

  5. Remplacez les espaces réservés SERVICE-ACCOUNT-NAME et YOUR_PROJECT_ID dans la fonction generateAccessToken() respectivement par dialogflow-client et l'ID de votre projet Firebase. Les espaces réservés font partie du nom du compte de service, qui se présente sous la forme :

    SERVICE-ACCOUNT-NAME@YOUR_PROJECT_ID.iam.gserviceaccount.com
    
  6. Déployez la fonction de service de jetons.

    firebase deploy --only functions
    

Déployer de l'agent de chronométrage

Pour déployer l'agent de chronométrage, créez un agent dans la console Dialogflow :

  1. Si vous n'avez aucun agent dans votre console Dialogflow, cliquez sur Créer un agent dans le menu de gauche. Sinon, cliquez sur le nom de l'agent actuel dans le menu de gauche et choisissez Créer un agent.

  2. Saisissez stopwatch comme nom d'agent.

  3. Choisissez une langue par défaut.

  4. Choisissez un fuseau horaire par défaut.

  5. Choisissez chronomètre dans le menu Projet Google.

  6. Cliquez sur Créer.

Le projet de l'application cliente inclut un fichier StopwatchAgent.zip que vous pouvez utiliser pour importer l'agent :

  1. Cliquez sur l'icône en forme de roue dentée () située à côté du nom de l'agent dans le menu de gauche.
  2. Cliquez sur l'onglet Exporter et importer.
  3. Cliquez sur Importer depuis un fichier zip.
  4. Sélectionnez le fichier StopwatchAgent.zip.
  5. Saisissez IMPORT dans le champ de texte pour confirmer l'opération.
  6. Cliquez sur Importer.

Explorer le code

Les applications clientes peuvent obtenir des identifiants éphémères en appelant la fonction getOAuthToken() du service de jetons. La méthode getOAuthToken() accomplit les tâches suivantes :

  1. Elle vérifie que la requête en cours est authentifiée. La fonction génère une erreur si la requête n'est pas authentifiée.
  2. Elle essaie de récupérer un jeton de la base de données et effectue l'une des actions suivantes :
    1. S'il existe un jeton dans la base de données et qu'il n'expire pas dans les cinq minutes, la fonction le renvoie au client.
    2. Si la base de données ne contient pas de jeton ou si le jeton expire dans les cinq minutes, la fonction récupère un jeton de l'API IAM et le transmet au client. La fonction enregistre le jeton dans la base de données pour le traitement de futures requêtes client.

L'exemple de code suivant montre la fonction getOAuthToken() :

exports.getOAuthToken = functions.https.onCall(async (data, context) => {
  // Checking that the user is authenticated.
  if (!context.auth) {
    // Throwing an HttpsError so that the client gets the error details.
    throw new functions.https.HttpsError(
      'failed-precondition',
      'The function must be called ' + 'while authenticated.'
    );
  }
  // Retrieve the token from the database
  const docRef = db.collection('ShortLivedAuthTokens').doc('OauthToken');

  const doc = await docRef.get();

  try {
    if (doc.exists && isValid(doc.data().expireTime)) {
      //push notification
      pushNotification(
        data['deviceID'],
        doc.data().accessToken,
        doc.data().expireTime
      );
      return doc.data();
    } else {
      const result = await retrieveCredentials(context);
      console.log('Print result from retrieveCredentials functions');
      console.log(result);
      pushNotification(
        data['deviceID'],
        result['accessToken'],
        result['expireTime']
      );
      return result;
    }
  } catch (err) {
    console.log('Error retrieving token', err);
    pushNotification(data['deviceID'], 'Error retrieving token', 'Error');
    // return 'Error retrieving token';
    return 'Error retrieving token';
  }
});

Pour récupérer les identifiants, le service de jetons envoie une requête au point de terminaison /computeMetadata/v1/instance/service-accounts/default/token de l'API IAM, comme indiqué dans le code suivant :

const retrieveCredentials = (context) => {
  return new Promise((resolve) => {
    // To create a new access token, we first have to retrieve the credentials
    // of the service account that will make the generateTokenRequest().
    // To do that, we will use the App Engine Default Service Account.
    const options = {
      host: 'metadata.google.internal',
      path: '/computeMetadata/v1/instance/service-accounts/default/token',
      method: 'GET',
      headers: {'Metadata-Flavor': 'Google'},
    };

    const get_req = http.get(options, (res) => {
      let body = '';

      res.on('data', (chunk) => {
        body += chunk;
      });

      res.on('end', async () => {
        const response = JSON.parse(body);
        const result = await generateAccessToken(
          context,
          response.access_token,
          response.token_type
        );
        return resolve(result);
      });
    });
    get_req.on('error', (e) => {
      //console.log('Error retrieving credentials', e.message);
      return `Error retrieving token${e.message}`;
    });
    get_req.end();
  });
};
exports.retrieveCredentials = retrieveCredentials;

Pour en savoir plus sur le service de jetons, consultez le fichier index.js qui définit la fonctionnalité Cloud Functions for Firebase.

Effectuer un nettoyage

Pour éviter que les ressources utilisées dans ce tutoriel soient facturées sur votre compte Google Cloud, supprimez les projets Google Cloud et Firebase. Bien que vous ayez créé le projet dans la console Firebase, vous pouvez également le supprimer dans Cloud Console.

  1. Dans Cloud Console, accédez à la page Gérer les ressources.

    Accéder à la page Gérer les ressources

  2. Dans la liste des projets, sélectionnez le projet que vous souhaitez supprimer, puis cliquez sur Supprimer .
  3. Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez sur Arrêter pour supprimer le projet.