Crie um fluxo de trabalho com intervenção humana através de callbacks


Este tutorial mostra-lhe como criar um fluxo de trabalho de tradução que aguarda a sua entrada, ou seja, a intervenção humana, e que liga uma base de dados do Firestore, duas funções do Cloud Run, a API Cloud Translation e uma página Web que usa o SDK do Firebase para atualizar em tempo real.

Com os fluxos de trabalho, pode suportar um ponto final de retorno de chamada (ou webhook) que aguarda que os pedidos HTTP cheguem a esse ponto final, retomando a execução do fluxo de trabalho num momento posterior. Neste caso, o fluxo de trabalho aguarda a sua entrada para rejeitar ou validar a tradução de algum texto, mas também pode aguardar um processo externo. Para mais informações, consulte a secção Aguarde através de callbacks.

Arquitetura

Este tutorial cria uma app Web que lhe permite fazer o seguinte:

  1. Na página Web de tradução, introduza o texto que quer traduzir de inglês para francês. Clique em Traduzir.
  2. A partir da página Web, é chamada uma função do Cloud Run que inicia a execução do fluxo de trabalho. O texto a traduzir é transmitido como um parâmetro tanto à função como ao fluxo de trabalho.
  3. O texto é guardado numa base de dados do Cloud Firestore. A Cloud Translation API é invocada. A tradução devolvida é armazenada na base de dados. A app Web é implementada através do Firebase Hosting e é atualizada em tempo real para apresentar o texto traduzido.
  4. O passo create_callback no fluxo de trabalho cria um URL do ponto final de retorno de chamada que também é guardado na base de dados do Firestore. A página Web apresenta agora um botão Validar e um botão Rejeitar.
  5. O fluxo de trabalho está agora pausado e aguarda um pedido HTTP POST explícito para o URL do ponto final de retorno de chamada.
  6. Pode decidir se quer validar ou rejeitar a tradução. Quando um utilizador clica num botão, é chamada uma segunda função do Cloud Run que, por sua vez, chama o ponto final de retorno de chamada criado pelo fluxo de trabalho, transmitindo o estado de aprovação. O fluxo de trabalho retoma a execução e guarda um estado de aprovação de true ou false na base de dados do Firestore.

Este diagrama oferece uma vista geral do processo:

Fluxo de trabalho com chamada de retorno

Objetivos

  • Implemente uma app Web.
  • Crie uma base de dados do Firestore para armazenar pedidos de tradução.
  • Implemente funções do Cloud Run para executar o fluxo de trabalho.
  • Implemente e execute um fluxo de trabalho para orquestrar todo o processo.

Custos

Neste documento, usa os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custos com base na sua utilização projetada, use a calculadora de preços.

Os novos Google Cloud utilizadores podem ser elegíveis para uma avaliação gratuita.

Antes de começar

As restrições de segurança definidas pela sua organização podem impedir a conclusão dos seguintes passos. Para informações de resolução de problemas, consulte o artigo Desenvolva aplicações num ambiente Google Cloud restrito.

  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. Se estiver a usar um fornecedor de identidade (IdP) externo, primeiro, tem de iniciar sessão na CLI gcloud com a sua identidade federada.

  4. Para inicializar a CLI gcloud, execute o seguinte comando:

    gcloud init
  5. 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.

  6. Verify that billing is enabled for your Google Cloud project.

  7. 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
  8. Install the Google Cloud CLI.

  9. Se estiver a usar um fornecedor de identidade (IdP) externo, primeiro, tem de iniciar sessão na CLI gcloud com a sua identidade federada.

  10. Para inicializar a CLI gcloud, execute o seguinte comando:

    gcloud init
  11. 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.

  12. Verify that billing is enabled for your Google Cloud project.

  13. 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
  14. Atualize os componentes da CLI do Google Cloud:
    gcloud components update
  15. Inicie sessão com a sua conta:
    gcloud auth login
  16. Defina o ID do projeto e a localização predefinida usados neste tutorial:
    export GOOGLE_CLOUD_PROJECT=PROJECT_ID
    export REGION=REGION
    gcloud config set workflows/location ${REGION}

    Substitua o seguinte:

    • PROJECT_ID: o ID do seu Google Cloud projeto. Pode encontrar o ID do projeto na página Boas-vindas da consola Google Cloud .
    • REGION: a localização dos fluxos de trabalho suportados à sua escolha.

  17. Implemente a primeira função do Cloud Run

    Esta função do Cloud Run inicia a execução do fluxo de trabalho. O texto a traduzir é transmitido como um parâmetro tanto para a função como para o fluxo de trabalho.

    1. Crie um diretório denominado callback-translation e com subdiretórios denominados invokeTranslationWorkflow,translationCallbackCall e public:

      mkdir -p ~/callback-translation/{invokeTranslationWorkflow,translationCallbackCall,public}
    2. Altere para o diretório invokeTranslationWorkflow:

      cd ~/callback-translation/invokeTranslationWorkflow
    3. Crie um ficheiro de texto com o nome de ficheiro index.js que contenha o seguinte código Node.js:

      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. Crie um ficheiro de texto com o nome package.json que contenha os seguintes metadados npm:

      {
        "name": "launch-translation-workflow",
        "version": "0.0.1",
        "dependencies": {
          "@google-cloud/workflows": "^1.2.5",
          "cors": "^2.8.5"
        }
      }
      
    5. Implemente a função com um acionador HTTP e permita o acesso não autenticado:

      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

      A implementação da função pode demorar alguns minutos. Em alternativa, pode usar a interface de funções do Cloud Run na Google Cloud consola para implementar a função.

    6. Depois de implementar a função, pode confirmar a propriedade httpsTrigger.url:

      gcloud functions describe invokeTranslationWorkflow

      Anote o URL devolvido para o poder usar num passo posterior.

    Implemente a segunda função do Cloud Run

    Esta função do Cloud Run faz um pedido HTTP POST ao ponto final de retorno de chamada criado pelo fluxo de trabalho, transmitindo um estado de aprovação que reflete se a tradução é validada ou rejeitada.

    1. Altere para o diretório translationCallbackCall:

      cd ../translationCallbackCall
    2. Crie um ficheiro de texto com o nome de ficheiro index.js que contenha o seguinte código Node.js:

      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. Crie um ficheiro de texto com o nome package.json que contenha os seguintes metadados npm:

      {
        "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. Implemente a função com um acionador HTTP e permita o acesso não autenticado:

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

      A implementação da função pode demorar alguns minutos. Em alternativa, pode usar a interface de funções do Cloud Run na Google Cloud consola para implementar a função.

    5. Depois de implementar a função, pode confirmar a propriedade httpsTrigger.url:

      gcloud functions describe translationCallbackCall

      Anote o URL devolvido para o poder usar num passo posterior.

    Implemente o fluxo de trabalho

    Um fluxo de trabalho é composto por uma série de passos descritos através da sintaxe Workflows, que pode ser escrita no formato YAML ou JSON. Esta é a definição do fluxo de trabalho. Depois de criar um fluxo de trabalho, implementa-o para o disponibilizar para execução.

    1. Altere para o diretório callback-translation:

      cd ..
    2. Crie um ficheiro de texto com o nome de ficheiro translation-validation.yaml e com o seguinte conteúdo:

      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. Depois de criar o fluxo de trabalho, pode implementá-lo, mas não execute o fluxo de trabalho:

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

    Crie a sua app Web

    Crie uma app Web que chame uma função da nuvem que inicie a execução do fluxo de trabalho. A página Web é atualizada em tempo real para apresentar o resultado do pedido de tradução.

    1. Altere para o diretório public:

      cd public
    2. Crie um ficheiro de texto com o nome de ficheiro index.html que contenha a seguinte marcação HTML. (Num passo posterior, vai modificar o ficheiro index.html e adicionar os scripts do 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. Crie um ficheiro de texto com o nome de ficheiro script.js que contenha o seguinte código JavaScript:

      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. Edite o ficheiro script.js, substituindo os marcadores de posição UPDATE_ME pelos URLs das funções do Cloud Run que anotou anteriormente.

      1. No método translateBtn.addEventListener, substitua const fnUrl = UPDATE_ME; por:

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

      2. Na função callCallbackUrl, substitua const fnUrl = UPDATE_ME; por:

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

    5. Crie um ficheiro de texto com o nome de ficheiro style.css que contenha os seguintes estilos em cascata:

      * {
          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;
      }
      

    Adicione o Firebase à sua app Web

    Neste tutorial, a página HTML, o script JavaScript e a folha de estilos CSS são implementados como recursos estáticos através do Firebase Hosting, mas podem ser alojados em qualquer lugar e publicados localmente na sua própria máquina para fins de teste.

    Crie um projeto do Firebase

    Antes de poder adicionar o Firebase à sua app, tem de criar um projeto do Firebase para associar à sua app.

    1. Na consola do Firebase, clique em Criar um projeto e, de seguida, selecione o seu Google Cloud projeto existente no menu pendente para adicionar recursos do Firebase a esse projeto.

    2. Clique em Continuar até ver a opção para adicionar o Firebase.

    3. Ignorar a configuração do Google Analytics para o seu projeto.

    4. Clique em Adicionar Firebase.

    O Firebase aprovisiona automaticamente recursos para o seu projeto do Firebase. Quando o processo estiver concluído, acede à página de vista geral do seu projeto na consola do Firebase.

    Registe a sua app no Firebase

    Depois de ter um projeto do Firebase, pode adicionar a sua app para a Web ao projeto.

    1. No centro da página de vista geral do projeto, clique no ícone Web (</>) para iniciar o fluxo de trabalho de configuração.

    2. Introduza uma alcunha para a sua app.

      Isto só é visível para si na consola do Firebase.

    3. Ignore a configuração do Firebase Hosting por agora.

    4. Clique em Registar app e continue para a consola.

    Ative o Cloud Firestore

    A app Web usa o Cloud Firestore para receber e guardar dados. Tem de ativar o Cloud Firestore.

    1. Na secção Compilar da consola do Firebase, clique em Base de dados do Firestore.

      (Pode ter de expandir primeiro o painel de navegação do lado esquerdo para ver a secção Criar.)

    2. No painel do Cloud Firestore, clique em Criar base de dados.

    3. Selecione Iniciar no modo de teste, usando uma regra de segurança como a seguinte:

      rules_version = '2';
      service cloud.firestore {
      match /databases/{database}/documents {
        match /{document=**} {
          allow read, write;
        }
      }
      }
    4. Clique em Seguinte depois de ler a exclusão de responsabilidade acerca das regras de segurança.

    5. Defina a localização onde os seus dados do Cloud Firestore são armazenados. Pode aceitar a predefinição ou escolher uma região perto de si.

    6. Clique em Ativar para aprovisionar o Firestore.

    Adicione o SDK do Firebase e inicialize o Firebase

    O Firebase fornece bibliotecas JavaScript para a maioria dos produtos do Firebase. Antes de usar o Firebase Hosting, tem de adicionar os SDKs do Firebase à sua app Web.

    1. Para inicializar o Firebase na sua app, tem de fornecer a configuração do projeto do Firebase da app.
      1. Na consola do Firebase, aceda às Definições do projeto .
      2. No painel As suas apps, selecione a sua app.
      3. No painel Configuração e configuração do SDK, para carregar bibliotecas do SDK do Firebase a partir da RFC, selecione RFC.
      4. Copie o fragmento para o ficheiro index.html na parte inferior da etiqueta <body>, substituindo os valores dos marcadores de posição XXXX.
    2. Instale o SDK Firebase JavaScript.

      1. Se ainda não tiver um ficheiro package.json, crie um executando o seguinte comando a partir do diretório callback-translation:

        npm init
      2. Instale o pacote npm firebase e guarde-o no ficheiro package.json executando:

        npm install firebase

    Inicialize e implemente o seu projeto

    Para associar os ficheiros do projeto local ao projeto do Firebase, tem de inicializar o projeto. Em seguida, pode implementar a sua app Web.

    1. No diretório callback-translation, execute o seguinte comando:

      firebase init
    2. Selecione a opção Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys.

    3. Opte por usar um projeto existente e introduza o ID do projeto.

    4. Aceite public como o diretório raiz público predefinido.

    5. Opte por configurar uma app de página única.

    6. Evite a configuração de compilações e implementações automáticas com o GitHub.

    7. Na mensagem File public/index.html already exists. Overwrite?, escreva Não.

    8. Altere para o diretório public:

      cd public
    9. No diretório public, execute o seguinte comando para implementar o seu projeto no site:

      firebase deploy --only hosting

    Teste a app Web localmente

    O Firebase Hosting permite-lhe ver e testar alterações localmente e interagir com recursos de projetos de back-end emulados. Quando usa firebase serve, a sua app interage com um back-end emulado para o conteúdo e a configuração de alojamento, mas com o seu back-end real para todos os outros recursos do projeto. Para este tutorial, pode usar firebase serve, mas não é recomendado quando faz testes mais extensivos.

    1. No diretório public, execute o seguinte comando:

      firebase serve
    2. Abra a sua app Web no URL local devolvido (normalmente, http://localhost:5000).

    3. Introduza algum texto em inglês e, de seguida, clique em Traduzir.

      Deve ser apresentada uma tradução do texto em francês.

    4. Agora, pode clicar em Validar ou Rejeitar.

      Na base de dados do Firestore, pode verificar o conteúdo. Deve ser semelhante ao seguinte:

      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."
      

      O estado approved é true ou false, consoante valide ou rejeite a tradução.

    Parabéns! Criou um fluxo de trabalho de tradução com intervenção humana que usa callbacks dos fluxos de trabalho.

    Limpar

    Se criou um novo projeto para este tutorial, elimine o projeto. Se usou um projeto existente e quer mantê-lo sem as alterações adicionadas neste tutorial, elimine os recursos criados para o tutorial.

    Elimine o projeto

    A forma mais fácil de eliminar a faturação é eliminar o projeto que criou para o tutorial.

    Para eliminar o projeto:

    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.

    Elimine recursos de tutoriais

    1. Remova a configuração predefinida da CLI gcloud que adicionou durante a configuração do tutorial:

      gcloud config unset workflows/location
    2. Elimine o fluxo de trabalho criado neste tutorial:

      gcloud workflows delete WORKFLOW_NAME
    3. Elimine as funções do Cloud Run que criou neste tutorial:

      gcloud functions delete FUNCTION_NAME

      Também pode eliminar funções do Cloud Run a partir da Google Cloud consola.

    O que se segue?