Créer un workflow avec intervention humaine à l'aide de rappels


Ce tutoriel explique comment créer un workflow de traduction qui attend votre entrée (intervention humaine) et qui connecte une base de données Firestore, deux fonctions Cloud Run, l'API Cloud Translation et une page Web qui utilise le SDK Firebase pour le mettre à jour en temps réel.

Avec Workflows, vous pouvez accepter un point de terminaison de rappel (ou webhook) qui attend que les requêtes HTTP arrivent à ce point de terminaison, et reprend l'exécution du workflow ultérieurement. Dans ce cas, le workflow attend que votre entrée rejette ou valide la traduction d'un texte, mais il peut également attendre un processus externe. Pour en savoir plus, consultez la section Attendre l'utilisation de rappels.

Architecture

Ce tutoriel crée une application Web qui vous permet d'effectuer les opérations suivantes:

  1. Sur la page Web de traduction, saisissez le texte que vous souhaitez traduire de l'anglais vers le français. Cliquez sur Traduire.
  2. À partir de la page Web, une fonction Cloud Run qui lance l'exécution du workflow. Le texte à traduire est transmis en tant que paramètre à la fonction et au workflow.
  3. Le texte est enregistré dans une base de données Cloud Firestore. L'API Cloud Translation est appelée. La traduction renvoyée est stockée dans la base de données. L'application Web est déployée à l'aide de Firebase Hosting et est mise à jour en temps réel pour afficher le texte traduit.
  4. L'étape create_callback du workflow crée une URL de point de terminaison de rappel qui est également enregistrée dans la base de données Firestore. La page Web affiche maintenant un bouton Valider et un bouton Refuser.
  5. Le workflow est maintenant mis en pause et attend une requête HTTP POST explicite vers l'URL du point de terminaison de rappel.
  6. Vous pouvez décider de valider ou de refuser la traduction. Cliquez sur un bouton pour appeler une deuxième fonction Cloud Run qui, à son tour, appelle le point de terminaison de rappel créé par le workflow, en transmettant l'état d'approbation. Le workflow reprend son exécution et enregistre l'état d'approbation true ou false dans la base de données Firestore.

Ce diagramme offre un aperçu du processus:

Workflow avec rappel

Objectifs

  • Déployez une application Web.
  • Créez une base de données Firestore pour stocker les requêtes de traduction.
  • Déployez des fonctions Cloud Run pour exécuter le workflow.
  • Déployer et exécuter un workflow pour orchestrer l'ensemble du processus.

Coûts

Dans ce document, vous utilisez les composants facturables suivants de Google Cloud :

Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût. Les nouveaux utilisateurs de Google Cloud peuvent bénéficier d'un essai gratuit.

Avant de commencer

Les contraintes de sécurité définies par votre organisation peuvent vous empêcher d'effectuer les étapes suivantes. Pour obtenir des informations de dépannage, consultez la page Développer des applications dans un environnement Google Cloud limité.

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Install the Google Cloud CLI.
  3. To initialize the gcloud CLI, run the following command:

    gcloud init
  4. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  5. Make sure that billing is enabled for your Google Cloud project.

  6. Enable the App Engine, Cloud Build, Cloud Run functions, Firestore, Translation, and Workflows APIs:

    gcloud services enable appengine.googleapis.com cloudbuild.googleapis.com cloudfunctions.googleapis.com firestore.googleapis.com translate.googleapis.com workflows.googleapis.com
  7. Install the Google Cloud CLI.
  8. To initialize the gcloud CLI, run the following command:

    gcloud init
  9. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  10. Make sure that billing is enabled for your Google Cloud project.

  11. Enable the App Engine, Cloud Build, Cloud Run functions, Firestore, Translation, and Workflows APIs:

    gcloud services enable appengine.googleapis.com cloudbuild.googleapis.com cloudfunctions.googleapis.com firestore.googleapis.com translate.googleapis.com workflows.googleapis.com
  12. Mettez à jour les composants de Google Cloud CLI :
    gcloud components update
  13. Connectez-vous à votre compte :
    gcloud auth login
  14. Définissez l'ID du projet et l'emplacement par défaut utilisés dans ce tutoriel:
    export GOOGLE_CLOUD_PROJECT=PROJECT_ID
    export REGION=REGION
    gcloud config set workflows/location ${REGION}

    Remplacez les éléments suivants :

    • PROJECT_ID : ID de votre projet Google Cloud. Vous pouvez trouver l'ID de votre projet sur la page Bienvenue de la console Google Cloud.
    • REGION : emplacement Workflows compatible de votre choix.

Déployer la première fonction Cloud Run

Cette fonction Cloud Run lance l'exécution du workflow. Le texte à traduire est transmis en tant que paramètre à la fonction et au workflow.

  1. Créez un répertoire appelé callback-translation et avec des sous-répertoires appelés invokeTranslationWorkflow, translationCallbackCall et public:

    mkdir -p ~/callback-translation/{invokeTranslationWorkflow,translationCallbackCall,public}
  2. Accédez au répertoire invokeTranslationWorkflow :

    cd ~/callback-translation/invokeTranslationWorkflow
  3. Créez un fichier texte avec le nom de fichier index.js contenant le code Node.js suivant:

    const cors = require('cors')({origin: true});
    const {ExecutionsClient} = require('@google-cloud/workflows');
    const client = new ExecutionsClient();
    
    exports.invokeTranslationWorkflow = async (req, res) => {
      cors(req, res, async () => {
        const text = req.body.text;
        console.log(`Translation request for "${text}"`);
    
        const PROJECT_ID = process.env.PROJECT_ID;
        const CLOUD_REGION = process.env.CLOUD_REGION;
        const WORKFLOW_NAME = process.env.WORKFLOW_NAME;
    
        const execResponse = await client.createExecution({
          parent: client.workflowPath(PROJECT_ID, CLOUD_REGION, WORKFLOW_NAME),
          execution: {
            argument: JSON.stringify({text})
          }
        });
        console.log(`Translation workflow execution request: ${JSON.stringify(execResponse)}`);
    
        const execName = execResponse[0].name;
        console.log(`Created translation workflow execution: ${execName}`);
    
        res.set('Access-Control-Allow-Origin', '*');
        res.status(200).json({executionId: execName});
      });
    };
  4. Créez un fichier texte portant le nom de fichier package.json et contenant les métadonnées npm suivantes:

    {
      "name": "launch-translation-workflow",
      "version": "0.0.1",
      "dependencies": {
        "@google-cloud/workflows": "^1.2.5",
        "cors": "^2.8.5"
      }
    }
    
  5. Déployer la fonction avec un déclencheur HTTP et autoriser les accès non authentifiés :

    gcloud functions deploy invokeTranslationWorkflow \
    --region=${REGION} \
    --runtime nodejs14 \
    --entry-point=invokeTranslationWorkflow \
    --set-env-vars PROJECT_ID=${GOOGLE_CLOUD_PROJECT},CLOUD_REGION=${REGION},WORKFLOW_NAME=translation_validation \
    --trigger-http \
    --allow-unauthenticated

    Le déploiement de la fonction peut prendre quelques minutes. Vous pouvez également utiliser l'interface Cloud Run Functions dans la console Google Cloud pour déployer la fonction.

  6. Une fois la fonction déployée, vous pouvez confirmer la propriété httpsTrigger.url :

    gcloud functions describe invokeTranslationWorkflow

    Notez l'URL renvoyée afin de pouvoir l'utiliser ultérieurement.

Déployer la deuxième fonction Cloud Run

Cette fonction Cloud Run envoie une requête HTTP POST au point de terminaison de rappel créé par le workflow, en transmettant un état d'approbation qui indique si la traduction est validée ou refusée.

  1. Accédez au répertoire translationCallbackCall :

    cd ../translationCallbackCall
  2. Créez un fichier texte avec le nom de fichier index.js contenant le code Node.js suivant:

    const cors = require('cors')({origin: true});
    const fetch = require('node-fetch');
    
    exports.translationCallbackCall = async (req, res) => {
      cors(req, res, async () => {
        res.set('Access-Control-Allow-Origin', '*');
    
        const {url, approved} = req.body;
        console.log("Approved? ", approved);
        console.log("URL = ", url);
        const {GoogleAuth} = require('google-auth-library');
        const auth = new GoogleAuth();
        const token = await auth.getAccessToken();
        console.log("Token", token);
    
        try {
          const resp = await fetch(url, {
              method: 'POST',
              headers: {
                  'accept': 'application/json',
                  'content-type': 'application/json',
                  'authorization': `Bearer ${token}`
              },
              body: JSON.stringify({ approved })
          });
          console.log("Response = ", JSON.stringify(resp));
    
          const result = await resp.json();
          console.log("Outcome = ", JSON.stringify(result));
    
          res.status(200).json({status: 'OK'});
        } catch(e) {
          console.error(e);
    
          res.status(200).json({status: 'error'});
        }
      });
    };
  3. Créez un fichier texte portant le nom de fichier package.json et contenant les métadonnées npm suivantes:

    {
      "name": "approve-translation-workflow",
      "version": "0.0.1",
      "dependencies": {
        "cors": "^2.8.5",
        "node-fetch": "^2.6.1",
        "google-auth-library": "^7.1.1"
      }
    }
    
  4. Déployer la fonction avec un déclencheur HTTP et autoriser les accès non authentifiés :

    gcloud functions deploy translationCallbackCall \
    --region=${REGION} \
    --runtime nodejs14 \
    --entry-point=translationCallbackCall \
    --trigger-http \
    --allow-unauthenticated

    Le déploiement de la fonction peut prendre quelques minutes. Vous pouvez également utiliser l'interface Cloud Run Functions dans la console Google Cloud pour déployer la fonction.

  5. Une fois la fonction déployée, vous pouvez confirmer la propriété httpsTrigger.url :

    gcloud functions describe translationCallbackCall

    Notez l'URL renvoyée afin de pouvoir l'utiliser ultérieurement.

Déployer le workflow

Un workflow est constitué d'une série d'étapes décrites à l'aide de la syntaxe Workflows, qui peut être écrite au format YAML ou JSON. Il s'agit de la définition du workflow. Après avoir créé un workflow, vous pouvez le déployer pour le rendre disponible en exécution.

  1. Accédez au répertoire callback-translation :

    cd ..
  2. Créez un fichier texte avec le nom de fichier translation-validation.yaml avec le contenu suivant :

    main:
        params: [translation_request]
        steps:
            - log_request:
                call: sys.log
                args:
                    text: ${translation_request}
            - vars:
                assign:
                    - exec_id: ${sys.get_env("GOOGLE_CLOUD_WORKFLOW_EXECUTION_ID")}
                    - text_to_translate: ${translation_request.text}
                    - database_root: ${"projects/" + sys.get_env("GOOGLE_CLOUD_PROJECT_ID") + "/databases/(default)/documents/translations/"}
            - log_translation_request:
                call: sys.log
                args:
                    text: ${text_to_translate}
    
            - store_translation_request:
                call: googleapis.firestore.v1.projects.databases.documents.patch
                args:
                    name: ${database_root + exec_id}
                    updateMask:
                        fieldPaths: ['text']
                    body:
                        fields:
                            text:
                                stringValue: ${text_to_translate}
                result: store_translation_request_result
    
            - translate:
                call: googleapis.translate.v2.translations.translate
                args:
                    query:
                        q: ${text_to_translate}
                        target: "FR"
                        format: "text"
                        source: "EN"
                result: translation_result
            - assign_translation:
                assign:
                    - translation: ${translation_result.data.translations[0].translatedText} 
            - log_translation_result:
                call: sys.log
                args:
                    text: ${translation}
    
            - store_translated_text:
                call: googleapis.firestore.v1.projects.databases.documents.patch
                args:
                    name: ${database_root + exec_id}
                    updateMask:
                        fieldPaths: ['translation']
                    body:
                        fields:
                            translation:
                                stringValue: ${translation}
                result: store_translation_request_result   
    
            - create_callback:
                call: events.create_callback_endpoint
                args:
                    http_callback_method: "POST"
                result: callback_details
            - log_callback_details:
                call: sys.log
                args:
                    text: ${callback_details}
    
            - store_callback_details:
                call: googleapis.firestore.v1.projects.databases.documents.patch
                args:
                    name: ${database_root + exec_id}
                    updateMask:
                        fieldPaths: ['callback']
                    body:
                        fields:
                            callback:
                                stringValue: ${callback_details.url}
                result: store_callback_details_result
    
            - await_callback:
                call: events.await_callback
                args:
                    callback: ${callback_details}
                    timeout: 3600
                result: callback_request
            - assign_approval:
                assign:
                    - approved: ${callback_request.http_request.body.approved}
    
            - store_approval:
                call: googleapis.firestore.v1.projects.databases.documents.patch
                args:
                    name: ${database_root + exec_id}
                    updateMask:
                        fieldPaths: ['approved']
                    body:
                        fields:
                            approved:
                                booleanValue: ${approved}
                result: store_approval_result
    
            - return_outcome:
                return:
                    text: ${text_to_translate}
                    translation: ${translation}
                    approved: ${approved}
  3. Après avoir créé le workflow, vous pouvez le déployer. Toutefois, vous ne devez pas l'exécuter:

    gcloud workflows deploy translation_validation --source=translation-validation.yaml

Créer votre application Web

créer une application Web qui appelle une fonction Cloud qui lance l'exécution du workflow. La page Web est mise à jour en temps réel pour afficher le résultat de la requête de traduction.

  1. Accédez au répertoire public :

    cd public
  2. Créez un fichier texte avec le nom de fichier index.html contenant le balisage HTML suivant. (Dans une étape ultérieure, vous modifierez le fichier index.html et ajouterez les scripts du SDK Firebase.)

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
    
        <title>Frenglish translation — Feature Workflows callbacks</title>
    
        <link rel="stylesheet"
            href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.0.0-beta.42/dist/themes/base.css">
        <script type="module"
            src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.0.0-beta.42/dist/shoelace.js"></script>
        <link rel="stylesheet" href="./style.css">
    </head>
    
    <body>
        <h1>Translate from English to French</h1>
    
        <sl-form class="form-overview">
            <sl-textarea id="text" placeholder="The quick brown fox jumps over the lazy dog."
                label="English text to translate"></sl-textarea>
            <p></p>
            <sl-button id="translateBtn" type="primary">Translate</sl-button>
            <p></p>
            <sl-alert id="translation" type="primary">
                Le rapide renard brun saute au dessus du chien paresseux.
            </sl-alert>
            <p></p>
            <div id="buttonRow" style="display: none;">
                <sl-button id="validateBtn" type="success">Validate</sl-button>
                <sl-button id="rejectBtn" type="danger">Reject</sl-button>
            </div>
            <p></p>
            <sl-alert id="validationAlert" type="success">
                <sl-icon slot="icon" name="check2-circle"></sl-icon>
                <strong>The translation has been validated</strong><br>
                Glad that you liked our translation! We'll save it in our database.
            </sl-alert>
            <sl-alert id="rejectionAlert" type="danger">
                <sl-icon slot="icon" name="exclamation-octagon"></sl-icon>
                <strong>The translation has been rejected</strong><br>
                A pity the translation isn't good! We'll do better next time!
            </sl-alert>
            <p></p>
            <sl-button id="newBtn" style="display: none;" type="primary">New translation</sl-button>
        </sl-form>
    
        <script src="https://www.gstatic.com/firebasejs/8.6.3/firebase-app.js"></script>
        <script src="https://www.gstatic.com/firebasejs/8.6.3/firebase-firestore.js"></script>
    
        <script>
            var firebaseConfig = {
                apiKey: "XXXX",
                authDomain: "XXXX",
                projectId: "XXXX",
                storageBucket: "XXXX",
                messagingSenderId: "XXXX",
                appId: "XXXX",
                measurementId: "XXXX"
            };
            // Initialize Firebase
            firebase.initializeApp(firebaseConfig);
        </script>
        <script src="./script.js" type="module"></script>
    </body>
    
    </html>
    
  3. Créez un fichier texte avec le nom de fichier script.js contenant le code JavaScript suivant :

    document.addEventListener("DOMContentLoaded", async function (event) {
        const textArea = document.getElementById("text");
        textArea.focus();
    
        const newBtn = document.getElementById("newBtn");
        newBtn.addEventListener("sl-focus", event => {
            event.target.blur();
            window.location.reload();
        });
    
        const translationAlert = document.getElementById("translation");
        const buttonRow = document.getElementById("buttonRow");
    
        var callbackUrl = "";
    
        const validationAlert = document.getElementById("validationAlert");
        const rejectionAlert = document.getElementById("rejectionAlert");
        const validateBtn = document.getElementById("validateBtn");
        const rejectBtn = document.getElementById("rejectBtn");
    
        const translateBtn = document.getElementById("translateBtn");
        translateBtn.addEventListener("sl-focus", async event => {
            event.target.disabled = true;
            event.target.loading = true;
            textArea.disabled = true;
    
            console.log("Text to translate = ", textArea.value);
    
            const fnUrl = UPDATE_ME;
    
            try {
                console.log("Calling workflow executor function...");
                const resp = await fetch(fnUrl, {
                    method: "POST",
                    headers: {
                        "accept": "application/json",
                        "content-type": "application/json"
                    },
                    body: JSON.stringify({ text: textArea.value })
                });
                const executionResp = await resp.json();
                const executionId = executionResp.executionId.slice(-36);
                console.log("Execution ID = ", executionId);
    
                const db = firebase.firestore();
                const translationDoc = db.collection("translations").doc(executionId);
    
                var translationReceived = false;
                var callbackReceived =  false;
                var approvalReceived = false;
                translationDoc.onSnapshot((doc) => {
                    console.log("Firestore update", doc.data());
                    if (doc.data()) {
                        if ("translation" in doc.data()) {
                            if (!translationReceived) {
                                console.log("Translation = ", doc.data().translation);
                                translationReceived = true;
                                translationAlert.innerText = doc.data().translation;
                                translationAlert.open = true;
                            }
                        }
                        if ("callback" in doc.data()) {
                            if (!callbackReceived) {
                                console.log("Callback URL = ", doc.data().callback);
                                callbackReceived = true;
                                callbackUrl = doc.data().callback;
                                buttonRow.style.display = "block";
                            }
                        }
                        if ("approved" in doc.data()) {
                            if (!approvalReceived) {
                                const approved = doc.data().approved;
                                console.log("Approval received = ", approved);
                                if (approved) {
                                    validationAlert.open = true;
                                    buttonRow.style.display = "none";
                                    newBtn.style.display = "inline-block";   
                                } else {
                                    rejectionAlert.open = true;
                                    buttonRow.style.display = "none";
                                    newBtn.style.display = "inline-block";
                                }
                                approvalReceived = true;
                            }
                        }
                    }
                });
            } catch (e) {
                console.log(e);
            }
            event.target.loading = false;
        });
    
        validateBtn.addEventListener("sl-focus", async event => {
            validateBtn.disabled = true;
            rejectBtn.disabled = true;
            validateBtn.loading = true;
            validateBtn.blur();
    
            // call callback
            await callCallbackUrl(callbackUrl, true);
        });
    
        rejectBtn.addEventListener("sl-focus", async event => {
            rejectBtn.disabled = true;
            validateBtn.disabled = true;
            rejectBtn.loading = true;
            rejectBtn.blur();
    
            // call callback
            await callCallbackUrl(callbackUrl, false);
        });
    
    });
    
    async function callCallbackUrl(url, approved) {
        console.log("Calling callback URL with status = ", approved);
    
        const fnUrl = UPDATE_ME;
        try {
            const resp = await fetch(fnUrl, {
                method: "POST",
                headers: {
                    "accept": "application/json",
                    "content-type": "application/json"
                },
                body: JSON.stringify({ url, approved })
            });
            const result = await resp.json();
            console.log("Callback answer = ", result);
        } catch(e) {
            console.log(e);
        }
    }
  4. Modifiez le fichier script.js en remplaçant les espaces réservés UPDATE_ME par les URL de fonction Cloud Run que vous avez notées précédemment.

    1. Dans la méthode translateBtn.addEventListener, remplacez const fnUrl = UPDATE_ME; par:

      const fnUrl = "https://REGION-PROJECT_ID.cloudfunctions.net/invokeTranslationWorkflow";

    2. Dans la fonction callCallbackUrl, remplacez const fnUrl = UPDATE_ME; par:

      const fnUrl = "https://REGION-PROJECT_ID.cloudfunctions.net/translationCallbackCall";

  5. Créez un fichier texte avec le nom de fichier style.css contenant les styles en cascade suivants:

    * {
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
    }
    
    body {
        margin: 20px;
    }
    
    h1, h2, h3, h4 {
        color: #0ea5e9;
    }
    

Ajouter Firebase à votre application Web

Dans ce tutoriel, la page HTML, le script JavaScript et la feuille de style CSS sont déployés en tant qu'éléments statiques à l'aide de Firebase Hosting, mais ils peuvent être hébergés n'importe où et diffusés localement sur votre propre machine à des fins de test.

Créer un projet Firebase

Avant de pouvoir ajouter Firebase à votre application, vous devez créer un projet Firebase pour vous connecter à votre application.

  1. Dans la console Firebase : cliquez sur Créer un projet, puis sélectionnez Projet Google Cloud dans le menu déroulant pour ajouter Firebase des ressources à ce projet.

  2. Cliquez sur Continue (Continuer) jusqu'à ce que l'option permettant d'ajouter Firebase soit affichée.

  3. Ignorez la configuration de Google Analytics pour votre projet.

  4. Cliquez sur Ajouter Firebase :

Firebase provisionne automatiquement des ressources pour votre projet Firebase. Une fois le processus terminé, vous êtes redirigé vers la page de présentation de votre projet dans la console Firebase.

Enregistrer votre application auprès de Firebase

Une fois que vous avez créé un projet Firebase, vous pouvez y ajouter votre application Web.

  1. Au centre de la page de présentation du projet, cliquez sur l'icône Web (</>) pour lancer le workflow de configuration.

  2. Saisissez un pseudo pour votre application.

    Il n'est visible que par vous dans la console Firebase.

  3. Ignorez la configuration de Firebase Hosting pour le moment.

  4. Cliquez sur Enregistrer l'application et accédez à la console.

Activer Cloud Firestore

L'application Web utilise Cloud Firestore pour recevoir et enregistrer des données. Vous devez activer Cloud Firestore.

  1. Dans la section Build de la console Firebase, cliquez sur Firestore Database (Base de données Firestore).

    (Vous devrez peut-être d'abord développer le volet de navigation de gauche pour afficher la section Build.)

  2. Dans le volet Cloud Firestore, cliquez sur Créer une base de données.

  3. Sélectionnez Commencer en mode test à l'aide d'une règle de sécurité semblable à celle-ci:

    rules_version = '2';
    service cloud.firestore {
    match /databases/{database}/documents {
      match /{document=**} {
        allow read, write;
      }
    }
    }
  4. Cliquez sur Suivant après avoir lu la clause de non-responsabilité concernant les règles de sécurité.

  5. Définissez l'emplacement de stockage de vos données Cloud Firestore. Vous pouvez accepter la valeur par défaut ou choisir une région proche de vous.

  6. Cliquez sur Activer pour provisionner Firestore.

Ajouter le SDK Firebase et initialiser Firebase

Firebase fournit des bibliothèques JavaScript pour la plupart des produits Firebase. Avant d'utiliser Firebase Hosting, vous devez ajouter les SDK Firebase à votre application Web.

  1. Pour initialiser Firebase dans votre application, vous devez fournir la configuration du projet Firebase de votre application.
    1. Dans la console Firebase, accédez à vos Paramètres du projet .
    2. Dans le volet Vos applications, sélectionnez votre application.
    3. Dans le volet Configuration du SDK, sélectionnez CDN pour charger les bibliothèques du SDK Firebase à partir du CDN.
    4. Copiez l'extrait dans le fichier index.html au bas du tag <body>, en remplaçant les valeurs de l'espace réservé XXXX.
  2. Installez le SDK Firebase JavaScript.

    1. Si vous n'avez pas encore de fichier package.json, créez-en un en exécutant la commande suivante à partir du répertoire callback-translation:

      npm init
    2. Installez le package npm firebase et enregistrez-le dans votre fichier package.json en exécutant la commande suivante:

      npm install --save firebase

Initialiser et déployer votre projet

Pour connecter vos fichiers de projet local à votre projet Firebase, vous devez initialiser votre projet. Vous pouvez ensuite déployer votre application Web.

  1. Depuis le répertoire callback-translation, exécutez la commande suivante :

    firebase init
  2. Cochez l'option Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys.

  3. Choisissez un projet existant et saisissez votre ID de projet.

  4. Acceptez public en tant que répertoire racine public par défaut.

  5. Configurez une application monopage.

  6. Ignorez la configuration des builds et des déploiements automatiques avec GitHub.

  7. À l'invite File public/index.html already exists. Overwrite?, saisissez Non.

  8. Accédez au répertoire public :

    cd public
  9. Dans le répertoire public, exécutez la commande suivante pour déployer votre projet sur votre site:

    firebase deploy --only hosting

Tester l'application Web localement

Firebase Hosting vous permet d'afficher et de tester les modifications en local et interagir avec les ressources du projet backend émulé. Lorsque vous utilisez firebase serve, votre application interagit avec un backend émulé pour votre contenu et votre configuration d'hébergement, mais votre backend réel pour toutes les autres ressources de projet. Pour ce tutoriel, vous pouvez utiliser firebase serve, mais cette approche n'est pas recommandée lorsque vous effectuez des tests plus approfondis.

  1. Depuis le répertoire public, exécutez la commande suivante :

    firebase serve
  2. Ouvrez votre application Web à l'URL locale renvoyée (généralement http://localhost:5000).

  3. Saisissez du texte en anglais, puis cliquez sur Traduire.

    Une traduction du texte en français doit s'afficher.

  4. Vous pouvez désormais cliquer sur Valider ou Refuser.

    Dans la base de données Firestore, vous pouvez vérifier le contenu. Celles-ci se présentent comme suit :

    approved: true
    callback: "https://workflowexecutions.googleapis.com/v1/projects/26811016474/locations/us-central1/workflows/translation_validation/executions/68bfce75-5f62-445f-9cd5-eda23e6fa693/callbacks/72851c97-6bb2-45e3-9816-1e3dcc610662_1a16697f-6d90-478d-9736-33190bbe222b"
    text: "The quick brown fox jumps over the lazy dog."
    translation: "Le renard brun rapide saute par-dessus le chien paresseux."
    

    L'état approved est true ou false selon que vous validez ou refusez la traduction.

Félicitations ! Vous avez créé un workflow de traduction avec intervention humaine qui utilise des rappels Workflows.

Effectuer un nettoyage

Si vous avez créé un projet pour ce tutoriel, supprimez-le. Si vous avez utilisé un projet existant et que vous souhaitez le conserver sans les modifications du présent tutoriel, supprimez les ressources créées pour ce tutoriel.

Supprimer le projet

Le moyen le plus simple d'empêcher la facturation est de supprimer le projet que vous avez créé pour ce tutoriel.

Pour supprimer le projet :

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Supprimer les ressources du tutoriel

  1. Supprimez la configuration par défaut de la gcloud CLI que vous avez ajoutée lors de l'atelier configuration du tutoriel:

    gcloud config unset workflows/location
  2. Supprimez le workflow créé dans ce tutoriel :

    gcloud workflows delete WORKFLOW_NAME
  3. Supprimez les fonctions Cloud Run que vous avez créées dans ce tutoriel:

    gcloud functions delete FUNCTION_NAME

    Vous pouvez également supprimer des fonctions Cloud Run à partir de la console Google Cloud.

Étape suivante