From 1f7e7a7e8b6030c280c4bf904146cb26a2c12bfd Mon Sep 17 00:00:00 2001 From: REDNBLACK Date: Wed, 2 Nov 2016 20:53:19 +0300 Subject: [PATCH] Working reply to chat --- src/domain/pair.py | 81 +++++++++++++++++++++++++++++++++++++--------- src/message.py | 34 +++++++++++++------ 2 files changed, 89 insertions(+), 26 deletions(-) diff --git a/src/domain/pair.py b/src/domain/pair.py index 6c4b410..c2a3950 100644 --- a/src/domain/pair.py +++ b/src/domain/pair.py @@ -1,9 +1,12 @@ +import random +from datetime import datetime, timedelta + from orator.orm import Model from orator.orm import belongs_to from orator.orm import has_many -import src.domain.reply import src.domain.chat +import src.domain.reply import src.domain.word @@ -22,17 +25,32 @@ class Pair(Model): def chat(self): return src.domain.chat.Chat + @belongs_to + def first(self): + return src.domain.word.Word + + @belongs_to + def second(self): + return src.domain.word.Word + @staticmethod def generate(message): - return '' - # generate_story(message, message.words, rand(2) + 1) + return Pair.generate_story(message, message.words, random.randint(0, 2) + 1) + + @staticmethod + def generate_story(message, words, sentences): + words_ids = src.domain.word.Word.where_in('word', words).get().pluck('id').all() + + result = [] + for _ in range(0, sentences): + result.append(Pair.__generate_sentence(message, words_ids)) + + return ' '.join(result) @staticmethod def learn(message): src.domain.word.Word.learn(message.words) - print("Msg words: " + str(message.words)) - words = [None] for word in message.words: words.append(word) @@ -41,14 +59,10 @@ class Pair(Model): if words[-1:] is not None: words.append(None) - print("Words: "+str(words)) - while any(word for word in words): trigram = words[:3] words.pop(0) - print("Trigram: " + str(trigram)) trigram_word_ids = list(map(lambda x: None if x is None else src.domain.word.Word.where('word', word).first().id, trigram)) - print("TrigramId: " + str(trigram_word_ids)) pair = Pair.first_or_create(chat_id=message.chat.id, first_id=trigram_word_ids[0], second_id=trigram_word_ids[1]) @@ -61,11 +75,46 @@ class Pair(Model): else: src.domain.reply.Reply.create(pair_id=pair.id, word_id=last_trigram_id) + @staticmethod + def __generate_sentence(message, word_ids): + sentence = '' + safety_counter = 50 + first_word = None + second_words = list(word_ids) + while safety_counter > 0: + pair = Pair.__get_pair(chat_id=message.chat.id, first_id=first_word, second_ids=second_words) + replies = getattr(pair, 'replies', []) + safety_counter -= 1 + if pair is None or len(replies) == 0: + continue + reply = random.choice(replies.all()) + first_word = pair.second.id + second_words = getattr(reply.word, 'id', []) + if sentence == '': + sentence = Pair.__capitalize(pair.second.word) + " " + word_ids.remove(pair.second.id) + reply_word = getattr(reply.word, 'word', '') + if reply_word not in sentence and Pair.__capitalize(reply_word) not in sentence: + sentence += reply_word + sentence = sentence.strip() + if sentence[-1:] not in Pair.end_sentence: + sentence += random.choice(list(Pair.end_sentence)) - # @staticmethod - # def get_pair(chat_id, first_id, second_id): - # Pair.includes(Pair.replies()) - # .where(chat_id: chat_id, first_id: first_id, second_id: second_id) - # .where("created_at < :latest", latest: 10.minutes.ago) - # .limit(3)\ - # .sample \ No newline at end of file + return sentence + + @staticmethod + def __capitalize(string): + return string[:1].upper() + string[1:] + + @staticmethod + def __get_pair(chat_id, first_id, second_ids): + pairs = Pair.with_('replies')\ + .where('chat_id', chat_id)\ + .where('first_id', first_id)\ + .where_in('second_id', second_ids)\ + .where('created_at', '<', (datetime.now() - timedelta(seconds=10 * 60)))\ + .limit(3)\ + .get()\ + .all() + + return random.choice(pairs) if len(pairs) != 0 else None diff --git a/src/message.py b/src/message.py index a9a0247..88cf569 100644 --- a/src/message.py +++ b/src/message.py @@ -4,6 +4,7 @@ import random import src.domain.chat as chat import src.domain.pair as pair + class Message: def __init__(self, bot, message, config): self.bot = bot @@ -13,7 +14,8 @@ class Message: self.chat.migrate_to_chat_id = message.migrate_to_chat_id if self.has_text(): - logging.debug("[chat %s %s bare_text] %s" %(self.chat.chat_type, self.chat.telegram_id, self.message.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() self.command = self.__get_command() if self.text[0] == '/' else None @@ -36,33 +38,44 @@ class Message: return self.message.entities is not None def has_anchors(self): - return self.has_text() and (any(x in self.words for x in self.config['bot']['anchors'].split(','))) + return self.has_text() and \ + (any(x in self.message.text.split(' ') for x in self.config['bot']['anchors'].split(','))) def is_private(self): return self.message.chat.type == 'private' def is_reply_to_bot(self): - return self.message.reply_to_message is not None \ - and self.message.reply_to_message.from_user.username == self.config['bot']['name'] + reply_to_message = getattr(self.message, 'reply_to_message', None) + from_user = getattr(reply_to_message, 'from_user', None) + user_name = getattr(from_user, 'username', None) + + return user_name == self.config['bot']['name'] def is_random_answer(self): - return random.randint(1, 100) < self.chat.random_chance + return random.randint(0, 100) < self.chat.random_chance def is_command(self): return self.command is not None def __answer(self, message): - logging.debug("[Chat %s %s answer] %s" % (self.chat.chat_type, self.chat.telegram_id, 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) + 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_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(): + 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) @@ -72,7 +85,8 @@ class Message: for entity in self.message.entities: text[entity.offset:entity.length] = ' ' * entity.length result = list(map(lambda x: x.lower(), ''.join(text).split(' '))) - logging.debug("[chat %s %s get_words] %s" % (self.chat.chat_type, self.chat.telegram_id, result)) + logging.debug("[chat %s %s get_words] %s" % + (self.chat.chat_type, self.chat.telegram_id, result)) return result