Skip to content

Commit

Permalink
Change logic adapters to just return one value
Browse files Browse the repository at this point in the history
This change is being made to simplify logic adapters and to
remove redundant data since the confidence score is now being
stored on the statement object.
  • Loading branch information
gunthercox committed Jan 15, 2017
1 parent 23974d5 commit 351971a
Show file tree
Hide file tree
Showing 20 changed files with 80 additions and 66 deletions.
4 changes: 2 additions & 2 deletions chatterbot/chatterbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,9 @@ def generate_response(self, input_statement, session_id=None):
self.storage.generate_base_query(self, session_id)

# Select a response to the input statement
confidence, response = self.logic.process(input_statement)
response = self.logic.process(input_statement)

return input_statement, response, confidence
return input_statement, response, response.confidence

def learn_response(self, statement, previous_statement):
"""
Expand Down
2 changes: 1 addition & 1 deletion chatterbot/logic/best_match.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,4 @@ def process(self, input_statement):
# Set confidence to zero because a random response is selected
response.confidence = 0

return response.confidence, response
return response
10 changes: 9 additions & 1 deletion chatterbot/logic/logic_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,18 @@ def process(self, statement):
:param statement: An input statement to be processed by the logic adapter.
:type statement: Statement
:rtype: float, Statement
:rtype: Statement
"""
raise self.AdapterMethodNotImplementedError()

@property
def class_name(self):
"""
Return the name of the current logic adapter class.
This is typically used for logging and debugging.
"""
return str(self.__class__.__name__)

class EmptyDatasetException(Exception):

def __init__(self, value='An empty set was received when at least one statement was expected.'):
Expand Down
2 changes: 1 addition & 1 deletion chatterbot/logic/low_confidence.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ def process(self, input_statement):
else:
self.default_response.confidence = 0

return self.default_response.confidence, self.default_response
return self.default_response
8 changes: 4 additions & 4 deletions chatterbot/logic/mathematical_evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ def can_process(self, statement):
Determines whether it is appropriate for this
adapter to respond to the user input.
"""
confidence, response = self.process(statement)
self.cache[statement.text] = (confidence, response)
return confidence == 1
response = self.process(statement)
self.cache[statement.text] = response
return response.confidence == 1

def process(self, statement):
"""
Expand Down Expand Up @@ -100,7 +100,7 @@ def process(self, statement):
except:
response.confidence = 0

return response.confidence, response
return response

def simplify_chunks(self, input_text):
"""
Expand Down
24 changes: 18 additions & 6 deletions chatterbot/logic/multi_adapter.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
import warnings
from collections import Counter
from chatterbot import utils
from .logic_adapter import LogicAdapter
Expand Down Expand Up @@ -34,18 +35,29 @@ def process(self, statement):

for adapter in self.get_adapters():
if adapter.can_process(statement):
confidence, output = adapter.process(statement)
results.append((confidence, output, ))

output = adapter.process(statement)

if type(output) == tuple:
warnings.warn(
'{} returned two values when just a Statement object was expected. '
'You should update your logic adapter to return just the Statement object. '
'Make sure that statement.confidence is being set.'.format(adapter.class_name),
DeprecationWarning
)
output = output[1]

results.append((output.confidence, output, ))

self.logger.info(
'{} selected "{}" as a response with a confidence of {}'.format(
str(adapter.__class__), output.text, confidence
adapter.class_name, output.text, output.confidence
)
)

if confidence > max_confidence:
if output.confidence > max_confidence:
result = output
max_confidence = confidence
max_confidence = output.confidence
else:
self.logger.info(
'Not processing the statement using {}'.format(
Expand All @@ -64,7 +76,7 @@ def process(self, statement):
max_confidence = self.get_greatest_confidence(result, results)

result.confidence = max_confidence
return max_confidence, result
return result

def get_greatest_confidence(self, statement, options):
"""
Expand Down
2 changes: 1 addition & 1 deletion chatterbot/logic/no_knowledge_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ def process(self, statement):
else:
statement.confidence = 1

return statement.confidence, statement
return statement
2 changes: 1 addition & 1 deletion chatterbot/logic/specific_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ def process(self, statement):
else:
self.response_statement.confidence = 0

return self.response_statement.confidence, self.response_statement
return self.response_statement
2 changes: 1 addition & 1 deletion chatterbot/logic/time_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,4 @@ def process(self, statement):
response = Statement('The current time is ' + now.strftime('%I:%M %p'))

response.confidence = confidence
return confidence, response
return response
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ def test_no_known_responses(self):
return_value=Statement('Random')
)

confidence, match = self.adapter.process(Statement('Blah'))
match = self.adapter.process(Statement('Blah'))

self.assertEqual(confidence, 0)
self.assertEqual(match.confidence, 0)
self.assertEqual(match.text, 'Random')
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ def test_exact_input(self):
])

happy_statement = Statement('I enjoy raspberry ice cream.')
confidence, response = self.adapter.process(happy_statement)
response = self.adapter.process(happy_statement)

self.assertEqual(confidence, 1)
self.assertEqual(response.confidence, 1)
self.assertEqual(response.text, 'I am glad to hear that.')

Expand All @@ -45,8 +44,7 @@ def test_close_input(self):
])

happy_statement = Statement('I enjoy raspberry.')
confidence, response = self.adapter.process(happy_statement)
response = self.adapter.process(happy_statement)

self.assertEqual(response.text, 'I am glad to hear that.')
self.assertAlmostEqual(confidence, 0.75, places=1)
self.assertAlmostEqual(response.confidence, 0.75, places=1)
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,7 @@ def test_no_known_responses(self):
return_value=Statement('Random')
)

confidence, match = self.adapter.process(Statement('Blah'))
match = self.adapter.process(Statement('Blah'))

self.assertEqual(confidence, 0)
self.assertEqual(match.confidence, 0)
self.assertEqual(match.text, 'Random')
4 changes: 2 additions & 2 deletions tests/logic_adapter_tests/test_data_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ def process(self, statement):
statement.add_extra_data('pos_tags', 'NN')

self.chatbot.storage.update(statement)

return 1, statement
statement.confidence = 1
return statement


class DataCachingTests(ChatBotTestCase):
Expand Down
12 changes: 9 additions & 3 deletions tests/logic_adapter_tests/test_logic_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,21 @@ def setUp(self):
super(LogicAdapterTestCase, self).setUp()
self.adapter = LogicAdapter()

def test_class_name(self):
"""
Test that the logic adapter can return its own class name.
"""
self.assertEqual(self.adapter.class_name, 'LogicAdapter')

def test_can_process(self):
"""
This method should return true by default.
"""
self.assertTrue(self.adapter.can_process(""))
self.assertTrue(self.adapter.can_process(''))

def test_process(self):
with self.assertRaises(LogicAdapter.AdapterMethodNotImplementedError):
self.adapter.process("")
self.adapter.process('')

def test_set_statement_comparison_function_string(self):
adapter = LogicAdapter(
Expand All @@ -48,4 +54,4 @@ def test_set_response_selection_method_callable(self):
adapter = LogicAdapter(
response_selection_method=get_first_response
)
self.assertTrue(callable(adapter.select_response))
self.assertTrue(callable(adapter.select_response))
6 changes: 2 additions & 4 deletions tests/logic_adapter_tests/test_low_confidence_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,8 @@ def test_high_confidence(self):
Test the case that a high confidence response is known.
"""
statement = Statement('What is your quest?')
confidence, match = self.adapter.process(statement)
match = self.adapter.process(statement)

self.assertEqual(confidence, 0)
self.assertEqual(match.confidence, 0)
self.assertEqual(match, self.adapter.default_response)

Expand All @@ -55,8 +54,7 @@ def test_low_confidence(self):
Test the case that a high confidence response is not known.
"""
statement = Statement('Is this a tomato?')
confidence, match = self.adapter.process(statement)
match = self.adapter.process(statement)

self.assertEqual(confidence, 1)
self.assertEqual(match.confidence, 1)
self.assertEqual(match, self.adapter.default_response)
32 changes: 16 additions & 16 deletions tests/logic_adapter_tests/test_mathematical_evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,25 +63,25 @@ def setUp(self):

def test_addition_operator(self):
statement = Statement('What is 100 + 54?')
confidence, response = self.adapter.process(statement)
response = self.adapter.process(statement)
self.assertEqual(response.text, '( 100 + 54 ) = 154')
self.assertEqual(response.confidence, 1)

def test_subtraction_operator(self):
statement = Statement('What is 100 - 58?')
confidence, response = self.adapter.process(statement)
response = self.adapter.process(statement)
self.assertEqual(response.text, '( 100 - 58 ) = 42')
self.assertEqual(response.confidence, 1)

def test_multiplication_operator(self):
statement = Statement('What is 100 * 20')
confidence, response = self.adapter.process(statement)
response = self.adapter.process(statement)
self.assertEqual(response.text, '( 100 * 20 ) = 2000')
self.assertEqual(response.confidence, 1)

def test_division_operator(self):
statement = Statement('What is 100 / 20')
confidence, response = self.adapter.process(statement)
response = self.adapter.process(statement)
self.assertEqual(response.confidence, 1)

if self.python_version <= 2:
Expand All @@ -91,31 +91,31 @@ def test_division_operator(self):

def test_exponent_operator(self):
statement = Statement('What is 2 ^ 10')
confidence, response = self.adapter.process(statement)
response = self.adapter.process(statement)
self.assertEqual(response.text, '( 2 ^ 10 ) = 1024')
self.assertEqual(response.confidence, 1)

def test_parenthesized_multiplication_and_addition(self):
statement = Statement('What is 100 + ( 1000 * 2 )?')
confidence, response = self.adapter.process(statement)
response = self.adapter.process(statement)
self.assertEqual(response.text, '( 100 + ( ( 1000 * ( 2 ) ) ) ) = 2100')
self.assertEqual(response.confidence, 1)

def test_parenthesized_with_words(self):
statement = Statement('What is four plus 100 + ( 100 * 2 )?')
confidence, response = self.adapter.process(statement)
response = self.adapter.process(statement)
self.assertEqual(response.text, '( 4 + ( 100 + ( ( 100 * ( 2 ) ) ) ) ) = 304')
self.assertEqual(response.confidence, 1)

def test_word_numbers_addition(self):
statement = Statement('What is one hundred + four hundred?')
confidence, response = self.adapter.process(statement)
response = self.adapter.process(statement)
self.assertEqual(response.text, '( 100 + 400 ) = 500')
self.assertEqual(response.confidence, 1)

def test_word_division_operator(self):
statement = Statement('What is 100 divided by 100?')
confidence, response = self.adapter.process(statement)
response = self.adapter.process(statement)

if self.python_version <= 2:
self.assertEqual(response.text, '( 100 / 100 ) = 1')
Expand All @@ -126,7 +126,7 @@ def test_word_division_operator(self):

def test_large_word_division_operator(self):
statement = Statement('What is one thousand two hundred four divided by one hundred?')
confidence, response = self.adapter.process(statement)
response = self.adapter.process(statement)

if self.python_version <= 2:
self.assertEqual(response.text, '( 1000 + 200 + 4 ) / ( 100 ) = 12')
Expand All @@ -137,37 +137,37 @@ def test_large_word_division_operator(self):

def test_negative_multiplication(self):
statement = Statement('What is -105 * 5')
confidence, response = self.adapter.process(statement)
response = self.adapter.process(statement)
self.assertEqual(response.text, '( -105 * 5 ) = -525')
self.assertEqual(response.confidence, 1)

def test_negative_decimal_multiplication(self):
statement = Statement('What is -100.5 * 20?')
confidence, response = self.adapter.process(statement)
response = self.adapter.process(statement)
self.assertEqual(response.text, '( -100.5 * 20 ) = -2010.0')
self.assertEqual(response.confidence, 1)

def test_pi_constant(self):
statement = Statement('What is pi plus one ?')
confidence, response = self.adapter.process(statement)
response = self.adapter.process(statement)
self.assertEqual(response.text, '3.141693 + ( 1 ) = 4.141693')
self.assertEqual(response.confidence, 1)

def test_e_constant(self):
statement = Statement('What is e plus one ?')
confidence, response = self.adapter.process(statement)
response = self.adapter.process(statement)
self.assertEqual(response.text, '2.718281 + ( 1 ) = 3.718281')
self.assertEqual(response.confidence, 1)

def test_log_function(self):
statement = Statement('What is log 100 ?')
confidence, response = self.adapter.process(statement)
response = self.adapter.process(statement)
self.assertEqual(response.text, 'log ( 100 ) = 2.0')
self.assertEqual(response.confidence, 1)

def test_square_root_function(self):
statement = Statement('What is the sqrt 144 ?')
confidence, response = self.adapter.process(statement)
response = self.adapter.process(statement)
self.assertEqual(response.text, 'sqrt ( 144 ) = 12.0')
self.assertEqual(response.confidence, 1)

3 changes: 1 addition & 2 deletions tests/logic_adapter_tests/test_multi_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,8 @@ def test_sub_adapter_agreement(self):
self.adapter.add_adapter('tests.logic_adapter_tests.test_multi_adapter.TestAdapterB')
self.adapter.add_adapter('tests.logic_adapter_tests.test_multi_adapter.TestAdapterC')

confidence, statement = self.adapter.process(Statement('Howdy!'))
statement = self.adapter.process(Statement('Howdy!'))

self.assertEqual(confidence, 0.5)
self.assertEqual(statement.confidence, 0.5)
self.assertEqual(statement, 'Good morning.')

Expand Down
6 changes: 2 additions & 4 deletions tests/logic_adapter_tests/test_specific_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ def test_exact_match(self):
Test the case that an exact match is given.
"""
statement = Statement('Open sesame!')
confidence, match = self.adapter.process(statement)
match = self.adapter.process(statement)

self.assertEqual(confidence, 1)
self.assertEqual(match.confidence, 1)
self.assertEqual(match, self.adapter.response_statement)

Expand All @@ -31,8 +30,7 @@ def test_not_exact_match(self):
Test the case that an exact match is not given.
"""
statement = Statement('Open says me!')
confidence, match = self.adapter.process(statement)
match = self.adapter.process(statement)

self.assertEqual(confidence, 0)
self.assertEqual(match.confidence, 0)
self.assertEqual(match, self.adapter.response_statement)
Loading

0 comments on commit 351971a

Please sign in to comment.