Working reply to chat

This commit is contained in:
REDNBLACK 2016-11-02 20:53:19 +03:00
parent bff075f40a
commit 1f7e7a7e8b
2 changed files with 89 additions and 26 deletions

View File

@ -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
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

View File

@ -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