Skip to content

Commit

Permalink
Replace filter classes with a single method
Browse files Browse the repository at this point in the history
  • Loading branch information
gunthercox committed Nov 18, 2018
1 parent 26bf1d2 commit 6dcdb07
Show file tree
Hide file tree
Showing 10 changed files with 50 additions and 152 deletions.
3 changes: 0 additions & 3 deletions chatterbot/chatterbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ def __init__(self, name, **kwargs):
self.input = utils.initialize_class(input_adapter, self, **kwargs)
self.output = utils.initialize_class(output_adapter, self, **kwargs)

filters = kwargs.get('filters', tuple())
self.filters = tuple([utils.import_module(F)() for F in filters])

# Add required system logic adapter
for system_logic_adapter in system_logic_adapters:
utils.validate_adapter_class(system_logic_adapter, LogicAdapter)
Expand Down
65 changes: 17 additions & 48 deletions chatterbot/filters.py
Original file line number Diff line number Diff line change
@@ -1,57 +1,26 @@
"""
Filters set the base query that gets passed to the storage adapter.
"""


class Filter(object):
"""
A base filter object from which all other
filters should be subclassed.
"""

def filter_selection(self, chatterbot, conversation):
"""
Because this is the base filter class, this method just
returns the storage adapter's base query. Other filters
are expected to override this method.
"""
return chatterbot.storage.base_query


class RepetitiveResponseFilter(Filter):
def get_recent_repeated_responses(chatbot, conversation, sample=10, threshold=3, quantity=3):
"""
A filter that eliminates possibly repetitive responses to prevent
a chat bot from repeating statements that it has recently said.
"""
from collections import Counter

def filter_selection(self, chatterbot, conversation):
from collections import Counter

# Get the 10 most recent statements from the conversation
conversation_statements = chatterbot.storage.filter(
conversation=conversation,
order_by=['id']
)[-10:]

text_of_recent_responses = [
statement.in_response_to for statement in conversation_statements
if statement is not None and statement.in_response_to is not None
]

counter = Counter(text_of_recent_responses)
# Get the most recent statements from the conversation
conversation_statements = list(chatbot.storage.filter(
conversation=conversation,
order_by=['id']
))[sample * -1:]

# Find the three most common responses from the conversation
most_common = counter.most_common(3)
text_of_recent_responses = [
statement.text for statement in conversation_statements
]

# Return the query with no changes if there are no statements to exclude
if not most_common:
return super(RepetitiveResponseFilter, self).filter_selection(
chatterbot,
conversation
)
counter = Counter(text_of_recent_responses)

query = chatterbot.storage.base_query.statement_in_response_to_not_in(
[text[0] for text in most_common]
)
# Find the n most common responses from the conversation
most_common = counter.most_common(quantity)

return query
return [
counted[0] for counted in most_common
if counted[1] >= threshold
]
10 changes: 9 additions & 1 deletion chatterbot/logic/best_match.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from chatterbot.logic import LogicAdapter
from chatterbot import filters


class BestMatch(LogicAdapter):
Expand Down Expand Up @@ -48,9 +49,15 @@ def process(self, input_statement):
input_statement.text, closest_match.text
))

recent_repeated_responses = filters.get_recent_repeated_responses(
self.chatbot,
input_statement.conversation
)

# Get all statements that are in response to the closest match
response_list = self.chatbot.storage.filter(
in_response_to=closest_match.text
in_response_to=closest_match.text,
exclude_text=recent_repeated_responses
)

if response_list:
Expand All @@ -64,6 +71,7 @@ def process(self, input_statement):
response_list,
self.chatbot.storage
)

response.confidence = closest_match.confidence
self.chatbot.logger.info('Response selected. Using "{}"'.format(response.text))
else:
Expand Down
7 changes: 0 additions & 7 deletions docs/chatterbot.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ to the user.
Defaults to ``"chatterbot.output.OutputAdapter"``.
:type output_adapter: str

:param filters: A list of dot-notated import paths to filter classes to be used by the chat bot.
:type filters: list

:param logger: A ``Logger`` object.
:type logger: logging.Logger

Expand All @@ -50,10 +47,6 @@ Example chat bot parameters
],
input_adapter='my.input.AdapterClass',
output_adapter='my.output.AdapterClass',
filters=[
'my.filter.FilterClass1',
'my.filter.FilterClass2'
],
logger=custom_logger
)
Expand Down
19 changes: 19 additions & 0 deletions docs/filters.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
=======
Filters
=======

Filters are an efficient way to create queries that can be passed to ChatterBot's storage adapters.
Filters will reduce the number of statements that a chat bot has to process when it is selecting a response.

Setting filters
===============

.. code-block:: python
chatbot = ChatBot(
"My ChatterBot",
filters=[filters.get_recent_repeated_responses]
)
.. automodule:: chatterbot.filters
:members:
56 changes: 0 additions & 56 deletions docs/filters/create_a_new_filter.rst

This file was deleted.

28 changes: 0 additions & 28 deletions docs/filters/index.rst

This file was deleted.

2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Contents:
input/index
output/index
storage/index
filters/index
filters
chatterbot
conversations
comparisons
Expand Down
4 changes: 0 additions & 4 deletions examples/terminal_mongo_example.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from chatterbot import ChatBot


# Uncomment the following lines to enable verbose logging
# import logging
# logging.basicConfig(level=logging.INFO)
Expand All @@ -13,9 +12,6 @@
logic_adapters=[
'chatterbot.logic.BestMatch'
],
filters=[
'chatterbot.filters.RepetitiveResponseFilter'
],
input_adapter='chatterbot.input.TerminalAdapter',
output_adapter='chatterbot.output.TerminalAdapter',
database_uri='mongodb://localhost:27017/chatterbot-database'
Expand Down
8 changes: 4 additions & 4 deletions tests/test_filters.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
from tests.base_case import ChatBotMongoTestCase
from chatterbot import filters


class RepetitiveResponseFilterTestCase(ChatBotMongoTestCase):
"""
Test case for the RepetitiveResponseFilter class.
Test case for the repetitive response filter.
"""

def test_filter_selection(self):
"""
Test that repetitive responses are filtered out of the results.
"""
from chatterbot.conversation import Statement
from chatterbot.filters import RepetitiveResponseFilter
from chatterbot.trainers import ListTrainer

self.chatbot.filters = (RepetitiveResponseFilter(), )
self.chatbot.filters = (filters.get_recent_repeated_responses, )

self.trainer = ListTrainer(
self.chatbot,
Expand All @@ -38,5 +38,5 @@ def test_filter_selection(self):
first_response = self.chatbot.get_response(statement)
second_response = self.chatbot.get_response(statement)

self.assertEqual('I am good.', first_response.text)
self.assertEqual('How are you?', first_response.text)
self.assertEqual('Hi', second_response.text)

0 comments on commit 6dcdb07

Please sign in to comment.