Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return confidence value on statement object #565

Merged
merged 2 commits into from
Jan 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions chatterbot/conversation/statement.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ def __init__(self, text, **kwargs):

self.extra_data = kwargs.pop('extra_data', {})

# This is the confidence with which the chat bot believes
# this is an accurate response. This value is set when the
# statement is returned by the chat bot.
self.confidence = 0

self.storage = None

def __str__(self):
Expand Down
5 changes: 5 additions & 0 deletions chatterbot/ext/django_chatterbot/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ class Statement(models.Model):

extra_data = models.CharField(max_length=500)

# This is the confidence with which the chat bot believes
# this is an accurate response. This value is set when the
# statement is returned by the chat bot.
confidence = 0

def __str__(self):
if len(self.text.strip()) > 60:
return '{}...'.format(self.text[:57])
Expand Down
6 changes: 5 additions & 1 deletion chatterbot/logic/best_match.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ def get(self, input_statement):
'No statements have known responses. ' +
'Choosing a random response to return.'
)
return 0, self.chatbot.storage.get_random()
random_response = self.chatbot.storage.get_random()
random_response.confidence = 0
return random_response.confidence, random_response
else:
raise self.EmptyDatasetException()

Expand All @@ -37,6 +39,7 @@ def get(self, input_statement):
max_confidence = confidence
closest_match = statement

closest_match.confidence = max_confidence
return max_confidence, closest_match

def can_process(self, statement):
Expand Down Expand Up @@ -81,4 +84,5 @@ def process(self, input_statement):
# Set confidence to zero because a random response is selected
confidence = 0

response.confidence = confidence
return confidence, response
5 changes: 4 additions & 1 deletion chatterbot/logic/low_confidence.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ def process(self, input_statement):
else:
confidence = 0

return confidence, Statement(self.default_response)
response = Statement(self.default_response)
response.confidence = confidence

return confidence, response
11 changes: 8 additions & 3 deletions chatterbot/logic/mathematical_evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,19 @@ def process(self, statement):

# Returning important information
try:
expression += "= " + str(
expression += '= ' + str(
eval(expression, {f: getattr(numpy, f) for f in self.functions})
)

response = Statement(expression)
response.confidence = 1

# return a confidence of 1 if the expression could be evaluated
return 1, Statement(expression)
return 1, response
except:
return 0, Statement(expression)
response = Statement(expression)
response.confidence = 0
return 0, response

def simplify_chunks(self, input_text):
"""
Expand Down
1 change: 1 addition & 0 deletions chatterbot/logic/multi_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ def process(self, statement):
result = most_common[0][0]
max_confidence = self.get_greatest_confidence(result, results)

result.confidence = max_confidence
return max_confidence, result

def get_greatest_confidence(self, statement, options):
Expand Down
6 changes: 4 additions & 2 deletions chatterbot/logic/no_knowledge_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ def process(self, statement):
"""

if self.chatbot.storage.count():
return 0, statement
statement.confidence = 0
else:
statement.confidence = 1

return 1, statement
return statement.confidence, statement
7 changes: 4 additions & 3 deletions chatterbot/logic/specific_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ def can_process(self, statement):
return False

def process(self, statement):
confidence = 0

if statement == self.input_text:
confidence = 1
self.response_statement.confidence = 1
else:
self.response_statement.confidence = 0

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

response.confidence = confidence
return confidence, response
9 changes: 8 additions & 1 deletion docs/conversations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ has returned based on some input.
.. autoclass:: chatterbot.conversation.Statement
:members:

.. autoinstanceattribute:: chatterbot.conversation.Statement.confidence

ChatterBot's logic adapters assign a confidence score to the statement
before it is returned. The confidence score indicates the degree of
certainty with which the chat bot believes this is the correct response
to the given input.

.. _conversation_responses:

Responses
Expand Down Expand Up @@ -93,4 +100,4 @@ is shown bellow.
chatbot = ChatBot(
# ...
statement_comparison_function=levenshtein_distance
)
)
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def test_confidence_exact_match(self):
confidence, match = self.adapter.get(statement)

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

def test_confidence_half_match(self):
possible_choices = [
Expand All @@ -63,6 +64,7 @@ def test_confidence_half_match(self):
confidence, match = self.adapter.get(statement)

self.assertEqual(confidence, 0.5)
self.assertEqual(match.confidence, 0.5)

def test_confidence_no_match(self):
possible_choices = [
Expand All @@ -74,6 +76,7 @@ def test_confidence_no_match(self):
confidence, match = self.adapter.get(statement)

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

def test_no_known_responses(self):
"""
Expand All @@ -90,4 +93,5 @@ def test_no_known_responses(self):
confidence, 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 @@ -32,6 +32,7 @@ def test_exact_input(self):
confidence, 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.')

def test_close_input(self):
Expand All @@ -48,3 +49,4 @@ def test_close_input(self):

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 @@ -76,4 +76,5 @@ def test_no_known_responses(self):
confidence, match = self.adapter.process(Statement('Blah'))

self.assertEqual(confidence, 0)
self.assertEqual(match.confidence, 0)
self.assertEqual(match.text, 'Random')
2 changes: 2 additions & 0 deletions tests/logic_adapter_tests/test_low_confidence_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def test_high_confidence(self):
confidence, match = self.adapter.process(statement)

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

def test_low_confidence(self):
Expand All @@ -57,4 +58,5 @@ def test_low_confidence(self):
confidence, match = self.adapter.process(statement)

self.assertEqual(confidence, 1)
self.assertEqual(match.confidence, 1)
self.assertEqual(match, self.adapter.default_response)
15 changes: 15 additions & 0 deletions tests/logic_adapter_tests/test_mathematical_evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,24 @@ def test_addition_operator(self):
statement = Statement('What is 100 + 54?')
confidence, 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)
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)
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)
self.assertEqual(response.confidence, 1)

if self.python_version <= 2:
self.assertEqual(response.text, '( 100 / 20 ) = 5')
Expand All @@ -89,16 +93,19 @@ def test_parenthesized_multiplication_and_addition(self):
statement = Statement('What is 100 + ( 1000 * 2 )?')
confidence, 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)
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)
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?')
Expand All @@ -109,6 +116,8 @@ def test_word_division_operator(self):
else:
self.assertEqual(response.text, '( 100 / 100 ) = 1.0')

self.assertEqual(response.confidence, 1)

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)
Expand All @@ -118,23 +127,29 @@ def test_large_word_division_operator(self):
else:
self.assertEqual(response.text, '( 1000 + 200 + 4 ) / ( 100 ) = 12.04')

self.assertEqual(response.confidence, 1)

def test_negative_multiplication(self):
statement = Statement('What is -105 * 5')
confidence, 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)
self.assertEqual(response.text, '( -100.5 * 20 ) = -2010.0')
self.assertEqual(response.confidence, 1)

def test_constants(self):
statement = Statement('What is pi plus e ?')
confidence, response = self.adapter.process(statement)
self.assertEqual(response.text, '3.141693 + 2.718281 = 5.859974')
self.assertEqual(response.confidence, 1)

def test_math_functions(self):
statement = Statement('What is log ( 5 + 6 ) * sqrt ( 12 ) ?')
confidence, response = self.adapter.process(statement)
self.assertEqual(response.text, 'log ( ( 5 + ( 6 ) * sqrt ( ( 12 ) ) ) ) = 3.24977779033')
self.assertEqual(response.confidence, 1)

13 changes: 10 additions & 3 deletions tests/logic_adapter_tests/test_multi_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,25 @@
class TestAdapterA(LogicAdapter):

def process(self, statement):
return 0.2, Statement('Good morning.')
response = Statement('Good morning.')
response.confidence = 0.2
return response.confidence, response


class TestAdapterB(LogicAdapter):

def process(self, statement):
return 0.5, Statement('Good morning.')
response = Statement('Good morning.')
response.confidence = 0.5
return response.confidence, response


class TestAdapterC(LogicAdapter):

def process(self, statement):
return 0.7, Statement('Good night.')
response = Statement('Good night.')
response.confidence = 0.7
return response.confidence, response


class MultiLogicAdapterTestCase(ChatBotTestCase):
Expand All @@ -42,6 +48,7 @@ def test_sub_adapter_agreement(self):
confidence, statement = self.adapter.process(Statement('Howdy!'))

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

def test_get_greatest_confidence(self):
Expand Down
2 changes: 2 additions & 0 deletions tests/logic_adapter_tests/test_specific_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def test_exact_match(self):
confidence, match = self.adapter.process(statement)

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

def test_not_exact_match(self):
Expand All @@ -33,4 +34,5 @@ def test_not_exact_match(self):
confidence, match = self.adapter.process(statement)

self.assertEqual(confidence, 0)
self.assertEqual(match.confidence, 0)
self.assertEqual(match, self.adapter.response_statement)
2 changes: 2 additions & 0 deletions tests/logic_adapter_tests/test_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ def test_positive_input(self):
confidence, response = self.adapter.process(statement)

self.assertEqual(confidence, 1)
self.assertEqual(response.confidence, 1)
self.assertIn("The current time is ", response.text)

def test_negative_input(self):
statement = Statement("What is an example of a pachyderm?")
confidence, response = self.adapter.process(statement)

self.assertEqual(confidence, 0)
self.assertEqual(response.confidence, 0)
self.assertIn("The current time is ", response.text)

Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def test_best_match(self):
confidence, response = adapter.process(statement1)

self.assertEqual(response.text, 'Yes')
self.assertEqual(response.confidence, 1)
self.assertEqual(confidence, 1)

def test_low_confidence(self):
Expand All @@ -60,6 +61,7 @@ def test_mathematical_evaluation(self):
confidence, response = adapter.process(statement)

self.assertEqual(response.text, '( 6 + 6 ) = 12')
self.assertEqual(response.confidence, 1)

def test_time(self):
from chatterbot.logic import TimeLogicAdapter
Expand All @@ -72,3 +74,4 @@ def test_time(self):
confidence, response = adapter.process(statement)

self.assertIn('The current time is', response.text)
self.assertEqual(response.confidence, 1)