Human-in-the-Loop-Workflow mit Callbacks erstellen


In dieser Anleitung erfahren Sie, wie Sie einen Übersetzungsworkflow erstellen, der auf Sie – den Human in the Loop – und Ihre Eingabe wartet, und der eine Firestore-Datenbank, zwei Cloud Functions-Funktionen, die Cloud Translation API und eine Webseite verbindet, die das Firebase SDK nutzt, um in Echtzeit eine Aktualisierung durchzuführen.

Mit Workflows können Sie einen Callback-Endpunkt (oder Webhook) unterstützen, der darauf wartet, dass HTTP-Anfragen an diesem Endpunkt ankommen, und die Ausführung des Workflows zu einem späteren Zeitpunkt fortsetzt. In diesem Fall wartet der Workflow auf die Ablehnung oder Validierung der Übersetzung eines Textes, aber es könnte auch ein externer Prozess sein. Weitere Informationen finden Sie unter Mit Callbacks warten.

Architektur

In dieser Anleitung wird eine Webanwendung erstellt, mit der Sie Folgendes tun können:

  1. Geben Sie auf der Übersetzungswebseite den Text ein, der vom Englischen ins Französische übersetzt werden soll. Klicken Sie auf Übersetzen.
  2. Auf der Webseite wird eine Cloud Functions-Funktion aufgerufen, die die Ausführung des Workflows startet. Der zu übersetzende Text wird als Parameter sowohl an die Funktion als auch an den Workflow übergeben.
  3. Der Text wird in einer Cloud Firestore-Datenbank gespeichert. Cloud Translation API aufgerufen wird. Die zurückgegebene Übersetzung wird in der Datenbank gespeichert. Die Webanwendung wird mit Firebase Hosting bereitgestellt und in Echtzeit aktualisiert, um den übersetzten Text anzuzeigen.
  4. Mit dem Schritt create_callback im Workflow wird eine Callback-Endpunkt-URL erstellt, die auch in der Firestore-Datenbank gespeichert wird. Auf der Webseite werden jetzt die Schaltflächen Validieren und Ablehnen angezeigt.
  5. Der Workflow wird jetzt angehalten und wartet auf eine explizite HTTP-POST-Anfrage an die Callback-Endpunkt-URL.
  6. Sie können entscheiden, ob die Übersetzung validiert oder abgelehnt werden soll. Wenn Sie auf eine Schaltfläche klicken, wird eine zweite Cloud Functions-Funktion aufgerufen, die wiederum den vom Workflow erstellten Callback-Endpunkt aufruft und den Genehmigungsstatus übergibt. Der Workflow setzt die Ausführung fort und speichert den Genehmigungsstatus true oder false in der Firestore-Datenbank.

Dieses Diagramm gibt einen Überblick über den Prozess:

Workflow mit Callback

Lernziele

  • Webanwendung bereitstellen
  • Firestore-Datenbank zum Speichern von Übersetzungsanfragen erstellen
  • Cloud Functions zum Ausführen des Workflows bereitstellen
  • Workflow zur Orchestrierung des gesamten Prozesses bereitstellen und ausführen

Kosten

In diesem Dokument verwenden Sie die folgenden kostenpflichtigen Komponenten von Google Cloud:

Mit dem Preisrechner können Sie eine Kostenschätzung für Ihre voraussichtliche Nutzung vornehmen. Neuen Google Cloud-Nutzern steht möglicherweise eine kostenlose Testversion zur Verfügung.

Hinweise

Von Ihrer Organisation definierte Sicherheitsbeschränkungen verhindern möglicherweise, dass die folgenden Schritte ausgeführt werden. Informationen zur Fehlerbehebung finden Sie unter Anwendungen in einer eingeschränkten Google Cloud-Umgebung entwickeln.

  1. Melden Sie sich bei Ihrem Google Cloud-Konto an. Wenn Sie mit Google Cloud noch nicht vertraut sind, erstellen Sie ein Konto, um die Leistungsfähigkeit unserer Produkte in der Praxis sehen und bewerten zu können. Neukunden erhalten außerdem ein Guthaben von 300 $, um Arbeitslasten auszuführen, zu testen und bereitzustellen.
  2. Installieren Sie die Google Cloud CLI.
  3. Führen Sie folgenden Befehl aus, um die gcloud CLI zu initialisieren:

    gcloud init
  4. Google Cloud-Projekt erstellen oder auswählen.

    • Erstellen Sie ein Google Cloud-Projekt:

      gcloud projects create PROJECT_ID

      Ersetzen Sie PROJECT_ID durch einen Namen für das Google Cloud-Projekt, das Sie erstellen.

    • Wählen Sie das von Ihnen erstellte Google Cloud-Projekt aus:

      gcloud config set project PROJECT_ID

      Ersetzen Sie PROJECT_ID durch den Namen Ihres Google Cloud-Projekts.

  5. Die Abrechnung für das Google Cloud-Projekt muss aktiviert sein.

  6. Aktivieren Sie die App Engine, Cloud Build, Cloud 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. Installieren Sie die Google Cloud CLI.
  8. Führen Sie folgenden Befehl aus, um die gcloud CLI zu initialisieren:

    gcloud init
  9. Google Cloud-Projekt erstellen oder auswählen.

    • Erstellen Sie ein Google Cloud-Projekt:

      gcloud projects create PROJECT_ID

      Ersetzen Sie PROJECT_ID durch einen Namen für das Google Cloud-Projekt, das Sie erstellen.

    • Wählen Sie das von Ihnen erstellte Google Cloud-Projekt aus:

      gcloud config set project PROJECT_ID

      Ersetzen Sie PROJECT_ID durch den Namen Ihres Google Cloud-Projekts.

  10. Die Abrechnung für das Google Cloud-Projekt muss aktiviert sein.

  11. Aktivieren Sie die App Engine, Cloud Build, Cloud 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. Aktualisieren Sie die Google Cloud CLI-Komponenten:
    gcloud components update
  13. Melden Sie sich mit Ihrem -Konto an:
    gcloud auth login
  14. Legen Sie die in dieser Anleitung verwendete Projekt-ID und den Standardspeicherort fest:
    export GOOGLE_CLOUD_PROJECT=PROJECT_ID
    export REGION=REGION
    gcloud config set workflows/location ${REGION}
    

    Ersetzen Sie Folgendes:

    • PROJECT_ID ist Ihre Google Cloud-Projekt-ID. Sie finden Ihre Projekt-ID in der Google Cloud Console auf der Willkommensseite.
    • REGION: der Standort Ihrer Wahl für unterstützte Workflows.

Erste Cloud Functions-Funktion bereitstellen

Diese Cloud Functions-Funktion startet die Ausführung des Workflows. Der zu übersetzende Text wird als Parameter sowohl an die Funktion als auch an den Workflow übergeben.

  1. Erstellen Sie ein Verzeichnis namens callback-translation mit den Unterverzeichnissen invokeTranslationWorkflow, translationCallbackCall und public:

    mkdir -p ~/callback-translation/{invokeTranslationWorkflow,translationCallbackCall,public}
    
  2. Wechseln Sie in das Verzeichnis invokeTranslationWorkflow:

    cd ~/callback-translation/invokeTranslationWorkflow
    
  3. Erstellen Sie eine Textdatei mit dem Dateinamen index.js, die den folgenden Node.js-Code enthält:

    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. Erstellen Sie eine Textdatei mit dem Dateinamen package.json, die die folgenden npm-Metadaten enthält:

    {
      "name": "launch-translation-workflow",
      "version": "0.0.1",
      "dependencies": {
        "@google-cloud/workflows": "^1.2.5",
        "cors": "^2.8.5"
      }
    }
    
  5. Stellen Sie die Funktion mit einem HTTP-Trigger bereit und lassen Sie nicht authentifizierten Zugriff zu:

    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
    

    Die Bereitstellung der Funktion kann einige Minuten dauern. Alternativ können Sie die Cloud Functions-Oberfläche in der Google Cloud Console verwenden, um die Funktion bereitzustellen.

  6. Nachdem die Funktion bereitgestellt wurde, können Sie das Attribut httpsTrigger.url bestätigen:

    gcloud functions describe invokeTranslationWorkflow
    

    Notieren Sie sich die zurückgegebene URL, damit Sie sie in einem späteren Schritt verwenden können.

Die zweite Cloud Functions-Funktion bereitstellen

Diese Cloud Functions-Funktion stellt eine HTTP-POST-Anfrage an den vom Workflow erstellten Callback-Endpunkt und übergibt einen Genehmigungsstatus, der angibt, ob die Übersetzung validiert oder abgelehnt wurde.

  1. Wechseln Sie in das Verzeichnis translationCallbackCall:

    cd ../translationCallbackCall
    
  2. Erstellen Sie eine Textdatei mit dem Dateinamen index.js, die den folgenden Node.js-Code enthält:

    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. Erstellen Sie eine Textdatei mit dem Dateinamen package.json, die die folgenden npm-Metadaten enthält:

    {
      "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. Stellen Sie die Funktion mit einem HTTP-Trigger bereit und lassen Sie nicht authentifizierten Zugriff zu:

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

    Die Bereitstellung der Funktion kann einige Minuten dauern. Alternativ können Sie die Cloud Functions-Oberfläche in der Google Cloud Console verwenden, um die Funktion bereitzustellen.

  5. Nachdem die Funktion bereitgestellt wurde, können Sie das Attribut httpsTrigger.url bestätigen:

    gcloud functions describe translationCallbackCall
    

    Notieren Sie sich die zurückgegebene URL, damit Sie sie in einem späteren Schritt verwenden können.

Workflow bereitstellen

Ein Workflow besteht aus einer Reihe von Schritten, die mit der Workflows-Syntax beschrieben werden. Diese kann entweder im YAML- oder JSON-Format geschrieben werden. Dies ist die Definition des Workflows. Nachdem Sie einen Workflow erstellt haben, stellen Sie ihn bereit, um ihn für die Ausführung verfügbar zu machen.

  1. Wechseln Sie in das Verzeichnis callback-translation:

    cd ..
    
  2. Erstellen Sie eine Textdatei mit dem Dateinamen translation-validation.yaml und folgendem Inhalt:

    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. Nachdem Sie den Workflow erstellt haben, können Sie ihn bereitstellen, aber nicht den Workflow ausführen:

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

Webanwendung erstellen

Erstellen Sie eine Webanwendung, die eine Cloud Functions-Funktion aufruft, die die Ausführung des Workflows startet. Die Webseite wird in Echtzeit aktualisiert, um das Ergebnis der Übersetzungsanfrage anzuzeigen.

  1. Wechseln Sie in das Verzeichnis public:

    cd public
    
  2. Erstellen Sie eine Textdatei mit dem Dateinamen index.html, die das folgende HTML-Markup enthält. In einem späteren Schritt ändern Sie die Datei index.html und fügen die Firebase SDK-Skripts hinzu.

    <!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. Erstellen Sie eine Textdatei mit dem Dateinamen script.js, die den folgenden JavaScript-Code enthält:

    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. Bearbeiten Sie die Datei script.js und ersetzen Sie die Platzhalter UPDATE_ME durch die zuvor notierten Cloud Functions-URL-URLs.

    1. Ersetzen Sie in der Methode translateBtn.addEventListener const fnUrl = UPDATE_ME; durch:

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

    2. Ersetzen Sie in der Funktion callCallbackUrl const fnUrl = UPDATE_ME; durch:

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

  5. Erstellen Sie eine Textdatei mit dem Dateinamen style.css, die die folgenden kaskadierenden Stile enthält:

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

Firebase zu meiner Web-App hinzufügen

In dieser Anleitung werden die HTML-Seite, das JavaScript-Skript und das CSS-Stylesheet als statische Assets mit Firebase Hosting bereitgestellt. Sie können jedoch überall gehostet und zu Testzwecken lokal auf Ihrem eigenen Computer bereitgestellt werden.

Firebase-Projekt erstellen

Bevor Sie Firebase zu Ihrer Anwendung hinzufügen können, müssen Sie ein Firebase-Projekt erstellen, um eine Verbindung zu Ihrer Anwendung herzustellen.

  1. Klicken Sie in der Firebase Console auf Projekt erstellen und wählen Sie im Drop-down-Menü das vorhandene Google Cloud-Projekt aus, um diesem Projekt Firebase-Ressourcen hinzuzufügen.

  2. Klicken Sie auf Weiter, bis Sie die Option zum Hinzufügen von Firebase sehen.

  3. Überspringen Sie die Einrichtung von Google Analytics für Ihr Projekt.

  4. Klicken Sie auf Firebase hinzufügen.

Firebase stellt automatisch Ressourcen für Ihr Firebase-Projekt bereit. Nach Abschluss des Vorgangs werden Sie zur Übersichtsseite für Ihr Projekt in der Firebase Console weitergeleitet.

App bei Firebase registrieren

Nachdem Sie ein Firebase-Projekt haben, können Sie Ihre Webanwendung hinzufügen.

  1. Klicken Sie in der Mitte der Projektübersicht auf das Symbol Web (</>), um den Einrichtungsworkflow zu starten.

  2. Geben Sie einen Alias für die Anwendung ein.

    Dieser ist nur in der Firebase Console sichtbar.

  3. Überspringen Sie die Einrichtung von Firebase Hosting.

  4. Klicken Sie auf App registrieren und fahren Sie mit der Konsole fort.

Cloud Firestore aktivieren

Die Webanwendung verwendet Cloud Firestore, um Daten zu empfangen und zu speichern. Sie müssen Cloud Firestore aktivieren.

  1. Klicken Sie im Abschnitt Build in der Firebase Console auf Firestore-Datenbank.

    Möglicherweise müssen Sie zuerst den linken Navigationsbereich erweitern, um den Abschnitt Build einzublenden.

  2. Klicken Sie im Cloud Firestore-Bereich auf Datenbank erstellen.

  3. Wählen Sie Im Testmodus starten mit einer Sicherheitsregel wie der folgenden aus:

    rules_version = '2';
    service cloud.firestore {
    match /databases/{database}/documents {
      match /{document=**} {
        allow read, write;
      }
    }
    }
    
  4. Klicken Sie auf Weiter, nachdem Sie den Haftungsausschluss zu den Sicherheitsregeln gelesen haben.

  5. Legen Sie den Speicherort für Cloud Firestore-Daten fest. Sie können die Standardeinstellung übernehmen oder eine Region in Ihrer Nähe auswählen.

  6. Klicken Sie auf Aktivieren, um Firestore bereitzustellen.

Firebase SDK hinzufügen und Firebase initialisieren

Firebase stellt JavaScript-Bibliotheken für die meisten Firebase-Produkte bereit. Bevor Sie Firebase Hosting verwenden, müssen Sie die Firebase SDKs Ihrer Webanwendung hinzufügen.

  1. Zum Initialisieren von Firebase in Ihrer Anwendung müssen Sie die Firebase-Projektkonfiguration Ihrer Anwendung angeben.
    1. Rufen Sie in der Firebase Console die Projekteinstellungen auf.
    2. Wählen Sie im Bereich Meine Apps Ihre App aus.
    3. Wählen Sie im Bereich SDK-Einrichtung und -Konfiguration die Option CDN aus, um Firebase SDK-Bibliotheken aus dem CDN zu laden.
    4. Kopieren Sie das Snippet in die Datei index.html am Ende des <body>-Tags und ersetzen Sie die Platzhalterwerte XXXX.
  2. Installieren Sie das Firebase JavaScript SDK.

    1. Wenn Sie noch keine package.json-Datei haben, erstellen Sie eine mit dem folgenden Befehl im Verzeichnis callback-translation:

      npm init
    2. Installieren Sie das npm-Paket firebase und speichern Sie es in der package.json-Datei:

      npm install --save firebase

Projekt initialisieren und bereitstellen

Sie müssen Ihr Projekt initialisieren, um Ihre lokalen Projektdateien mit Ihrem Firebase-Projekt zu verbinden. Sie können dann Ihre Webanwendung bereitstellen.

  1. Führen Sie im Verzeichnis callback-translation den folgenden Befehl aus:

    firebase init
  2. Wählen Sie die Option Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys aus.

  3. Verwenden Sie ein vorhandenes Projekt und geben Sie Ihre Projekt-ID ein.

  4. Übernehmen Sie public als standardmäßiges öffentliches Stammverzeichnis.

  5. Konfigurieren Sie eine einseitige App.

  6. Überspringen Sie die Einrichtung automatischer Builds und Bereitstellungen mit GitHub.

  7. Geben Sie bei der Eingabeaufforderung File public/index.html already exists. Overwrite? Nein ein.

  8. Wechseln Sie in das Verzeichnis public:

    cd public
  9. Führen Sie im Verzeichnis public den folgenden Befehl aus, um das Projekt auf Ihrer Website bereitzustellen:

    firebase deploy --only hosting

Webanwendung lokal testen

Mit Firebase Hosting können Sie Änderungen lokal ansehen und testen und mit emulierten Back-End-Projektressourcen interagieren. Wenn Sie firebase serve verwenden, interagiert Ihre Anwendung mit einem emulierten Backend für Ihre Hosting-Inhalte und Ihre Konfiguration, aber Ihr echtes Backend tut dies für alle anderen Projektressourcen. Für diese Anleitung können Sie firebase serve verwenden. Dies wird jedoch nicht empfohlen, wenn Sie umfangreichere Tests durchführen.

  1. Führen Sie im Verzeichnis public den folgenden Befehl aus:

    firebase serve
  2. Öffnen Sie Ihre Webanwendung unter der zurückgegebenen lokalen URL (in der Regel http://localhost:5000).

  3. Geben Sie Text in Englisch ein und klicken Sie dann auf Übersetzen.

    Eine Übersetzung des Textes auf Französisch sollte angezeigt werden.

  4. Sie können jetzt auf Validieren oder Ablehnen klicken.

    In der Firestore-Datenbank können Sie den Inhalt prüfen. Diese sollten in etwa so aussehen:

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

    Der Status approved lautet true oder false, je nachdem, ob Sie die Übersetzung validieren oder ablehnen.

Glückwunsch! Sie haben einen Human-in-the-Loop-Workflow erstellt, der Workflow-Callbacks verwendet.

Bereinigen

Wenn Sie ein neues Projekt für diese Anleitung erstellt haben, löschen Sie das Projekt. Wenn Sie ein vorhandenes Projekt verwendet haben und es beibehalten möchten, ohne die Änderungen in dieser Anleitung hinzuzufügen, löschen Sie die für die Anleitung erstellten Ressourcen.

Projekt löschen

Am einfachsten vermeiden Sie weitere Kosten durch Löschen des für die Anleitung erstellten Projekts.

So löschen Sie das Projekt:

  1. Wechseln Sie in der Google Cloud Console zur Seite Ressourcen verwalten.

    Zur Seite „Ressourcen verwalten“

  2. Wählen Sie in der Projektliste das Projekt aus, das Sie löschen möchten, und klicken Sie dann auf Löschen.
  3. Geben Sie im Dialogfeld die Projekt-ID ein und klicken Sie auf Shut down (Beenden), um das Projekt zu löschen.

Anleitungsressourcen löschen

  1. Entfernen Sie die Standardkonfiguration für die gcloud CLI, die Sie während der Einrichtung der Anleitung hinzugefügt haben:

    gcloud config unset workflows/location
    
  2. Löschen Sie den in dieser Anleitung erstellten Workflow:

    gcloud workflows delete WORKFLOW_NAME
    
  3. Löschen Sie die Cloud Functions-Funktion, die Sie in dieser Anleitung erstellt haben:

    gcloud functions delete FUNCTION_NAME
    

    Sie können Cloud Functions-Funktionen auch über die Google Cloud Console löschen.

Nächste Schritte