Skip to content

Commit

Permalink
Migrate math evaluation plugin to logic adapter.
Browse files Browse the repository at this point in the history
  • Loading branch information
gunthercox committed Jan 16, 2016
1 parent 0d46588 commit 1b2d740
Show file tree
Hide file tree
Showing 12 changed files with 129 additions and 144 deletions.
10 changes: 0 additions & 10 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
sudo: false
language: python

python:
Expand All @@ -20,12 +19,3 @@ script:

after_success:
- coveralls

deploy:
provider: pypi
user: gunthercox
password:
secure: H9/MovOgi49YQbL2oTBz5Nrkkc2n/mIxEUQcSCEjvuVcv9oXQjiajqHgMmkuRITMvcNpd9sT25qk5t6pXSIRQfbSvr7DXSsOvNcms1bC5F7M3UWGGRobe1DtQBSlmq6l5zfBnfMoJE4gsRVFEero9owodVscPUSPqrCiRGgeiik=
on:
tags: true
branch: master
1 change: 0 additions & 1 deletion chatterbot/adapters/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@ def __init__(self, **kwargs):

def set_context(self, context):
self.context = context

1 change: 1 addition & 0 deletions chatterbot/adapters/logic/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
from .time_adapter import TimeLogicAdapter
from .multi_adapter import MultiLogicAdapter
from .no_knowledge_adapter import NoKnowledgeAdapter
from .evaluate_mathematically import EvaluateMathematically
Original file line number Diff line number Diff line change
@@ -1,42 +1,39 @@
from .plugin import PluginAdapter
from chatterbot.adapters.logic import LogicAdapter
from chatterbot.conversation import Statement
import re
import os, json
import decimal

class EvaluateMathematically(PluginAdapter):

def should_answer(self, input_text):
class EvaluateMathematically(LogicAdapter):

def can_process(self, statement):
"""
Determines whether it is appropriate for this plugin
to respond to the user input.
"""
confidence, response = self.process(statement)
return confidence, response

response = self.process( input_text )

if response is False:
return False
else:
return True


def process(self, input_text):
def process(self, statement):
"""
Takes a statement string.
Returns the simplified statement string
with the mathematical terms "solved".
"""
input_text = statement.text

# Getting the mathematical terms within the input statement
expression = self.simplify_chunks( self.normalize( input_text ) )
expression = self.simplify_chunks(self.normalize(input_text))

# Returning important information
try:
expression += '= ' + str( eval( expression ) )
expression += '= ' + str(eval(expression))

return expression
# return a confidence of 1 if the expression could be evaluated
return 1, Statement(expression)
except:
return False

return 0, Statement(expression)

def simplify_chunks(self, input_text):
"""
Expand All @@ -47,24 +44,23 @@ def simplify_chunks(self, input_text):

for chunk in input_text.split():

is_chunk_integer = self.is_integer( chunk )
is_chunk_integer = self.is_integer(chunk)

if is_chunk_integer is False:
is_chunk_float = self.is_float( chunk )
is_chunk_float = self.is_float(chunk)

if is_chunk_float is False:
is_chunk_operator = self.is_operator( chunk )
is_chunk_operator = self.is_operator(chunk)

if not is_chunk_operator is False:
string += str( is_chunk_operator ) + ' '
string += str(is_chunk_operator) + ' '
else:
string += str( is_chunk_float ) + ' '
string += str(is_chunk_float) + ' '
else:
string += str( is_chunk_integer ) + ' '
string += str(is_chunk_integer) + ' '

return string


def is_float(self, string):
"""
If the string is a float, returns
Expand All @@ -77,7 +73,6 @@ def is_float(self, string):
except decimal.DecimalException:
return False


def is_integer(self, string):
"""
If the string is an integer, returns
Expand All @@ -86,11 +81,10 @@ def is_integer(self, string):
"""

try:
return int( string )
return int(string)
except:
return False


def is_operator(self, string):
"""
If the string is an operator, returns
Expand All @@ -103,31 +97,30 @@ def is_operator(self, string):
else:
return False


def normalize(self, string):
"""
Normalizes input text, reducing errors
and improper calculations.
"""

# If the string is empty, just return it
if len( string ) is 0:
if len(string) is 0:
return string

# Setting all words to lowercase
string = string.lower()

# Removing punctuation
if not string[-1].isalnum():
string = string[ : -1 ]
string = string[:-1]

# Removing words
string = self.substitute_words( string )
string = self.substitute_words(string)

# Returning normalized text
return string

def load_data( self, language ):
def load_data(self, language):
"""
Load language-specific data
"""
Expand All @@ -137,49 +130,48 @@ def load_data( self, language ):
data = json.load(data_file)
self.data = data


def substitute_words(self, string):
"""
Substitutes numbers for words.
"""

self.load_data( "english" )
self.load_data("english")

condensed_string = '_'.join( string.split() )
condensed_string = '_'.join(string.split())

for word in self.data[ "words" ]:
condensed_string = re.sub( '_'.join( word.split( ' ' ) ), self.data[ "words" ][ word ], condensed_string )
for word in self.data["words"]:
condensed_string = re.sub('_'.join(word.split(' ')), self.data["words"][word], condensed_string)

for number in self.data[ "numbers" ]:
condensed_string = re.sub( number, str( self.data[ "numbers" ][ number ] ), condensed_string )
for number in self.data["numbers"]:
condensed_string = re.sub(number, str(self.data["numbers"][number]), condensed_string)

for scale in self.data[ "scales" ]:
condensed_string = re.sub( "_" + scale, " " + self.data[ "scales" ][ scale ], condensed_string)
for scale in self.data["scales"]:
condensed_string = re.sub("_" + scale, " " + self.data["scales"][scale], condensed_string)

condensed_string = condensed_string.split( '_' )
for chunk_index in range( 0, len( condensed_string ) ):
condensed_string = condensed_string.split('_')
for chunk_index in range(0, len(condensed_string)):
value = ""

try:
value = str( eval( condensed_string[ chunk_index ] ) )
value = str(eval(condensed_string[chunk_index]))

condensed_string[ chunk_index ] = value
condensed_string[chunk_index] = value
except:
pass

for chunk_index in range( 0, len( condensed_string ) ):
if self.is_integer( condensed_string[ chunk_index ] ) or self.is_float( condensed_string[ chunk_index ] ):
for chunk_index in range(0, len(condensed_string)):
if self.is_integer(condensed_string[chunk_index]) or self.is_float(condensed_string[chunk_index]):
i = 1
start_index = chunk_index
end_index = -1
while( chunk_index + i < len( condensed_string ) and ( self.is_integer( condensed_string[ chunk_index + i ] ) or self.is_float( condensed_string[ chunk_index + i ] ) ) ):
while (chunk_index + i < len(condensed_string) and (self.is_integer(condensed_string[chunk_index + i]) or self.is_float(condensed_string[chunk_index + i]))):
end_index = chunk_index + i
i += 1

for sub_chunk in range( start_index, end_index ):
condensed_string[ sub_chunk ] += " +"
for sub_chunk in range(start_index, end_index):
condensed_string[sub_chunk] += " +"

condensed_string[ start_index ] = "( " + condensed_string[ start_index ]
condensed_string[ end_index ] += " )"
condensed_string[start_index] = "( " + condensed_string[start_index]
condensed_string[end_index] += " )"

return ' '.join( condensed_string )
return ' '.join(condensed_string)
3 changes: 0 additions & 3 deletions chatterbot/adapters/plugins/__init__.py

This file was deleted.

17 changes: 0 additions & 17 deletions chatterbot/adapters/plugins/plugin.py

This file was deleted.

28 changes: 0 additions & 28 deletions chatterbot/adapters/plugins/plugin_chooser.py

This file was deleted.

10 changes: 0 additions & 10 deletions chatterbot/chatterbot.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from .adapters import Adaptation
from .conversation import Statement
from .utils.module_loading import import_module


class ChatBot(Adaptation):
Expand All @@ -27,9 +26,6 @@ def __init__(self, name, **kwargs):
"chatterbot.adapters.io.TerminalAdapter"
)

PluginChooser = import_module("chatterbot.adapters.plugins.PluginChooser")
self.plugin_chooser = PluginChooser(**kwargs)

self.add_adapter(storage_adapter, **kwargs)
self.add_adapter(io_adapter, **kwargs)

Expand Down Expand Up @@ -65,12 +61,6 @@ def get_response(self, input_text):
"""
input_statement = Statement(input_text)

# Applying plugin logic to see whether the chatbot should respond in this way
plugin_response = self.plugin_chooser.choose(input_statement)

if not plugin_response is False:
return self.io.process_response(Statement(plugin_response))

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

Expand Down
19 changes: 19 additions & 0 deletions examples/math_and_time.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from chatterbot import ChatBot


bot = ChatBot(
"Math & Time Bot",
logic_adapters=[
"chatterbot.adapters.logic.EvaluateMathematically",
"chatterbot.adapters.logic.TimeLogicAdapter"
],
io_adapter="chatterbot.adapters.io.NoOutputAdapter"
)

# Print an example of getting one math based response
response = bot.get_response("What is 4 + 9?")
print(response)

# Print an example of getting one time based response
response = bot.get_response("What time is it?")
print(response)
Loading

0 comments on commit 1b2d740

Please sign in to comment.