From ee3152fd765d103cd525b154d8fcf20c0873f956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=BF=E3=81=9E=40CrazyBeatCoder?= Date: Thu, 16 Aug 2018 14:00:40 +0900 Subject: [PATCH 1/3] style(*.py): refactoring 'main.py'. ref #419 @1.0h --- domain.py | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.py | 67 +++----------------------------------- 2 files changed, 101 insertions(+), 63 deletions(-) create mode 100644 domain.py diff --git a/domain.py b/domain.py new file mode 100644 index 0000000..5e68154 --- /dev/null +++ b/domain.py @@ -0,0 +1,97 @@ +# -*- coding: UTF-8 -*- + +# Copyright 2018 [name of copyright owner] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import logging + +import infra + +ASK_CONTINUE_EVENT = u'ASK_CONTINUE_EVENT' +ASK_WORD_EVENT = u'ASK_WORD_EVENT' +DECLARE_USER_LOSE_EVENT = u'DECLARE_USER_LOSE_EVENT' + + +def ask_continue(obj): + queryResult = obj[u'queryResult'] + return { + u'followupEventInput': { + u'name': ASK_CONTINUE_EVENT, + u'languageCode': queryResult[u'languageCode'], + } + } + + +def set_continue(obj): + queryResult = obj[u'queryResult'] + return { + u'followupEventInput': { + u'name': ASK_WORD_EVENT, + u'languageCode': queryResult[u'languageCode'], + } + } + + +def response_word(obj): + originalDetectIntentRequest = obj['originalDetectIntentRequest'] + queryResult = obj[u'queryResult'] + userId = originalDetectIntentRequest[u'payload'][u'user'][u'userId'] + queryText = queryResult[u'queryText'] + if queryText == ASK_WORD_EVENT: + return { + u'fulfillmentText': u'しりとり、の、リ', + } + else: + logging.info(queryText) + reading = infra.search_reading_from_dic(queryText) + if reading: + logging.info(reading) + reading_end = reading[-1] + if infra.check_last_word_datastore(userId, reading): + if reading_end == u'ン': + infra.reset_datastore(userId) + return { + u'followupEventInput': { + u'name': DECLARE_USER_LOSE_EVENT, + u'languageCode': queryResult[u'languageCode'], + } + } + elif infra.check_word_datastore(userId, reading): + infra.save_word_datastore(userId, reading) + word_record = infra.search_word_record_from_dic( + userId, reading_end) + logging.info(word_record) + word = word_record[u'org'][0] + infra.save_word_datastore(userId, word_record[u'key']) + fulfillmentText = word + u'、の、' + word_record[u'end'] + logging.info(fulfillmentText) + return { + u'fulfillmentText': fulfillmentText, + } + else: + return { + u'fulfillmentText': u'それは使用済みの言葉です', + } + else: + return { + u'fulfillmentText': infra.get_last_word_datastore(userId) + u'で始まる言葉を使ってください', + } + else: + return { + u'fulfillmentText': u'それは知らない言葉です', + } diff --git a/main.py b/main.py index a75b236..9474ec9 100644 --- a/main.py +++ b/main.py @@ -22,16 +22,12 @@ import logging import webapp2 -import infra +import domain GOOGLE_ASSISTANT_WELCOME_INTENT = u'Google Assistant Welcome Intent' ASK_CONTINUE_INTENT = u'Ask Continue Intent' ASK_WORD_INTENT = u'Ask Word Intent' -ASK_CONTINUE_EVENT = u'ASK_CONTINUE_EVENT' -ASK_WORD_EVENT = u'ASK_WORD_EVENT' -DECLARE_USER_LOSE_EVENT = u'DECLARE_USER_LOSE_EVENT' - class MainPage(webapp2.RequestHandler): def get(self): @@ -46,70 +42,15 @@ def post(self): # responseId = obj['responseId'] # session = obj['session'] queryResult = obj[u'queryResult'] - originalDetectIntentRequest = obj['originalDetectIntentRequest'] intentDisplayName = queryResult[u'intent'][u'displayName'] - userId = originalDetectIntentRequest[u'payload'][u'user'][u'userId'] self.response.headers['Content-Type'] = 'application/json' if intentDisplayName == GOOGLE_ASSISTANT_WELCOME_INTENT: - obj = { - u'followupEventInput': { - u'name': ASK_CONTINUE_EVENT, - u'languageCode': queryResult[u'languageCode'], - } - } + obj = domain.ask_continue(obj) elif intentDisplayName == ASK_CONTINUE_INTENT: - obj = { - u'followupEventInput': { - u'name': ASK_WORD_EVENT, - u'languageCode': queryResult[u'languageCode'], - } - } + obj = domain.set_continue(obj) elif intentDisplayName == ASK_WORD_INTENT: - queryText = queryResult[u'queryText'] - if queryText == ASK_WORD_EVENT: - obj = { - u'fulfillmentText': u'しりとり、の、リ', - } - else: - logging.info(queryText) - reading = infra.search_reading_from_dic(queryText) - if reading: - logging.info(reading) - reading_end = reading[-1] - if infra.check_last_word_datastore(userId, reading): - if reading_end == u'ン': - infra.reset_datastore(userId) - obj = { - u'followupEventInput': { - u'name': DECLARE_USER_LOSE_EVENT, - u'languageCode': queryResult[u'languageCode'], - } - } - elif infra.check_word_datastore(userId, reading): - infra.save_word_datastore(userId, reading) - word_record = infra.search_word_record_from_dic( - userId, reading_end) - logging.info(word_record) - word = word_record[u'org'][0] - infra.save_word_datastore(userId, word_record[u'key']) - fulfillmentText = word + u'、の、' + word_record[u'end'] - logging.info(fulfillmentText) - obj = { - u'fulfillmentText': fulfillmentText, - } - else: - obj = { - u'fulfillmentText': u'それは使用済みの言葉です', - } - else: - obj = { - u'fulfillmentText': infra.get_last_word_datastore(userId) + u'で始まる言葉を使ってください', - } - else: - obj = { - u'fulfillmentText': u'それは知らない言葉です', - } + obj = domain.response_word(obj) else: obj = { u'fulfillmentText': queryResult[u'queryText'], From 5c8070114d4d0b10a7710ae1f11dbda07f0356a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=BF=E3=81=9E=40CrazyBeatCoder?= Date: Thu, 16 Aug 2018 16:28:10 +0900 Subject: [PATCH 2/3] feat(*.py): add limit count of words that Google Home will response. fix #419 @2.5h --- domain.py | 70 ++++++++++++++++++++++++++++++++++---------- infra.py | 87 +++++++++++++++++++++++++++++++++++++++++++------------ main.py | 3 ++ 3 files changed, 127 insertions(+), 33 deletions(-) diff --git a/domain.py b/domain.py index 5e68154..b4c33dc 100644 --- a/domain.py +++ b/domain.py @@ -25,6 +25,7 @@ ASK_CONTINUE_EVENT = u'ASK_CONTINUE_EVENT' ASK_WORD_EVENT = u'ASK_WORD_EVENT' DECLARE_USER_LOSE_EVENT = u'DECLARE_USER_LOSE_EVENT' +DECLARE_GOOGLE_HOME_LOSE_EVENT = u'DECLARE_GOOGLE_HOME_LOSE_EVENT' def ask_continue(obj): @@ -52,7 +53,12 @@ def response_word(obj): queryResult = obj[u'queryResult'] userId = originalDetectIntentRequest[u'payload'][u'user'][u'userId'] queryText = queryResult[u'queryText'] + + user = infra.load_user(userId) + if queryText == ASK_WORD_EVENT: + infra.reset_datastore(user) + infra.save_word_datastore(user, u'シリトリ') return { u'fulfillmentText': u'しりとり、の、リ', } @@ -62,36 +68,70 @@ def response_word(obj): if reading: logging.info(reading) reading_end = reading[-1] - if infra.check_last_word_datastore(userId, reading): + if infra.check_last_word_datastore(user, reading): if reading_end == u'ン': - infra.reset_datastore(userId) + infra.reset_datastore(user) return { u'followupEventInput': { u'name': DECLARE_USER_LOSE_EVENT, u'languageCode': queryResult[u'languageCode'], } } - elif infra.check_word_datastore(userId, reading): - infra.save_word_datastore(userId, reading) - word_record = infra.search_word_record_from_dic( - userId, reading_end) - logging.info(word_record) - word = word_record[u'org'][0] - infra.save_word_datastore(userId, word_record[u'key']) - fulfillmentText = word + u'、の、' + word_record[u'end'] - logging.info(fulfillmentText) - return { - u'fulfillmentText': fulfillmentText, - } + elif infra.check_word_datastore(user, reading): + infra.save_word_datastore(user, reading) + if infra.is_need_google_home_lose(user): + return { + u'followupEventInput': { + u'name': DECLARE_GOOGLE_HOME_LOSE_EVENT, + u'languageCode': queryResult[u'languageCode'], + } + } + else: + word_record = infra.search_word_record_from_dic( + user, reading_end) + logging.info(word_record) + word = word_record[u'org'][0] + infra.save_word_datastore(user, word_record[u'key']) + fulfillmentText = word + u'、の、' + word_record[u'end'] + logging.info(fulfillmentText) + return { + u'fulfillmentText': fulfillmentText, + } else: return { u'fulfillmentText': u'それは使用済みの言葉です', } else: return { - u'fulfillmentText': infra.get_last_word_datastore(userId) + u'で始まる言葉を使ってください', + u'fulfillmentText': infra.get_last_word_datastore(user) + u'で始まる言葉を使ってください', } else: return { u'fulfillmentText': u'それは知らない言葉です', } + + +def response_lose_word(obj): + originalDetectIntentRequest = obj['originalDetectIntentRequest'] + userId = originalDetectIntentRequest[u'payload'][u'user'][u'userId'] + + user = infra.load_user(userId) + reading_end = user.last_word[-1] + + word_record = infra.search_lose_word_record_from_dic( + user, reading_end) + logging.info(word_record) + fulfillmentText = u'' + if word_record: + word = word_record[u'org'][0] + infra.save_word_datastore(user, word_record[u'key']) + fulfillmentText += word + u'。' + fulfillmentText += u'あら、「ん」で終わってしまいました。' + else: + fulfillmentText += u'うーん、「' + reading_end + u'」で始まる言葉が思いつきません。' + fulfillmentText += u'私の負けです。' + logging.info(fulfillmentText) + infra.reset_datastore(user) + return { + u'fulfillmentText': fulfillmentText, + } diff --git a/infra.py b/infra.py index 421568c..50030b1 100644 --- a/infra.py +++ b/infra.py @@ -23,6 +23,10 @@ import json import random +# しりとりが WORDS_COUNT_LIMIT 以上続いたら AI が降参する +WORDS_COUNT_LIMIT = 10 + + with open('data/dict.json') as json_file: json_dic = json.load(json_file) @@ -34,36 +38,51 @@ class User(ndb.Model): date = ndb.DateTimeProperty(auto_now_add=True) -def reset_datastore(user_id): +def load_user(user_id): try: user = User.get_by_id(user_id) + if user: + return user + except Exception: + pass + + user = User(id=user_id) + user.words = None + user.last_word = None + user.count = 0 + user.date = None + return user + + +def reset_datastore(user): + try: user.key.delete() + user.words = None + user.last_word = None + user.count = 0 + user.date = None except Exception: pass -def get_last_word_datastore(user_id): +def get_last_word_datastore(user): try: - user = User.get_by_id(user_id) - if user.last_word == u'': - return u'リ' return user.last_word[-1] except Exception: - return u'リ' + pass -def check_last_word_datastore(user_id, check_word): +def check_last_word_datastore(user, check_word): try: - if check_word[0] == get_last_word_datastore(user_id): + if check_word[0] == get_last_word_datastore(user): return True return False except Exception: return True -def check_word_datastore(user_id, check_word): +def check_word_datastore(user, check_word): try: - user = User.get_by_id(user_id) words = user.words.split(u',') if check_word in words: return False @@ -72,15 +91,15 @@ def check_word_datastore(user_id, check_word): return True -def save_word_datastore(user_id, save_word): +def save_word_datastore(user, save_word): try: - user = User.get_by_id(user_id) - user.words += u',' + save_word + if user.words: + user.words += u',' + save_word + else: + user.words = save_word user.count += 1 except Exception: - user = User(id=user_id) - user.words = save_word - user.count = 1 + pass user.last_word = save_word user.put() @@ -99,7 +118,7 @@ def search_reading_from_dic(search_word): return u'' -def search_word_record_from_dic(user_id, search_first): +def search_word_record_from_dic(user, search_first): """json形式の辞書ファイルを全探索し、読みが search_first で始まる適当な単語レコードを返す。 無効な単語(既出の単語・存在しない単語・「ん」で終わる単語)のレコードは返さない。 @@ -116,10 +135,42 @@ def search_word_record_from_dic(user_id, search_first): if dict_record[u'end'] == u'ン': continue # Google Home は既出の単語を言わない - if not check_word_datastore(user_id, dict_record[u'key']): + if not check_word_datastore(user, dict_record[u'key']): continue dict_record_list.append(dict_record) if dict_record_list: return dict_record_list[random.randint(0, len(dict_record_list) - 1)] else: return {} + + +def search_lose_word_record_from_dic(user, search_first): + """json形式の辞書ファイルを全探索し、読みが search_first で始まり + かつ、「ん」で終わる単語レコードを返す。 + + :param unicode search_first: カタカナ 1 文字 + :rtype: dict + :return: 検索した単語レコード(辞書にない場合は空の辞書) + """ + dict_record_list = [] + for dict_record in json_dic: + # search_first で始まる単語レコードを検索する + if dict_record[u'first'] != search_first: + continue + # 「ん」で終わる単語を検索する + if dict_record[u'end'] == u'ン': + dict_record_list.append(dict_record) + if dict_record_list: + return dict_record_list[random.randint(0, len(dict_record_list) - 1)] + else: + return {} + + +def is_need_google_home_lose(user): + """Google Home の負け処理が必要であるかを返す。 + + :param infra.User user: ユーザ + :rtype: bool + :return: Google Home の負け処理が必要であるか + """ + return user.count >= WORDS_COUNT_LIMIT diff --git a/main.py b/main.py index 9474ec9..100e496 100644 --- a/main.py +++ b/main.py @@ -27,6 +27,7 @@ GOOGLE_ASSISTANT_WELCOME_INTENT = u'Google Assistant Welcome Intent' ASK_CONTINUE_INTENT = u'Ask Continue Intent' ASK_WORD_INTENT = u'Ask Word Intent' +DECLARE_GOOGLE_HOME_LOSE_INTENT = u'Declare Google Home Lose Intent' class MainPage(webapp2.RequestHandler): @@ -51,6 +52,8 @@ def post(self): obj = domain.set_continue(obj) elif intentDisplayName == ASK_WORD_INTENT: obj = domain.response_word(obj) + elif intentDisplayName == DECLARE_GOOGLE_HOME_LOSE_INTENT: + obj = domain.response_lose_word(obj) else: obj = { u'fulfillmentText': queryResult[u'queryText'], From 449178e404f72258612c945b90d04b652c636be1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=BF=E3=81=9E=40CrazyBeatCoder?= Date: Sat, 15 Sep 2018 10:18:25 +0900 Subject: [PATCH 3/3] fix(*.py): Fixed test_post_ask_word_intent_2 (test_main.TestWebApp). fix #426 @1.5h --- domain.py | 8 +++++--- infra.py | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/domain.py b/domain.py index b4c33dc..dcdeebd 100644 --- a/domain.py +++ b/domain.py @@ -27,6 +27,8 @@ DECLARE_USER_LOSE_EVENT = u'DECLARE_USER_LOSE_EVENT' DECLARE_GOOGLE_HOME_LOSE_EVENT = u'DECLARE_GOOGLE_HOME_LOSE_EVENT' +DATASTORE_DEFAULT_LAST_WORD = u'シリトリ' + def ask_continue(obj): queryResult = obj[u'queryResult'] @@ -54,11 +56,11 @@ def response_word(obj): userId = originalDetectIntentRequest[u'payload'][u'user'][u'userId'] queryText = queryResult[u'queryText'] - user = infra.load_user(userId) + user = infra.load_user(userId, DATASTORE_DEFAULT_LAST_WORD) if queryText == ASK_WORD_EVENT: infra.reset_datastore(user) - infra.save_word_datastore(user, u'シリトリ') + user = infra.load_user(userId, DATASTORE_DEFAULT_LAST_WORD) return { u'fulfillmentText': u'しりとり、の、リ', } @@ -115,7 +117,7 @@ def response_lose_word(obj): originalDetectIntentRequest = obj['originalDetectIntentRequest'] userId = originalDetectIntentRequest[u'payload'][u'user'][u'userId'] - user = infra.load_user(userId) + user = infra.load_user(userId, DATASTORE_DEFAULT_LAST_WORD) reading_end = user.last_word[-1] word_record = infra.search_lose_word_record_from_dic( diff --git a/infra.py b/infra.py index 50030b1..fca4418 100644 --- a/infra.py +++ b/infra.py @@ -38,7 +38,7 @@ class User(ndb.Model): date = ndb.DateTimeProperty(auto_now_add=True) -def load_user(user_id): +def load_user(user_id, default_last_word): try: user = User.get_by_id(user_id) if user: @@ -51,6 +51,7 @@ def load_user(user_id): user.last_word = None user.count = 0 user.date = None + save_word_datastore(user, default_last_word) return user