Write your first flow

Write complex business logic with basic flow code.

Remove unused files

Let's do a bit of clean up first.

  • Open your app in the Meya Console.
  • Select the Flows page.
  • Delete the following flow files:
    • welcome.yaml
    • hi.yaml
    • catchall.yaml
  • Select the Components page.
  • Delete:
    • welcome.py

Update the welcome message

Your initial message to the user should give them an indication of what they can do with your app. Let's encourage the user to create an order by giving them a quick reply button.

  • Select the Flows page.
  • Open the open_page.yaml file in the code editor and paste the following BFML code, click Save (you can ignore the error message for now, this will be fixed when adding the other flows):
triggers:
  - type: page_open
  - keyword: start

steps:
  - say: Hi, I'm Pizza Bot! I can help you order a pizza.
    quick_replies:
      - text: Order
        action:
          flow: flow.order
          transfer: true
    composer:
      visibility: hide

🚧

Whitespace

Flow code is written in Bot Flow Markup Language, which is based on YAML. This means that whitespace, including indentation, is very important. You'll get errors if your flow code is not indented properly. Make sure your flow code looks like the above code example.

Lines 8-10: When the user clicks the quick reply, it will launch the yet-to-be-created order.yaml file. transfer: true means that we don't want to return to the open_page.yaml flow when the order.yaml flow completes (check the Flows guide for a detailed explanation of the flow component).

Lines 11-12: Since our bot is going to be menu-driven, we don't want to expose the composer, which let's the user enter any text they want. As an extension of this project you could try adding the Dialogflow integration so your app can understand your user's free text, but for now, let's continue with a menu-only bot.

Create the order flow

  • Select the Flows page.
  • Click the Create flow button.
  • Rename the flow from new_flow.yaml to order.yaml.
  • Paste the following code into the code editor, and click Save (ignore the error message for now):
steps:
  - ask: What size of pizza would you like?
    quick_replies:
      - text: Small
        data:
          size: small
          price: 6
      - text: Medium
        data:
          size: medium
          price: 10
      - text: Large
        data:
          size: large
          price: 14
      - text: Cancel order
        action:
          jump: cancel
    composer:
      visibility: hide

  - flow_set:
      ingredients: []
      message: What ingredients you like to add

  - (add ingredients)
  - ask: (@ flow.message )
    quick_replies:
      - text: Pepperoni
        result: pepperoni
      - text: Olives
        result: olives
      - text: Chicken
        result: chicken
      - text: Hot peppers
        result: hot peppers
      - text: Feta cheese
        result: feta
      - text: Green pepper
        result: green pepper
      - text: Onion
        result: onion
      - text: Done
        action:
          jump: get user info
      - text: Cancel order
        action:
          jump: cancel
    composer:
      visibility: hide
  - flow_set:
      ingredients: (@ flow.ingredients + [flow.result] )
  - flow_set:
      message: |
        **Added: (@ flow.ingredients | join(", ") )**

        What else?
  - jump: add ingredients

  - (get user info)
  - flow: flow.get_user_info
  - tiles:
      - title: Your order
        rows:
          -   - cell: Size
                value: (@ flow.size )
          -   - cell: Ingredients
                value: (@ flow.ingredients | join(", ") )
          -   - cell: For delivery?
                value: (@ flow.is_delivery )
          -   - cell: Address
                value: (@ user.home_address )
          -   - cell: Payment method
                value: (@ flow.payment_method )
          -   - cell: Total
                value: $(@ flow.price ) + tax
    ask: Here's a summary of your order.
    quick_replies:
      - text: Submit order
        action: next
      - text: Cancel
        action:
          jump: cancel

  - type: component.submit
    api_token: (@ vault.api_token )
    size: (@ flow.size )
    ingredients: (@ flow.ingredients )
    address: (@ user.home_address )
    payment_method: (@ flow.payment_method )
    is_delivery: (@ flow.is_delivery )
  - if: (@ flow.result )
    then:
      say: >
        Your order is submitted and will be
        (%- if flow.is_delivery %)
          delivered
        (%- else %)
          ready for pickup
        (%- endif %)
        in 20 minutes.
    else:
      say: I wasn't able to place your order. To place your order, please give us
        a call at 1-800-123-4567.
  - flow: flow.open_page
    transfer: true

  - (cancel)
  - say: Okay, I've cancelled your order.
  - flow: flow.open_page
    transfer: true

Let's take a minute to understand what's going on here.

Lines 3-18: When the user clicks on one of these quick reply buttons, the size and price of the pizza will be stored on flow scope at flow.size and flow.price, respectively.

Lines 22-24: Next, we initialize a list of ingredients and a message we'll use to prompt the user for their selection.

Lines 51-57: After the user selects an ingredient, we add it to the list and update our message to include the list of selected ingredients. Note that we need to use two flow_set components so that the message variable has the latest version of the ingredients list.

Line 58: We use the jump component to jump back to the add ingredients label so the user can keep selecting ingredients.

Once the user clicks the Done quick reply, they'll jump to the get user info label.

Lines 62-83: We use a tile component to summarize the order details.

Lines 85-91: In a future step, we'll build a custom component to actually place the order. you can see from this BFML, though, that we'll provide it with an API key and the order details.

Lines 92-104: Depending on whether the custom component returns true or false, we'll display a final message to the user.

Vizualize the flow

  • Open the order.yaml flow in the code editor.
  • Click on the Visual button.
2540

Create the user info flow

Although we could include this code in the order.yaml flow, it makes sense to split this out into another flow so that each flow has a specific purpose: The previous flow is for customizing the pizza; this flow is for providing user info, such as payment method and delivery address.

  • Select the Flows page.
  • Click the Create flow button.
  • Rename the flow from new_flow.yaml to get_user_info.yaml.
  • Paste the following code into the code editor, and click Save (ignore the error message for now):
steps:
  - ask: How will you be paying?
    quick_replies:
      - Cash
      - Credit/debit
    composer:
      visibility: hide
  - flow_set: payment_method

  - ask: Is this for take-out, or delivery?
    quick_replies:
      - text: Take-out
        result: false
      - text: Delivery
        result: true
      - text: Cancel order
        action:
          jump: cancel
    composer:
      visibility: hide
  - flow_set: is_delivery

  - if: (@ flow.is_delivery )
    then: next
    else:
      jump: end

  - if: (@ user.home_address | default(false) )
    then:
      jump: end
    else: next
  - ask: What is your address?
  - user_set: home_address

  - (end)
  - end:
      payment_method: (@ flow.payment_method )
      is_delivery: (@ flow.is_delivery )

  - (cancel)
  - say: Okay, I've cancelled your order.
  - flow: flow.open_page
    transfer: true

Having already written the order.yaml flow, this flow will probably make sense pretty quickly:

  • We ask a series of questions about the user,
  • offer them quick reply buttons to make the process as easy as possible, and
  • save the results to either flow or user scope.

📘

user scope

Line 33: We're using user scope here because this piece of data (the user's home address) is unlikely to change often. By saving it to user scope, we ensure that the user won't need to type it again when they order pizza from us in the future.

Lines 36-38: The end component ends the flow and returns the user to the parent flow, which in this case is order.yaml. Since payment_method and is_delivery are stored on flow scope, they'll disappear as soon as we leave the get_user_info.yaml flow. The end component lets us specify a YAML dictionary of data we want to pass back to the order.yaml flow's flow scope so we can keep working with it. (Check the Flows guide for more detailed info on the end component).

Vizualize the flow

  • Open the get_user_info.yaml flow in the code editor.
  • Click on the Visual button.
2544

(Optional) Local IDE

Remove files

Remove the following files:

  • flow/welcome.yaml
  • flow/hi.yaml
  • flow/catchall.yaml
  • component/welcome.py

Update bot config

Open bot/default.yaml and update name to Pizza Bot.

Let's also change the default bot avatar to this pizza slice icon: icon

Here's what your file should look like:

type: meya.bot.element
name: Pizza Bot
avatar:
  image: https://images.vexels.com/media/users/3/157209/isolated/preview/725aa2473489db2e550656210c557f18-cheesy-pizza-icon-by-vexels.png
markdown: true

Create new files

Create the following files in your IDE:

  • flow/order.yaml: paste the content of the order.yaml file above.
  • flow/get_user_info.yaml: paste the content of the get_user_info.yaml file above.

Update the following files in your IDE:

  • flow/open_page.yaml: paste the content of the open_page.yaml file above.

What’s Next

Next, we'll add the component.order.submit component referenced in the order.yaml flow.