imaginaryfriend/src/domain/pair.py

148 lines
4.3 KiB
Python
Raw Normal View History

2016-11-02 18:53:19 +01:00
from datetime import datetime, timedelta
2016-10-31 22:11:25 +01:00
from orator.orm import Model
from orator.orm import belongs_to
2016-11-01 22:01:40 +01:00
from orator.orm import has_many
2016-11-07 21:06:30 +01:00
from src.utils import *
2016-11-01 23:22:26 +01:00
import src.domain.chat
2016-11-02 18:53:19 +01:00
import src.domain.reply
2016-11-01 23:22:26 +01:00
import src.domain.word
2016-10-31 22:11:25 +01:00
class Pair(Model):
2016-11-01 22:01:40 +01:00
__guarded__ = ['id']
# TODO Move to config
2016-11-11 13:10:04 +01:00
end_sentence = '.....!!?'
all = '.!?,;:()"\'
2016-11-01 22:01:40 +01:00
2016-10-31 22:11:25 +01:00
@has_many
def replies(self):
2016-11-01 23:22:26 +01:00
return src.domain.reply.Reply
2016-10-31 22:11:25 +01:00
@belongs_to
def chat(self):
2016-11-01 23:22:26 +01:00
return src.domain.chat.Chat
2016-11-01 22:01:40 +01:00
2016-11-02 18:53:19 +01:00
@belongs_to
def first(self):
return src.domain.word.Word
@belongs_to
def second(self):
return src.domain.word.Word
2016-11-01 22:01:40 +01:00
@staticmethod
def generate(message):
2016-11-02 18:53:19 +01:00
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)
2016-11-01 22:01:40 +01:00
@staticmethod
def learn(message):
2016-11-01 23:22:26 +01:00
src.domain.word.Word.learn(message.words)
2016-11-01 22:01:40 +01:00
words = [None]
for word in message.words:
words.append(word)
2016-11-07 21:06:30 +01:00
if word[-1] in Pair.end_sentence:
2016-11-01 22:01:40 +01:00
words.append(None)
2016-11-07 21:06:30 +01:00
if words[-1] is not None:
2016-11-01 22:01:40 +01:00
words.append(None)
while any(word for word in words):
trigram = words[:3]
first_word_id, second_word_id, *third_word_id = list(map(
2016-11-07 21:06:30 +01:00
lambda x: None if x is None else src.domain.word.Word.where('word', x).first().id,
trigram
))
third_word_id = None if len(third_word_id) == 0 else third_word_id[0]
words.pop(0)
2016-11-07 21:06:30 +01:00
pair = Pair.where('chat_id', message.chat.id)\
.where('first_id', first_word_id)\
.where('second_id', second_word_id)\
2016-11-07 21:06:30 +01:00
.first()
if pair is None:
pair = Pair.create(chat_id=message.chat.id,
first_id=first_word_id,
second_id=second_word_id)
2016-11-07 21:06:30 +01:00
reply = pair.replies().where('word_id', third_word_id).first()
2016-11-01 22:01:40 +01:00
if reply is not None:
2016-11-01 23:22:26 +01:00
reply.count += 1
reply.save()
2016-11-01 22:01:40 +01:00
else:
pair.replies().create(pair_id=pair.id, word_id=third_word_id)
2016-11-01 22:01:40 +01:00
2016-11-02 18:53:19 +01:00
@staticmethod
def __generate_sentence(message, word_ids):
2016-11-05 17:07:02 +01:00
sentences = []
2016-11-02 18:53:19 +01:00
safety_counter = 50
first_word = None
second_words = list(word_ids)
2016-11-05 17:07:02 +01:00
2016-11-02 18:53:19 +01:00
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
2016-11-05 17:07:02 +01:00
2016-11-02 18:53:19 +01:00
if pair is None or len(replies) == 0:
continue
2016-11-05 17:07:02 +01:00
2016-11-02 18:53:19 +01:00
reply = random.choice(replies.all())
first_word = pair.second.id
2016-11-07 21:06:30 +01:00
# TODO. WARNING! Do not try to fix, it's magic, i have no clue why
try:
second_words = [reply.word.id]
except AttributeError:
second_words = None
2016-11-05 17:07:02 +01:00
if len(sentences) == 0:
2016-11-09 19:50:39 +01:00
sentences.append(capitalize(pair.second.word))
2016-11-02 18:53:19 +01:00
word_ids.remove(pair.second.id)
2016-11-05 17:07:02 +01:00
2016-11-07 21:06:30 +01:00
# TODO. WARNING! Do not try to fix, it's magic, i have no clue why
try:
reply_word = reply.word.word
except AttributeError:
reply_word = None
if reply_word is not None:
2016-11-05 17:07:02 +01:00
sentences.append(reply_word)
2016-11-07 21:06:30 +01:00
else:
break
2016-11-05 17:07:02 +01:00
sentence = ' '.join(sentences).strip()
2016-11-02 18:53:19 +01:00
if sentence[-1:] not in Pair.end_sentence:
sentence += random.choice(list(Pair.end_sentence))
return sentence
@staticmethod
def __get_pair(chat_id, first_id, second_ids):
2016-11-08 19:40:20 +01:00
ten_minutes_ago = datetime.now() - timedelta(seconds=10 * 60)
2016-11-02 18:53:19 +01:00
pairs = Pair.with_('replies')\
.where('chat_id', chat_id)\
.where('first_id', first_id)\
.where_in('second_id', second_ids)\
2016-11-08 19:40:20 +01:00
.where('created_at', '<', ten_minutes_ago)\
2016-11-02 18:53:19 +01:00
.limit(3)\
.get()\
.all()
2016-11-01 22:01:40 +01:00
2016-11-07 21:06:30 +01:00
return random_element(pairs)