Last time we managed to create a terminal based chatbot with Chatterbot that can understand basic scheduling instructions. Today, we will take that simple terminal application and drop it into a Django application. This will allow us to wrap our chatbot’s functionality within a full fledged web server that can receive RESTful requests. It will also allow us to create a separate service that can schedule real appointments.

Getting Started

Be sure to install Django in your local environment and then freeze your dependencies to your requirements.txt file.

$ pip install django && pip-chill > requirements.txt

Shuffling around the project takes a little bit of work but the basic structure of the new Django application will contain the same custom logic adapter, preprocessor functions, and tests that we wrote last time under the chatbot namespace.

├── manage.py
├── requirements.txt
└── schedule_bot
    ├── __init__.py
    ├── asgi.py
    ├── chatbot
    │   ├── __init__.py
    │   ├── chatbot.py
    │   ├── logic
    │   │   ├── __init__.py
    │   │   └── schedule_adapter.py
    │   ├── preprocessors.py
    │   ├── tests
    │   │   ├── __init__.py
    │   │   ├── test_chatbot.py
    │   │   └── test_logic_adapters.pyc
    │   ├── urls.py
    │   └── views.py
    ├── scheduler
    │   ├── __init__.py
    │   ├── admin.py
    │   ├── apps.py
    │   ├── migrations
    │   │   └── __init__.py
    │   ├── models.py
    │   ├── tests.py
    │   ├── urls.py
    │   └── views.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

Our chatbot app will be concerned with parsing and interpreting incoming API requests with the user’s input. We will have another app called scheduler that will be concerned with taking these instructions, checking availability, and writing the appointments to the database. We can get a pretty nice admin interface for free when we choose to build a backend server application with Django. This will provide a convenient interface for viewing appointments and updating availability preferences. These preferences might include the time of the day that appointments can be scheduled, black out days, and how to handle conflicts.

There are also two new files in our chatbot folder called urls.py and views.py. For anyone not familiar with Django, these two files will be used to define the bots API endpoint and behavior. We will return to these two files after we first define our robot’s basic configuration in the Django settings.

Configuring Our Chatbot In Django Settings

Our configuration is going to look very similar to what we already have in chatbot/tests/test_chatbot.py. The only difference from before is that we are defining the chatbot in a compatible json format. We will also need to register our chatbot application along with the chatterbot.ext.django_chatterbot external library.

# schedule_bot/settings.py

...

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'schedule_bot.chatbot',
    'chatterbot.ext.django_chatterbot'
]

...

CHATTERBOT = {
    'name': 'Schedule Bot',
    'logic_adapters': [
        'schedule_bot.chatbot.logic.schedule_adapter.Schedule',
        {
            'import_path': 'chatterbot.logic.BestMatch',
            'default_response': "I'm sorry I don't understand. I like to schedule appointments.",
            'maxiumum_similarity_threshold': 0.90
        }
    ],
    'preprocessors': [
        'schedule_bot.chatbot.preprocessors.format_dates',
        'schedule_bot.chatbot.preprocessors.capitalize_months'
    ]
}

The CHATTERBOT configuration settings can now be imported into our chatbot.ChatBotApiView to create an instance of our chatbot to interpret incoming API requests.

Completing the API Interface

We will need to setup an API Endpoint and a Chatbot View that can interpret the incoming API requests. Our API endpoint will be called ‘api/chatbot’ and it will be used to interpret JSON strings attached to the request body.

 
# schedule_bot/chatbot/urls.py

from django.conf.urls import url
from schedule_bot.chatbot.views import ChatBotApiView

urlpatterns = [
    url(r'^api/chatbot/', ChatBotApiView.as_view(), name='chatbot')
]

The actual ChatBotApiView is a Django class based view. For the GET request we will simply return the name of the chatbot defined in the ChatBotApiView.chatbot property. The POST request scans the input string for the requisite ‘text’ key and then parses the response with our chatbot’s get_response method. This response is serialized and then returned as a valid Json response.

@method_decorator(csrf_exempt, name='dispatch')
class ChatBotApiView(View):
    chatbot = ChatBot(**settings.CHATTERBOT)

    def post(self, request, *args, **kwargs):
        input = json.loads(request.body.decode('utf-8'))

        if 'text' not in input:
            return JsonResponse({
                'text': [
                    'The attribute "text" is required.'
                ]
            }, status=400)

        response = self.chatbot.get_response(input['text'])

        response_data = response.serialize()

        return JsonResponse(response_data, status=200)

    def get(self, request, *args, **kwargs):
        return JsonResponse({
            'name': self.chatbot.name
        })

At this point we should be able to send a POST request and receive a response that confirms the scheduled appointment.

curl --request POST \
  --url http://localhost:8000/api/chatbot/ \
  --header 'Content-Type: application/json' \
  --data '{"text": "Ok. I would like to make an appointment for november 7th at 8 AM"}'

=>
{
  "id": null,
  "text": "scheduling appointment for 11/07/21 at 08:00:00",
  "search_text": "",
  "conversation": "",
  "persona": "bot:Schedule Bot",
  "tags": [],
  "in_response_to": "Ok. I would like to make an appointment for November 7th at 8 AM",
  "search_in_response_to": "",
  "created_at": "2021-01-11T12:40:26.301Z"
}

Next Steps

Next time we will complete the work needed to actually schedule the appointment. This will require receiving the requested time, checking to see if that time is available, and relaying a response back to the chatbot App. At this juncture, we can begin to also think about the front end that we want to use with this service. This could include a React Application with an embedded chat widget or even an incoming sms message from twilio. I look forward to exploring both options once we have implemented the scheduling functionality for our chatbot.