Skip to content

Conversations

ffb255 edited this page May 23, 2020 · 9 revisions

When it comes to chatbots, you probably don't want to react to single keywords, but instead, you might need to gather information from the user, using a conversation. Let's say that you want your chatbot to provide a rich user onboarding experience for your application users. In the onboarding process, we are going to ask the user for their first name and email address - that's a perfect fit for conversations! (from botman)
Important!: By default, Botter uses File System Json Cache. This driver uses Hard Drive for storing data. We recommend you using a better and optimized driver like Redis. Check the Botter Object Instance wiki section for more information about migrating to Redis.

Quick Start

You can start a conversation with startConversation()

On::text("/signup", function() use($botter){
     $botter->startConversation(new SignupConversation);
});

And take a look at SignupConversation class (a class extended from ffb255\Botter\Conversations\Conversation class):

use ffb255\Botter\Conversations\Conversation;

class SignupConversation extends Conversation {
     public function start()
     {
          $this->say("Welcome, Whats your name?");
          $this->next("askEmail");
     }

     public function askEmail()
     {
          $this->name = $this->getAnswer()->getText();
          $this->say("Whats your email?");
          $this->next("finishSignup");
     }

     public function finishSignup()
     {
          // Insert user data do DB
          // ..
          $name = $this->name;
          $this->say("Thanks {$name}! Your account has been created.");
          $this->finish();
     }
}

looks easy!
When you start a conversation with startConversation(), Botter automatiaclly call start() method on your Conversation Class, and a conversation begin start with user.
Then you determine the next step in your conversation by $this->next(). Each method in you class can be a step in your conversation.


Conversation Class

A conversation class extends from ffb255\Botter\Conversations\Conversation parent class. This class determines a logic for your bot conversation. Each method is a step of conversation.
All conversation starts with the start() method in your class.

use ffb255\Botter\Conversations\Conversation;
// Simple conversation logic class
class SignupConversation extends Conversation {
     public function start(){
         // First step in your conversation
     }
}

You can access to Botter instance via $this->botter and access to all Botter methods.

class SignupConversation extends Conversation {
     public function start(){
         $this->botter->say("Hello");
     }
}

For convenience, the two methods say() and reply() are directly applicable. But for other Botther methods you should call Botter instance in $this->botter.


1. Set Next Step

You can set the next step in your conversation with $this->next() method, accept a string parameter from your next step method name.

class SignupConversation extends Conversation {
     public function start(){
         $this->botter->say("Hello, you are in start method. Your next request will be sent to secondStep()");
         $this->next("secondStep");
     }

     public function secondStep() {
          $this->botter->say("You are in second step. Your next request will be sent to thirdStep()");
          $this->next("thirdStep");
     }

     public function thirdStep() {
          $this->botter->say("You are third step. your conversation will be end after this message.");
          $this->finish();
     }
}

2. Conversation Storage

In your conversation logic class, when you set a property, it automatically saves into user conversation storage, and you can access this data during the next requests.

     public function start()
     {
          $this->say("Welcome, Whats your name?");
          $this->next("askEmail");
     }

     public function askEmail()
     {
          $this->name = $this->botter->getUpdate()->getMessage()->getText();
          $this->say("Whats your email?");
          $this->next("finishSignup");
     }

     public function finishSignup()
     {
          // Insert user data do DB
          // ..
          $name = $this->name;
          $this->say("Thanks {$name}! Your account has been created.");
          $this->finish();
     }
}

3. Jump into Step

When you use $this->next(), You are setting your next request step. But you can jump into another step in current request with $this->jumpTo().
Check this example:

class SignupConversation extends Conversation {
     public function start()
     {
          $this->say("How old are you?");
          $this->next("checkAge");
     }

     public function checkAge()
     {
          $age = $this->botter->getUpdate()->getMessage()->getText();

          if ( $age > 18 ) {
               $this->jumpTo("finishSignup");
          } else {
               $this->say("You are under 18! Enter your age again");
               return;
          }
     }

     public function finishSignup()
     {
          $this->say("You are signed up successfully!");
          $this->finish();
     }
}

4. Ending Conversation

As you saw previously, You can stop conversation with $this->finish(). This method will finish the current conversation with the user.

class SignupConversation extends Conversation {
     public function start(){
         $this->say("Hello and Bye");
         $this->finish()
     }
}

5. Ask, Then!

$this->ask() and $this->then() are two useful methods in Botter conversations. These methods allow you to validate user input and decide which method should handle the request in next step.
Let's re-write our previous example about asking age conversation:

class SignupConversation extends Conversation {
     public function start()
     {
          $this->ask("How old are you?")->then(function(){
               $age = $this->getAnswer()->getText();
               if ($age > 18){
                    $this->jumpTo("finishSignup");
               } else{
                    $this->say("You are under 18! Enter your age again");
               }
          });
     }

     public function finishSignup()
     {
          $this->say("You are signed up successfully!");
          $this->finish();
     }
}

Note: If you pass string to $this->ask(), Botter will send message to your user with this string, But you can pass an anonymous function:

$this->ask(function(){
     // Do something
     // ..
     $this->say("How old are you?");
})->then(function(){
     $age = $this->getAnswer()->getText();
     if ($age > 18){
          $this->jumpTo("finishSignup");
     } else{
          $this->say("You are under 18! Enter your age again");
     }
});

6. More functionality with boot()

As botter 1.2.0, you can add a boot() method to your conversation logic class. Botter automatically calls this method before each step and you can have more control over your conversation flow. Let's consider you need to add a /cancel command to stop conversation in any step:

class BookingFlightConversation extends Conversation {
    // This method will call in any request on this conversation
    public function boot(){
        $userText = $this->botter->getUpdate()->getMessage()->getText();
        if ($userText == '/cancel') {
            $this->reply("No Problem! Enter /start to open main menu");
            $this->finish();
         }
    }

    public function start(){
        $this->say("Where do you want to travel?");
        $this->next('askTripTime');
    }

    public function askTripTime(){
        $this->destination = $this->botter->getUpdate()->getMessage()->getText();
        $this->say("Cool, When do you want to travel to {$this->destination}?");
        $this->next('askFellowTraveler');
    }

    public function askFellowTraveler(){
        $this->tripTime = $this->botter->getUpdate()->getMessage()->getText();
        $this->say("How many companions do you have in this trip?");
        $this->next('bookTravel');
    }

    public function bookTravel(){
        $this->numberOfFellowTraveler = $this->botter->getUpdate()->getMessage()->getText();
        $this->say("All done! Your trip to {$this->destination} booked for {$this->tripTime} with {$this->numberOfFellowTraveler} passangers");
        $this->finish();
    }
}

As You can see, when we enter /cancel in this conversation, `boot()` finished the converation.

7. Start a conversation from a custom step (Instead of start())

As you saw previously, When you call $botter->startConversation() it automatically call your conversation start() method. You can change this behavior by pass your custom method name:

class SignupConversation extends Conversation {
     public function myStarterMethod(){
         $this->say("Hello and Bye");
         $this->finish()
     }
}

On::text("/signup", function() use($botter){
     $botter->startConversation(new SignupConversation, 'myStarterMethod');
});

It may help you to make resumable conversations.

Clone this wiki locally