Online-Abholung im Geschäft: Bonjour-Mahlzeit – Teil 2 – Einkaufswagen erstellen

1. Einführung

53003251caaf2be5.png 8826bd8cb0c0f1c7.png

Zuletzt aktualisiert:30.10.2020

Einkaufswagen in Business Messages erstellen

Dies ist das zweite Codelab einer Reihe zum Aufbau einer User Journey für die Option „Online kaufen, im Geschäft abholen“. Bei vielen E-Commerce-Pfaden ist ein Einkaufswagen entscheidend, um aus Nutzern zahlende Kunden zu machen. Der Warenkorb bietet Ihnen außerdem die Möglichkeit, Ihre Kunden besser zu verstehen und ihnen Vorschläge zu anderen Artikeln unterbreiten zu können, die sie interessieren könnten. In diesem Codelab konzentrieren wir uns auf die Gestaltung des Einkaufswagens und die Bereitstellung der Anwendung in der Google App Engine.

Was macht einen guten Einkaufswagen aus?

Einkaufswagen sind der Schlüssel zu einem erfolgreichen Online-Shopping. Wie sich herausstellt, ist Business Messages nicht nur gut geeignet, um Fragen und Antworten zu einem Produkt mit potenziellen Kunden zu ermöglichen, sondern kann auch das gesamte Einkaufserlebnis bis hin zum Abschluss einer Zahlung innerhalb des Gesprächs erleichtern.

9d17537b980d0e62.png

Ein gutes Einkaufserlebnis ermöglicht es Nutzern, über einen guten Einkaufswagen hinauszugehen, Artikel nach Kategorie zu durchsuchen und das Unternehmen andere Produkte zu empfehlen, die für den Käufer interessant sein könnten. Nachdem die Nutzenden weitere Artikel in den Einkaufswagen gelegt haben, können sie ihren gesamten Einkaufswagen überprüfen und vor dem Bezahlen Artikel entfernen oder weitere Artikel hinzufügen.

Inhalt

In diesem Abschnitt der Codelab-Serie erweitern Sie den digitalen Agent, den Sie in Teil 1 für das fiktive Unternehmen Bonjour Meal erstellt haben. So können Nutzer einen Artikelkatalog durchsuchen und Artikel in den Einkaufswagen legen.

In diesem Codelab wird Ihre App

  • Fragenkatalog in Business Messages anzeigen
  • Artikel vorschlagen, die Nutzer interessieren könnten
  • Inhalt des Einkaufswagens überprüfen und eine Zusammenfassung des Gesamtpreises erstellen

ab2fb6a4ed33a129.png

Aufgaben in diesem Lab

  • Webanwendung in App Engine auf der Google Cloud Platform bereitstellen
  • Einen dauerhaften Speichermechanismus verwenden, um den Status eines Einkaufswagens zu speichern

In diesem Codelab geht es vor allem um die Erweiterung des digitalen Kundenservicemitarbeiters aus Teil 1 dieser Codelab-Serie.

Voraussetzungen

  • Ein GCP-Projekt, das registriert und für die Verwendung mit Business Messages genehmigt wurde
  • Auf unserer Entwicklerwebsite finden Sie eine Anleitung dazu,
  • Eine JSON-Datei mit Anmeldedaten für das Dienstkonto, die für Ihr GCP-Projekt generiert wurde
  • Ein Gerät mit Android 5 oder höher ODER ein iOS-Gerät mit der Google Maps App
  • Erfahrung in der Programmierung von Webanwendungen
  • Eine Internetverbindung!

2. Einrichtung

In diesem Codelab wird davon ausgegangen, dass Sie Ihren ersten Agent erstellt und Teil 1 des Codelabs abgeschlossen haben. Daher werden wir nicht auf die Grundlagen der Aktivierung der Business Messages API und der Business Communications APIs, der Erstellung von Dienstkontoschlüsseln, der Bereitstellung einer Anwendung oder der Einrichtung eines Webhooks in der Business Communications Console eingehen. Vor diesem Hintergrund wird eine Beispielanwendung geklont, um sicherzustellen, dass Ihre Anwendung mit dem übereinstimmt, auf dem wir aufbauen. Außerdem aktivieren wir die API für Datenspeicher auf der Google Cloud Platform, um die zum Warenkorb gehörenden Daten dauerhaft zu speichern.

Anwendung aus GitHub klonen

Klonen Sie in einem Terminal das Beispiel für den Django Echo-Bot mit dem folgenden Befehl in das Arbeitsverzeichnis Ihres Projekts:

$ git clone https://github.com/google-business-communications/bm-bonjour-meal-django-starter-code

Kopieren Sie die für das Dienstkonto erstellte JSON-Anmeldedatendatei in den Ressourcenordner des Beispiels und benennen Sie die Anmeldedaten in „bm-agent-service-account-credentials.json“ um.

bm-bonjour-meal-django-starter-code/bonjourmeal-codelab/step-2/resources/bm-agent-service-account-credentials.json

Google Datastore API aktivieren

In Teil 1 dieses Codelabs haben Sie die Business Messages API, die Business Communication API und die Cloud Build API aktiviert.

Da wir für dieses Codelab mit Google Datastore arbeiten, müssen wir auch diese API aktivieren:

  1. Öffnen Sie die Google Datastore API in der Google Cloud Console.
  2. Prüfen Sie, ob Sie mit dem richtigen GCP-Projekt arbeiten.
  3. Klicken Sie auf Aktivieren.

Beispielanwendung bereitstellen

Rufen Sie in einem Terminal das Verzeichnis Schritt 2 des Beispiels auf.

Führen Sie die folgenden Befehle in einem Terminal aus, um das Beispiel bereitzustellen:

$ gcloud config set project PROJECT_ID*
$ gcloud app deploy
  • PROJECT_ID ist die Projekt-ID des Projekts, mit dem Sie sich bei den APIs registriert haben.

Notieren Sie sich die URL der bereitgestellten Anwendung in der Ausgabe des letzten Befehls:

Deployed service [default] to [https://PROJECT_ID.appspot.com]

Der Code, den Sie gerade bereitgestellt haben, enthält eine Webanwendung mit einem Webhook, um Nachrichten von Business Messages zu empfangen. Es enthält alles, was wir aus Teil 1 des Codelabs gemacht haben. Konfigurieren Sie den Webhook, falls Sie dies noch nicht getan haben.

Die Anwendung reagiert auf einige einfache Anfragen, z. B. wenn ein Nutzer nach den Öffnungszeiten von Bonjour Meal fragt. Teste dies auf deinem Mobilgerät über die Test-URLs, die du in der Business Communications Console in den Agent-Informationen abrufen kannst. Über die Test-URLs wird Business Messages auf Ihrem Mobilgerät gestartet und Sie können dort mit dem Agent interagieren.

3. Produktkatalog

Ein Inventarsystem

In den meisten Fällen ist eine direkte Integration in das Inventar einer Marke über eine interne API möglich. In anderen Fällen können Sie eine Webseite kopieren oder Ihr eigenes Inventar-Tracking-System erstellen. Wir konzentrieren uns nicht auf den Aufbau eines Inventarsystems, verwenden wir eine einfache statische Datei, die Bilder und Produktinformationen für den Agent enthält. In diesem Abschnitt rufen wir Informationen aus dieser statischen Datei ab, blenden diese in der Konversation ein und ermöglichen es einem Nutzer, die Artikel zu durchsuchen, die in den Einkaufswagen gelegt werden können.

Die statische Inventardatei sieht so aus:

bonjourmeal-codelab/step-2/resources/inventory.json

{

    "food": [
        {
            "id":0,
            "name": "Ham and cheese sandwich",
            "price": "6.99",
            "image_url": "https://storage.googleapis.com/bonjour-rail.appspot.com/ham-and-cheese.png",
            "remaining": 8
        },
        {
            "id":1,
            "name": "Chicken veggie wrap",
            "price": "9.99",
            "image_url": "https://storage.googleapis.com/bonjour-rail.appspot.com/chicken-veggie-wrap.png",
            "remaining": 2
        },
        {
            "id":2,
            "name": "Assorted cheese plate",
            "price": "7.99",
            "image_url": "https://storage.googleapis.com/bonjour-rail.appspot.com/assorted-cheese-plate.png",
            "remaining": 6
        },
        {
            "id":3,
            "name": "Apple walnut salad",
            "price": "12.99",
            "image_url": "https://storage.googleapis.com/bonjour-rail.appspot.com/apple-walnut-salad.png",
            "remaining": 1
        }
    ]
}

Lassen Sie uns die Python-Anwendung abrufen, um diese Datei einzulesen.

Aus unserem Bestand

Das Inventar ist eine statische Datei namens „inventory.json“. im Verzeichnis „./resources“ finden. Wir müssen view.py etwas Python-Logik hinzufügen, um den Inhalt der JSON-Datei zu lesen und dann in der Konversation anzuzeigen. Erstellen wir nun eine Funktion, die Daten aus der JSON-Datei einliest und die Liste der verfügbaren Produkte zurückgibt.

Diese Funktionsdefinition kann an einer beliebigen Stelle in view.py platziert werden.

bonjourmeal-codelab/step-2/bopis/views.py

...
def get_inventory_data():
        f = open(INVENTORY_FILE)
        inventory = json.load(f)
        return inventory
...

So erhalten wir das, was wir benötigen, um die Daten aus dem Inventar zu lesen. Jetzt müssen wir eine Möglichkeit finden, diese Produktinformationen in das Gespräch einzubringen.

Produktkatalog einblenden

Zur Vereinfachung dieses Codelabs haben wir einen allgemeinen Produktkatalog, um alle Inventarelemente in der Business Messages-Unterhaltung über ein einzelnes Rich-Card-Karussell anzuzeigen.

Um den Produktkatalog anzusehen, erstellen wir einen Antwortvorschlag mit dem Text „Menü anzeigen“ und postbackData „show-product-catalog“. Wenn Nutzer auf die vorgeschlagene Antwort tippen und Ihre Webanwendung die Postback-Daten erhält, senden wir das Rich Card-Karussell. Fügen wir nun eine neue Konstante für diese vorgeschlagene Antwort oben in view.py ein.

bonjourmeal-codelab/step-2/bopis/views.py

...
CMD_SHOW_PRODUCT_CATALOG = 'show-product-catalog'
...

Von hier aus parsen wir die Nachricht und leiten sie an eine neue Funktion weiter, die ein Rich-Karten-Karussell mit dem Produktkatalog sendet. Erweitern Sie zuerst die route_message-Funktion, um die Funktion „send_product_catalog“ aufzurufen. wenn auf die vorgeschlagene Antwort getippt wird. Dann definieren wir die Funktion.

Fügen Sie im folgenden Snippet der if-Anweisung in der Funktion route_message eine zusätzliche Bedingung hinzu, um zu prüfen, ob normalized_message der zuvor definierten Konstante CMD_SHOW_PRODUCT_CATALOG entspricht.

bonjourmeal-codelab/step-2/bopis/views.py

...
def route_message(message, conversation_id):
    '''
    Routes the message received from the user to create a response.

    Args:
        message (str): The message text received from the user.
        conversation_id (str): The unique id for this user and agent.
    '''
    normalized_message = message.lower()

    if normalized_message == CMD_RICH_CARD:
        send_rich_card(conversation_id)
    elif normalized_message == CMD_CAROUSEL_CARD:
        send_carousel(conversation_id)
    elif normalized_message == CMD_SUGGESTIONS:
        send_message_with_suggestions(conversation_id)
    elif normalized_message == CMD_BUSINESS_HOURS_INQUIRY:
        send_message_with_business_hours(conversation_id)
    elif normalized_message == CMD_ONLINE_SHOPPING_INQUIRY:
        send_online_shopping_info_message(conversation_id)
    elif normalized_message == CMD_SHOW_PRODUCT_CATALOG:
        send_product_catalog(conversation_id)
    else:
        echo_message(message, conversation_id)
...

Nun schließen wir den Ablauf ab und definieren send_product_catalog. send_product_catalog ruft get_menu_carousel, auf, wodurch ein Karussell mit Rich Cards aus der bereits gelesenen Inventardatei generiert wird.

Die Funktionsdefinitionen können an einer beliebigen Stelle in view.py platziert werden. Beachten Sie, dass das folgende Snippet zwei neue Konstanten verwendet, die oben in der Datei hinzugefügt werden sollten.

bonjourmeal-codelab/step-2/bopis/views.py

...

CMD_ADD_ITEM = 'add-item'
CMD_SHOW_CART = 'show-cart'

...

def get_menu_carousel():
    """Creates a sample carousel rich card.

    Returns:
       A :obj: A BusinessMessagesCarouselCard object with three cards.
    """

    inventory = get_inventory_data()

    card_content = []

    for item in inventory['food']:
        card_content.append(BusinessMessagesCardContent(
            title=item['name'],
            description=item['price'],
            suggestions=[
                BusinessMessagesSuggestion(
                    reply=BusinessMessagesSuggestedReply(
                        text='Add item',
                        postbackData='{'+f'"action":"{CMD_ADD_ITEM}","item_name":"{item["id"]}"'+'}'))

                ],
            media=BusinessMessagesMedia(
                height=BusinessMessagesMedia.HeightValueValuesEnum.MEDIUM,
                contentInfo=BusinessMessagesContentInfo(
                    fileUrl=item['image_url'],
                    forceRefresh=False))))

    return BusinessMessagesCarouselCard(
        cardContents=card_content,
        cardWidth=BusinessMessagesCarouselCard.CardWidthValueValuesEnum.MEDIUM)

def send_product_catalog(conversation_id):
    """Sends the product catalog to the conversation_id.

    Args:
        conversation_id (str): The unique id for this user and agent.
    """
    rich_card = BusinessMessagesRichCard(carouselCard=get_menu_carousel())

    fallback_text = ''

    # Construct a fallback text for devices that do not support carousels
    for card_content in rich_card.carouselCard.cardContents:
        fallback_text += (card_content.title + '\n\n' + card_content.description
                          + '\n\n' + card_content.media.contentInfo.fileUrl
                          + '\n---------------------------------------------\n\n')

    message_obj = BusinessMessagesMessage(
        messageId=str(uuid.uuid4().int),
        representative=BOT_REPRESENTATIVE,
        richCard=rich_card,
        fallback=fallback_text,
        suggestions=[
        BusinessMessagesSuggestion(
            reply=BusinessMessagesSuggestedReply(
                text='See my cart',
                postbackData=CMD_SHOW_CART)
            ),
        BusinessMessagesSuggestion(
            reply=BusinessMessagesSuggestedReply(
                text='See the menu',
                postbackData=CMD_SHOW_PRODUCT_CATALOG)
            ),
        ]
        )

    send_message(message_obj, conversation_id)
...

Wenn Sie sich die Erstellung der Karussellelemente ansehen, erstellen wir auch eine Instanz der BusinessMessagesSuggestion-Klasse. Jeder Vorschlag stellt eine Nutzerauswahl für ein Produkt im Karussell dar. Wenn ein Nutzer auf die vorgeschlagene Antwort tippt, sendet Business Messages die „postbackData“ (PostbackData) an den Webhook, in denen der Artikel und die Aktion beschrieben werden, die der Nutzer ausführen möchte (hinzufügen oder aus dem Einkaufswagen entfernen). Im folgenden Abschnitt parsen wir Nachrichten, die so aussehen, um den Artikel tatsächlich in den Einkaufswagen zu legen.

Nachdem wir diese Änderungen vorgenommen haben, stellen wir die Webanwendung nun in Google App Engine bereit und testen die Erfahrung!

$ gcloud app deploy

Wenn die Konversationsoberfläche auf Ihrem Mobilgerät geladen ist, senden Sie die Nachricht „show-product-catalog“. Nun sollten Sie ein Karussell mit Produkten sehen, das so aussieht.

4639da46bcc5230c.png

Wenn Sie auf Element hinzufügen tippen, passiert nichts, außer der Agent gibt die Postback-Daten aus der vorgeschlagenen Antwort zurück. Im nächsten Abschnitt nutzen wir den Produktkatalog, um den Warenkorb zu erstellen, dem der Artikel hinzugefügt werden soll.

Sie können den gerade erstellten Produktkatalog auf verschiedene Arten erweitern. Sie haben möglicherweise andere Getränkekarte oder vegetarische Optionen. Mit Karussells oder Vorschlags-Chips können Nutzer die Menüoptionen aufschlüsseln, um zu einer Reihe von Produkten zu gelangen, nach denen sie suchen. Versuchen Sie als Erweiterung dieses Codelabs, das Produktkatalogsystem zu erweitern, sodass Nutzende Getränke getrennt von Lebensmitteln im Menü anzeigen oder sogar vegetarische Optionen angeben können.

4. Einkaufswagen

In diesem Abschnitt des Codelabs bauen wir die Einkaufswagenfunktion auf, die auf dem vorherigen Abschnitt aufbaut, in dem wir die verfügbaren Produkte durchsuchen können.

Unter anderem ermöglicht die wichtigste User Experience das Hinzufügen von Artikeln zum Einkaufswagen und das Entfernen von Artikeln aus dem Einkaufswagen, die Anzahl der einzelnen Artikel im Einkaufswagen zu verfolgen und die Artikel im Einkaufswagen zu überprüfen.

Wenn wir den Status des Warenkorbs verfolgen, müssen die Daten in der Webanwendung dauerhaft gespeichert werden. Um das Experimentieren und die Bereitstellung zu vereinfachen, verwenden wir für die dauerhafte Speicherung von Daten in der Google Cloud Platform Google Datastore. Die Unterhaltungs-ID zwischen einem Nutzer und dem Unternehmen bleibt konstant, sodass wir sie verwenden können, um Nutzer mit Einkaufswagenartikeln zu verknüpfen.

Stellen wir zunächst eine Verbindung zu Google Datastore her und speichern die Konversations-ID, wenn wir sie sehen.

Mit Datastore verbinden

Wir stellen immer dann eine Verbindung zum Google-Datenspeicher her, wenn eine Interaktion mit dem Einkaufswagen ausgeführt wird, beispielsweise wenn ein Nutzer einen Artikel hinzufügt oder löscht. Weitere Informationen zur Verwendung dieser Clientbibliothek für die Interaktion mit Google Datastore finden Sie in der offiziellen Dokumentation.

Das folgende Snippet definiert eine Funktion zum Aktualisieren des Einkaufswagens. Die Funktion verwendet die folgende Eingabe: conversation_id und message. message enthält JSON, das die Aktion beschreibt, die der Nutzer ausführen möchte. Diese JSON-Datei ist bereits in Ihr Karussell mit dem Produktkatalog integriert. Die Funktion erstellt einen Google Datastore-Client und ruft sofort eine ShoppingCart-Entität ab, deren Schlüssel die Unterhaltungs-ID ist.

Kopieren Sie die folgende Funktion in Ihre Datei "views.py". Im nächsten Abschnitt gehen wir näher darauf ein.

bonjourmeal-codelab/step-2/bopis/views.py

from google.oauth2 import service_account
from google.cloud import datastore

def update_shopping_cart(conversation_id, message):
        credentials = service_account.Credentials.from_service_account_file(
        SERVICE_ACCOUNT_LOCATION)

        client = datastore.Client(credentials=credentials)
        key = client.key('ShoppingCart', conversation_id)
        entity = datastore.Entity(key=key)
        result = client.get(key)
        
        # TODO: Add logic to add and remove items from cart
        
        entity.update(result)
        client.put(entity)

Erweitern wir nun diese Funktion, um einen Artikel in den Warenkorb zu legen.

Artikel zum Einkaufswagen hinzufügen

Wenn der Nutzer auf eine vorgeschlagene Aktion Artikel hinzufügen aus dem Produktkarussell tippt, enthalten die postbackData-Elemente JSON-Daten mit einer Beschreibung der Aktion, die der Nutzer ausführen möchte. Das JSON-Wörterbuch hat zwei Schlüssel, „action“. und „item_name“ Dieses JSON-Wörterbuch wird an Ihren Webhook gesendet. „item_name“ ist die eindeutige Kennung, die dem Element in der Datei Inventory.json zugeordnet ist.

Sobald der „cart“-Befehl und der Warenkorbartikel aus der Nachricht geparst wurden, können wir bedingte Anweisungen schreiben, um den Artikel hinzuzufügen. Hier einige Grenzfälle, die Sie berücksichtigen sollten, wenn der Datenspeicher die Konversations-ID noch nie gesehen hat oder wenn der Einkaufswagen dieses Element zum ersten Mal erhält. Im Folgenden finden Sie eine Erweiterung der oben definierten update_shopping_cart-Funktion. Durch diese Änderung wird ein Artikel in den Einkaufswagen gelegt, der in Google Datastore gespeichert wird.

Das folgende Snippet ist eine Erweiterung der vorherigen Funktion, die zu view.py hinzugefügt wurde. Sie können die Differenz hinzufügen oder das Snippet kopieren und die vorhandene Version der Funktion update_shopping_cart ersetzen.

bonjourmeal-codelab/step-2bopis/views.py

def update_shopping_cart(conversation_id, message):
    credentials = service_account.Credentials.from_service_account_file(
      SERVICE_ACCOUNT_LOCATION)
    inventory = get_inventory_data()

    cart_request = json.loads(message)
    cart_cmd = cart_request["action"]
    cart_item = cart_request["item_name"]

    item_name = inventory['food'][int(cart_item)]['name']

    client = datastore.Client(credentials=credentials)
    key = client.key('ShoppingCart', conversation_id)
    entity = datastore.Entity(key=key)
    result = client.get(key)

    if result is None:
        if cart_cmd == CMD_ADD_ITEM:
            entity.update({
                item_name: 1
            })

    else:
        if cart_cmd == CMD_ADD_ITEM:
            if result.get(item_name) is None:
                result[item_name] = 1
            else:
                result[item_name] = result[item_name] + 1

        entity.update(result)
    client.put(entity)

Diese Funktion wird später erweitert, um das Szenario zu unterstützen, bei dem cart_cmd den String „del-item“ enthält. definiert in CMD_DEL_ITEM.

Vernetzung

Fügen Sie die Sanitärleitungen in die Funktion route_message ein, damit die Funktion update_shopping_cart aufgerufen wird, wenn Sie eine Meldung zum Hinzufügen eines Artikels zum Einkaufswagen erhalten. Außerdem müssen Sie eine Konstante zum Hinzufügen von Elementen definieren. Verwenden Sie dazu die im gesamten Codelab verwendete Konvention.

bonjourmeal-codelab/step-2bopis/views.py

...

CMD_DEL_ITEM = 'del-item'

...

def route_message(message, conversation_id):
    '''
    Routes the message received from the user to create a response.

    Args:
        message (str): The message text received from the user.
        conversation_id (str): The unique id for this user and agent.
    '''
    normalized_message = message.lower()

    if normalized_message == CMD_RICH_CARD:
        send_rich_card(conversation_id)
    elif normalized_message == CMD_CAROUSEL_CARD:
        send_carousel(conversation_id)
    elif normalized_message == CMD_SUGGESTIONS:
        send_message_with_suggestions(conversation_id)
    elif normalized_message == CMD_BUSINESS_HOURS_INQUIRY:
        send_message_with_business_hours(conversation_id)
    elif normalized_message == CMD_ONLINE_SHOPPING_INQUIRY:
        send_online_shopping_info_message(conversation_id)
    elif normalized_message == CMD_SHOW_PRODUCT_CATEGORY:
        send_product_catalog(conversation_id)
    elif CMD_ADD_ITEM in normalized_message or CMD_DEL_ITEM in normalized_message:
       update_shopping_cart(conversation_id, message)
    else:
        echo_message(message, conversation_id)

...

Derzeit haben wir die Möglichkeit, Artikel in den Warenkorb zu legen. Wenn Sie Ihre Änderungen in Google App Engine bereitstellen, sollten die Änderungen für den Einkaufswagen im Google Datastore-Dashboard in der GCP Console angezeigt werden. Im folgenden Screenshot der Google Datastore-Konsole sehen Sie eine einzelne Entität, die nach der Unterhaltungs-ID benannt ist, gefolgt von einigen Beziehungen zu Inventarartikeln und der Menge der Artikel, die sich im Einkaufswagen befinden.

619dc18a8136ea69.png

Im nächsten Abschnitt erstellen wir eine Möglichkeit, Artikel im Warenkorb aufzulisten. Der Überprüfungsmechanismus für den Warenkorb sollte alle Artikel im Warenkorb, die Menge dieser Artikel und eine Option zum Entfernen eines Artikels aus dem Warenkorb anzeigen.

Artikel im Einkaufswagen werden überprüft

Nur durch die Auflistung der Artikel im Warenkorb können wir den Status des Warenkorbs nachvollziehen und feststellen, welche Artikel wir entfernen können.

Sende zuerst eine freundliche Nachricht wie „Hier ist dein Einkaufswagen:“, gefolgt von einer weiteren Nachricht, die ein Rich-Karten-Karussell mit zugehörigen Antwortvorschlägen für „Eine entfernen“ enthält. oder „Eine hinzufügen“. Das Rich-Card-Karussell sollte zusätzlich die Anzahl der im Einkaufswagen gespeicherten Artikel auflisten.

Sie sollten Folgendes beachten, bevor wir tatsächlich unsere Funktion schreiben: Wenn sich nur eine Art von Artikel im Warenkorb befindet, können wir ihn nicht als Karussell darstellen. Rich-Card-Karussells müssen mindestens zwei Karten enthalten. Wenn sich im Einkaufswagen keine Artikel befinden, soll eine einfache Meldung angezeigt werden, die besagt, dass der Einkaufswagen leer ist.

Definieren wir vor diesem Hintergrund eine Funktion namens send_shopping_cart. Diese Funktion stellt eine Verbindung zu Google Datastore her und fordert eine ShoppingCart-Entität basierend auf der Unterhaltungs-ID an. Anschließend rufen wir die get_inventory_data-Funktion auf und verwenden ein Richcard-Karussell, um den Status des Einkaufswagens zu melden. Außerdem müssen wir die ID eines Produkts anhand des Namens abrufen und wir können eine Funktion deklarieren, die in Google Datastore untersucht wird, um diesen Wert zu ermitteln. Während das Karussell erstellt wird, können wir Antwortvorschläge zum Löschen von Artikeln zuordnen oder Artikel anhand der Produkt-ID hinzufügen. Das folgende Snippet führt alle diese Vorgänge aus. Kopieren Sie den Code an einer beliebigen Stelle in die Datei view.py.

bonjourmeal-codelab/step-2/bopis/views.py

...
def get_id_by_product_name(product_name):
  inventory = get_inventory_data()
  for item in inventory['food']:
    if item['name'] == product_name:
      return int(item['id'])
  return False


def send_shopping_cart(conversation_id):
  credentials = service_account.Credentials.from_service_account_file(
      SERVICE_ACCOUNT_LOCATION)

  # Retrieve the inventory data
  inventory = get_inventory_data()

  # Pull the data from Google Datastore
  client = datastore.Client(credentials=credentials)
  key = client.key('ShoppingCart', conversation_id)
  result = client.get(key)

  shopping_cart_suggestions = [
      BusinessMessagesSuggestion(
          reply=BusinessMessagesSuggestedReply(
              text='See total price', postbackData='show-cart-price')),
      BusinessMessagesSuggestion(
          reply=BusinessMessagesSuggestedReply(
              text='Empty the cart', postbackData='empty-cart')),
      BusinessMessagesSuggestion(
          reply=BusinessMessagesSuggestedReply(
              text='See the menu', postbackData=CMD_SHOW_PRODUCT_CATALOG)),
  ]

  if result is None or len(result.items()) == 0:
    message_obj = BusinessMessagesMessage(
        messageId=str(uuid.uuid4().int),
        representative=BOT_REPRESENTATIVE,
        text='There are no items in your shopping cart.',
        suggestions=shopping_cart_suggestions)

    send_message(message_obj, conversation_id)
  elif len(result.items()) == 1:

    for product_name, quantity in result.items():
      product_id = get_id_by_product_name(product_name)

      fallback_text = ('You have one type of item in the shopping cart')

      rich_card = BusinessMessagesRichCard(
          standaloneCard=BusinessMessagesStandaloneCard(
              cardContent=BusinessMessagesCardContent(
                  title=product_name,
                  description=f'{quantity} in cart.',
                  suggestions=[
                      BusinessMessagesSuggestion(
                          reply=BusinessMessagesSuggestedReply(
                              text='Remove one',
                              postbackData='{'+f'"action":"{CMD_DEL_ITEM}","item_name":"{product_id}"'+'}'))
                  ],
                  media=BusinessMessagesMedia(
                      height=BusinessMessagesMedia.HeightValueValuesEnum.MEDIUM,
                      contentInfo=BusinessMessagesContentInfo(
                          fileUrl=inventory['food'][product_id]
                          ['image_url'],
                          forceRefresh=False)))))

      message_obj = BusinessMessagesMessage(
          messageId=str(uuid.uuid4().int),
          representative=BOT_REPRESENTATIVE,
          richCard=rich_card,
          suggestions=shopping_cart_suggestions,
          fallback=fallback_text)

      send_message(message_obj, conversation_id)
  else:
    cart_carousel_items = []

    # Iterate through the cart and generate a carousel of items
    for product_name, quantity in result.items():
      product_id = get_id_by_product_name(product_name)

      cart_carousel_items.append(
          BusinessMessagesCardContent(
              title=product_name,
              description=f'{quantity} in cart.',
              suggestions=[
                  BusinessMessagesSuggestion(
                      reply=BusinessMessagesSuggestedReply(
                          text='Remove one',
                          postbackData='{'+f'"action":"{CMD_DEL_ITEM}","item_name":"{product_id}"'+'}'))
              ],
              media=BusinessMessagesMedia(
                  height=BusinessMessagesMedia.HeightValueValuesEnum.MEDIUM,
                  contentInfo=BusinessMessagesContentInfo(
                      fileUrl=inventory['food'][product_id]
                      ['image_url'],
                      forceRefresh=False))))

    rich_card = BusinessMessagesRichCard(
        carouselCard=BusinessMessagesCarouselCard(
            cardContents=cart_carousel_items,
            cardWidth=BusinessMessagesCarouselCard.CardWidthValueValuesEnum
            .MEDIUM))

    fallback_text = ''

    # Construct a fallback text for devices that do not support carousels
    for card_content in rich_card.carouselCard.cardContents:
      fallback_text += (
          card_content.title + '\n\n' + card_content.description + '\n\n' +
          card_content.media.contentInfo.fileUrl +
          '\n---------------------------------------------\n\n')

    message_obj = BusinessMessagesMessage(
        messageId=str(uuid.uuid4().int),
        representative=BOT_REPRESENTATIVE,
        richCard=rich_card,
        suggestions=shopping_cart_suggestions,
        fallback=fallback_text,
    )

    send_message(message_obj, conversation_id)

...

Vergewissere dich, dass du CMD_SHOW_CART bereits oben in view.py definiert hast, und ruf send_shopping_cart auf, wenn der Nutzer eine Nachricht mit dem Text „show-cart“ sendet.

bonjourmeal-codelab/step-2/bopis/views.py

...
def route_message(message, conversation_id):
    '''
    Routes the message received from the user to create a response.

    Args:
        message (str): The message text received from the user.
        conversation_id (str): The unique id for this user and agent.
    '''
    normalized_message = message.lower()

    if normalized_message == CMD_RICH_CARD:
        send_rich_card(conversation_id)
    elif normalized_message == CMD_CAROUSEL_CARD:
        send_carousel(conversation_id)
    elif normalized_message == CMD_SUGGESTIONS:
        send_message_with_suggestions(conversation_id)
    elif normalized_message == CMD_BUSINESS_HOURS_INQUIRY:
        send_message_with_business_hours(conversation_id)
    elif normalized_message == CMD_ONLINE_SHOPPING_INQUIRY:
        send_online_shopping_info_message(conversation_id)
    elif normalized_message == CMD_SHOW_PRODUCT_CATEGORY:
        send_product_catalog(conversation_id)
    elif CMD_ADD_ITEM in normalized_message or CMD_DEL_ITEM in normalized_message:
        update_shopping_cart(conversation_id, message)
    elif normalized_message == CMD_SHOW_CART:
        send_shopping_cart(conversation_id)
    else:
        echo_message(message, conversation_id)
...

34801776a97056ac.png

Wenn Sie „Einkaufswagen anzeigen“ eingeben, erhalten Sie basierend auf der Logik, die wir in der send_shopping_cart-Funktion eingeführt haben, entweder eine Nachricht, die besagt, dass sich nichts im Einkaufswagen befindet, eine Rich Card mit einem bestimmten Artikel im Einkaufswagen oder ein Karussell mit Karten, auf denen mehrere Artikel angezeigt werden. Außerdem gibt es drei Antwortvorschläge: „Gesamtpreis ansehen“, „Einkaufswagen leeren“ und „Menü anzeigen“.

Implementieren Sie die oben aufgeführten Codeänderungen, um zu testen, ob Ihr Einkaufswagen die von Ihnen hinzugefügten Artikel erfasst und dass Sie den Einkaufswagen in der Unterhaltungsoberfläche überprüfen können, wie in den Screenshots oben gezeigt. Sie können die Änderungen mit diesem Befehl bereitstellen. Führen Sie dazu das Verzeichnis aus Schritt 2 aus, in das Sie Ihre Änderungen einfügen.

$ gcloud app deploy

Wir erstellen den Bericht „Gesamtpreis anzeigen“ im nächsten Abschnitt, nachdem Sie die Funktionalität zum Entfernen eines Artikels aus dem Warenkorb erstellt haben. Die Funktion „get_cart_price“ verhält sich ähnlich wie „Zum Einkaufswagen“ verwenden, da sie die Daten in Datastore mit der Datei „inventory.json“ vergleicht, um einen Gesamtpreis für den Einkaufswagen zu ermitteln. Das ist praktisch für den nächsten Teil des Codelab, in dem wir die Zahlungsfunktion integrieren.

Artikel werden aus dem Einkaufswagen entfernt

Schließlich können wir das Warenkorbverhalten vervollständigen, indem wir eine Funktion zum Entfernen des Warenkorbs einführen. Ersetzen Sie die vorhandene update_shopping_cart-Funktion durch das folgende Snippet.

bonjourmeal-codelab/step-2/ bopis/views.py

def update_shopping_cart(conversation_id, message):
    credentials = service_account.Credentials.from_service_account_file(
      SERVICE_ACCOUNT_LOCATION)
    inventory = get_inventory_data()

    cart_request = json.loads(message)
    cart_cmd = cart_request["action"]
    cart_item = cart_request["item_name"]

    item_name = inventory['food'][int(cart_item)]['name']


    client = datastore.Client(credentials=credentials)
    key = client.key('ShoppingCart', conversation_id)
    entity = datastore.Entity(key=key)
    result = client.get(key)

    if result is None:
        if cart_cmd == CMD_ADD_ITEM:
            entity.update({
                item_name: 1
            })
        elif cart_cmd == CMD_DEL_ITEM:
            # The user is trying to delete an item from an empty cart. Pass and skip
            pass

    else:
        if cart_cmd == CMD_ADD_ITEM:
            if result.get(item_name) is None:
                result[item_name] = 1
            else:
                result[item_name] = result[item_name] + 1

        elif cart_cmd == CMD_DEL_ITEM:
            if result.get(item_name) is None:
                # The user is trying to remove an item that's no in the shopping cart. Pass and skip
                pass
            elif result[item_name] - 1 > 0:
                result[item_name] = result[item_name] - 1
            else:
                del result[item_name]

        entity.update(result)
    client.put(entity)

Bestätigungsnachricht senden

Wenn der Nutzer einen Artikel in den Einkaufswagen legt, solltest du eine Bestätigungsnachricht senden, in der die Aktion bestätigt wird und die Anfrage bearbeitet wurde. Dies trägt nicht nur dazu bei, Erwartungen zu wecken, sondern hält auch das Gespräch in Gang.

Erweitern Sie nun die update_shopping_cart-Funktion, sodass eine Nachricht an die Unterhaltungs-ID gesendet wird, in der Sie darüber informiert werden, dass der Artikel hinzugefügt oder entfernt wurde. Außerdem erhalten Sie Vorschläge, wie Sie den Einkaufswagen überprüfen oder das Menü noch einmal ansehen können.

bonjourmeal-codelab/step-2/bopis/views.py

def update_shopping_cart(conversation_id, message):

     # No changes to the function, except appending the following logic
     ...
   
    if cart_cmd == CMD_ADD_ITEM:
        message = 'Great! You\'ve added an item to the cart.'
    else:
        message = 'You\'ve removed an item from the cart.'

    message_obj = BusinessMessagesMessage(
        messageId=str(uuid.uuid4().int),
        representative=BOT_REPRESENTATIVE,
        text=message,
        suggestions=[
            BusinessMessagesSuggestion(
            reply=BusinessMessagesSuggestedReply(
                text='Review shopping cart',
                postbackData=CMD_SHOW_CART)
            ),
            BusinessMessagesSuggestion(
            reply=BusinessMessagesSuggestedReply(
                text='See menu again',
                postbackData=CMD_SHOW_PRODUCT_CATALOG)
            ),
            ])
    send_message(message_obj, conversation_id)

905a1f3d89893ba0.png

Das sollte sein! Eine voll funktionsfähige Einkaufswagenfunktion, die es Nutzern ermöglicht, Artikel hinzuzufügen, zu entfernen und Artikel im Einkaufswagen zu überprüfen.

Wenn Sie die Einkaufswagenfunktion in der Unterhaltung in Business Messages sehen möchten, müssen Sie die Anwendung bereitstellen, um mit dem Agent zu interagieren. Führen Sie dazu diesen Befehl im Verzeichnis Schritt 2 aus.

$ gcloud app deploy

5. Zahlungen werden vorbereitet

Um die Integration eines Zahlungsabwicklers im nächsten Teil der Serie vorzubereiten, benötigen wir eine Möglichkeit, den Preis des Warenkorbs zu ermitteln. Wir erstellen nun eine Funktion, die den Preis durch einen Vergleich der Warenkorbdaten im Google Datastore abruft, den Preis jedes Artikels aus dem Inventar abruft und den Preis mit der Menge jedes Artikels im Warenkorb multipliziert.

bonjourmeal-codelab/step-2/bopis/views.py

...
def get_cart_price(conversation_id):
    # Pull the data from Google Datastore
    credentials = service_account.Credentials.from_service_account_file(
    SERVICE_ACCOUNT_LOCATION)
    client = datastore.Client(credentials=credentials)
    key = client.key('ShoppingCart', conversation_id)
    entity = datastore.Entity(key=key)
    result = client.get(key)

    # Retrieve the inventory data
    inventory = get_inventory_data()
   
    # Start off with a total of 0 before adding up the total
    total_price = 0

    if len(result.items()) != 0:
      for product_name, quantity in result.items():
        total_price = total_price + float(
            inventory['food'][get_id_by_product_name(product_name)]['price']) * int(quantity)

    return total_price

...

Und schließlich können wir diese Funktion verarbeiten und eine Nachricht an den Nutzer senden.

bonjourmeal-codelab/step-2/bopis/views.py

...

def send_shopping_cart_total_price(conversation_id):
    cart_price = get_cart_price(conversation_id)

    message_obj = BusinessMessagesMessage(
        messageId=str(uuid.uuid4().int),
        representative=BOT_REPRESENTATIVE,
        suggestions=[],
        text=f'Your cart\'s total price is ${cart_price}.')

    send_message(message_obj, conversation_id)
...

Um alles miteinander zu verknüpfen, aktualisieren wir die route_message-Funktion und die Konstante, um die obige Logik auszulösen.

bonjourmeal-codelab/step-2/bopis/views.py

...
CMD_GET_CART_PRICE = 'show-cart-price'
...
def route_message(message, conversation_id):
    '''
    Routes the message received from the user to create a response.

    Args:
        message (str): The message text received from the user.
        conversation_id (str): The unique id for this user and agent.
    '''
    normalized_message = message.lower()

    if normalized_message == CMD_RICH_CARD:
        send_rich_card(conversation_id)
    elif normalized_message == CMD_CAROUSEL_CARD:
        send_carousel(conversation_id)
    elif normalized_message == CMD_SUGGESTIONS:
        send_message_with_suggestions(conversation_id)
    elif normalized_message == CMD_BUSINESS_HOURS_INQUIRY:
        send_message_with_business_hours(conversation_id)
    elif normalized_message == CMD_ONLINE_SHOPPING_INQUIRY:
        send_online_shopping_info_message(conversation_id)
    elif normalized_message == CMD_SHOW_PRODUCT_CATEGORY:
        send_product_catalog(conversation_id)
    elif CMD_ADD_ITEM in normalized_message or CMD_DEL_ITEM in normalized_message:
        update_shopping_cart(conversation_id, message)
    elif normalized_message == CMD_SHOW_CART:
        send_shopping_cart(conversation_id)
    elif normalized_message == CMD_GET_CART_PRICE:
        send_shopping_cart_total_price(conversation_id)
    else:
        echo_message(message, conversation_id)
...

Hier sind einige Screenshots, die zeigen, was die obige Logik bewirkt:

8feacf94ed0ac6c4.png

Wenn die Integration mit dem Zahlungsabwickler im nächsten Teil des Codelabs bereit ist, rufen wir die Funktion get_cart_price auf, um die Daten an den Zahlungsabwickler zu übergeben und den Zahlungsablauf zu starten.

Sie können diese Einkaufswagenfunktion in der Unterhaltung in Business Messages ausprobieren, indem Sie die Anwendung bereitstellen und mit dem Agent interagieren.

$ gcloud app deploy

6. Glückwunsch

Herzlichen Glückwunsch, Sie haben erfolgreich einen Einkaufswagen in Business Messages erstellt.

In diesem Codelab haben wir nicht die Funktion zum Leeren des Einkaufswagens behandelt. Wenn du möchtest, kannst du die App so erweitern, dass die Option „Warenkorb leeren“ ausgefüllt wird. . Die Lösung ist in Schritt 3 des von Ihnen geklonten Quellcodes verfügbar.

In einem späteren Abschnitt werden wir einen externen Zahlungsabwickler einbinden, damit Ihre Nutzer Zahlungstransaktionen bei Ihrer Marke durchführen können.

Was macht einen guten Einkaufswagen aus?

Eine positive Nutzererfahrung mit dem Einkaufswagen in einer Konversation unterscheidet sich nicht von einer mobilen App oder in einem Geschäft. Die Möglichkeit, Artikel hinzuzufügen, Artikel zu entfernen und den Preis des Warenkorbs zu berechnen, sind nur einige der Funktionen, die wir in diesem Codelab kennengelernt haben. Im Gegensatz zu einem echten Einkaufswagen können Sie jederzeit den Preis aller Artikel im Einkaufswagen sehen, während Sie Artikel hinzufügen oder entfernen. Diese hochwertigen Funktionen heben Ihren konversationellen Handel hervor.

Was liegt als Nächstes an?

Wenn Sie bereit sind, können Sie sich einige der folgenden Themen ansehen, um mehr über die komplexeren Interaktionen in Business Messages zu erfahren:

Referenzdokumente