Chatterbot: Removing input & output adapters (in the distant future)

Created on 23 Dec 2016  路  14Comments  路  Source: gunthercox/ChatterBot

Pros:

  • Doing this makes it possible for ChatterBot maintainers to focus on the communication aspect of the project instead of maintaining numerous modules for integrations with existing communication APIs. There will always be new communication APIs being created. As the number of these APIs that ChatterBot supports increases over time it will become more difficult to maintain them. Instead of expending time maintaining these integrations and adding new integrations to ChatterBot, it might be better to put that effort into making sure that ChatterBot is generally usable with existing software libraries and clients designed to connect to those APIs.
  • Being required to create an input and an output adapter to connect to a particular API can restrict the developer by requiring them to work around the constraints of ChatterBot's input and output adapters.

Cons:

  • Developers who have created applications that use ChatterBot's input and output adapter classes probably won't be happy.
  • Session management would likely have to be handled by the developer, so it would need to be really easy to use. At the moment, session management primarily occurs internally because it does not have the most friendly interface.

How would things change if input and output adapters were removed?

With the current version of ChatterBot, if we want our chat bot to interact with some source of data, then we would need an input and an output adapter. Lets use MailGun's API as an example. In this case, we need an input adapter to check MailGun for new messages and an output adapter to send the chat bot's responses back to whoever sent them.


Here is an example of the input adapter for MailGun.

import datetime
from chatterbot.input import InputAdapter
from chatterbot.conversation import Statement

class Mailgun(InputAdapter):

def __init__(self, kwargs):
super(Mailgun, self).__init__(
kwargs)

# Use the bot's name for the name of the sender
self.name = kwargs.get('name')
self.from_address = kwargs.get('mailgun_from_address')
self.api_key = kwargs.get('mailgun_api_key')
self.endpoint = kwargs.get('mailgun_api_endpoint')

def get_email_stored_events(self):
import requests

yesterday = datetime.datetime.now() - datetime.timedelta(1)
return requests.get(
'{}/events'.format(self.endpoint),
auth=('api', self.api_key),
params={
'begin': yesterday.isoformat(),
'ascending': 'yes',
'limit': 1
}
)

def get_stored_email_urls(self):
response = self.get_email_stored_events()
data = response.json()

for item in data.get('items', []):
if 'storage' in item:
if 'url' in item['storage']:
yield item['storage']['url']

def get_message(self, url):
import requests

return requests.get(
url,
auth=('api', self.api_key)
)

def process_input(self, statement):
urls = self.get_stored_email_urls()
url = first(urls)

response = self.get_message(url)
message = response.json()

text = message.get('stripped-text')

return Statement(text)


Here is an example of the output adapter for MailGun.

from .output_adapter import OutputAdapter

class Mailgun(OutputAdapter):

def __init__(self, **kwargs):
    super(Mailgun, self).__init__(**kwargs)

    # Use the bot's name for the name of the sender
    self.name = kwargs.get('name')
    self.from_address = kwargs.get('mailgun_from_address')
    self.api_key = kwargs.get('mailgun_api_key')
    self.endpoint = kwargs.get('mailgun_api_endpoint')
    self.recipients = kwargs.get('mailgun_recipients')

def send_message(self, subject, text, from_address, recipients):
"""
* subject: Subject of the email.
* text: Text body of the email.
* from_email: The email address that the message will be sent from.
* recipients: A list of recipient email addresses.
"""
import requests

return requests.post(
self.endpoint,
auth=('api', self.api_key),
data={
'from': '%s <%s>' % (self.name, from_address),
'to': recipients,
'subject': subject,
'text': text
})

def process_response(self, statement, session_id=None):
"""
Send the response statement as an email.
"""
subject = 'Message from %s' % (self.name)

self.send_message(
subject,
statement.text,
self.from_address,
self.recipients
)

return statement

Input and output adapters are used by the chat bot as follows.

  1. First, a chat bot's get_response() method is called.
  2. The get_response method gets a Statement object as input from the input adapter.
  3. The input statement is evaluated by the chat bot and a response is produced.
  4. The response is passed to the output adapter.

Note the following:

  • The get_response() method can take optional parameters depending on the input adapter that is being used.
  • The get_response() method always returns the response that was passed to the output adapter.

Now that we have covered how things currently are, lets go over how things would be different if there were no input or output adapters.

  1. The developer would write their code to check MailGun's API for new messages.
  2. If a new message was found then a Statement object would be passed to the chat bot's get_response method.
  3. The get_response() method would return the chat bot's response (a Statement object) to the input statement.
  4. The developer would send this response back to the original sender.

To reiterate the main motivation behind this change: it is difficult to maintain code for every communications API. This change is meant to simplify things so that other libraries can handle interacting with external data sources and ChatterBot will just handle generating the response.

Additionally, input and output adapters don't always work with all developer's code setups. They assume that you want to create your chat bot entirely inside of ChatterBot related classes. Instead of trying to support every use case it seems like it would be simpler to simplify how ChatterBot gets and returns information in general.

depreciation

Most helpful comment

@lucaszanella I've updated the original ticket to cover how things would work if input and output adapters were discontinued. It's under the new section titled:

How would things change if input and output adapters were removed?

Let me know if you have any questions.

All 14 comments

Looks good, one question on session management, Please correct me if i am wrong

Developer
He has create a session object and reuse the same

End user
i.e If a user installed chatbot on his machine, started an basic example, there is no session management?

The examples would have to be modified to manage sessions properly. For most of the simple examples that are currently included with ChatterBot there would be just one session.

I didn't understand. How will the bot talk to the world? For example, I was going to develop a ZeroMQ input/output. How I'm supposed to integrate it with the bot in the future when there is no input/output adapters? I thought it was a nice idea to have a base class and then people could install the desired adapters. Didn't understand why you're removing it.

I will try to write below what i understood, @gunthercox please correct if i wrong.

ChatterBot maintainers to focus on the communication aspect

This means user look on only chatterbot specific data, not looking for integration which currently chatterbot providing (HipChat, Microsoft, etc.)

from chatterbot.trainers import ListTrainer

conversation = [
    "Hello",
    "Hi there!",
    "How are you doing?",
    "I'm doing great.",
    "That is good to hear",
    "Thank you.",
    "You're welcome."
]

chatbot.set_trainer(ListTrainer)
chatbot.train(conversation)

How will the bot talk to the world?

chatterbot will expose its Northbound API to end user, using that API his/her develop their application.

@lucaszanella I've updated the original ticket to cover how things would work if input and output adapters were discontinued. It's under the new section titled:

How would things change if input and output adapters were removed?

Let me know if you have any questions.

@gunthercox and @vkosuri ,
If I understood well, there will be some kind of asynchronous Statement and maybe a session to have conversations(user) related with external conversations(?) (API exposed or consumed) and eventually the Statement will appear in brain (data) and/or will be show in the user conversation.

Said that, it will expand/change how ChatterBot interact, and how logic adapters process the new information. It will enable to integrate with Zapier(?), IFTTT(?) some kind of API that send/receive push notifications. Well, will expose API to integrate. Right or I went too far?

Thanks

@davizucon I believe what you are describing is accurate. After this change is made the only difference there will be is that programmers will pass data TO chatterbot and a response will be returned, they will then write code to do something with that response. Right now input and output adapters are somewhat limiting to the developer and I would prefer to encourage design patterns that don't force the developer into a difficult or limited scope.

@gunthercox Master, I have created a repo https://github.com/vkosuri/chatterbot-io-adapters to address this issue, if it looks to good, I will make PR to remove io adapter from chatterbot.

@vkosuri Please don't make that change yet unless doing so is absolutely necessary. I'd like to minimize the number of changes that occur in the next release (0.8) and as far as I am aware removing support for IO adapters is fairly low priority.

@gunthercox Thank you master, Meanwhile Can add these Slack #682, Facebook #917, Discord #1009 to that package https://github.com/vkosuri/chatterbot-io-adapters, is that ok?

If the io adapters for those tickets get created, then yes, feel free to close their corresponding tickets off. Even if ChatterBot drops support for IO adapters there will still be a migration plan to so that some of their code can be re-used.

@gunthercox When will io adapters be removed completely? Is there a version planed where they will be removed?

@pylobot Currently there is no planned release date for this change. Removing support for IO adapters is very low priority.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings