Crea un flujo de trabajo con interacción humana mediante devoluciones de llamada


En este instructivo, se muestra cómo crear un flujo de trabajo de traducción que espere tu entrada (la interacción humana) y que conecte una base de datos de Firestore, dos Cloud Functions, la API de Cloud Translation y una página web que use el SDK de Firebase para actualizar en tiempo real.

Con Workflows, puedes admitir un extremo de devolución de llamada (o webhook) que espera a que las solicitudes HTTP lleguen a ese extremo y reanuda la ejecución del flujo de trabajo más adelante. En este caso, el flujo de trabajo espera a que la entrada rechace o valide la traducción de algún texto, pero también podría esperar un proceso externo. Para obtener más información, consulta Espera con devoluciones de llamada.

Arquitectura

En este instructivo, se crea una app web que te permite hacer lo siguiente:

  1. En la página web de traducción, ingresa el texto que deseas traducir del inglés al francés. Haz clic en Traducir.
  2. Desde la página web, se llama a una función de Cloud Functions que inicia la ejecución del flujo de trabajo. El texto que se traducirá se pasa como parámetro a la función y al flujo de trabajo.
  3. El texto se guarda en una base de datos de Cloud Firestore. API de Cloud Translation. La traducción que se muestra se almacena en la base de datos. La app web se implementa mediante Firebase Hosting y se actualiza en tiempo real para mostrar el texto traducido.
  4. El paso create_callback del flujo de trabajo crea una URL de extremo de devolución de llamada que también se guarda en la base de datos de Firestore. En la página web, ahora se muestran los botones Validar y Rechazar.
  5. El flujo de trabajo ahora está en pausa y espera una solicitud HTTP POST explícita a la URL del extremo de devolución de llamada.
  6. Puedes validar o rechazar la traducción. Cuando haces clic en un botón, se llama a una segunda Cloud Function que, a su vez, llama al extremo de devolución de llamada que creó el flujo de trabajo y pasa el estado de aprobación. El flujo de trabajo reanuda su ejecución y guarda un estado de aprobación de true o false en la base de datos de Firestore.

En este diagrama, se proporciona una descripción general del proceso:

Flujo de trabajo con devolución de llamada

Objetivos

  • Implementar una app web
  • Crear una base de datos de Firestore para almacenar solicitudes de traducción
  • Implementar Cloud Functions para ejecutar el flujo de trabajo
  • Implementar y ejecutar un flujo de trabajo para organizar todo el proceso

Costos

En este documento, usarás los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios. Es posible que los usuarios nuevos de Google Cloud califiquen para obtener una prueba gratuita.

Antes de comenzar

Es posible que las restricciones de seguridad que define tu organización no te permitan completar los siguientes pasos. Para obtener información sobre la solución de problemas, consulta Desarrolla aplicaciones en un entorno de Google Cloud restringido.

  1. Accede a tu cuenta de Google Cloud. Si eres nuevo en Google Cloud, crea una cuenta para evaluar el rendimiento de nuestros productos en situaciones reales. Los clientes nuevos también obtienen $300 en créditos gratuitos para ejecutar, probar y, además, implementar cargas de trabajo.
  2. Instala Google Cloud CLI.
  3. Para inicializar la CLI de gcloud, ejecuta el siguiente comando:

    gcloud init
  4. Crea o selecciona un proyecto de Google Cloud.

    • Crea un proyecto de Google Cloud:

      gcloud projects create PROJECT_ID

      Reemplaza PROJECT_ID por un nombre para el proyecto de Google Cloud que estás creando.

    • Selecciona el proyecto de Google Cloud que creaste:

      gcloud config set project PROJECT_ID

      Reemplaza PROJECT_ID por el nombre del proyecto de Google Cloud.

  5. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud.

  6. Habilita las APIs de App Engine, Cloud Build, Cloud Functions, Firestore, Translation, and Workflows :

    gcloud services enable appengine.googleapis.com cloudbuild.googleapis.com cloudfunctions.googleapis.com firestore.googleapis.com translate.googleapis.com workflows.googleapis.com
  7. Instala Google Cloud CLI.
  8. Para inicializar la CLI de gcloud, ejecuta el siguiente comando:

    gcloud init
  9. Crea o selecciona un proyecto de Google Cloud.

    • Crea un proyecto de Google Cloud:

      gcloud projects create PROJECT_ID

      Reemplaza PROJECT_ID por un nombre para el proyecto de Google Cloud que estás creando.

    • Selecciona el proyecto de Google Cloud que creaste:

      gcloud config set project PROJECT_ID

      Reemplaza PROJECT_ID por el nombre del proyecto de Google Cloud.

  10. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud.

  11. Habilita las APIs de App Engine, Cloud Build, Cloud Functions, Firestore, Translation, and Workflows :

    gcloud services enable appengine.googleapis.com cloudbuild.googleapis.com cloudfunctions.googleapis.com firestore.googleapis.com translate.googleapis.com workflows.googleapis.com
  12. Actualiza los componentes de Google Cloud CLI:
    gcloud components update
  13. Accede con tu cuenta:
    gcloud auth login
  14. Configura el ID del proyecto y la ubicación predeterminada que se usa en este instructivo:
    export GOOGLE_CLOUD_PROJECT=PROJECT_ID
    export REGION=REGION
    gcloud config set workflows/location ${REGION}
    

    Reemplaza lo siguiente:

    • PROJECT_ID: tu ID del proyecto de Google Cloud. Puedes encontrar el ID del proyecto en la página Te damos la bienvenida de la consola de Google Cloud.
    • REGION: Es la ubicación de Workflows compatible que elijas.

Implementa la primera Cloud Function

Esta Cloud Function inicia la ejecución del flujo de trabajo. El texto que se traducirá se pasa como parámetro a la función y al flujo de trabajo.

  1. Crea un directorio llamado callback-translation con subdirectorios llamados invokeTranslationWorkflow, translationCallbackCall y public:

    mkdir -p ~/callback-translation/{invokeTranslationWorkflow,translationCallbackCall,public}
    
  2. Cambia al directorio invokeTranslationWorkflow:

    cd ~/callback-translation/invokeTranslationWorkflow
    
  3. Crea un archivo de texto con el nombre de archivo index.js que contenga el siguiente código de 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. Crea un archivo de texto con el nombre de archivo package.json que contenga los siguientes metadatos npm:

    {
      "name": "launch-translation-workflow",
      "version": "0.0.1",
      "dependencies": {
        "@google-cloud/workflows": "^1.2.5",
        "cors": "^2.8.5"
      }
    }
    
  5. Implementa la función con un activador HTTP y permite el acceso sin autenticación:

    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
    

    La función puede tardar unos minutos en implementarse. También puedes usar la interfaz de Cloud Functions en la consola de Google Cloud para implementar la función.

  6. Una vez que se implementa la función, puedes confirmar la propiedad httpsTrigger.url:

    gcloud functions describe invokeTranslationWorkflow
    

    Toma nota de la URL que se muestra para que puedas usarla en un paso posterior.

Implementa la segunda Cloud Function

Esta Cloud Function realiza una solicitud HTTP POST al extremo de devolución de llamada que crea el flujo de trabajo y pasa un estado de aprobación que refleja si la traducción se validó o se rechazó.

  1. Cambia al directorio translationCallbackCall:

    cd ../translationCallbackCall
    
  2. Crea un archivo de texto con el nombre de archivo index.js que contenga el siguiente código de 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. Crea un archivo de texto con el nombre de archivo package.json que contenga los siguientes metadatos 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. Implementa la función con un activador HTTP y permite el acceso sin autenticación:

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

    La función puede tardar unos minutos en implementarse. También puedes usar la interfaz de Cloud Functions en la consola de Google Cloud para implementar la función.

  5. Una vez que se implementa la función, puedes confirmar la propiedad httpsTrigger.url:

    gcloud functions describe translationCallbackCall
    

    Toma nota de la URL que se muestra para que puedas usarla en un paso posterior.

Implementa el flujo de trabajo

Un flujo de trabajo está compuesto por una serie de pasos descritos con la sintaxis de Workflows, que se pueden escribir en formato YAML o JSON. Esta es la definición del flujo de trabajo. Después de crear un flujo de trabajo, debes implementarlo para que esté disponible para su ejecución.

  1. Cambia al directorio callback-translation:

    cd ..
    
  2. Crea un archivo de texto con el nombre de archivo translation-validation.yaml y con el siguiente contenido:

    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. Después de crear el flujo de trabajo, puedes implementarlo, pero no lo ejecutes:

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

Crea tu app web

Crear una app web que llame a una Cloud Function que inicie la ejecución del flujo de trabajo La página web se actualiza en tiempo real para mostrar el resultado de la solicitud de traducción.

  1. Cambia al directorio public:

    cd public
    
  2. Crea un archivo de texto con el nombre de archivo index.html que contenga el siguiente lenguaje de marcado HTML. En un paso posterior, modificarás el archivo index.html y agregarás las secuencias de comandos del SDK de 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. Crea un archivo de texto con el nombre de archivo script.js que contenga el siguiente 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. Edita el archivo script.js y reemplaza los marcadores de posición UPDATE_ME por las URLs de Cloud Functions que anotaste antes.

    1. En el método translateBtn.addEventListener, reemplaza const fnUrl = UPDATE_ME; por lo siguiente:

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

    2. En la función callCallbackUrl, reemplaza const fnUrl = UPDATE_ME; por lo siguiente:

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

  5. Crea un archivo de texto con el nombre de archivo style.css que contenga los siguientes estilos en cascada:

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

Agregue Firebase a su aplicación web

En este instructivo, la página HTML, la secuencia de comandos de JavaScript y la hoja de estilo de CSS se implementan como recursos estáticos con Firebase Hosting, pero se pueden alojar en cualquier lugar y entregarse de forma local en tu propia máquina para realizar pruebas.

Crea un proyecto de Firebase

Antes de que puedas agregar Firebase a tu app, debes crear un proyecto de Firebase y conectarlo a ella.

  1. En Firebase console, haz clic en Crear un proyecto y, luego, selecciona tu proyecto de Google Cloud existente en el menú desplegable para agregar recursos de Firebase a ese proyecto.

  2. Haz clic en Continuar hasta que veas la opción para agregar Firebase.

  3. Omite la configuración de Google Analytics para tu proyecto.

  4. Haz clic en Agregar Firebase:

Firebase aprovisiona los recursos para tu proyecto de forma automática. Cuando finalice, verás la página de descripción general del proyecto en Firebase console.

Registra tu app en Firebase

Cuando tengas un proyecto de Firebase, podrás agregarle tu app web.

  1. En el centro de la página de descripción general del proyecto, haz clic en el ícono de Web (</>) para iniciar el flujo de trabajo de configuración.

  2. Ingresa un sobrenombre para la app.

    Solo tú podrás verlo en Firebase console.

  3. Omite la configuración de Firebase Hosting por ahora.

  4. Haz clic en Registrar app y ve a la consola.

Habilite Cloud Firestore

La aplicación web usa Cloud Firestore para recibir y guardar datos. Deberás habilitar Cloud Firestore.

  1. En la sección Compilación de Firebase console, haz clic en Base de datos de Firestore.

    (es posible que primero debas expandir el panel de navegación izquierdo para ver la sección Build).

  2. En el panel Cloud Firestore, haz clic en Crear base de datos.

  3. Selecciona Comenzar en modo de prueba con una regla de seguridad como la siguiente:

    rules_version = '2';
    service cloud.firestore {
    match /databases/{database}/documents {
      match /{document=**} {
        allow read, write;
      }
    }
    }
    
  4. Haz clic en Siguiente después de leer la renuncia de responsabilidad sobre las reglas de seguridad.

  5. Configura la ubicación en la que se almacenan tus datos de Cloud Firestore. Puedes aceptar el valor predeterminado o elegir una región cercana.

  6. Haz clic en Habilitar para aprovisionar Firestore.

Agrega el SDK de Firebase y, luego, inicializa Firebase

Firebase proporciona bibliotecas de JavaScript para la mayoría de los productos de Firebase. Antes de usar Firebase Hosting, debes agregar los SDK de Firebase a tu app web.

  1. Para inicializar Firebase en tu app, debes proporcionar la configuración del proyecto de Firebase de tu app.
    1. En Firebase console, ve a Configuración del proyecto .
    2. En el panel Tus apps, selecciona tu app.
    3. En el panel Configuración del SDK, selecciona CDN para cargar las bibliotecas del SDK de Firebase desde la CDN.
    4. Copia el fragmento en tu archivo index.html en la parte inferior de la etiqueta <body> y reemplaza los valores del marcador de posición XXXX.
  2. Instala el SDK de Firebase JavaScript.

    1. Si aún no tienes un archivo package.json, ejecuta el siguiente comando desde el directorio callback-translation para crear uno:

      npm init
    2. Instala el paquete de npm firebase y guárdalo en tu archivo package.json ejecutando lo siguiente:

      npm install --save firebase

Inicializa y, luego, implementa tu proyecto

Para conectar los archivos del proyecto local al proyecto de Firebase, debes inicializar el proyecto. Luego, puedes implementar tu app web.

  1. Desde el directorio callback-translation, ejecuta el siguiente comando:

    firebase init
  2. Selecciona la opción Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys.

  3. Elige usar un proyecto existente y, luego, ingresa el ID del proyecto.

  4. Acepta public como el directorio raíz público predeterminado.

  5. Opta por configurar una app de una sola página.

  6. Omite la configuración de implementaciones y compilaciones automáticas con GitHub.

  7. En el mensaje File public/index.html already exists. Overwrite?, escribe No.

  8. Cambia al directorio public:

    cd public
  9. Desde el directorio public, ejecuta el siguiente comando para implementar el proyecto en el sitio:

    firebase deploy --only hosting

Prueba la app web de manera local

Firebase Hosting te permite ver y probar los cambios de forma local y, además, interactuar con los recursos del proyecto de backend emulado. Cuando usas firebase serve, tu app interactúa con un backend emulado para el contenido y la configuración de hosting, pero con tu backend real para todos los demás recursos del proyecto. Para este instructivo, puedes usar firebase serve, pero no se recomienda cuando se realizan pruebas más extensas.

  1. Desde el directorio public, ejecuta el siguiente comando:

    firebase serve
  2. Abre la aplicación web en la URL local que se muestra (por lo general, http://localhost:5000).

  3. Ingresa el texto en inglés y, luego, haz clic en Traducir.

    Se debe mostrar una traducción del texto en francés.

  4. Ahora puedes hacer clic en Validar o Rechazar.

    En la base de datos de Firestore, puedes verificar el contenido. Debería parecerse a lo siguiente:

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

    El estado approved es true o false, dependiendo de si validas o rechazas la traducción.

¡Felicitaciones! Creaste un flujo de trabajo de traducción con interacción humana que usa devoluciones de llamada de Workflows.

Limpia

Si creaste un proyecto nuevo para este instructivo, bórralo. Si usaste un proyecto existente y deseas conservarlo sin los cambios que se agregaron en este instructivo, borra los recursos creados para el instructivo.

Borra el proyecto

La manera más fácil de eliminar la facturación es borrar el proyecto que creaste para el instructivo.

Para borrar el proyecto, haz lo siguiente:

  1. En la consola de Google Cloud, ve a la página Administrar recursos.

    Ir a Administrar recursos

  2. En la lista de proyectos, elige el proyecto que quieres borrar y haz clic en Borrar.
  3. En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrar el proyecto.

Elimina recursos de instructivos

  1. Quita la configuración predeterminada de gcloud CLI que agregaste durante la configuración del instructivo:

    gcloud config unset workflows/location
    
  2. Borra el flujo de trabajo que se creó en este instructivo:

    gcloud workflows delete WORKFLOW_NAME
    
  3. Borra las funciones de Cloud Functions que creaste en este instructivo:

    gcloud functions delete FUNCTION_NAME
    

    También puedes borrar funciones de Cloud Functions en la consola de Google Cloud.

¿Qué sigue?