Creating a Chatbot using a Finite State Machine

Published on

4th April 2019

Ever since reading about how the FaceTime bug that Apple face earlier this year could have been prevented using Finite State Machines, I’ve been eager to start experimenting with them for my own personal projects. The FaceTime bug was an issue in the code which inadvertently allowed users to be able to listening to the person on the other end before they have even accepted the call.

What is a Finite State Machine?

A Finite State Machine, or FSM, is a computational model that can be used to represent and control execution flow. It is built up of one or more states and can only be in a single active state at any given time. An input to the machine causes a transition to the next state and each state defines the state to switch to for a given input.

Traffic lights are a great example of modelling the way FSM’s work, see below.

Traffic Lights modelled as a state machine

Unsplash rebuilt their image uploader as a Finite State Machine and wrote about it. The uploader has 3 high level states: Form, PublishingInProgress, PublishingComplete. From the diagram below, you can quickly see the 3 different states and the events that cause transitions to a new state.

The Finite State Machine diagram of Unsplash's image uploader

FSM for a chatbot

I wanted to create a very simple chatbot without an NLP that can be easily changed that doesn’t limit the look of the UI.

You can quickly see how using a FSM would be perfect for a simple chatbot implementation where the state changes based on a trigger (user input). Each state would represent a bot response.

How

At an abstract level, the code to represent the finite state machine looks as below.

function chatBot(state, event) {
  let nextStates;
  let messages;

  switch (state) {
    case "greetings":
      // possible transitions
      nextStates = ["about", "help"];
      messages = ["Hey there", "What can I help you with?"];
      // depending on the event (input), transition the state
      nextState = nextStates.find(item => item.toLowerCase() === event.toLowerCase())
      // update the current state of the FSM
      setState(nextState);
      
      return { messages: messages, buttons: nextStates };
    case "about":
      // possible transitions
      nextStates = ["blog", "help"];
      messages = ["I am a developer", "Currently working in London", "I like spanish music"];
      // depending on the event (input), transition the state
      nextState = nextStates.find(item => item.toLowerCase() === event.toLowerCase())
      // update the current state of the FSM
      setState(nextState);

      return { messages: messages, buttons: nextStates };
    case "help": 
      // possible transitions
      nextStates = ["about", "greetings"];
      messages = ["I am a (very) simple implementation of a FSM"];
      // depending on the event (input), transition the state
      nextState = nextStates.find(item => item.toLowerCase() === event.toLowerCase())
      // update the current state of the FSM
      setState(nextState);

      return { messages: messages, buttons: nextStates };
  }
}

The diagram below shows the different states of the FSM and triggers from state to state.

Visual representation of a simple FSM implementation

You can check out my final implementation on GitHub where I create each of these states using a pseudo switch from a JSON object representing the conversation.s

Published on

4th April 2019