Buy Online Pickup In Store: Bonjour Meal - Part 2 - Building a Shopping Cart
Informationen zu diesem Codelab
1. Einführung
Zuletzt aktualisiert: 30.10.2020
Einkaufswagen in Business Messages
Dies ist das zweite Codelab in einer Reihe, die darauf abzielt, eine User Journey für den Kauf im Internet mit Abholung im Geschäft zu erstellen. Bei vielen E-Commerce-Kaufprozessen ist ein Einkaufswagen entscheidend für den Erfolg der Umwandlung von Nutzern in zahlende Kunden. Der Einkaufswagen ist auch eine Möglichkeit, Ihre Kunden besser zu verstehen und ihnen Vorschläge zu anderen Artikeln zu machen, die sie interessieren könnten. In diesem Codelab konzentrieren wir uns auf den Aufbau des Einkaufswagens und die Bereitstellung der Anwendung in der Google App Engine.
Was macht einen guten Einkaufswagen aus?
Einkaufswagen sind ein wichtiger Bestandteil eines erfolgreichen Online-Shoppings. Wie sich herausstellte, eignen sich Business Messages nicht nur gut für Fragen und Antworten zu einem Produkt mit einem potenziellen Kunden, sondern können auch den gesamten Kaufprozess bis hin zur Zahlung innerhalb der Unterhaltung erleichtern.
Ein guter Einkaufswagen ist nur ein Teil des Einkaufserlebnisses. Nutzer sollten auch nach Kategorien suchen und sich von Unternehmen andere Produkte empfehlen lassen können, die für sie interessant sein könnten. Nachdem der Nutzer weitere Artikel in den Einkaufswagen gelegt hat, kann er den gesamten Warenkorb prüfen und Artikel entfernen oder weitere hinzufügen, bevor er zur Kasse geht.
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, damit Nutzer einen Artikelkatalog durchsuchen und Artikel in einen Einkaufswagen legen können.
In diesem Codelab wird Ihre App
- Katalog mit Fragen in Business Messages anzeigen
- Elemente vorschlagen, die Nutzer interessieren könnten
- Inhalt des Einkaufswagens prüfen und eine Zusammenfassung des Gesamtpreises erstellen
Aufgaben in diesem Lab
- Webanwendung in der App Engine auf der Google Cloud Platform bereitstellen
- Status eines Einkaufswagens mit einem persistenten Speichermechanismus speichern
In diesem Codelab geht es darum, den digitalen Kundenservicemitarbeiter 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 findest du auf unserer Entwicklerwebsite.
- Eine JSON-Anmeldedatendatei für das Dienstkonto, die für Ihr GCP-Projekt generiert wurde
- Ein Android-Gerät mit Version 5 ODER ein iOS-Gerät mit der Google Maps App
- Erfahrung mit 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 nicht auf die Grundlagen des Aktivierens der Business Messages APIs und der Business Communications APIs, das Erstellen von Dienstkontoschlüsseln, das Bereitstellen einer Anwendung oder das Einrichten Ihres Webhooks in der Business Communications Console eingehen. Wir werden jedoch eine Beispielanwendung klonen, um sicherzustellen, dass Ihre Anwendung mit der Basis übereinstimmt, auf der wir aufbauen. Außerdem aktivieren wir die API für Datastore auf der Google Cloud Platform, um Daten zum Einkaufswagen dauerhaft zu speichern.
Anwendung aus GitHub klonen
Klonen Sie in einem Terminal das Django-Echo-Bot-Beispiel 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 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 in der Google Cloud Console die Google Datastore API.
- Achten Sie darauf, dass Sie mit dem richtigen GCP-Projekt arbeiten.
- Klicken Sie auf Aktivieren.
Beispielanwendung bereitstellen
Rufen Sie in einem Terminal das Verzeichnis „step-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 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 mit den Test-URLs testen, die Sie in der Business Communications Console unter „Agent-Informationen“ abrufen können. Über die Test-URLs wird Business Messages auf Ihrem Mobilgerät gestartet und Sie können dort mit Ihrem Kundenservicemitarbeiter interagieren.
3. Produktkatalog
Ein Inventarsystem
In den meisten Fällen können Sie sich über eine interne API direkt in das Inventar einer Marke einbinden. In anderen Fällen können Sie eine Webseite scrapen oder ein eigenes Inventar-Tracking-System erstellen. Wir konzentrieren uns nicht darauf, ein Inventarsystem zu erstellen, sondern verwenden eine einfache statische Datei mit Bildern und Produktinformationen für unseren Kundenservicemitarbeiter. In diesem Abschnitt rufen wir Informationen aus dieser statischen Datei ab, fügen sie der Unterhaltung hinzu und ermöglichen es Nutzern, die verfügbaren Artikel zu durchsuchen und in den Einkaufswagen zu legen.
Die Datei mit dem statischen Inventar 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 so konfigurieren, dass sie diese Datei liest.
Daten aus unserem Inventar lesen
Das Inventar ist eine statische Datei namens „inventory.json“, die sich im Verzeichnis „./resources“ befindet. Wir müssen 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 einliest 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
...
Damit sollten wir alles haben, was wir zum Lesen der Daten aus dem Inventar benötigen. Jetzt brauchen wir eine Möglichkeit, diese Produktinformationen in die Unterhaltung einzubringen.
Produktkatalog präsentieren
In diesem Codelab verwenden wir zur Vereinfachung einen allgemeinen Produktkatalog, um alle Inventarelemente über ein einziges Karussell mit Rich Cards in der Unterhaltung in Messages anzuzeigen.
Um den Produktkatalog aufzurufen, erstellen wir eine vorgeschlagene Antwort mit dem Text „Menü anzeigen“ und den Postback-Daten „show-product-catalog
“. Wenn Nutzer auf die vorgeschlagene Antwort tippen und Ihre Webanwendung die Postback-Daten empfängt, senden wir das Karussell mit den Rich Cards. Fügen wir oben in „views.py“ eine neue Konstante für diese vorgeschlagene Antwort hinzu.
bonjourmeal-codelab/step-2/bopis/views.py
...
CMD_SHOW_PRODUCT_CATALOG = 'show-product-catalog'
...
Anschließend wird die Nachricht geparst und an eine neue Funktion weitergeleitet, die ein Karussell mit Rich Cards mit dem Produktkatalog sendet. Erweitern Sie zuerst die Funktion route_message
, um die Funktion „send_product_catalog
“ aufzurufen, wenn die vorgeschlagene Antwort angetippt wird. Anschließend definieren wir die Funktion.
Fügen Sie im folgenden Snippet der If-Anweisung in der route_message
-Funktion 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)
...
Und wir sollten den Ablauf abschließen und send_product_catalog
definieren. send_product_catalog
ruft get_menu_carousel,
auf, das das Karussell mit den Rich Cards aus der zuvor eingelesenen Inventardatei generiert.
Die Funktionsdefinitionen können überall in „views.py“ platziert werden. Im folgenden Snippet werden zwei neue Konstanten verwendet, die oben in die Datei eingefü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, wird auch eine Instanz der Klasse BusinessMessagesSuggestion
erstellt. Jeder Vorschlag steht für eine Nutzerauswahl für ein Produkt im Karussell. Wenn ein Nutzer auf die vorgeschlagene Antwort tippt, sendet Business Messages die Postback-Daten, die JSON mit einer Beschreibung des Artikels und der Aktion enthalten, die der Nutzer ausführen möchte (in den Einkaufswagen legen oder daraus entfernen), an Ihren Webhook. Im folgenden Abschnitt werden wir Nachrichten wie diese analysieren, um den Artikel dem Einkaufswagen hinzufügen zu können.
Nachdem wir diese Änderungen vorgenommen haben, können wir die Webanwendung in der Google App Engine bereitstellen und testen.
$ gcloud app deploy
Wenn die Konversationsoberfläche auf Ihrem Mobilgerät geladen ist, senden Sie die Nachricht „show-product-catalog“. Daraufhin sollte ein Karussell mit Produkten angezeigt werden, das so aussieht:
Wenn Sie auf Element hinzufügen tippen,passiert nichts weiter. Der Kundenservicemitarbeiter gibt lediglich die Postback-Daten aus der vorgeschlagenen Antwort zurück. Im nächsten Abschnitt verwenden wir den Produktkatalog, um den Einkaufswagen zu erstellen, in dem der Artikel hinzugefügt wird.
Der gerade erstellte Produktkatalog kann auf verschiedene Arten erweitert werden. Möglicherweise haben Sie verschiedene Getränkeoptionen oder vegetarische Optionen. Karussells oder Vorschlags-Chips sind eine gute Möglichkeit, Nutzern die Möglichkeit zu geben, Menüoptionen zu durchsuchen, um die gewünschten Produkte zu finden. Als Erweiterung dieses Codelabs können Sie das Produktkatalogsystem so erweitern, dass Nutzer Getränke im Menü getrennt von Speisen ansehen oder sogar vegetarische Optionen angeben können.
4. Einkaufswagen
In diesem Abschnitt des Codelabs bauen wir die Funktionen des Einkaufswagens auf dem vorherigen Abschnitt auf, sodass wir die verfügbaren Produkte durchsuchen können.
Nutzer können unter anderem Artikel in den Einkaufswagen legen, Artikel aus dem Einkaufswagen entfernen, die Anzahl der einzelnen Artikel im Einkaufswagen im Blick behalten und die Artikel im Einkaufswagen ansehen.
Wenn wir den Status des Einkaufswagens im Auge behalten möchten, müssen wir Daten in der Webanwendung speichern. Zur Vereinfachung von Tests und Bereitstellung 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.
Stellen wir zuerst eine Verbindung zu Google Datastore her und speichern die Unterhaltungs-ID, sobald sie angezeigt wird.
Verbindung mit 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 nimmt die folgenden Eingaben an: 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 das Karussell mit dem Produktkatalog eingebunden. 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 die Datei „views.py“. Im nächsten Abschnitt gehen wir darauf näher 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 diese Funktion, um einen Artikel in den Einkaufswagen zu legen.
Artikel in den Einkaufswagen legen
Wenn der Nutzer im Produktkarussell auf eine vorgeschlagene Aktion Artikel hinzufügen tippt, enthält „postbackData“ JSON-Daten, die die Aktion beschreiben, die der Nutzer ausführen möchte. Das JSON-Wörterbuch hat zwei Schlüssel: „action“ und „item_name“. Es wird an deinen Webhook gesendet. Das Feld „item_name“ ist die eindeutige Kennung, die dem Artikel in „inventory.json“ zugeordnet ist.
Nachdem wir den Warenkorbbefehl und das Warenkorbelement aus der Nachricht geparst haben, können wir bedingte Anweisungen schreiben, um das Element hinzuzufügen. Einige Grenzfälle, die Sie hier berücksichtigen sollten, sind, wenn die Unterhaltungs-ID noch nie im Datenspeicher vorhanden war oder wenn der Einkaufswagen diesen Artikel zum ersten Mal erhält. Im Folgenden wird die oben definierte Funktion update_shopping_cart
erweitert. 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 Ihrer Datei „views.py“ hinzugefügt wurde. Sie können den Unterschied 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, die erforderlichen Codezeilen in die route_message
-Funktion einzufügen, damit die update_shopping_cart
-Funktion aufgerufen wird, wenn Sie eine Nachricht erhalten, dass Sie einen Artikel in den Einkaufswagen legen sollen. Außerdem müssen Sie eine Konstante zum Hinzufügen von Elementen definieren. Verwenden Sie dabei 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 der Google App Engine bereitstellen, sollten die Änderungen am Einkaufswagen im Google Datastore-Dashboard in der GCP Console zu sehen sein. Im Screenshot unten der Google Datastore Console ist eine einzelne Entität zu sehen, die nach der Unterhaltungs-ID benannt ist. Es folgen einige Beziehungen zu Inventarartikeln und die Menge dieser Artikel, die sich im Einkaufswagen befinden.
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 Sie die Artikel im Einkaufswagen auflisten, können wir den Status des Einkaufswagens nachvollziehen und wissen, welche Artikel wir entfernen können.
Senden Sie zuerst eine freundliche Nachricht wie „Hier ist Ihr Einkaufswagen:“ und dann eine weitere Nachricht mit einem Karussell mit Rich Cards, die Vorschläge für Antworten wie „Artikel entfernen“ oder „Artikel hinzufügen“ enthalten. Im Karussell mit der erweiterten Karte sollte außerdem die Anzahl der im Einkaufswagen gespeicherten Artikel aufgeführt werden.
Bevor wir mit dem Schreiben der Funktion beginnen, sollten wir uns Folgendes bewusst machen: Wenn sich nur ein Artikeltyp im Einkaufswagen befindet, können wir ihn nicht als Karussell rendern. Karussells mit Infokarten müssen mindestens zwei Karten enthalten. Wenn sich dagegen keine Artikel im Einkaufswagen befinden, soll eine einfache Meldung angezeigt werden, dass der Einkaufswagen leer ist.
Definieren wir dazu eine Funktion namens send_shopping_cart
. Diese Funktion stellt eine Verbindung zu Google Datastore her und fordert eine ShoppingCart-Entität anhand der Unterhaltungs-ID an. Anschließend rufen wir die Funktion get_inventory_data
auf und verwenden ein Karussell mit Rich Cards, um den Status des Einkaufswagens zu melden. Außerdem müssen wir die ID eines Produkts anhand des Namens abrufen. Dazu können wir eine Funktion deklarieren, die in Google Datastore nach diesem Wert sucht. Während das Karussell erstellt wird, können wir vorgeschlagene Antworten zuordnen, um Elemente zu löschen oder Elemente anhand der Produkt-ID hinzuzufügen. Im folgenden Snippet werden alle diese Vorgänge ausgeführt. Fügen Sie den Code an einer beliebigen Stelle in „views.py“ ein.
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)
...
Du musst CMD_SHOW_CART
oben in „views.py“ definiert haben und send_shopping_cart
aufrufen, 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)
...
Basierend auf der Logik, die wir in der send_shopping_cart
-Funktion eingeführt haben, erhalten wir, wenn Sie „show-cart“ eingeben, entweder die Meldung, dass sich nichts im Einkaufswagen befindet, eine Rich Card mit dem einen Artikel im Einkaufswagen oder ein Karussell mit Karten mit mehreren Artikeln. Außerdem haben wir drei vorgeschlagene Antworten: „Gesamtpreis ansehen“, „Einkaufswagen leeren“ und „Menü ansehen“.
Testen Sie die obigen Codeänderungen, um zu prüfen, ob die Artikel, die Sie hinzufügen, im Einkaufswagen erfasst werden und ob Sie den Einkaufswagen wie in den Screenshots oben gezeigt auf der Oberfläche für Unterhaltungen überprüfen können. Sie können die Änderungen mit diesem Befehl aus dem Verzeichnis „Schritt 2“, in dem Sie die Änderungen vornehmen, bereitstellen.
$ gcloud app deploy
Wir erstellen die Funktion „Gesamtpreis ansehen“ im nächsten Abschnitt, nachdem wir die Funktion zum Entfernen eines Artikels aus dem Einkaufswagen erstellt haben. Die Funktion get_cart_price
verhält sich ähnlich wie die Funktion „Einkaufswagen ansehen“: Sie vergleicht Daten im Datastore mit der Datei „inventory.json“, um einen Gesamtpreis für den Einkaufswagen zu ermitteln. Das ist praktisch für den nächsten Teil des Codelabs, in dem wir Zahlungen einbinden.
Artikel aus dem Einkaufswagen entfernen
Zum Abschluss können wir das Verhalten des Einkaufswagens vervollständigen, indem wir eine Funktion zum Entfernen des Wagens 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, sollten Sie ihm eine Bestätigungsnachricht senden, in der Sie seine Aktion bestätigen und ihm mitteilen, dass Sie seine Anfrage bearbeitet haben. So können Sie nicht nur die Erwartungen steuern, sondern auch die Unterhaltung am Laufen halten.
Erweitern wir die Funktion update_shopping_cart
so, dass eine Nachricht an die Unterhaltungs-ID gesendet wird, in der steht, dass der Artikel hinzugefügt oder entfernt wurde, und Vorschläge gemacht werden, 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 sein. Ein voll funktionsfähiger Einkaufswagen, mit dem Nutzer Artikel hinzufügen, entfernen und im Einkaufswagen ansehen können.
Wenn Sie die Einkaufswagenfunktion in der Business Messages-Unterhaltung sehen möchten, müssen Sie die Anwendung bereitstellen, um mit Ihrem Kundenservicemitarbeiter 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. Erstellen wir eine Funktion, die den Preis für uns abruft, indem sie die Daten im Einkaufswagen in Google Datastore abgleicht, den Preis jedes Artikels aus dem Inventar abruft und den Preis mit der Stückzahl jedes Artikels im Einkaufswagen 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 verwenden 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 zusammenzuführen, aktualisieren wir die Funktion route_message
und die Konstante, um die oben beschriebene 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 beschriebenen Logik erreicht wird:
Wenn wir im nächsten Teil des Codelabs die Integration mit dem Zahlungsabwickler vornehmen, rufen wir die Funktion get_cart_price
auf, um die Daten an den Zahlungsabwickler weiterzuleiten und den Zahlungsvorgang zu starten.
Sie können diese Einkaufswagenfunktion auch in einer Business Messages-Unterhaltung testen, indem Sie die Anwendung bereitstellen und mit Ihrem Kundenservicemitarbeiter interagieren.
$ gcloud app deploy
6. Glückwunsch
Herzlichen Glückwunsch! Sie haben in Business Messages einen Einkaufswagen erstellt.
In diesem Codelab haben wir die Funktion zum Leeren des gesamten Einkaufswagens nicht behandelt. Sie können die Anwendung gerne erweitern, um die Funktion „Einkaufswagen leeren“ zu implementieren. Die Lösung finden Sie in Schritt 3 des geklonten Quellcodes.
In einem späteren Abschnitt integrieren wir einen externen Zahlungsabwickler, damit Ihre Nutzer eine Zahlungstransaktion mit Ihrer Marke abschließen können.
Was macht einen guten Einkaufswagen aus?
Ein guter Einkaufswagen in einem Chat unterscheidet sich nicht von einem in einer mobilen App oder in einem Geschäft. In diesem Codelab haben wir nur einige Funktionen kennengelernt, z. B. das Hinzufügen und Entfernen von Artikeln und das Berechnen des Preises des Einkaufswagens. Anders als bei einem realen Einkaufswagen können Sie den Preis aller Artikel im Einkaufswagen jederzeit sehen, wenn Sie Artikel hinzufügen oder entfernen. Mit diesen nützlichen Funktionen können Sie sich von der Konkurrenz abheben.
Was liegt als Nächstes an?
Wenn Sie bereit sind, können Sie sich die folgenden Themen ansehen, um mehr über komplexere Interaktionen zu erfahren, die Sie mit Business Messages erzielen können:
- So 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