1. บทนำ

อัปเดตล่าสุด: 30-10-2020
สร้างรถเข็นช็อปปิ้งใน Business Messages
นี่คือโค้ดแล็บที่ 2 ในชุดโค้ดแล็บที่มีเป้าหมายเพื่อสร้างเส้นทางของผู้ใช้ในการซื้อออนไลน์และมารับสินค้าที่ร้าน ในเส้นทางอีคอมเมิร์ซหลายเส้นทาง รถเข็นช็อปปิ้งเป็นกุญแจสำคัญสู่ความสำเร็จในการเปลี่ยนผู้ใช้ให้กลายเป็นลูกค้าที่ชำระเงิน นอกจากนี้ รถเข็นช็อปปิ้งยังเป็นวิธีทำความเข้าใจลูกค้าได้ดียิ่งขึ้น และเป็นวิธีเสนอคำแนะนำเกี่ยวกับสินค้าอื่นๆ ที่ลูกค้าอาจสนใจ ใน Codelab นี้ เราจะมุ่งเน้นที่การสร้างประสบการณ์รถเข็นช็อปปิ้งและการติดตั้งใช้งานแอปพลิเคชันใน Google App Engine
รถเข็นช็อปปิ้งที่ดีควรเป็นอย่างไร
รถเข็นช็อปปิ้งเป็นกุญแจสำคัญในการสร้างประสบการณ์การช็อปปิ้งออนไลน์ที่ประสบความสำเร็จ ปรากฏว่าข้อความธุรกิจไม่ได้มีดีแค่การอำนวยความสะดวกในการถามตอบเกี่ยวกับผลิตภัณฑ์กับผู้มีโอกาสเป็นลูกค้าเท่านั้น แต่ยังช่วยอำนวยความสะดวกในประสบการณ์การช็อปปิ้งทั้งหมดไปจนถึงการชำระเงินภายในแชทได้อีกด้วย

นอกเหนือจากรถเข็นช็อปปิ้งที่ดีแล้ว ประสบการณ์การช็อปปิ้งที่ดีจะช่วยให้ผู้ใช้เลือกดูสินค้าตามหมวดหมู่ได้ และช่วยให้ธุรกิจแนะนำผลิตภัณฑ์อื่นๆ ที่ผู้ซื้ออาจสนใจได้ หลังจากเพิ่มสินค้าลงในรถเข็นช็อปปิ้งแล้ว ผู้ใช้จะตรวจสอบรถเข็นทั้งหมดได้ และสามารถนำสินค้าออกหรือเพิ่มสินค้าก่อนชำระเงินได้
สิ่งที่คุณจะสร้าง
ในส่วนนี้ของชุด Codelab คุณจะได้ขยายเอเจนต์ดิจิทัลที่สร้างขึ้นในส่วนที่ 1 สำหรับบริษัทสมมติ Bonjour Meal เพื่อให้ผู้ใช้เรียกดูแคตตาล็อกสินค้าและเพิ่มสินค้าลงในรถเข็นช็อปปิ้งได้
ใน Codelab นี้ แอปของคุณจะทำสิ่งต่อไปนี้
- แสดงแคตตาล็อกคำถามภายใน Business Messages
- แนะนำไอเทมที่ผู้ใช้อาจสนใจ
- ตรวจสอบเนื้อหาของรถเข็นช็อปปิ้งและสร้างสรุปราคารวม

สิ่งที่คุณจะได้เรียนรู้
- วิธีนำเว็บแอปพลิเคชันไปใช้งานใน App Engine บน Google Cloud Platform
- วิธีใช้กลไกการจัดเก็บข้อมูลแบบถาวรเพื่อบันทึกสถานะของรถเข็นช็อปปิ้ง
Codelab นี้มุ่งเน้นที่การขยายเอเจนต์ดิจิทัลจากส่วนที่ 1 ของชุด Codelab นี้
สิ่งที่คุณต้องมี
- โปรเจ็กต์ GCP ที่ลงทะเบียนและได้รับอนุมัติให้ใช้กับ Business Messages
- ดูวิธีการได้ที่เว็บไซต์ของนักพัฒนาซอฟต์แวร์
- ไฟล์ข้อมูลเข้าสู่ระบบ JSON ของบัญชีบริการที่สร้างขึ้นสำหรับโปรเจ็กต์ GCP
- อุปกรณ์ Android 5 ขึ้นไปหรืออุปกรณ์ iOS ที่มีแอป Google Maps
- ประสบการณ์ด้านการเขียนโปรแกรมเว็บแอปพลิเคชัน
- การเชื่อมต่ออินเทอร์เน็ต
2. การเริ่มตั้งค่า
Codelab นี้ถือว่าคุณได้สร้าง Agent แรกและทำส่วนที่ 1 ของ Codelab เสร็จแล้ว ดังนั้น เราจะไม่พูดถึงพื้นฐานของการเปิดใช้ Business Messages และ Business Communications API, การสร้างคีย์บัญชีบริการ, การติดตั้งใช้งานแอปพลิเคชัน หรือการตั้งค่า Webhook ใน Business Communications Console อย่างไรก็ตาม เราจะโคลนแอปพลิเคชันตัวอย่างเพื่อให้แน่ใจว่าแอปพลิเคชันของคุณสอดคล้องกับสิ่งที่เรากำลังสร้างขึ้น และเราจะเปิดใช้ API สำหรับ Datastore ใน Google Cloud Platform เพื่อให้สามารถจัดเก็บข้อมูลที่เกี่ยวข้องกับรถเข็นช็อปปิ้งได้
โคลนแอปพลิเคชันจาก GitHub
ในเทอร์มินัล ให้โคลนตัวอย่างบ็อต Echo ของ Django ไปยังไดเรกทอรีการทำงานของโปรเจ็กต์ด้วยคำสั่งต่อไปนี้
$ git clone https://github.com/google-business-communications/bm-bonjour-meal-django-starter-code
คัดลอกไฟล์ข้อมูลเข้าสู่ระบบ JSON ที่สร้างขึ้นสำหรับบัญชีบริการไปยังโฟลเดอร์ทรัพยากรของตัวอย่าง แล้วเปลี่ยนชื่อข้อมูลเข้าสู่ระบบเป็น "bm-agent-service-account-credentials.json"
bm-bonjour-meal-django-starter-code/bonjourmeal-codelab/step-2/resources/bm-agent-service-account-credentials.json
เปิดใช้ Google Datastore API
ในส่วนที่ 1 ของโค้ดแล็บนี้ คุณได้เปิดใช้ Business Messages API, Business Communications API และ Cloud Build API
สำหรับโค้ดแล็บนี้ เนื่องจากเราจะทำงานกับ Google Datastore จึงต้องเปิดใช้ API นี้ด้วย
- เปิด Google Datastore API ใน Google Cloud Console
- ตรวจสอบว่าคุณกำลังทำงานกับโปรเจ็กต์ GCP ที่ถูกต้อง
- คลิกเปิดใช้
การทําให้แอปพลิเคชันตัวอย่างใช้งานได้
ในเทอร์มินัล ให้ไปที่ไดเรกทอรี step-2 ของตัวอย่าง
เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัลเพื่อติดตั้งใช้งานตัวอย่าง
$ gcloud config set project PROJECT_ID*
$ gcloud app deploy
- PROJECT_ID คือรหัสโปรเจ็กต์ของโปรเจ็กต์ที่คุณใช้ลงทะเบียนกับ API
จด URL ของแอปพลิเคชันที่ติดตั้งใช้งานในเอาต์พุตของคำสั่งสุดท้าย
Deployed service [default] to [https://PROJECT_ID.appspot.com]
โค้ดที่คุณเพิ่งติดตั้งใช้งานมีเว็บแอปพลิเคชันที่มีเว็บฮุคเพื่อรับข้อความจาก Business Messages ซึ่งมีทุกอย่างที่เราทำตั้งแต่ส่วนที่ 1 ของโค้ดแล็บ โปรดกำหนดค่า Webhook หากยังไม่ได้ทำ
แอปพลิเคชันจะตอบคำถามง่ายๆ บางอย่าง เช่น ผู้ใช้ถามเกี่ยวกับเวลาทำการของ Bonjour Meal คุณควรทดสอบในอุปกรณ์เคลื่อนที่ผ่าน URL สำหรับทดสอบที่ดึงมาจากข้อมูลตัวแทนภายในคอนโซล Business Communications URL ทดสอบจะเปิดประสบการณ์การใช้งาน Business Messages บนอุปกรณ์เคลื่อนที่ และคุณจะเริ่มโต้ตอบกับตัวแทนได้ที่นั่น
3. แคตตาล็อกสินค้า
ระบบสินค้าคงคลัง
ในกรณีส่วนใหญ่ คุณสามารถผสานรวมกับพื้นที่โฆษณาของแบรนด์ได้โดยตรงผ่าน API ภายใน ในกรณีอื่นๆ คุณอาจคัดลอกข้อมูลจากหน้าเว็บหรือสร้างระบบติดตามพื้นที่โฆษณาของคุณเอง เราไม่ได้มุ่งเน้นที่การสร้างระบบสินค้าคงคลัง แต่จะใช้ไฟล์แบบคงที่อย่างง่ายที่มีรูปภาพและข้อมูลผลิตภัณฑ์สำหรับเอเจนต์ ในส่วนนี้ เราจะดึงข้อมูลจากไฟล์แบบคงที่นี้ แสดงข้อมูลดังกล่าวในการสนทนา และอนุญาตให้ผู้ใช้เรียกดูสินค้าที่พร้อมเพิ่มลงในรถเข็นช็อปปิ้ง
ไฟล์สินค้าคงคลังแบบคงที่จะมีลักษณะดังนี้
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
}
]
}
มาทำให้แอปพลิเคชัน Python อ่านไฟล์นี้กัน
การอ่านจากคลังของเรา
พื้นที่โฆษณาเป็นไฟล์แบบคงที่ชื่อ "inventory.json" ซึ่งอยู่ในไดเรกทอรี ./resources เราต้องเพิ่มตรรกะ Python บางอย่างลงใน views.py เพื่ออ่านเนื้อหาของไฟล์ JSON แล้วแสดงในการสนทนา มาสร้างฟังก์ชันที่อ่านข้อมูลจากไฟล์ JSON และแสดงรายการผลิตภัณฑ์ที่มีกัน
คุณวางคำจำกัดความฟังก์ชันนี้ได้ทุกที่ใน views.py
bonjourmeal-codelab/step-2/bopis/views.py
...
def get_inventory_data():
f = open(INVENTORY_FILE)
inventory = json.load(f)
return inventory
...
ซึ่งจะช่วยให้เรามีข้อมูลที่จำเป็นในการอ่านข้อมูลจากสินค้าคงคลัง ตอนนี้เราต้องการวิธีแสดงข้อมูลผลิตภัณฑ์นี้ในการสนทนา
การแสดงแคตตาล็อกผลิตภัณฑ์
เพื่อความสะดวกในโค้ดแล็บนี้ เรามีแคตตาล็อกผลิตภัณฑ์ทั่วไปเพื่อแสดงสินค้าคงคลังทั้งหมดในการสนทนาของ Business Messages ผ่านภาพสไลด์ริชการ์ดเดียว
หากต้องการดูแคตตาล็อกผลิตภัณฑ์ เราจะสร้างคำตอบที่แนะนำซึ่งมีข้อความ "แสดงเมนู" และ postbackData "show-product-catalog" เมื่อผู้ใช้แตะคำตอบที่แนะนำและเว็บแอปพลิเคชันของคุณได้รับข้อมูลการแจ้งผล Conversion เราจะส่งภาพสไลด์การ์ด Rich มาเพิ่มค่าคงที่ใหม่สำหรับคำตอบที่แนะนำนี้ที่ด้านบนของ views.py กัน
bonjourmeal-codelab/step-2/bopis/views.py
...
CMD_SHOW_PRODUCT_CATALOG = 'show-product-catalog'
...
จากนั้นเราจะแยกวิเคราะห์ข้อความและกำหนดเส้นทางไปยังฟังก์ชันใหม่ที่ส่งภาพหมุนการ์ดริชมีเดียซึ่งมีแคตตาล็อกผลิตภัณฑ์ ก่อนอื่น ให้ขยายฟังก์ชัน route_message เพื่อเรียกใช้ฟังก์ชัน "send_product_catalog" เมื่อแตะคำตอบที่แนะนำ จากนั้นเราจะกำหนดฟังก์ชัน
ในข้อมูลโค้ดต่อไปนี้ ให้เพิ่มเงื่อนไขเพิ่มเติมลงในคำสั่ง if ในฟังก์ชัน route_message เพื่อตรวจสอบว่า normalized_message เท่ากับค่าคงที่ที่เรากำหนดไว้ก่อนหน้านี้หรือไม่ CMD_SHOW_PRODUCT_CATALOG
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)
...
และอย่าลืมทำตามขั้นตอนให้เสร็จสิ้นและกำหนด send_product_catalog send_product_catalog เรียกใช้ get_menu_carousel, ซึ่งจะสร้างภาพสไลด์ของการ์ดริชมีเดียจากไฟล์สินค้าคงคลังที่เราอ่านก่อนหน้านี้
คุณวางคำจำกัดความฟังก์ชันไว้ที่ใดก็ได้ใน views.py โปรดทราบว่าข้อมูลโค้ดต่อไปนี้ใช้ค่าคงที่ใหม่ 2 รายการซึ่งควรเพิ่มไว้ที่ด้านบนของไฟล์
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)
...
หากคุณตรวจสอบการสร้างรายการภาพสไลด์ เราจะสร้างอินสแตนซ์ของคลาส BusinessMessagesSuggestion ด้วย คำแนะนำแต่ละรายการแสดงถึงสิ่งที่ผู้ใช้เลือกสำหรับผลิตภัณฑ์ในภาพสไลด์ เมื่อผู้ใช้แตะการตอบกลับที่แนะนำ Business Messages จะส่ง postbackData ที่มี JSON ซึ่งอธิบายรายการและการดำเนินการที่ผู้ใช้ต้องการทำ (เพิ่มหรือนำออกจากรถเข็น) ไปยัง Webhook ของคุณ ในส่วนต่อไปนี้ เราจะแยกวิเคราะห์ข้อความที่มีลักษณะเช่นนี้เพื่อให้เพิ่มสินค้าลงในรถเข็นได้จริง
ตอนนี้เราได้ทำการเปลี่ยนแปลงเหล่านี้แล้ว มาติดตั้งใช้งานเว็บแอปพลิเคชันใน Google App Engine และลองใช้ประสบการณ์การใช้งานกันเลย
$ gcloud app deploy
เมื่อโหลดแพลตฟอร์มการสนทนาในอุปกรณ์เคลื่อนที่แล้ว ให้ส่งข้อความ "show-product-catalog" แล้วคุณจะเห็นภาพสไลด์ของผลิตภัณฑ์ที่มีลักษณะดังนี้

หากคุณแตะเพิ่มรายการ จะไม่มีอะไรเกิดขึ้นจริง ยกเว้นเอเจนต์จะส่งข้อมูลการรายงานผล Conversion กลับจากคำตอบที่แนะนำ ในส่วนถัดไป เราจะใช้แคตตาล็อกผลิตภัณฑ์และใช้เพื่อสร้างรถเข็นช็อปปิ้งที่จะเพิ่มสินค้า
คุณขยายแคตตาล็อกผลิตภัณฑ์ที่เพิ่งสร้างได้หลายวิธี คุณอาจมีตัวเลือกเมนูเครื่องดื่มหรือตัวเลือกมังสวิรัติที่แตกต่างกัน การใช้ภาพสไลด์หรือชิปคำแนะนำเป็นวิธีที่ยอดเยี่ยมในการช่วยให้ผู้ใช้เจาะลึกตัวเลือกเมนูเพื่อไปยังชุดผลิตภัณฑ์ที่กำลังมองหา ลองขยายระบบแคตตาล็อกผลิตภัณฑ์เพื่อให้ผู้ใช้ดูเครื่องดื่มแยกจากอาหารในเมนู หรือแม้แต่ระบุตัวเลือกอาหารมังสวิรัติได้ ซึ่งเป็นส่วนขยายของโค้ดแล็บนี้
4. รถเข็นช็อปปิ้ง
ในส่วนนี้ของโค้ดแล็บ เราจะสร้างฟังก์ชันรถเข็นช็อปปิ้งโดยต่อยอดจากส่วนก่อนหน้าซึ่งช่วยให้เราเรียกดูผลิตภัณฑ์ที่มีได้
ประสบการณ์รถเข็นช็อปปิ้งที่สำคัญช่วยให้ผู้ใช้เพิ่มสินค้าลงในรถเข็น นำสินค้าออกจากรถเข็น ติดตามจำนวนสินค้าแต่ละรายการในรถเข็น และตรวจสอบสินค้าในรถเข็นได้
การติดตามสถานะของรถเข็นช็อปปิ้งหมายความว่าเราต้องเก็บข้อมูลไว้ในเว็บแอปพลิเคชัน เราจะใช้ Google Datastore ใน Google Cloud Platform เพื่อคงข้อมูลไว้เพื่อให้การทดลองและการติดตั้งใช้งานเป็นไปอย่างง่ายดาย รหัสการสนทนาจะคงที่ระหว่างผู้ใช้กับธุรกิจ ดังนั้นเราจึงใช้รหัสนี้เพื่อเชื่อมโยงผู้ใช้กับสินค้าในรถเข็นช็อปปิ้งได้
มาเริ่มต้นด้วยการเชื่อมต่อกับ Google Datastore และบันทึกรหัสการสนทนาเมื่อเราเห็นรหัส
การเชื่อมต่อกับ Datastore
เราจะเชื่อมต่อกับ Google Datastore ทุกครั้งที่มีการโต้ตอบกับรถเข็นช็อปปิ้ง เช่น เมื่อผู้ใช้เพิ่มหรือลบสินค้า ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ไลบรารีของไคลเอ็นต์นี้เพื่อโต้ตอบกับ Google Datastore ได้ที่เอกสารประกอบอย่างเป็นทางการ
ข้อมูลโค้ดต่อไปนี้กําหนดฟังก์ชันเพื่ออัปเดตรถเข็นช็อปปิ้ง ฟังก์ชันนี้รับอินพุต conversation_id และ message message มี JSON ที่อธิบายการดำเนินการที่ผู้ใช้ต้องการทำ ซึ่งรวมอยู่ในภาพสไลด์ที่แสดงแคตตาล็อกผลิตภัณฑ์อยู่แล้ว ฟังก์ชันนี้จะสร้างไคลเอ็นต์ Google Datastore และดึงข้อมูลเอนทิตี ShoppingCart ทันที ซึ่งคีย์คือรหัสการสนทนา
คัดลอกฟังก์ชันต่อไปนี้ไปยังไฟล์ views.py เราจะขยายความในส่วนถัดไป
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)
มาขยายฟังก์ชันนี้เพื่อเพิ่มสินค้าลงในรถเข็นกัน
การเพิ่มสินค้าลงในรถเข็น
เมื่อผู้ใช้แตะการดำเนินการที่แนะนำ เพิ่มสินค้า จากแคโรเซลผลิตภัณฑ์ postbackData จะมี JSON ที่อธิบายการดำเนินการที่ผู้ใช้ต้องการทำ พจนานุกรม JSON มีคีย์ 2 รายการ ได้แก่ "action" และ "item_name" และระบบจะส่งพจนานุกรม JSON นี้ไปยัง Webhook ของคุณ ฟิลด์ "item_name" คือตัวระบุที่ไม่ซ้ำกันซึ่งเชื่อมโยงกับสินค้าใน inventory.json
เมื่อมีคำสั่งรถเข็นและรายการรถเข็นที่แยกวิเคราะห์จากข้อความแล้ว เราจะเขียนคำสั่งแบบมีเงื่อนไขเพื่อเพิ่มรายการได้ กรณีที่ควรพิจารณาที่นี่คือหาก Datastore ไม่เคยเห็นรหัสการสนทนาหรือหากรถเข็นช็อปปิ้งได้รับสินค้าเป็นครั้งแรก ต่อไปนี้คือส่วนขยายของupdate_shopping_cartฟังก์ชันการทำงานที่กำหนดไว้ข้างต้น การเปลี่ยนแปลงนี้จะเพิ่มสินค้าลงในรถเข็นช็อปปิ้งซึ่ง Google Datastore จะเก็บไว้
ข้อมูลโค้ดต่อไปนี้เป็นการขยายฟังก์ชันก่อนหน้าที่เพิ่มลงใน views.py คุณสามารถเพิ่มความแตกต่าง หรือคัดลอกข้อมูลโค้ดและแทนที่ฟังก์ชัน 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)
เราจะขยายฟังก์ชันนี้ในภายหลังเพื่อรองรับสถานการณ์ที่ cart_cmd มีสตริง "del-item" ที่กำหนดไว้ใน CMD_DEL_ITEM
การเชื่อมโยง
ตรวจสอบว่าคุณได้เพิ่มการเชื่อมต่อในฟังก์ชัน route_message เพื่อให้ระบบเรียกใช้ฟังก์ชัน update_shopping_cart หากคุณได้รับข้อความให้เพิ่มสินค้าลงในรถเข็น นอกจากนี้ คุณยังต้องกำหนดค่าคงที่สำหรับการเพิ่มรายการโดยใช้รูปแบบที่เราใช้ตลอดทั้งโค้ดแล็บ
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)
...
ตอนนี้เรามีฟีเจอร์ที่ช่วยให้เพิ่มสินค้าลงในรถเข็นช็อปปิ้งได้ หากคุณนําการเปลี่ยนแปลงไปใช้กับ Google App Engine คุณควรจะเห็นการเปลี่ยนแปลงรถเข็นช็อปปิ้งแสดงในแดชบอร์ด Google Datastore ที่อยู่ในคอนโซล GCP ดูภาพหน้าจอของคอนโซล Google Datastore ด้านล่าง จะเห็นเอนทิตีเดียวซึ่งตั้งชื่อตามรหัสการสนทนา ตามด้วยความสัมพันธ์กับสินค้าคงคลังและจำนวนสินค้าเหล่านั้นในรถเข็นช็อปปิ้ง

ในส่วนถัดไป เราจะสร้างวิธีแสดงรายการในรถเข็นช็อปปิ้ง กลไกการตรวจสอบรถเข็นช็อปปิ้งควรแสดงสินค้าทั้งหมดในรถเข็น จำนวนสินค้าเหล่านั้น และตัวเลือกในการนำสินค้าออกจากรถเข็น
ตรวจสอบสินค้าในรถเข็น
การแสดงรายการสินค้าในรถเข็นช็อปปิ้งเป็นวิธีเดียวที่เราจะเข้าใจสถานะของรถเข็นช็อปปิ้งและทราบว่าเรานำสินค้าใดออกได้
ก่อนอื่นให้ส่งข้อความที่เป็นมิตร เช่น "นี่คือรถเข็นช็อปปิ้งของคุณ" ตามด้วยข้อความอีกข้อความที่มีภาพสไลด์ Rich Card พร้อมคำตอบที่แนะนำที่เกี่ยวข้องสำหรับ "นำออก 1 รายการ" หรือ "เพิ่ม 1 รายการ" นอกจากนี้ แคร์รอสเซลริชการ์ดควรแสดงจำนวนสินค้าที่บันทึกไว้ในรถเข็นด้วย
สิ่งที่คุณควรทราบก่อนที่เราจะไปเขียนฟังก์ชันจริงๆ ก็คือ หากมีสินค้าเพียงประเภทเดียวในรถเข็นช็อปปิ้ง เราจะแสดงเป็นภาพสไลด์ไม่ได้ ภาพหมุนริชการ์ดต้องมีการ์ดอย่างน้อย 2 ใบ ในทางกลับกัน หากไม่มีสินค้าในรถเข็น เราต้องการแสดงข้อความง่ายๆ ที่ระบุว่ารถเข็นว่างเปล่า
เมื่อทราบดังนี้แล้ว เรามากำหนดฟังก์ชันที่ชื่อ send_shopping_cart กัน ฟังก์ชันนี้เชื่อมต่อกับ Google Datastore และขอเอนทิตี ShoppingCart ตามรหัสการสนทนา เมื่อได้ข้อมูลดังกล่าวแล้ว เราจะเรียกใช้ฟังก์ชัน get_inventory_data และใช้ภาพสไลด์การ์ดริชมีเดียเพื่อรายงานสถานะของรถเข็นช็อปปิ้ง นอกจากนี้ เรายังต้องรับรหัสของผลิตภัณฑ์ตามชื่อ และสามารถประกาศฟังก์ชันเพื่อค้นหาใน Google Datastore เพื่อกำหนดค่านั้นได้ ขณะที่สร้างภาพสไลด์ เราจะเชื่อมโยงคำตอบที่แนะนำเพื่อลบหรือเพิ่มสินค้าตามรหัสผลิตภัณฑ์ได้ ข้อมูลโค้ดด้านล่างจะดำเนินการทั้งหมดนี้ คัดลอกโค้ดไปยังส่วนใดก็ได้ใน 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)
...
ตรวจสอบว่าคุณได้กำหนด CMD_SHOW_CART ไว้ที่ด้านบนของ views.py แล้ว และเรียกใช้ send_shopping_cart หากผู้ใช้ส่งข้อความที่มีคำว่า "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)
...

ตามตรรกะที่เราแนะนำในฟังก์ชัน send_shopping_cart เมื่อคุณพิมพ์ "show-cart" เราจะแสดงข้อความที่ระบุว่าไม่มีสินค้าในรถเข็น การ์ดที่สมบูรณ์ซึ่งแสดงสินค้า 1 รายการในรถเข็น หรือภาพสไลด์ของการ์ดที่แสดงสินค้าหลายรายการ นอกจากนี้ เรายังมีคำตอบที่แนะนำ 3 รายการ ได้แก่ "ดูราคารวม" "ล้างรถเข็น" และ "ดูเมนู"
ลองใช้การเปลี่ยนแปลงโค้ดข้างต้นเพื่อทดสอบว่ารถเข็นช็อปปิ้งติดตามสินค้าที่คุณเพิ่ม และคุณสามารถตรวจสอบรถเข็นจากการสนทนาตามที่แสดงในภาพหน้าจอด้านบน คุณสามารถใช้คำสั่งนี้เพื่อนำการเปลี่ยนแปลงไปใช้จากไดเรกทอรี step-2 ที่คุณเพิ่มการเปลี่ยนแปลง
$ gcloud app deploy
เราจะสร้างฟีเจอร์ "ดูราคารวม" ในส่วนถัดไปหลังจากสร้างฟังก์ชันการทำงานเพื่อนำสินค้าออกจากรถเข็น ฟังก์ชัน get_cart_price จะทํางานคล้ายกับฟีเจอร์ "ดูรถเข็นช็อปปิ้ง" ในแง่ที่จะอ้างอิงข้อมูลใน Datastore กับไฟล์ inventory.json เพื่อแสดงราคารวมของรถเข็นช็อปปิ้ง ซึ่งจะมีประโยชน์สำหรับส่วนถัดไปของโค้ดแล็บที่เราจะผสานรวมกับการชำระเงิน
การนำสินค้าออกจากรถเข็น
สุดท้าย เราจะทำให้พฤติกรรมรถเข็นช็อปปิ้งสมบูรณ์ด้วยการเปิดตัวฟังก์ชันการนำรถเข็นออก แทนที่ฟังก์ชัน update_shopping_cart ที่มีอยู่ด้วยข้อมูลโค้ดต่อไปนี้
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)
การส่งข้อความยืนยัน
เมื่อผู้ใช้เพิ่มสินค้าลงในรถเข็น คุณควรส่งข้อความยืนยันเพื่อรับทราบการดำเนินการของผู้ใช้และแจ้งว่าคุณได้ประมวลผลคำขอของผู้ใช้แล้ว ซึ่งไม่เพียงช่วยกำหนดความคาดหวัง แต่ยังช่วยให้การสนทนาดำเนินต่อไปได้ด้วย
มาขยายฟังก์ชัน update_shopping_cart เพื่อให้ส่งข้อความไปยังรหัสการสนทนาที่ระบุว่ามีการเพิ่มหรือนำสินค้าออก และให้คำแนะนำในการตรวจสอบรถเข็นช็อปปิ้งหรือดูเมนูอีกครั้ง
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)

เท่านี้ก็เรียบร้อย ประสบการณ์รถเข็นช็อปปิ้งที่มีฟีเจอร์ครบถ้วน ซึ่งช่วยให้ผู้ใช้เพิ่ม นำออก และตรวจสอบสินค้าในรถเข็นได้
ในตอนนี้ หากต้องการดูฟังก์ชันรถเข็นช็อปปิ้งในการสนทนา Business Messages ให้ติดตั้งใช้งานแอปพลิเคชันเพื่อโต้ตอบกับเอเจนต์ โดยทำได้โดยการเรียกใช้คำสั่งนี้ในไดเรกทอรี step-2
$ gcloud app deploy
5. การเตรียมพร้อมสำหรับการชำระเงิน
ในการเตรียมพร้อมสำหรับการผสานรวมกับผู้ประมวลผลการชำระเงินในส่วนถัดไปของชุดบทความนี้ เราจำเป็นต้องมีวิธีรับราคาของรถเข็นช็อปปิ้ง มาสร้างฟังก์ชันที่ดึงราคาให้เราโดยการอ้างอิงโยงข้อมูลรถเข็นช็อปปิ้งใน Google Datastore ดึงราคาของสินค้าแต่ละรายการจากสินค้าคงคลัง และคูณราคาด้วยจำนวนสินค้าแต่ละรายการในรถเข็น
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
...
และสุดท้าย เราสามารถใช้ฟังก์ชันนั้นและส่งข้อความถึงผู้ใช้ได้
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)
...
เรามาอัปเดตฟังก์ชัน route_message และค่าคงที่เพื่อทริกเกอร์ตรรกะข้างต้นกัน
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)
...
ภาพหน้าจอบางส่วนที่แสดงให้เห็นว่าตรรกะข้างต้นทําอะไรได้บ้างมีดังนี้

เมื่อพร้อมที่จะผสานรวมกับผู้ประมวลผลการชำระเงินในส่วนถัดไปของ Codelab เราจะเรียกใช้ฟังก์ชัน get_cart_price เพื่อส่งข้อมูลไปยังผู้ประมวลผลการชำระเงินและเริ่มขั้นตอนการชำระเงิน
คุณลองใช้ฟังก์ชันรถเข็นช็อปปิ้งนี้ในการสนทนา Business Messages ได้อีกครั้งโดยการติดตั้งใช้งานแอปพลิเคชันและโต้ตอบกับตัวแทน
$ gcloud app deploy
6. ขอแสดงความยินดี
ยินดีด้วย คุณสร้างประสบการณ์รถเข็นช็อปปิ้งภายใน Business Messages ได้สำเร็จแล้ว
ฟีเจอร์ในการล้างรถเข็นช็อปปิ้งทั้งหมดเป็นสิ่งที่เราไม่ได้กล่าวถึงในโค้ดแล็บนี้ หากต้องการ ลองขยายแอปพลิเคชันเพื่อตอบสนองฟีเจอร์ "ล้างรถเข็น" โซลูชันนี้อยู่ในขั้นตอนที่ 3 ของซอร์สโค้ดที่คุณโคลน
ในส่วนถัดไป เราจะผสานรวมกับผู้ประมวลผลการชำระเงินภายนอกเพื่อให้ผู้ใช้ทำธุรกรรมการชำระเงินกับแบรนด์ของคุณได้
รถเข็นช็อปปิ้งที่ดีควรเป็นอย่างไร
ประสบการณ์รถเข็นช็อปปิ้งที่ดีในการสนทนาไม่แตกต่างจากแอปบนอุปกรณ์เคลื่อนที่หรือในร้านค้าจริง การเพิ่มสินค้า การนำสินค้าออก และการคำนวณราคารถเข็นเป็นเพียงฟีเจอร์บางส่วนที่เราได้สำรวจในโค้ดแล็บนี้ สิ่งที่แตกต่างจากรถเข็นช็อปปิ้งในโลกแห่งความเป็นจริงคือการดูราคาของสินค้าทั้งหมดในรถเข็นได้ทุกเมื่อที่คุณเพิ่มหรือนำสินค้าออก ฟีเจอร์ที่มีคุณค่าสูงเหล่านี้จะช่วยให้ประสบการณ์การสนทนาเพื่อการพาณิชย์ของคุณโดดเด่น
สิ่งต่อไปที่ควรทำ
เมื่อพร้อมแล้ว โปรดดูหัวข้อต่อไปนี้เพื่อเรียนรู้เกี่ยวกับการโต้ตอบที่ซับซ้อนมากขึ้นซึ่งคุณทำได้ใน Business Messages
- Business Messages ทำงานอย่างไร
- แนวทางปฏิบัติแนะนำ
- หลักเกณฑ์ด้านโลโก้
- ส่งต่อให้เจ้าหน้าที่บริการลูกค้า
เอกสารอ้างอิง
- SuggestedReply
- เอกสารอ้างอิงข้อความ Business Messages
- คำจำกัดความของ JSON สำหรับ RichCard