Reworked message handler

This commit is contained in:
REDNBLACK 2016-11-10 17:21:08 +03:00
parent ec183ea421
commit 9c30ae0789
5 changed files with 194 additions and 144 deletions

8
run.py
View File

@ -2,12 +2,20 @@ import logging.config
import configparser
from src.bot import Bot
from orator.orm import Model
from orator import DatabaseManager
def main():
config = configparser.ConfigParser()
config.read('./main.cfg', encoding='utf-8')
logging.basicConfig(level=config['logging']['level'])
logging.getLogger("telegram.bot").setLevel(logging.ERROR)
logging.getLogger("telegram.ext").setLevel(logging.ERROR)
Model.set_connection_resolver(DatabaseManager({'db': config['db']}))
Bot(config).run()
if __name__ == '__main__':

View File

@ -1,11 +1,8 @@
import logging
from telegram.ext import Updater
from telegram.ext import MessageHandler, Filters
from orator.orm import Model
from orator import DatabaseManager
from src.message import Message
from src.command_handler import CommandHandler
from src.message_handler import MessageHandler
class Bot:
@ -14,14 +11,9 @@ class Bot:
self.updater = Updater(token=config['bot']['token'])
self.dispatcher = self.updater.dispatcher
Model.set_connection_resolver(DatabaseManager({'db': config['db']}))
def message_handler(self, bot, update):
Message(bot=bot, message=update.message, config=self.config).process()
def run(self):
logging.info("Bot started")
message_handler = MessageHandler(Filters.text | Filters.sticker, self.message_handler)
message_handler = MessageHandler(self.config)
command_handler = CommandHandler()
self.dispatcher.add_handler(message_handler)

86
src/domain/message.py Normal file
View File

@ -0,0 +1,86 @@
import random
import src.domain.chat as chat
from src.utils import deep_get_attr
class Message:
def __init__(self, message, config):
self.message = message
self.config = config
self.chat = chat.Chat.get_chat(message)
if self.has_text():
self.text = message.text
self.words = self.__get_words()
else:
self.text = ''
def has_text(self):
"""Returns True if the message has text.
"""
return self.message.text != ''
def is_sticker(self):
"""Returns True if the message is a sticker.
"""
return self.message.sticker is not None
def is_editing(self):
"""Returns True if the message was edited.
"""
return self.message.edit_date is not None
def has_entities(self):
"""Returns True if the message has entities (attachments).
"""
return self.message.entities is not None
def has_anchors(self):
"""Returns True if the message contains at least one anchor from anchors config.
"""
anchors = self.config['bot']['anchors'].split(',')
return self.has_text() and \
(any(x in self.message.text.split(' ') for x in anchors))
def is_private(self):
"""Returns True if the message is private.
"""
return self.message.chat.type == 'private'
def is_bot_kicked(self):
"""Returns True if the bot was kicked from group.
"""
user_name = deep_get_attr(self.message, 'left_chat_member.username')
return user_name == self.config['bot']['name']
def is_bot_added(self):
"""Returns True if the bot was added to group.
"""
return False
def is_reply_to_bot(self):
"""Returns True if the message is a reply to bot.
"""
user_name = deep_get_attr(self.message, 'reply_to_message.from_user.username')
return user_name == self.config['bot']['name']
def is_random_answer(self):
"""Returns True if reply chance for this chat is high enough
"""
return random.randint(0, 100) < getattr(self.chat, 'random_chance', 5)
def is_command(self):
"""Returns True if the message is a command (`/start`, `/do_stuff`).
"""
return self.has_text() and self.text[0] == '/'
def __get_words(self):
text = list(self.text)
for entity in self.message.entities:
text[entity.offset:entity.length] = ' ' * entity.length
return list(filter(None, map(lambda x: x.lower(), ''.join(text).split(' '))))

View File

@ -1,134 +0,0 @@
import logging
import random
import src.domain.chat as chat
import src.domain.pair as pair
from src.utils import deep_get_attr
class Message:
def __init__(self, bot, message, config):
self.bot = bot
self.message = message
self.config = config
self.chat = chat.Chat.get_chat(message)
if self.has_text():
logging.debug("[Chat %s %s bare_text] %s" %
(self.chat.chat_type,
self.chat.telegram_id,
self.message.text))
self.text = message.text
self.words = self.__get_words()
def process(self):
if self.has_text() and not (self.is_editing() or self.is_command()):
return self.__process_message()
elif self.is_sticker():
return self.__process_sticker()
def has_text(self):
"""Returns True if the message has text.
"""
return self.message.text != ''
def is_sticker(self):
"""Returns True if the message is a sticker.
"""
return self.message.sticker is not None
def is_editing(self):
"""Returns True if the message was edited.
"""
return self.message.edit_date is not None
def has_entities(self):
"""Returns True if the message has entities (attachments).
"""
return self.message.entities is not None
def has_anchors(self):
"""Returns True if the message contains at least one anchor from anchors config.
"""
anchors = self.config['bot']['anchors'].split(',')
return self.has_text() and \
(any(x in self.message.text.split(' ') for x in anchors))
def is_private(self):
"""Returns True if the message is private.
"""
return self.message.chat.type == 'private'
def is_reply_to_bot(self):
"""Returns True if the message is a reply to bot.
"""
user_name = deep_get_attr(self.message, 'reply_to_message.from_user.username', None)
return user_name == self.config['bot']['name']
def is_random_answer(self):
"""Returns True if reply chance for this chat is high enough
"""
return random.randint(0, 100) < getattr(self.chat, 'random_chance', 5)
def is_command(self):
"""Returns True if the message is a command (`/start`, `/do_stuff`).
"""
return self.has_text() and self.text[0] == '/'
def __answer(self, message):
logging.debug("[Chat %s %s answer] %s" %
(self.chat.chat_type,
self.chat.telegram_id,
message))
self.bot.sendMessage(chat_id=self.chat.telegram_id, text=message)
def __reply(self, message):
logging.debug("[Chat %s %s reply] %s" %
(self.chat.chat_type,
self.chat.telegram_id,
message))
self.bot.sendMessage(chat_id=self.chat.telegram_id,
reply_to_message_id=self.message.message_id,
text=message)
def __process_sticker(self):
if self.has_anchors() \
or self.is_private() \
or self.is_reply_to_bot() \
or self.is_random_answer():
logging.debug("[Chat %s %s send_sticker]" %
(self.chat.chat_type, self.chat.telegram_id))
self.bot.sendSticker(chat_id=self.chat.telegram_id,
reply_to_message_id=self.message.message_id,
sticker="BQADAgADSAIAAkcGQwU-G-9SZUDTWAI")
def __process_message(self):
pair.Pair.learn(self)
if self.has_anchors() \
or self.is_private() \
or self.is_reply_to_bot() \
or self.is_random_answer():
reply = pair.Pair.generate(self)
if reply != '':
self.__answer(reply)
def __get_words(self):
text = list(self.text)
for entity in self.message.entities:
text[entity.offset:entity.length] = ' ' * entity.length
result = list(filter(None, map(lambda x: x.lower(), ''.join(text).split(' '))))
logging.debug("[Chat %s %s get_words] %s" %
(self.chat.chat_type,
self.chat.telegram_id,
' '.join(result)))
return result

98
src/message_handler.py Normal file
View File

@ -0,0 +1,98 @@
import logging
from telegram.ext import MessageHandler as ParentHandler, Filters
from src.domain.message import Message
from src.domain.pair import Pair
class MessageHandler(ParentHandler):
def __init__(self,
config,
allow_edited=False,
pass_update_queue=False,
pass_user_data=False,
pass_chat_data=False):
super(MessageHandler, self).__init__(
Filters.text | Filters.sticker | Filters.status_update,
self.handle,
pass_update_queue=pass_update_queue,
pass_job_queue=True,
pass_user_data=pass_user_data,
pass_chat_data=pass_chat_data,
allow_edited=allow_edited)
self.config = config
def handle(self, bot, update, job_queue):
print(job_queue)
message = Message(message=update.message, config=self.config)
if message.has_text():
logging.debug("[Chat %s %s bare_text] %s" %
(message.chat.chat_type,
message.chat.telegram_id,
message.text))
if message.has_text() and not (message.is_editing() or message.is_command()):
return self.__process_message(bot, message)
elif message.is_sticker():
return self.__process_sticker(bot, message)
elif message.is_bot_added():
return self.__process_bot_add(bot, message)
elif message.is_bot_kicked():
return self.__process_bot_kick(bot, message)
def __process_message(self, bot, message):
Pair.learn(message)
if message.has_anchors() \
or message.is_private() \
or message.is_reply_to_bot() \
or message.is_random_answer():
reply = Pair.generate(message)
if reply != '':
self.__answer(bot, message, reply)
def __process_sticker(self, bot, message):
if message.has_anchors() \
or message.is_private() \
or message.is_reply_to_bot() \
or message.is_random_answer():
self.__send_sticker(bot, message, "BQADAgADSAIAAkcGQwU-G-9SZUDTWAI")
def __process_bot_kick(self, bot, message):
logging.debug("[Chat %s %s bot_kicked]" %
(message.chat.chat_type, message.chat.telegram_id))
def __process_bot_add(self, bot, message):
logging.debug("[Chat %s %s bot_added]" %
(message.chat.chat_type, message.chat.telegram_id))
def __answer(self, bot, message, reply):
logging.debug("[Chat %s %s answer] %s" %
(message.chat.chat_type,
message.chat.telegram_id,
reply))
bot.sendMessage(chat_id=message.chat.telegram_id, text=reply)
def __reply(self, bot, message, reply):
logging.debug("[Chat %s %s reply] %s" %
(message.chat.chat_type,
message.chat.telegram_id,
reply))
bot.sendMessage(chat_id=message.chat.telegram_id,
reply_to_message_id=message.message.message_id,
text=reply)
def __send_sticker(self, bot, message, sticker_id):
logging.debug("[Chat %s %s send_sticker]" %
(message.chat.chat_type, message.chat.telegram_id))
bot.sendSticker(chat_id=message.chat.telegram_id,
reply_to_message_id=message.message.message_id,
sticker=sticker_id)