1. Einführung

Zuletzt aktualisiert: 30.10.2020
Warenkorb in Business Messages erstellen
Dies ist das zweite Codelab einer Reihe, in der es darum geht, eine User Journey für „Online kaufen, im Geschäft abholen“ zu erstellen. In vielen E-Commerce-Journeys ist ein Einkaufswagen entscheidend, um Nutzer in zahlende Kunden zu verwandeln. Über den Einkaufswagen können Sie Ihre Kunden besser kennenlernen und ihnen Vorschläge für andere Artikel machen, die sie interessieren könnten. In diesem Codelab konzentrieren wir uns auf die Entwicklung des Einkaufswagens und die Bereitstellung der Anwendung in Google App Engine.
Was macht einen guten Einkaufswagen aus?
Einkaufswagen sind der Schlüssel zu einem erfolgreichen Onlineshopping-Erlebnis. Business Messages eignet sich nicht nur für Fragen und Antworten zu einem Produkt mit einem potenziellen Kunden, sondern kann den gesamten Kaufprozess bis hin zur Zahlung innerhalb der Unterhaltung abwickeln.

Ein guter Warenkorb ist wichtig, aber ein gutes Einkaufserlebnis umfasst auch die Möglichkeit, Artikel nach Kategorie zu durchsuchen und Empfehlungen für andere Produkte zu erhalten, die den Käufer interessieren könnten. Nachdem der Nutzer weitere Artikel in den Einkaufswagen gelegt hat, kann er sich den gesamten Einkaufswagen ansehen und Artikel entfernen oder hinzufügen, bevor er den Kaufvorgang abschließt.
Umfang
In diesem Abschnitt der Codelab-Reihe erweitern Sie den digitalen Kundenservicemitarbeiter, den Sie in Teil 1 für das fiktive Unternehmen Bonjour Meal erstellt haben. Nutzer sollen nun einen Artikelkatalog durchsuchen und Artikel in einen Einkaufswagen legen können.
In diesem Codelab wird Ihre App
- Fragenkatalog in Business Messages anzeigen
- Nutzern Artikel vorschlagen, die sie interessieren könnten
- Inhalte des Einkaufswagens prüfen und eine Zusammenfassung des Gesamtpreises erstellen

Lerninhalte
- Webanwendung in App Engine in der Google Cloud Platform bereitstellen
- So verwenden Sie einen persistenten Speichermechanismus, um den Status eines Einkaufswagens zu speichern
In diesem Codelab geht es darum, den digitalen Agenten aus Teil 1 dieser Codelab-Reihe zu erweitern.
Voraussetzungen
- Ein GCP-Projekt, das für die Verwendung mit Business Messages registriert und genehmigt wurde
- Eine Anleitung dazu, wie
- Eine JSON-Datei mit Anmeldedaten für das Dienstkonto, die für Ihr GCP-Projekt generiert wurde
- Ein Android-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 Agenten erstellt und Teil 1 des Codelabs abgeschlossen haben. Daher werden wir die Grundlagen zum Aktivieren der Business Messages und Business Communications APIs, zum Erstellen von Dienstkontoschlüsseln, zum Bereitstellen einer Anwendung oder zum Einrichten Ihres Webhooks in der Business Communications Console nicht behandeln. Wir klonen eine Beispielanwendung, um sicherzustellen, dass Ihre Anwendung mit dem übereinstimmt, worauf wir aufbauen. Außerdem aktivieren wir die API für Datastore in der Google Cloud Platform, um Daten zum Einkaufswagen zu speichern.
Anwendung aus GitHub klonen
Klonen Sie in einem Terminal das Django Echo Bot Sample 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 JSON-Datei mit den Anmeldedaten, die für das Dienstkonto erstellt wurde, 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
Im ersten Teil dieses Codelabs haben Sie die Business Messages API, die Business Communications API und die Cloud Build API aktiviert.
Da wir in diesem Codelab mit Google Datastore arbeiten, müssen wir auch diese API aktivieren:
- Öffnen Sie die Google Datastore API in der Google Cloud Console.
- Achten Sie darauf, dass Sie das richtige GCP-Projekt verwenden.
- Klicken Sie auf Aktivieren.
Beispielanwendung bereitstellen
Wechseln Sie in einem Terminal zum Verzeichnis „step-2“ des Beispiels.
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 für die 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 zum Empfangen von Nachrichten von Business Messages. Es enthält alles, was wir in Teil 1 des Codelabs gemacht haben. Konfigurieren Sie Ihren Webhook, falls noch nicht geschehen.
Die Anwendung reagiert auf einige einfache Anfragen, z. B. wenn ein Nutzer nach den Öffnungszeiten von Bonjour Meal fragt. Sie sollten dies auf Ihrem Mobilgerät über die Test-URLs testen, die Sie in der Business Communications Console unter „Agent-Informationen“ abrufen können. Über die Test-URLs wird die Business Messages-Funktion auf Ihrem Mobilgerät gestartet und Sie können mit Ihrem Agenten interagieren.
3. Der Produktkatalog
Inventarsystem
In den meisten Fällen können Sie das Inventar einer Marke direkt über eine interne API einbinden. In anderen Fällen crawlen Sie möglicherweise eine Webseite oder erstellen ein eigenes Inventarverfolgungssystem. Wir möchten kein Inventarsystem erstellen, sondern verwenden eine einfache statische Datei, die Bilder und Produktinformationen für unseren Agenten enthält. In diesem Abschnitt rufen wir Informationen aus dieser statischen Datei ab, stellen sie im Gespräch dar und ermöglichen es einem Nutzer, die verfügbaren Artikel zu durchsuchen, die einem Einkaufswagen hinzugefügt 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
}
]
}
Wir lassen die Python-Anwendung diese Datei lesen.
Aus unserem Inventar lesen
Das Inventar ist eine statische Datei namens „inventory.json“ im Verzeichnis „./resources“. Wir müssen der Datei „views.py“ etwas Python-Logik hinzufügen, um den Inhalt der JSON-Datei zu lesen und dann in der Unterhaltung anzuzeigen. Erstellen wir eine Funktion, die Daten aus der JSON-Datei liest und die Liste der verfügbaren Produkte zurückgibt.
Diese Funktionsdefinition kann an beliebiger Stelle in „views.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 die Informationen, die wir zum Lesen der Daten aus dem Inventar benötigen. Jetzt benötigen wir eine Möglichkeit, diese Produktinformationen in die Unterhaltung einzubinden.
Produktkatalog präsentieren
In diesem Codelab verwenden wir einen allgemeinen Produktkatalog, um alle Inventarelemente in der Business Messages-Unterhaltung über ein einzelnes Karussell mit Rich Cards zu präsentieren.
Um den Produktkatalog aufzurufen, erstellen wir eine vorgeschlagene Antwort mit dem Text „Show Menu“ (Menü anzeigen) und postbackData „show-product-catalog“. Wenn Nutzer auf die vorgeschlagene Antwort tippen und Ihre Webanwendung die Postback-Daten empfängt, senden wir das Rich-Card-Karussell. Fügen wir oben in views.py eine neue Konstante für diesen Antwortvorschlag hinzu.
bonjourmeal-codelab/step-2/bopis/views.py
...
CMD_SHOW_PRODUCT_CATALOG = 'show-product-catalog'
...
Hier wird die Nachricht geparst und an eine neue Funktion weitergeleitet, die ein Rich-Card-Karussell mit dem Produktkatalog sendet. Erweitern Sie zuerst die Funktion route_message, um die Funktion send_product_catalog aufzurufen, wenn auf die vorgeschlagene Antwort getippt wird. Anschließend 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 Konstanten 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)
...
Wir müssen den Ablauf abschließen und send_product_catalog definieren. send_product_catalog ruft get_menu_carousel, auf, wodurch das Karussell mit Rich Cards aus der Inventardatei generiert wird, die wir zuvor eingelesen haben.
Die Funktionsdefinitionen können an beliebiger Stelle in „views.py“ platziert werden. Im folgenden Snippet werden 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 wir uns die Erstellung der Karussell-Elemente ansehen, erstellen wir auch eine Instanz der Klasse BusinessMessagesSuggestion. Jeder Vorschlag steht für die Auswahl eines Produkts im Karussell durch einen Nutzer. Wenn ein Nutzer auf die vorgeschlagene Antwort tippt, sendet Business Messages die postbackData, die JSON mit einer Beschreibung des Artikels und der gewünschten Nutzeraktion (dem Hinzufügen oder Entfernen aus dem Einkaufswagen) enthält, an Ihren Webhook. Im folgenden Abschnitt werden wir Nachrichten, die so aussehen, parsen, um den Artikel tatsächlich in den Einkaufswagen legen zu können.
Nachdem wir diese Änderungen vorgenommen haben, stellen wir die Webanwendung in Google App Engine bereit und probieren sie aus.
$ gcloud app deploy
Wenn Sie die unterhaltungsbasierte Oberfläche auf Ihrem Mobilgerät geladen haben, senden Sie die Nachricht „show-product-catalog“. Daraufhin sollte ein Produktkarussell wie dieses angezeigt werden.

Wenn Sie auf Element hinzufügen tippen, passiert nichts, außer dass der Agent die Postback-Daten aus der vorgeschlagenen Antwort wiederholt. Im nächsten Abschnitt verwenden wir den Produktkatalog, um den Einkaufswagen zu erstellen, in den der Artikel aufgenommen wird.
Der gerade erstellte Produktkatalog kann auf verschiedene Arten erweitert werden. Möglicherweise haben Sie andere Getränkekartenoptionen oder vegetarische Optionen. Mit Karussells oder Vorschlagschips können Nutzer Menüoptionen durchgehen, um zu einer Reihe von Produkten zu gelangen, nach denen sie suchen. Als Erweiterung dieses Codelabs können Sie das Produktkatalogsystem so erweitern, dass ein Nutzer Getränke im Menü separat von Speisen ansehen oder sogar vegetarische Optionen angeben kann.
4. Der Einkaufswagen
In diesem Abschnitt des Codelabs bauen wir die Warenkorbfunktion auf, die auf dem vorherigen Abschnitt basiert, in dem wir die verfügbaren Produkte durchsuchen können.
Die wichtigsten Funktionen des Einkaufswagens sind, dass Nutzer Artikel in den Einkaufswagen legen, Artikel aus dem Einkaufswagen entfernen, die Anzahl der einzelnen Artikel im Einkaufswagen im Blick behalten und Artikel im Einkaufswagen überprüfen können.
Um den Status des Einkaufswagens im Blick zu behalten, müssen wir Daten in der Webanwendung speichern. Um das Testen und Bereitstellen zu vereinfachen, verwenden wir Google Datastore in der Google Cloud Platform, um Daten zu speichern. Die Unterhaltungs-ID bleibt zwischen einem Nutzer und dem Unternehmen konstant. So können wir Nutzer mit Einkaufswagenartikeln verknüpfen.
Beginnen wir damit, eine Verbindung zu Google Datastore herzustellen und die Unterhaltungs-ID zu speichern, wenn wir sie sehen.
Verbindung zu Datastore herstellen
Wir stellen eine Verbindung zu Google Datastore her, wenn eine Interaktion mit dem Einkaufswagen ausgeführt wird, z. B. 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.
Im folgenden Snippet wird eine Funktion zum Aktualisieren des Einkaufswagens definiert. Die Funktion akzeptiert die folgenden Eingaben: conversation_id und message. message enthält JSON-Code, der die Aktion beschreibt, die der Nutzer ausführen möchte. Dieser 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 Konversations-ID ist.
Kopieren Sie die folgende Funktion in Ihre Datei „views.py“. Im nächsten Abschnitt werden wir noch genauer darauf eingehen.
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)
Wir erweitern diese Funktion, um einen Artikel in den Einkaufswagen zu legen.
Artikel in den Einkaufswagen legen
Wenn der Nutzer im Produktkarussell auf die vorgeschlagene Aktion Artikel hinzufügen tippt, enthält „postbackData“ JSON-Code, der die gewünschte Aktion des Nutzers beschreibt. Das JSON-Wörterbuch hat zwei Schlüssel: „action“ und „item_name“. Dieses JSON-Wörterbuch wird an Ihren Webhook gesendet. Das Feld „item_name“ ist die eindeutige Kennung, die dem Artikel in der Datei „inventory.json“ zugewiesen ist.
Sobald wir den Warenkorbbefehl und den Warenkorbartikel aus der Nachricht geparst haben, können wir bedingte Anweisungen schreiben, um den Artikel hinzuzufügen. Einige Grenzfälle, die Sie hier berücksichtigen sollten, sind, wenn die Konversations-ID noch nie im Datenspeicher vorhanden war oder wenn der Einkaufswagen diesen Artikel zum ersten Mal erhält. Das Folgende ist eine Erweiterung der oben definierten update_shopping_cart-Funktionalität. Durch diese Änderung wird dem Einkaufswagen ein Artikel hinzugefügt, der von Google Datastore gespeichert wird.
Das folgende Snippet ist eine Erweiterung der vorherigen Funktion, die Sie Ihrer Datei „views.py“ hinzugefügt haben. Sie können die Differenz hinzufügen oder das Snippet kopieren und die vorhandene Version der update_shopping_cart-Funktion 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, in dem cart_cmd den in CMD_DEL_ITEM definierten String „del-item“ enthält.
Zusammenfassung
Achten Sie darauf, dass Sie die erforderlichen Schritte in der Funktion route_message hinzufügen, damit die Funktion update_shopping_cart aufgerufen wird, wenn Sie eine Nachricht 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 Konvention, die wir im gesamten Codelab verwenden.
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 können wir Artikel in den Einkaufswagen legen. Wenn Sie Ihre Änderungen in Google App Engine bereitstellen, sollten die Änderungen am Warenkorb im Google Datastore-Dashboard in der GCP Console zu sehen sein. Im Screenshot unten sehen Sie die Google Datastore-Konsole. Es ist eine einzelne Entität zu sehen, die nach der Konversations-ID benannt ist, gefolgt von einigen Beziehungen zu Inventarartikeln und der Menge dieser Artikel im Einkaufswagen.

Im nächsten Abschnitt erstellen wir eine Möglichkeit, Artikel im Einkaufswagen aufzulisten. Der Mechanismus zur Überprüfung des Einkaufswagens sollte alle Artikel im Einkaufswagen, die Menge dieser Artikel und eine Option zum Entfernen eines Artikels aus dem Einkaufswagen anzeigen.
Artikel im Einkaufswagen prüfen
Nur wenn wir die Artikel im Einkaufswagen auflisten, können wir den Status des Einkaufswagens nachvollziehen und wissen, welche Artikel wir entfernen können.
Senden wir zuerst eine freundliche Nachricht wie „Hier ist dein Einkaufswagen:“, gefolgt von einer weiteren Nachricht mit einem Rich Card-Karussell mit zugehörigen Vorschlägen für Antworten wie „Einen Artikel entfernen“ oder „Einen Artikel hinzufügen“. Im Rich Card-Karussell sollte zusätzlich die Anzahl der im Einkaufswagen gespeicherten Artikel aufgeführt werden.
Bevor wir die Funktion schreiben, sollten wir Folgendes beachten: Wenn sich nur ein Artikeltyp im Einkaufswagen befindet, kann er nicht als Karussell gerendert werden. Karussells mit Rich Cards müssen mindestens zwei Karten enthalten. Wenn sich keine Artikel im Einkaufswagen befinden, soll eine einfache Meldung angezeigt werden, dass der Einkaufswagen leer ist.
Definieren wir also eine Funktion namens send_shopping_cart. Diese Funktion stellt eine Verbindung zu Google Datastore her und fordert eine ShoppingCart-Entität basierend auf der Konversations-ID an. Sobald wir diese Informationen haben, rufen wir die Funktion get_inventory_data auf und verwenden ein Karussell mit Rich Cards, um den Status des Einkaufswagens zu melden. Wir müssen auch die ID eines Produkts anhand des Namens abrufen. Dazu können wir eine Funktion deklarieren, die im Google-Datenspeicher nach diesem Wert sucht. Während das Karussell erstellt wird, können wir vorgeschlagene Antworten zum Löschen oder Hinzufügen von Elementen anhand der Produkt-ID zuordnen. Das folgende Snippet führt alle diese Vorgänge aus. Kopieren Sie den Code an eine beliebige Stelle in „views.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)
...
Achten Sie darauf, dass Sie CMD_SHOW_CART bereits oben in views.py definiert haben, und rufen Sie send_shopping_cart auf, wenn der Nutzer eine Nachricht mit „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)
...

Gemäß der Logik, die wir in der send_shopping_cart-Funktion eingeführt haben, erhalten wir, wenn Sie „show-cart“ eingeben, entweder eine Meldung, dass sich nichts im Warenkorb befindet, eine Rich Card mit dem einen Artikel im Warenkorb oder ein Karussell mit Karten mit mehreren Artikeln. Außerdem haben wir drei Antwortvorschläge: „Gesamtpreis ansehen“, „Warenkorb leeren“ und „Menü ansehen“.
Stellen Sie die oben genannten Codeänderungen bereit, um zu testen, ob in Ihrem Einkaufswagen Artikel erfasst werden, die Sie hinzufügen, und ob Sie den Einkaufswagen über die Konversationsoberfläche aufrufen können, wie in den Screenshots oben gezeigt. Sie können die Änderungen mit diesem Befehl bereitstellen, der im Verzeichnis „step-2“ ausgeführt wird, in dem Sie die Änderungen vornehmen.
$ gcloud app deploy
Die Funktion „Gesamtpreis ansehen“ wird im nächsten Abschnitt erstellt, nachdem die Funktion zum Entfernen eines Artikels aus dem Einkaufswagen implementiert wurde. Die Funktion get_cart_price verhält sich ähnlich wie die Funktion „Warenkorb ansehen“, da sie Daten in Datastore mit der Datei „inventory.json“ abgleicht, um einen Gesamtpreis für den Warenkorb zu ermitteln. Das ist für den nächsten Teil des Codelabs nützlich, in dem wir die Zahlungsfunktion einbinden.
Artikel aus dem Einkaufswagen entfernen
Schließlich können wir das Verhalten des Einkaufswagens vervollständigen, indem wir eine Funktion zum Entfernen des Einkaufswagens 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 Warenkorb legt, sollten Sie eine Bestätigungsnachricht senden, in der Sie seine Aktion bestätigen und angeben, dass Sie seine Anfrage bearbeitet haben. So werden nicht nur Erwartungen geweckt, sondern auch die Unterhaltung am Laufen gehalten.
Wir erweitern die Funktion update_shopping_cart so, dass eine Nachricht mit der Konversations-ID gesendet wird, in der angegeben wird, dass der Artikel hinzugefügt oder entfernt wurde. Außerdem werden Vorschläge gemacht, den Einkaufswagen zu überprüfen oder das Menü noch einmal aufzurufen.
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)

Das sollte es gewesen sein. Ein voll funktionsfähiger Einkaufswagen, in dem Nutzer Artikel hinzufügen, entfernen und überprüfen können.
Wenn Sie die Einkaufswagenfunktion in der Business Messages-Unterhaltung sehen möchten, stellen Sie die Anwendung bereit, um mit Ihrem Kundenservice-Agent zu interagieren. Führen Sie dazu diesen Befehl im Verzeichnis „step-2“ aus.
$ gcloud app deploy
5. Vorbereitung auf Zahlungen
Zur Vorbereitung auf die Integration mit einem Zahlungsabwickler im nächsten Teil der Reihe benötigen wir eine Möglichkeit, den Preis des Einkaufswagens abzurufen. Wir erstellen eine Funktion, die den Preis abruft, indem sie die Warenkorbdaten in Google Datastore abgleicht, 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
...
Schließlich können wir diese Funktion nutzen 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 zusammenzufassen, aktualisieren wir die Funktion route_message 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 mit der oben genannten Logik erreicht wird:

Wenn wir im nächsten Teil des Codelabs bereit sind, die Integration mit dem Zahlungsabwickler vorzunehmen, 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 Warenkorbfunktion noch einmal in der Business Messages-Unterhaltung testen, indem Sie die Anwendung bereitstellen und mit Ihrem Agent interagieren.
$ gcloud app deploy
6. Glückwunsch
Glückwunsch! Sie haben erfolgreich eine Warenkorbfunktion in Business Messages erstellt.
Eine Funktion, die wir in diesem Codelab nicht behandelt haben, ist das Leeren des gesamten Einkaufswagens. Wenn Sie möchten, können Sie die Anwendung so erweitern, dass sie die Funktion „Warenkorb leeren“ unterstützt. Die Lösung ist in Schritt 3 des geclonten Quellcodes verfügbar.
In einem späteren Abschnitt werden wir einen externen Zahlungsabwickler einbinden, damit Ihre Nutzer eine Zahlungstransaktion mit Ihrer Marke abschließen können.
Was macht einen guten Einkaufswagen aus?
Ein guter Einkaufswagen in einem Gespräch unterscheidet sich nicht von einem in einer mobilen App oder in einem physischen Geschäft. Artikel hinzufügen, Artikel entfernen und den Preis des Einkaufswagens berechnen – das sind nur einige der Funktionen, die wir in diesem Codelab untersucht haben. Ein Unterschied zum Einkaufswagen in der realen Welt besteht darin, dass Sie den Preis aller Artikel im Einkaufswagen jederzeit sehen können, wenn Sie Artikel hinzufügen oder entfernen. Mit diesen hochwertigen Funktionen können Sie Ihr dialogorientiertes Kauferlebnis von der Konkurrenz abheben.
Nächste Schritte
Wenn Sie bereit sind, können Sie sich die folgenden Themen ansehen, um mehr über komplexere Interaktionen zu erfahren, die Sie in Business Messages ermöglichen können:
- Wie funktionieren Business Messages?
- Best Practices
- Richtlinien für Logos
- Übergabe an Kundenservicemitarbeiter
Referenzdokumente
- SuggestedReply
- Referenzdokument für Business Messages-Nachrichten
- JSON-Definition für RichCard