Actions

If you read the previous page, you should already suspect what actions are.
To recap, each state has an action that triggers under some conditions. This action can be a hardcoded message or a python function.

Hardcoded actions

You can simply define a message to be sent directly from the YAML flow.
You can try making a flow just with these and test it in the web chat interface before moving on to Python code.
action:
  text: "How are you?"        # sends a text message
  replies:                    # sends quick replies below the message
  - "I'm fine!"
  - "Don't even ask"
  next: "next.root:"          # moves to a different state

Coding actions in Python

You can call a custom function anywhere where you would use a hardcoded action. The function can also be imported relatively to path of the YAML file.

# absolute import
action: chatbot.bots.default.conditions.bar
action: actions.foo  # relative import

The function takes one parameter - a Dialog object that you can use to send messages and access other APIs. It can also return the name of the next state (equivalent to next in YAML). The function should look at the conversation context (NLU entities), fetch any data it needs from external APIs and send messages to the user.

import random
from custom.logic import get_all_jokes

from botshot.core.dialog import Dialog
from botshot.core.responses import *

def show_joke(dialog: Dialog):
    jokes = get_all_jokes()
    joke = random.choice(jokes)
    dialog.send(joke)  # sends a string message
    return "next.root:"

Note

While waiting for the function to return, a typing indicator is displayed. (three dots in messenger)

Message templates

You can send messages by calling dialog.send(). This method requires one argument - the message!


The message should either be a string, a template from botshot.core.responses, or a list of these.
Here is a list of all the templates you can use:

Text message

A basic message with text. Can optionally have buttons or quick replies.
The officially supported button types are:
  • LinkButton(title, url) Redirects to a webpage upon being clicked.
  • PayloadButton(title, payload) Sends a special `postback message`_ on click.
  • PhoneButton(title, phone_number) Facebook only. Calls a number when clicked.
  • ShareButton() Facebook only. Opens the “Share” window.
The supported quick reply types are:
  • QuickReply(title) Used to suggest what the user can say. Sends “title” as a message.
  • LocationQuickReply() Facebook only. Opens the “Send location” window.
msg = "Botshot is the best!"
dialog.send(msg)

msg = TextMessage("I'm a message with buttons!")
msg.add_button(LinkButton("I'm a button", "https://example.com"))
msg.add_button(PayloadButton("Next page", payload={"_state": "next.root:"}))
msg.add_button(ShareButton())
# or ...
msg.with_buttons(button_list)
dialog.send(msg)

msg = TextMessage("I'm a message with quick replies!")
# or ...
msg.add_reply(LocationQuickReply())
msg.add_reply(QuickReply("Lorem ipsum ..."))
msg.add_reply("dolor sit amet ...")
# or ...
msg.with_replies(reply_list)

TODO picture, result on more platforms?

Note

Different platforms have different message limitations. For example, quick replies in Facebook Messenger can have a maximum of 20 characters.

Image message

TODO

Audio message

TODO

Video message

TODO

Card template

msg = CardTemplate(
    title="A card",
    subtitle="Hello world!",
    image_url="http://placehold.it/300x300",
    item_url="http://example.com"
)
msg.add_button(button)

List template

msg = ListTemplate()
msg.add_element(
    CardTemplate(
        title="Card 1",
        subtitle="Hello world!",
        image_url="http://placehold.it/300x300"
    )
)

Sending more messages at once

messages = []
for i in range(3):
    messages.append("Message #{}".format(i))
dialog.send(messages)

TODO picture

Warning

Avoid calling dialog.send() in a for loop. In bad network conditions, the messages might be sent in wrong order.

Scheduling messages

You can schedule a message to be sent in the future. You can optionally send it only if the user doesn’t say anything first.

payload = {"_state": "default.schedule", "schedule_id": "123"}

# Regular scheduled message - use a datetime or number of seconds
dialog.schedule(payload, at=None, seconds=None)

# Runs only if the user remains inactive
dialog.inactive(payload, seconds=None)