From 7b33a56c39dce32a9e029f6a53e4eef289fc8dd5 Mon Sep 17 00:00:00 2001 From: Artem Batalov Date: Sat, 5 Mar 2022 10:18:45 +0300 Subject: [PATCH 1/3] sdk_answer now returns synced random values --- core/basic_models/actions/string_actions.py | 25 +++++++++++++-------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/core/basic_models/actions/string_actions.py b/core/basic_models/actions/string_actions.py index 1918579c..201c9e32 100644 --- a/core/basic_models/actions/string_actions.py +++ b/core/basic_models/actions/string_actions.py @@ -2,6 +2,7 @@ import random from copy import copy from typing import Union, Dict, List, Any, Optional +from itertools import chain from lazy import lazy @@ -226,30 +227,36 @@ def __init__(self, items: Dict[str, Any], id: Optional[str] = None): # функция идет по RANDOM_PATH, числа в нем считает индексами массива, # INDEX_WILDCARD - произвольным индексом массива, прочее - ключами словаря - # в конце пути предполагается непустой массив, дойдя до которого из него выбирается случайный элемент - def random_by_path(self, input_dict, nested_key): + # в конце пути предполагается непустой массив + def get_by_path(self, input_dict: Union[list, dict], nested_key: list[str]) -> list[tuple[Union[list, dict], str]]: internal_dict_value = input_dict for ik, k in enumerate(nested_key): last_dict = internal_dict_value if k == self.INDEX_WILDCARD: - for wildcard_item in last_dict: - self.random_by_path(wildcard_item, nested_key[ik + 1:]) - return + return list(chain.from_iterable( + [self.get_by_path(wildcard_item, nested_key[ik + 1:]) for wildcard_item in last_dict] + )) if k.isdigit(): internal_dict_value = internal_dict_value[int(k)] else: internal_dict_value = internal_dict_value.get(k, None) if internal_dict_value is None: - return - last_dict[k] = random.choice(last_dict[k]) + return [] + return [(last_dict, k)] + + def do_random(self, input_dict: Union[list, dict]): + dicts = list(chain.from_iterable([self.get_by_path(input_dict, j) for j in self.RANDOM_PATH])) + max_length = max(map(lambda x: len(x[0][x[1]]), dicts)) + random_index = random.randrange(max_length) + for (d, k) in dicts: + d[k] = d[k][random_index % len(d[k])] def run(self, user: BaseUser, text_preprocessing_result: BaseTextPreprocessingResult, params: Optional[Dict[str, Union[str, float, int]]] = None) -> List[Command]: result = [] params = user.parametrizer.collect(text_preprocessing_result, filter_params={"command": self.command}) rendered = self._get_rendered_tree(self.nodes, params, self.no_empty_nodes) - for j in self.RANDOM_PATH: - self.random_by_path(rendered, j) + self.do_random(rendered) if rendered or not self.no_empty_nodes: result = [ Command( From a403dac5d1c3c659a3879d9a4fe5f58fe120a80d Mon Sep 17 00:00:00 2001 From: Artem Batalov Date: Sat, 5 Mar 2022 10:23:54 +0300 Subject: [PATCH 2/3] Fix typings --- core/basic_models/actions/string_actions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/basic_models/actions/string_actions.py b/core/basic_models/actions/string_actions.py index 201c9e32..c704ed62 100644 --- a/core/basic_models/actions/string_actions.py +++ b/core/basic_models/actions/string_actions.py @@ -1,7 +1,7 @@ # coding: utf-8 import random from copy import copy -from typing import Union, Dict, List, Any, Optional +from typing import Union, Dict, List, Any, Optional, Tuple from itertools import chain from lazy import lazy @@ -228,7 +228,7 @@ def __init__(self, items: Dict[str, Any], id: Optional[str] = None): # функция идет по RANDOM_PATH, числа в нем считает индексами массива, # INDEX_WILDCARD - произвольным индексом массива, прочее - ключами словаря # в конце пути предполагается непустой массив - def get_by_path(self, input_dict: Union[list, dict], nested_key: list[str]) -> list[tuple[Union[list, dict], str]]: + def get_by_path(self, input_dict: Union[list, dict], nested_key: List[str]) -> List[Tuple[Union[list, dict], str]]: internal_dict_value = input_dict for ik, k in enumerate(nested_key): last_dict = internal_dict_value From 3f258852bd3215c00b9dbc5c4ceddb06ba501fe8 Mon Sep 17 00:00:00 2001 From: Artem Batalov Date: Wed, 30 Mar 2022 06:32:33 +0300 Subject: [PATCH 3/3] Fix tests for sdk_answer --- .../action_test/test_action.py | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/tests/core_tests/basic_scenario_models_test/action_test/test_action.py b/tests/core_tests/basic_scenario_models_test/action_test/test_action.py index 31f811f7..fa8fc3e6 100644 --- a/tests/core_tests/basic_scenario_models_test/action_test/test_action.py +++ b/tests/core_tests/basic_scenario_models_test/action_test/test_action.py @@ -547,16 +547,20 @@ def test_typical_answer(self): } } } - exp1 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'Ivan Ivanov', 'items': [{'bubble': {'text': 'Text1'}}, {'card': {'type': 'simple_list', 'header': '1 доллар США ', 'items': [{'title': 'Купить', 'body': '67.73 RUR'}, {'title': 'Продать', 'body': '64.56 RUR'}], 'footer': 'Ivan Ivanov Сбербанк Онлайн на сегодня 17:53 при обмене до 1000 USD'}}], 'suggestions': {'buttons': [{'title': 'Отделения', 'action': {'text': 'Где ближайщие отделения сбера?', 'type': 'text'}}]}}}" - exp2 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'Ivan Ivanov', 'items': [{'bubble': {'text': 'Text2'}}, {'card': {'type': 'simple_list', 'header': '1 доллар США ', 'items': [{'title': 'Купить', 'body': '67.73 RUR'}, {'title': 'Продать', 'body': '64.56 RUR'}], 'footer': 'Ivan Ivanov Сбербанк Онлайн на сегодня 17:53 при обмене до 1000 USD'}}], 'suggestions': {'buttons': [{'title': 'Отделения', 'action': {'text': 'Где ближайщие отделения сбера?', 'type': 'text'}}]}}}" - exp3 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'pronounceText1', 'items': [{'bubble': {'text': 'Text1'}}, {'card': {'type': 'simple_list', 'header': '1 доллар США ', 'items': [{'title': 'Купить', 'body': '67.73 RUR'}, {'title': 'Продать', 'body': '64.56 RUR'}], 'footer': 'Ivan Ivanov Сбербанк Онлайн на сегодня 17:53 при обмене до 1000 USD'}}], 'suggestions': {'buttons': [{'title': 'Отделения', 'action': {'text': 'Где ближайщие отделения сбера?', 'type': 'text'}}]}}}" - exp4 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'pronounceText1', 'items': [{'bubble': {'text': 'Text2'}}, {'card': {'type': 'simple_list', 'header': '1 доллар США ', 'items': [{'title': 'Купить', 'body': '67.73 RUR'}, {'title': 'Продать', 'body': '64.56 RUR'}], 'footer': 'Ivan Ivanov Сбербанк Онлайн на сегодня 17:53 при обмене до 1000 USD'}}], 'suggestions': {'buttons': [{'title': 'Отделения', 'action': {'text': 'Где ближайщие отделения сбера?', 'type': 'text'}}]}}}" - expect_arr = [exp1, exp2, exp3, exp4] + exp1 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'Ivan Ivanov', 'items': [{'bubble': {'text': 'Text2'}}, {'card': {'type': 'simple_list', 'header': '1 доллар США ', 'items': [{'title': 'Купить', 'body': '67.73 RUR'}, {'title': 'Продать', 'body': '64.56 RUR'}], 'footer': 'Ivan Ivanov Сбербанк Онлайн на сегодня 17:53 при обмене до 1000 USD'}}], 'suggestions': {'buttons': [{'title': 'Отделения', 'action': {'text': 'Где ближайщие отделения сбера?', 'type': 'text'}}]}}}" + exp2 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'pronounceText1', 'items': [{'bubble': {'text': 'Text1'}}, {'card': {'type': 'simple_list', 'header': '1 доллар США ', 'items': [{'title': 'Купить', 'body': '67.73 RUR'}, {'title': 'Продать', 'body': '64.56 RUR'}], 'footer': 'Ivan Ivanov Сбербанк Онлайн на сегодня 17:53 при обмене до 1000 USD'}}], 'suggestions': {'buttons': [{'title': 'Отделения', 'action': {'text': 'Где ближайщие отделения сбера?', 'type': 'text'}}]}}}" + expect_arr = [exp1, exp2] + + nexp1 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'Ivan Ivanov', 'items': [{'bubble': {'text': 'Text1'}}, {'card': {'type': 'simple_list', 'header': '1 доллар США ', 'items': [{'title': 'Купить', 'body': '67.73 RUR'}, {'title': 'Продать', 'body': '64.56 RUR'}], 'footer': 'Ivan Ivanov Сбербанк Онлайн на сегодня 17:53 при обмене до 1000 USD'}}], 'suggestions': {'buttons': [{'title': 'Отделения', 'action': {'text': 'Где ближайщие отделения сбера?', 'type': 'text'}}]}}}" + nexp2 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'pronounceText1', 'items': [{'bubble': {'text': 'Text2'}}, {'card': {'type': 'simple_list', 'header': '1 доллар США ', 'items': [{'title': 'Купить', 'body': '67.73 RUR'}, {'title': 'Продать', 'body': '64.56 RUR'}], 'footer': 'Ivan Ivanov Сбербанк Онлайн на сегодня 17:53 при обмене до 1000 USD'}}], 'suggestions': {'buttons': [{'title': 'Отделения', 'action': {'text': 'Где ближайщие отделения сбера?', 'type': 'text'}}]}}}" + not_expect_arr = [nexp1, nexp2] + for i in range(10): action = SDKAnswer(items) result = action.run(user, None) self.assertEqual("ANSWER_TO_USER", result[0].name) self.assertTrue(str(result[0].raw) in expect_arr) + self.assertFalse(str(result[0].raw) in not_expect_arr) def test_typical_answer_without_items(self): @@ -571,10 +575,8 @@ def test_typical_answer_without_items(self): } } exp1 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'pronounceText1'}}" - exp2 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'pronounceText1'}}" - exp3 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'pronounceText2'}}" - exp4 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'pronounceText2'}}" - exp_list = [exp1, exp2, exp3, exp4] + exp2 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'pronounceText2'}}" + exp_list = [exp1, exp2] for i in range(10): action = SDKAnswer(items) result = action.run(user, None) @@ -609,15 +611,18 @@ def test_typical_answer_without_nodes(self): } } exp1 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'pronounceText1', 'suggestions': {'buttons': [{'title': 'Ivan Ivanov', 'action': {'text': 'отделения', 'type': 'text'}}, {'title': 'кредит1', 'action': {'text': 'кредит', 'type': 'text'}}]}}}" - exp2 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'pronounceText1', 'suggestions': {'buttons': [{'title': 'Ivan Ivanov', 'action': {'text': 'отделения', 'type': 'text'}}, {'title': 'кредит2', 'action': {'text': 'кредит', 'type': 'text'}}]}}}" - exp3 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'pronounceText1', 'suggestions': {'buttons': [{'title': 'отделения2', 'action': {'text': 'отделения', 'type': 'text'}}, {'title': 'кредит1', 'action': {'text': 'кредит', 'type': 'text'}}]}}}" - exp4 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'pronounceText1', 'suggestions': {'buttons': [{'title': 'отделения2', 'action': {'text': 'отделения', 'type': 'text'}}, {'title': 'кредит2', 'action': {'text': 'кредит', 'type': 'text'}}]}}}" - expect_arr = [exp1, exp2, exp3, exp4] + exp2 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'pronounceText1', 'suggestions': {'buttons': [{'title': 'отделения2', 'action': {'text': 'отделения', 'type': 'text'}}, {'title': 'кредит2', 'action': {'text': 'кредит', 'type': 'text'}}]}}}" + expect_arr = [exp1, exp2] + + nexp1 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'pronounceText1', 'suggestions': {'buttons': [{'title': 'Ivan Ivanov', 'action': {'text': 'отделения', 'type': 'text'}}, {'title': 'кредит2', 'action': {'text': 'кредит', 'type': 'text'}}]}}}" + nexp2 = "{'messageName': 'ANSWER_TO_USER', 'payload': {'pronounceText': 'pronounceText1', 'suggestions': {'buttons': [{'title': 'отделения2', 'action': {'text': 'отделения', 'type': 'text'}}, {'title': 'кредит1', 'action': {'text': 'кредит', 'type': 'text'}}]}}}" + not_expect_arr = [nexp1, nexp2] for i in range(10): action = SDKAnswer(items) result = action.run(user, None) self.assertEqual("ANSWER_TO_USER", result[0].name) self.assertTrue(str(result[0].raw) in expect_arr) + self.assertFalse(str(result[0].raw) in not_expect_arr) class SDKRandomAnswer(unittest.TestCase):