Acquista online Ritiro in negozio: Pasto Bonjour - Parte 2 - Costruire un carrello degli acquisti

Acquista online, ritira in negozio:
Bonjour Meal - Parte 2 - Creazione di un carrello degli acquisti

Informazioni su questo codelab

subjectUltimo aggiornamento: nov 14, 2024
account_circleScritto da: Adam Chan

1. Introduzione

53003251caaf2be5.png 8826bd8cb0c0f1c7.png

Ultimo aggiornamento: 30/10/2020

Creazione di un carrello degli acquisti su Business Messages

Questo è il secondo codelab di una serie finalizzata alla creazione di un percorso dell'utente per l'acquisto online e il ritiro in negozio. In molti percorsi di e-commerce, un carrello degli acquisti è fondamentale per convertire gli utenti in clienti paganti. Il carrello degli acquisti è anche un modo per comprendere meglio i tuoi clienti e offrire suggerimenti su altri articoli che potrebbero interessare loro. In questo codelab ci concentreremo sulla creazione dell'esperienza del carrello degli acquisti e sul deployment dell'applicazione in Google App Engine.

Quali sono le caratteristiche di un buon carrello degli acquisti?

I carrelli degli acquisti sono fondamentali per un'esperienza di acquisto online positiva. A quanto pare, Business Messages non è solo utile per facilitare le domande e le risposte su un prodotto con un potenziale cliente, ma può semplificare l'intera esperienza di acquisto fino al completamento di un pagamento all'interno della conversazione.

9d17537b980d0e62.png

Oltre a un buon carrello degli acquisti, un'esperienza di acquisto ottimale consente agli utenti di sfogliare gli articoli per categoria e permette all'attività di consigliare altri prodotti che potrebbero interessare all'acquirente. Dopo aver aggiunto altri articoli al carrello degli acquisti, l'utente può esaminare l'intero carrello ed essere in grado di rimuovere articoli o aggiungerne altri prima di effettuare il pagamento.

Cosa creerai

In questa sezione della serie di codelab, espandi l'agente digitale che hai creato nella parte 1 per la società fittizia Bonjour Meal, in modo che gli utenti possano sfogliare un catalogo di articoli e aggiungerli a un carrello degli acquisti.

In questo codelab, la tua app:

  • Mostrare un catalogo di domande in Business Messages
  • Suggerire articoli che potrebbero interessare agli utenti
  • Esamina i contenuti del carrello degli acquisti e crea un riepilogo del prezzo totale

ab2fb6a4ed33a129.png

Cosa imparerai a fare

  • Come eseguire il deployment di un'applicazione web su App Engine nella piattaforma Google Cloud
  • Come utilizzare un meccanismo di archiviazione permanente per salvare lo stato di un carrello degli acquisti

Questo codelab è incentrato sull'estensione dell'agente digitale della prima parte di questa serie di codelab.

Che cosa ti serve

2. Preparazione

Questo codelab presuppone che tu abbia creato il tuo primo agente e completato la parte 1 del codelab. Di conseguenza, non esamineremo le nozioni di base per attivare le API Business Messages e Business Communications, creare chiavi dell'account di servizio, eseguire il deployment di un'applicazione o configurare l'webhook nella console Business Communications. Detto questo, cloneremo un'applicazione di esempio per assicurarci che sia coerente con la base su cui stiamo lavorando e attiveremo l'API per Datastore sulla piattaforma Google Cloud per poter mantenere i dati relativi al carrello degli acquisti.

Clonazione dell'applicazione da GitHub

In un terminale, clona l'esempio di bot Django Echo nella directory di lavoro del progetto con il seguente comando:

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

Copia il file delle credenziali JSON creato per l'account di servizio nella cartella delle risorse del Sample e rinomina le credenziali in "bm-agent-service-account-credentials.json".

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

Attiva l'API Google Datastore

Nella Parte 1 di questo codelab hai attivato l'API Business Messages, l'API Business Communications e l'API Cloud Build.

Per questo codelab, poiché lavoreremo con Google Datastore, dobbiamo anche abilitare questa API:

  1. Apri l'API Google Datastore nella console Google Cloud.
  2. Assicurati di utilizzare il progetto Google Cloud corretto.
  3. Fai clic su Abilita.

Deployment dell'applicazione di esempio

In un terminale, vai alla directory step-2 dell'esempio.

Esegui i seguenti comandi in un terminale per eseguire il deployment dell'esempio:

$ gcloud config set project PROJECT_ID*
$
gcloud app deploy
  • PROJECT_ID è l'ID progetto che hai utilizzato per registrarti alle API.

Prendi nota dell'URL dell'applicazione di cui è stato eseguito il deployment nell'output dell'ultimo comando:

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

Il codice appena di cui hai eseguito il deployment contiene un'applicazione web con un webhook per ricevere messaggi da Business Messages. Contiene tutto ciò che abbiamo fatto nella parte 1 del codelab. Se non l'hai ancora fatto, configura il tuo webhook.

L'applicazione risponderà ad alcune semplici richieste, ad esempio un utente che chiede informazioni sugli orari di apertura di Bonjour Meal. Dovresti testarlo sul tuo dispositivo mobile tramite gli URL di test che puoi recuperare dalle informazioni sull'agente nella console Business Communications. Gli URL di test apriranno l'esperienza Business Messages sul tuo dispositivo mobile e potrai iniziare a interagire con il tuo agente.

3. Il catalogo dei prodotti

Un sistema di inventario

Nella maggior parte dei casi, puoi eseguire l'integrazione direttamente con l'inventario di un brand tramite un'API interna. In altri casi, potresti eseguire lo scraping di una pagina web o creare il tuo sistema di monitoraggio dell'inventario. Il nostro obiettivo non è creare un sistema di inventario; utilizzeremo un semplice file statico contenente immagini e informazioni sul prodotto per il nostro agente. In questa sezione, estrarremo le informazioni da questo file statico, le presenteremo nella conversazione e consentiremo a un utente di sfogliare gli articoli disponibili da aggiungere a un carrello degli acquisti.

Il file di inventario statico ha il seguente aspetto:

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
       
}
   
]
}

Facciamo in modo che l'applicazione Python legga questo file.

Lettura dal nostro inventario

L'inventario è un file statico denominato "inventory.json" che si trova nella directory ./resources. Dobbiamo aggiungere un po' di logica Python a views.py per leggere i contenuti del file JSON e poi mostrarli nella conversazione. Creiamo una funzione che legga i dati dal file JSON e restituisca l'elenco dei prodotti disponibili.

Questa definizione di funzione può essere posizionata in qualsiasi punto di views.py.

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

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

Dovrebbe darci ciò che ci serve per leggere i dati dall'inventario. Ora abbiamo bisogno di un modo per mostrare queste informazioni sul prodotto nella conversazione.

Visualizzazione del catalogo dei prodotti

Per semplicità, in questo codelab abbiamo un catalogo di prodotti generale per mostrare tutti gli articoli di inventario nella conversazione di Business Messages tramite un unico carosello di schede avanzate.

Per visualizzare il catalogo dei prodotti, creeremo una risposta suggerita con il testo "Mostra menu" e postbackData "show-product-catalog". Quando gli utenti toccano la risposta suggerita e la tua applicazione web riceve i dati di postback, invieremo il carosello di schede avanzate. Aggiungiamo una nuova costante per questa risposta suggerita nella parte superiore di views.py.

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

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

Da qui, analizziamo il messaggio e lo inoltriamo a una nuova funzione che invia un carosello di schede avanzate contenente il catalogo dei prodotti. Per prima cosa, espandi la funzione route_message per chiamare una funzione "send_product_catalog" quando viene toccata la risposta suggerita, quindi definisci la funzione.

Nel seguente snippet, aggiungi un'ulteriore condizione all'istruzione if nella funzione route_message per verificare se normalized_message è uguale alla costante CMD_SHOW_PRODUCT_CATALOG che abbiamo definito in precedenza.

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

Assicurati di completare il flusso e di definire send_product_catalog. send_product_catalog chiama get_menu_carousel, che genera il carosello di schede interattive dal file di inventario letto in precedenza.

Le definizioni delle funzioni possono essere posizionate ovunque in views.py. Tieni presente che lo snippet seguente utilizza due nuove costanti che devono essere aggiunte all'inizio del file.

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

Se esamini la creazione degli elementi del carosello, noterai che viene creata anche un'istanza della classe BusinessMessagesSuggestion. Ogni suggerimento rappresenta una selezione dell'utente per un prodotto nel carosello. Quando un utente tocca la risposta suggerita, Business Messages invia al tuo webhook i dati postback che contengono JSON che descrive l'articolo e l'azione che l'utente vuole eseguire (aggiungere o rimuovere dal carrello). Nella sezione seguente, analizzeremo i messaggi simili a questo per poter effettivamente aggiungere l'articolo al carrello.

Ora che abbiamo apportato queste modifiche, eseguiamo il deployment dell'applicazione web in Google App Engine e proviamo l'esperienza.

$ gcloud app deploy

Quando hai caricato la piattaforma di conversazione sul tuo dispositivo mobile, invia il messaggio "show-product-catalog" e dovresti visualizzare un carosello di prodotti simile a questo.

4639da46bcc5230c.png

Se tocchi Aggiungi elemento, non succede nulla, a parte il fatto che l'agente ripete i dati di postback della risposta suggerita. Nella sezione successiva utilizzeremo il catalogo dei prodotti per creare il carrello in cui verrà aggiunto l'articolo.

Il catalogo dei prodotti che hai appena creato può essere esteso in vari modi. Potresti avere diverse opzioni di menu per le bevande o opzioni vegetariane. L'utilizzo di caroselli o chip di suggerimento è un ottimo modo per consentire agli utenti di visualizzare le opzioni di menu e arrivare a un insieme di prodotti che stanno cercando. Come estensione di questo codelab, prova ad estendere il sistema del catalogo dei prodotti in modo che un utente possa visualizzare le bevande separatamente dal cibo nel menu o addirittura specificare le opzioni vegetariane.

4. Il carrello degli acquisti

In questa sezione del codelab, svilupperemo la funzionalità del carrello degli acquisti sulla base della sezione precedente, che ci consente di sfogliare i prodotti disponibili.

Tra le altre cose, l'esperienza principale del carrello degli acquisti consente agli utenti di aggiungere articoli al carrello, rimuoverli, tenere traccia del numero di ogni articolo nel carrello e rivedere gli articoli al suo interno.

Monitorare lo stato del carrello degli acquisti significa che dobbiamo mantenere i dati nell'applicazione web. Per semplificare la sperimentazione e il deployment, utilizzeremo Google Datastore nella piattaforma Google Cloud per la persistenza dei dati. L'ID conversazione rimane costante tra un utente e l'attività, quindi possiamo utilizzarlo per associare gli utenti agli articoli del carrello.

Iniziamo collegandoci a Google Datastore e mantenendo l'ID conversazione quando lo vediamo.

Connessione con Datastore

Ci connetteremo a Google Datastore ogni volta che viene eseguita un'interazione con il carrello degli acquisti, ad esempio quando un utente aggiunge o elimina un articolo. Per scoprire di più sull'utilizzo di questa libreria client per interagire con Google Datastore, consulta la documentazione ufficiale.

Lo snippet seguente definisce una funzione per aggiornare il carrello degli acquisti. La funzione accetta i seguenti input: conversation_id e message. message contiene JSON che descrive l'azione che l'utente vuole eseguire, che è già integrata nel carosello che mostra il catalogo dei prodotti. La funzione crea un client Google Datastore e recupera immediatamente un'entità ShoppingCart, dove la chiave è l'ID conversazione.

Copia la seguente funzione nel file views.py. Continueremo a parlarne nella prossima sezione.

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)

Estendiamo questa funzione per aggiungere un articolo al carrello.

Aggiunta di articoli al carrello

Quando l'utente tocca un'azione suggerita Aggiungi articolo dal carosello di prodotti, postbackData contiene JSON che descrive l'azione che l'utente vuole eseguire. Il dizionario JSON ha due chiavi, "action" e "item_name", e viene inviato all'webhook. Il campo "item_name" è l'identificatore univoco associato all'articolo in inventory.json.

Una volta che abbiamo il comando del carrello e l'elemento del carrello analizzato dal messaggio, possiamo scrivere istruzioni condizionali per aggiungerlo. Alcuni casi limite da considerare sono se Datastore non ha mai visto l'ID conversazione o se il carrello degli acquisti riceve questo articolo per la prima volta. Di seguito è riportata un'estensione della funzionalità update_shopping_cart definita sopra. Questa modifica aggiunge un articolo al carrello degli acquisti che viene mantenuto da Google Datastore.

Il seguente snippet è un'estensione della funzione precedente aggiunta a views.py. Non esitare ad aggiungere la differenza o a copiare lo snippet e a sostituire la versione esistente della funzione update_shopping_cart.

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)

Questa funzione verrà estesa in un secondo momento per supportare lo scenario in cui cart_cmd contiene la stringa "del-item" definita in CMD_DEL_ITEM.

Mettere tutto insieme

Assicurati di aggiungere la canalizzazione nella funzione route_message in modo che, se ricevi un messaggio per aggiungere un articolo al carrello, venga chiamata la funzione update_shopping_cart. Dovrai anche definire una costante per l'aggiunta di elementi utilizzando la convenzione che utilizziamo in tutto il codelab.

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)

...

Per il momento, abbiamo la possibilità di aggiungere articoli al carrello degli acquisti. Se esegui il deployment delle modifiche in Google App Engine, dovresti essere in grado di visualizzare le modifiche al carrello degli acquisti nella dashboard di Google Datastore disponibile nella Console Google Cloud. Guarda lo screenshot seguente della console Google Datastore: è presente una singola entità che prende il nome dall'ID conversazione, seguita da alcune relazioni con gli articoli di inventario e la quantità di questi articoli nel carrello degli acquisti.

619dc18a8136ea69.png

Nella sezione successiva, creeremo un modo per elencare gli articoli nel carrello degli acquisti. Il meccanismo di revisione del carrello degli acquisti dovrebbe mostrare tutti gli articoli nel carrello, la quantità di questi articoli e un'opzione per rimuovere un articolo dal carrello.

Controllare gli articoli nel carrello

Elencare gli articoli nel carrello è l'unico modo per comprendere lo stato del carrello e sapere quali articoli possiamo rimuovere.

Invia innanzitutto un messaggio amichevole come "Ecco il tuo carrello degli acquisti", seguito da un altro messaggio contenente un carosello di schede interattive con le risposte suggerite associate "Rimuovi uno" o "Aggiungi uno". Il carosello di schede avanzate deve inoltre elencare la quantità di articoli salvati nel carrello.

Un aspetto da tenere presente prima di scrivere la funzione: se nel carrello degli acquisti è presente un solo tipo di articolo, non possiamo visualizzarlo come carosello. I caroselli di schede avanzate devono contenere almeno due schede. Al contrario, se non ci sono articoli nel carrello, vogliamo mostrare un semplice messaggio che indica che il carrello è vuoto.

Tenendo presente questo, definiamo una funzione chiamata send_shopping_cart. Questa funzione si connette a Google Datastore e richiede un'entità ShoppingCart in base all'ID conversazione. Una volta ottenuti questi dati, chiameremo la funzione get_inventory_data e utilizzeremo un carosello di schede interattive per segnalare lo stato del carrello degli acquisti. Dovremo anche ottenere l'ID di un prodotto per nome e possiamo dichiarare una funzione per cercare in Google Datastore per determinare questo valore. Durante la produzione del carosello, possiamo associare le risposte suggerite per eliminare o aggiungere articoli in base all'ID prodotto. Lo snippet riportato di seguito esegue tutte queste operazioni. Copia il codice in qualsiasi punto di 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)

...

Assicurati di aver già definito CMD_SHOW_CART nella parte superiore di views.py e chiama send_shopping_cart se l'utente invia un messaggio contenente "show-cart".

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

In base alla logica che abbiamo introdotto nella funzione send_shopping_cart, quando digiti "show-cart", visualizzeremo un messaggio che indica che il carrello è vuoto, una scheda avanzata che mostra l'unico articolo nel carrello o un carosello di schede che mostrano più articoli. Inoltre, sono disponibili tre risposte suggerite: "Visualizza il prezzo totale", "Svuota il carrello" e "Visualizza il menu".

Prova a implementare le modifiche al codice riportate sopra per verificare che il carrello degli acquisti monitori gli articoli che aggiungi e che tu possa esaminare il carrello dalla piattaforma di conversazioni, come mostrato negli screenshot precedenti. Puoi eseguire il deployment delle modifiche con questo comando dalla directory step-2 in cui le stai aggiungendo.

$ gcloud app deploy

Creeremo la funzionalità "Visualizza il prezzo totale" nella sezione successiva, dopo aver creato la funzionalità per rimuovere un articolo dal carrello. La funzione get_cart_price si comporta in modo simile alla funzionalità "Visualizza il carrello degli acquisti" nel senso che eseguirà il controllo incrociato dei dati in Datastore con il file inventory.json per produrre un prezzo totale per il carrello degli acquisti. Ti servirà per la parte successiva del codelab, in cui eseguiamo l'integrazione con i pagamenti.

Rimuovere articoli dal carrello

Infine, possiamo completare il comportamento del carrello degli acquisti introducendo la funzionalità per rimuoverlo. Sostituisci la funzione update_shopping_cart esistente con lo snippet seguente.

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)

Invio di un messaggio di conferma

Quando l'utente aggiunge un articolo al carrello, devi inviare un messaggio di conferma per confermare la sua azione e l'elaborazione della sua richiesta. In questo modo, non solo puoi creare delle aspettative, ma anche mantenere viva la conversazione.

Estendiamo la funzione update_shopping_cart in modo che invii un messaggio all'ID conversazione che indica che l'articolo è stato aggiunto o rimosso e fornisca suggerimenti per rivedere il carrello degli acquisti o visualizzare di nuovo il menu.

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

Dovrebbe funzionare. Un'esperienza completa del carrello degli acquisti che consente a un utente di aggiungere, rimuovere e rivedere gli articoli nel carrello.

A questo punto, se vuoi visualizzare la funzionalità del carrello degli acquisti nella conversazione di Business Messages, esegui il deployment dell'applicazione per interagire con il tuo agente. A tale scopo, esegui questo comando nella directory step-2.

$ gcloud app deploy

5. Preparazione dei pagamenti

In preparazione all'integrazione con un elaboratore dei pagamenti nella prossima parte della serie, abbiamo bisogno di un modo per ottenere il prezzo del carrello degli acquisti. Creiamo una funzione che recuperi il prezzo facendo un incrocio dei dati del carrello degli acquisti in Google Datastore, recuperando il prezzo di ogni articolo dall'inventario e moltiplicando il prezzo per la quantità di ogni articolo nel carrello.

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

...

Infine, possiamo utilizzare questa funzione e inviare un messaggio all'utente.

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

Per mettere tutto insieme, aggiorniamo la funzione route_message e la costante per attivare la logica riportata sopra.

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

Ecco alcuni screenshot che mostrano cosa viene ottenuto con la logica riportata sopra:

8feacf94ed0ac6c4.png

Quando saremo pronti per l'integrazione con l'elaboratore dei pagamenti nella parte successiva del codelab, chiameremo la funzione get_cart_price per passare i dati all'elaboratore dei pagamenti e avviare il flusso di pagamento.

Anche in questo caso, puoi provare questa funzionalità del carrello degli acquisti nella conversazione di Business Messages implementando l'applicazione e interagendo con il tuo agente.

$ gcloud app deploy

6. Complimenti

Congratulazioni, hai creato un'esperienza di carrello degli acquisti in Business Messages.

Un aspetto che non abbiamo trattato in questo codelab è la funzionalità per svuotare l'intero carrello degli acquisti. Se vuoi, prova a estendere l'applicazione per soddisfare la funzionalità "Svuota il carrello". La soluzione è disponibile nel passaggio 3 del codice sorgente che hai clonato.

In una sezione futura, eseguiremo l'integrazione con un elaboratore dei pagamenti esterno per consentire agli utenti di completare una transazione di pagamento con il tuo brand.

Quali sono le caratteristiche di un buon carrello degli acquisti?

Un'esperienza positiva con il carrello degli acquisti in una conversazione non è diversa da quella di un'app mobile o di un negozio fisico. La possibilità di aggiungere articoli, rimuoverli e calcolare il prezzo del carrello sono solo alcune delle funzionalità che abbiamo esplorato in questo codelab. Una differenza rispetto a un carrello degli acquisti reale è la possibilità di vedere il prezzo di tutti gli articoli al suo interno in qualsiasi momento, man mano che li aggiungi o rimuovi. Questi tipi di funzionalità di alto valore faranno risaltare la tua esperienza di commercio conversazionale.

Passaggi successivi

Quando è tutto pronto, consulta alcuni dei seguenti argomenti per scoprire le interazioni più complesse che puoi realizzare in Business Messages:

Documentazione di riferimento