Skip to content
This repository has been archived by the owner on Jan 31, 2019. It is now read-only.

Commit

Permalink
Improve bot structure (#70)
Browse files Browse the repository at this point in the history
* Improve bot structure

* Update travis configurations

* Fix yaml style

* Fix broken URL on travis.yaml
  • Loading branch information
alexandrebarbaruiva committed Oct 8, 2018
1 parent 25ed5ca commit 486866e
Show file tree
Hide file tree
Showing 14 changed files with 191 additions and 242 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ ENV/

# User added
.DS_Store
*.ini
config.ini
/.gtm/
/rabot
db.sqlite*
Expand Down
5 changes: 3 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ env:
language: python
cache: pip
python:
- '3.6.5'
- 3.6.5
install:
- pip install -r requirements.txt
script:
Expand All @@ -17,7 +17,8 @@ before_install:
- openssl aes-256-cbc -K $encrypted_41103fb4d715_key -iv
$encrypted_41103fb4d715_iv -in config.ini.enc -out bot/config.ini -d
before_script:
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
- curl -L "https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64"
> ./cc-test-reporter
- chmod +x ./cc-test-reporter
- ./cc-test-reporter before-build
after_script:
Expand Down
73 changes: 36 additions & 37 deletions bot/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,8 @@
from telegram import Bot
from telegram.ext import Updater, CommandHandler, Dispatcher, MessageHandler, \
Filters
sys.path.append(
os.path.dirname(
os.path.dirname(os.path.realpath(__file__))
)
)

sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
from bot.communication import Communication
from bot.config_reader import retrieve_default

Expand All @@ -22,28 +19,30 @@ class Application:
oncoming messages and also handles all Telegram related commands.
Might soon have a sibling to deal with Facebook.
"""

def __init__(self, token, train=True, use_watson=True):
if train:
self.comm = Communication(use_watson)

logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
level=logging.INFO,
)
self.logger = logging.getLogger("log")
self.app = Bot(token)
self.updater = Updater(token)
self.dispatcher = self.updater.dispatcher

start_handler = CommandHandler('start', self.start)
start_handler = CommandHandler("start", self.start)
self.dispatcher.add_handler(start_handler)

info_handler = CommandHandler('info', self.info)
info_handler = CommandHandler("info", self.info)
self.dispatcher.add_handler(info_handler)

helpme_handler = CommandHandler('helpme', self.helpme)
helpme_handler = CommandHandler("helpme", self.helpme)
self.dispatcher.add_handler(helpme_handler)

contatos_handler = CommandHandler('contatos', self.contatos)
contatos_handler = CommandHandler("contatos", self.contatos)
self.dispatcher.add_handler(contatos_handler)

message_handler = MessageHandler(Filters.text, self.text_message)
Expand All @@ -61,15 +60,21 @@ def start(self, bot, update):
chat_id=update.message.chat_id, action=telegram.ChatAction.TYPING
)
sleep(3.5)
name = update.message['chat']['first_name']
start_text = f"Olá {name}, eu sou o Rabot.\n" + \
name = update.message["chat"]["first_name"]
start_text = (
f"Olá {name}, eu sou o Rabot.\n" +
"Um robô bem simpático criado para alegrar seu dia!\n"
)
bot.send_message(chat_id=update.message.chat_id, text=start_text)
start_text = "Se quiser saber mais sobre mim ou meus criadores " + \
start_text = (
"Se quiser saber mais sobre mim ou meus criadores " +
"basta digitar `/info` ;)"
)
bot.send_message(
chat_id=update.message.chat_id, text=start_text,
parse_mode=telegram.ParseMode.MARKDOWN)
chat_id=update.message.chat_id,
text=start_text,
parse_mode=telegram.ParseMode.MARKDOWN,
)
start_text = "Agora vamos lá. Em que posso ajudá-lo?"
bot.send_message(chat_id=update.message.chat_id, text=start_text)
return 0
Expand All @@ -88,7 +93,7 @@ def info(self, bot, update):
bot.send_message(
chat_id=update.message.chat_id,
text=info_text,
parse_mode=telegram.ParseMode.MARKDOWN
parse_mode=telegram.ParseMode.MARKDOWN,
)
return 0
return 1
Expand All @@ -106,7 +111,7 @@ def helpme(self, bot, update):
bot.send_message(
chat_id=update.message.chat_id,
text=helpme_text,
parse_mode=telegram.ParseMode.MARKDOWN
parse_mode=telegram.ParseMode.MARKDOWN,
)

def contatos(self, bot, update):
Expand All @@ -122,7 +127,7 @@ def contatos(self, bot, update):
bot.send_message(
chat_id=update.message.chat_id,
text=contatos_text,
parse_mode=telegram.ParseMode.MARKDOWN
parse_mode=telegram.ParseMode.MARKDOWN,
)

def text_message(self, bot, update):
Expand All @@ -134,14 +139,12 @@ def text_message(self, bot, update):
return 0

def error(self, bot, update, error):
self.logger.warning(
f'Update "{update}" caused error "{error}"'
)
self.logger.warning(f'Update "{update}" caused error "{error}"')
return 0

def run(self):
# Start the Bot
print('Bot configured. Receiving messages now.')
print("Bot configured. Receiving messages now.")
self.updater.start_polling()

# Run the bot until you press Ctrl-C or the process receives SIGINT,
Expand All @@ -151,29 +154,25 @@ def run(self):
return 0


if __name__ == '__main__':
if __name__ == "__main__":
# Variables set on Heroku
TOKEN = os.environ.get('TOKEN')
NAME = os.environ.get('NAME')
TOKEN = os.environ.get("TOKEN")
NAME = os.environ.get("NAME")
# Port is given by Heroku
PORT = os.environ.get('PORT')
PORT = os.environ.get("PORT")
if TOKEN is not None:
bot = Application(TOKEN, use_watson=False)
bot.updater.start_webhook(
listen="0.0.0.0",
port=int(PORT),
url_path=TOKEN
)
bot.updater.bot.set_webhook(
"https://{}.herokuapp.com/{}".format(NAME, TOKEN)
)
listen="0.0.0.0", port=int(PORT), url_path=TOKEN)
bot.updater.bot.set_webhook(f"https://{NAME}.herokuapp.com/{TOKEN}")
bot.updater.idle()

# Run on local system once detected that it's not on Heroku
else:
try:
token = retrieve_default()['token']
x = Application(token).run()
token = retrieve_default("TELEGRAM")["token"]
watson = eval(retrieve_default()["IBM Watson"])
x = Application(token=token, use_watson=watson).run()
except FileNotFoundError:
print('Configuration file not found.')
print("Configuration file not found.")
sys.exit(1)
74 changes: 35 additions & 39 deletions bot/communication.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,12 @@
from chatterbot.trainers import ChatterBotCorpusTrainer
from chatterbot.response_selection import get_random_response
from bot.config_reader import retrieve_default
sys.path.append(
os.path.dirname(
os.path.dirname(os.path.realpath(__file__))
)
)

sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
from bot.watson import Watson


class Communication:

def __init__(self, use_watson=False, train=True):
"""
Generator for dealing with most messages the bot will receive
Expand All @@ -25,59 +21,59 @@ def __init__(self, use_watson=False, train=True):
"Comms",
response_selection_method=get_random_response,
logic_adapters=[
{"import_path": "chatterbot.logic.BestMatch"},
{
'import_path': 'chatterbot.logic.BestMatch'
"import_path": "chatterbot.logic.LowConfidenceAdapter",
"threshold": 0.65,
"default_response": [
"Desculpa, mas não entendi sua mensagem.",
"Não compreendi, você pode repetir?",
"Como é? Não entendi",
],
},
{
'import_path': 'chatterbot.logic.LowConfidenceAdapter',
'threshold': 0.65,
'default_response':
[
'Desculpa, mas não entendi sua mensagem.',
'Não compreendi, você pode repetir?',
'Como é? Não entendi',
],
}
],
trainer='chatterbot.trainers.ChatterBotCorpusTrainer',
trainer="chatterbot.trainers.ChatterBotCorpusTrainer",
)
if train:
self.comm.train('bot/dialogs/')
self.comm.train("bot/dialogs/")
if use_watson:
try:
self.watson_analyzer = Watson(retrieve_default()['user'],
retrieve_default()['pass'])
self.watson_analyzer = Watson(
retrieve_default("WATSON")["user"],
retrieve_default("WATSON")["pass"],
)
self.watson_usage = True
except KeyError:
# If config.ini doesn't have the user and password:
# Alert user and end execution
print('Watson\'s user and password '
'need to be in configuration file.')
print("Watson's user and password"
"need to be in configuration file.")
exit()
else:
self.watson_usage = False
self.all_texts = ''
self.all_texts = ""

def respond(self, message):
"""
Receive message from user and returns corresponding answer.
"""
# if string isnt empty concatenate with space
if(self.all_texts):
self.all_texts += ' ' + message
if self.all_texts:
self.all_texts += " " + message
else:
self.all_texts = message

if(len(message) > 50 and self.watson_usage):
if len(message) > 50 and self.watson_usage:
analysis = self.watson_analyzer.get_analysis(message)

# Get top 1 categorie
top_score = (analysis['categories'][0]['score'])
top_label = (analysis['categories'][0]['label'])
top_score = analysis["categories"][0]["score"]
top_label = analysis["categories"][0]["label"]

# Print the leaf from category tree
leaf_category = top_label[top_label.rindex('/') + 1:]
return (f'Hmm, você está falando sobre {leaf_category}')
toplabel_index = top_label.rindex("/") + 1
leaf_category = top_label[toplabel_index:]
return f"Hmm, você está falando sobre {leaf_category}"
else:
return self.comm.get_response(self.clean(message))

Expand All @@ -94,31 +90,31 @@ def clean(self, message):
return message.lower()

def switch_abbreviations(self, message, files=["abbreviations.json"]):
message = " {} ".format(message)
message = f" {message} "
try:
for file in files:
FILE_PATH = str(os.getcwd()) + '/bot/dialogs/switches/' + file
with open(FILE_PATH, 'r') as file:
FILE_PATH = f"{str(os.getcwd())}/bot/dialogs/switches/{file}"
with open(FILE_PATH, "r") as file:
common_abbr = json.load(file)
for word in common_abbr:
message = message.replace(
(' ' + word + ' '), (' ' + common_abbr[word] + ' ')
(f" {word} "), (f" {common_abbr[word]} ")
)
message = message[1:-1]
return message
except FileNotFoundError:
raise FileNotFoundError

def remove_words(self, message, files=["articles.json", "pronouns.json"]):
message = " {} ".format(message)
message = f" {message} "
try:
for file in files:
FILE_PATH = str(os.getcwd()) + '/bot/dialogs/removals/' + file
with open(FILE_PATH, 'r') as file:
FILE_PATH = f"{str(os.getcwd())}/bot/dialogs/removals/{file}"
with open(FILE_PATH, "r") as file:
removals = json.load(file)

for word in removals:
message = message.replace((' ' + word + ' '), (' '))
message = message.replace((f" {word} "), (" "))
message = message[1:-1]
return message
except FileNotFoundError:
Expand Down
10 changes: 4 additions & 6 deletions bot/config_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@
from configparser import ConfigParser


def retrieve_default(filename='config.ini'):
def retrieve_default(section="MAIN", filename="config.ini"):
"""
Function to retrieve all informations from token file.
Usually retrieves from config.ini
"""
try:
FILE_PATH = str(os.getcwd()) + '/bot/' + filename
FILE_PATH = f"{str(os.getcwd())}/bot/{filename}"
config = ConfigParser()
with open(FILE_PATH) as config_file:
config.read_file(config_file)
return(config['DEFAULT'])
return config[section]
except FileNotFoundError:
config_information = '[DEFAULT]\ntoken=\nuser=\npass='
with open('config.ini', mode='w') as config_file:
config_file.write(config_information)
print("Não há arquivo de configuração, verificar 'config_sample.ini'")
raise FileNotFoundError
19 changes: 19 additions & 0 deletions bot/config_sample.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[MAIN]
# Set up which platforms to use.
# IBM Watson won't be used by default, only on dev for now.
# Facebook doesn't have implementation yet.
Telegram = True
IBM Watson = False
Facebook = False

[TELEGRAM]
token = SOME_RANDOM_TOKEN_PROVIDED_BY_BOTFATHER

[WATSON]
# Fill with your user and password. Soon there will be some sort of encryption
user=
password=

[FACEBOOK]
# Here just for show
token=

0 comments on commit 486866e

Please sign in to comment.