From 9e718b53ba5f4f89d95da0fe3b9f24d96b3b0e84 Mon Sep 17 00:00:00 2001 From: Fedor Ignatov Date: Wed, 20 Oct 2021 16:34:00 +0300 Subject: [PATCH] refactor: remove deeppavlov.configs.skills (#1499) * remove: deeppavlov.configs.skills * delete: aiml_skill component * remove: rasa_skill component * remove: DSLSkill component * docs: removed skills from docs apiref --- deeppavlov/configs/skills/aiml_skill.json | 44 --- deeppavlov/configs/skills/dsl_skill.json | 40 --- deeppavlov/configs/skills/rasa_skill.json | 39 --- deeppavlov/core/common/registry.json | 2 - .../core/common/requirements_registry.json | 7 - deeppavlov/requirements/aiml_skill.txt | 1 - deeppavlov/requirements/rasa_skill.txt | 1 - deeppavlov/skills/__init__.py | 0 deeppavlov/skills/aiml_skill/README.md | 6 - deeppavlov/skills/aiml_skill/__init__.py | 1 - deeppavlov/skills/aiml_skill/aiml_skill.py | 158 ---------- deeppavlov/skills/dsl_skill/__init__.py | 3 - deeppavlov/skills/dsl_skill/context.py | 53 ---- deeppavlov/skills/dsl_skill/dsl_skill.py | 225 --------------- .../skills/dsl_skill/handlers/__init__.py | 0 .../skills/dsl_skill/handlers/handler.py | 68 ----- .../dsl_skill/handlers/regex_handler.py | 80 ------ deeppavlov/skills/dsl_skill/utils.py | 22 -- deeppavlov/skills/rasa_skill/__init__.py | 1 - deeppavlov/skills/rasa_skill/rasa_skill.py | 269 ------------------ docs/apiref/skills.rst | 12 - docs/apiref/skills/aiml_skill.rst | 5 - docs/apiref/skills/dsl_skill.rst | 5 - docs/apiref/skills/rasa_skill.rst | 5 - docs/conf.py | 2 +- docs/features/skills/aiml_skill.rst | 44 --- docs/features/skills/dsl_skill.rst | 42 --- docs/features/skills/rasa_skill.rst | 50 ---- docs/index.rst | 3 - examples/gobot_md_yaml_configs_tutorial.ipynb | 1 - tests/test_aiml_skill.py | 37 --- tests/test_dsl_skill.py | 109 ------- tests/test_rasa_skill.py | 39 --- 33 files changed, 1 insertion(+), 1373 deletions(-) delete mode 100644 deeppavlov/configs/skills/aiml_skill.json delete mode 100644 deeppavlov/configs/skills/dsl_skill.json delete mode 100644 deeppavlov/configs/skills/rasa_skill.json delete mode 100644 deeppavlov/requirements/aiml_skill.txt delete mode 100644 deeppavlov/requirements/rasa_skill.txt delete mode 100644 deeppavlov/skills/__init__.py delete mode 100644 deeppavlov/skills/aiml_skill/README.md delete mode 100644 deeppavlov/skills/aiml_skill/__init__.py delete mode 100644 deeppavlov/skills/aiml_skill/aiml_skill.py delete mode 100644 deeppavlov/skills/dsl_skill/__init__.py delete mode 100644 deeppavlov/skills/dsl_skill/context.py delete mode 100644 deeppavlov/skills/dsl_skill/dsl_skill.py delete mode 100644 deeppavlov/skills/dsl_skill/handlers/__init__.py delete mode 100644 deeppavlov/skills/dsl_skill/handlers/handler.py delete mode 100644 deeppavlov/skills/dsl_skill/handlers/regex_handler.py delete mode 100644 deeppavlov/skills/dsl_skill/utils.py delete mode 100644 deeppavlov/skills/rasa_skill/__init__.py delete mode 100644 deeppavlov/skills/rasa_skill/rasa_skill.py delete mode 100644 docs/apiref/skills.rst delete mode 100644 docs/apiref/skills/aiml_skill.rst delete mode 100644 docs/apiref/skills/dsl_skill.rst delete mode 100644 docs/apiref/skills/rasa_skill.rst delete mode 100644 docs/features/skills/aiml_skill.rst delete mode 100644 docs/features/skills/dsl_skill.rst delete mode 100644 docs/features/skills/rasa_skill.rst delete mode 100644 tests/test_aiml_skill.py delete mode 100644 tests/test_dsl_skill.py delete mode 100644 tests/test_rasa_skill.py diff --git a/deeppavlov/configs/skills/aiml_skill.json b/deeppavlov/configs/skills/aiml_skill.json deleted file mode 100644 index 5a454fa4da..0000000000 --- a/deeppavlov/configs/skills/aiml_skill.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "chainer": { - "in": [ - "utterances_batch", - "states_batch" - ], - "out": [ - "responses_batch", - "confidences_batch", - "output_states_batch" - ], - "pipe": [ - { - "class_name": "aiml_skill", - "path_to_aiml_scripts": "{DOWNLOADS_PATH}/aiml_scripts", - "positive_confidence": 0.66, - "null_response": "I don't know", - "null_confidence": 0.33, - "in": [ - "utterances_batch", - "states_batch" - ], - "out": [ - "responses_batch", - "confidences_batch", - "output_states_batch" - ] - } - ] - }, - "metadata": { - "variables": { - "ROOT_PATH": "~/.deeppavlov", - "DOWNLOADS_PATH": "{ROOT_PATH}/downloads", - "MODELS_PATH": "{ROOT_PATH}/models" - }, - "download": [ - { - "url": "http://files.deeppavlov.ai/aiml_skill/aiml_scripts.tar.gz", - "subdir": "{DOWNLOADS_PATH}" - } - ] - } -} \ No newline at end of file diff --git a/deeppavlov/configs/skills/dsl_skill.json b/deeppavlov/configs/skills/dsl_skill.json deleted file mode 100644 index 296c0708ee..0000000000 --- a/deeppavlov/configs/skills/dsl_skill.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "chainer": { - "in": [ - "utterances_batch", - "user_ids_batch" - ], - "out": [ - "responses_batch", - "confidences_batch" - ], - "pipe": [ - { - "class_name": "ru_tokenizer", - "in": "utterances_batch", - "lowercase": true, - "out": "utterance_tokens_batch" - }, - { - "class_name": "DSLSkill", - "on_invalid_command": "Sorry, I do not understand you", - "null_confidence": 0.0, - "in": [ - "utterance_tokens_batch", - "user_ids_batch" - ], - "out": [ - "responses_batch", - "confidences_batch" - ] - } - ] - }, - "metadata": { - "variables": { - "ROOT_PATH": "~/.deeppavlov", - "DOWNLOADS_PATH": "{ROOT_PATH}/downloads", - "MODELS_PATH": "{ROOT_PATH}/models" - } - } -} \ No newline at end of file diff --git a/deeppavlov/configs/skills/rasa_skill.json b/deeppavlov/configs/skills/rasa_skill.json deleted file mode 100644 index 22936c660d..0000000000 --- a/deeppavlov/configs/skills/rasa_skill.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "chainer": { - "in": [ - "utterances" - ], - "out": [ - "responses_batch", - "confidences_batch" - ], - "pipe": [ - { - "class_name": "rasa_skill", - "path_to_models": "{PROJECT_ROOT}/models", - "in": [ - "utterances" - ], - "out": [ - "responses_batch", - "confidences_batch", - "output_states_batch" - ] - } - ] - }, - "metadata": { - "variables": { - "ROOT_PATH": "~/.deeppavlov", - "DOWNLOADS_PATH": "{ROOT_PATH}/downloads", - "MODELS_PATH": "{ROOT_PATH}/models", - "PROJECT_ROOT": "{DOWNLOADS_PATH}/rasa_tutorial_project" - }, - "download": [ - { - "url": "http://files.deeppavlov.ai/rasa_skill/rasa_tutorial_project.tar.gz", - "subdir": "{DOWNLOADS_PATH}" - } - ] - } -} diff --git a/deeppavlov/core/common/registry.json b/deeppavlov/core/common/registry.json index 51157417e7..2ed9d8e217 100644 --- a/deeppavlov/core/common/registry.json +++ b/deeppavlov/core/common/registry.json @@ -1,6 +1,5 @@ { "UD_pymorphy_lemmatizer": "deeppavlov.models.morpho_tagger.lemmatizer:UDPymorphyLemmatizer", - "aiml_skill": "deeppavlov.skills.aiml_skill.aiml_skill:AIMLSkill", "api_requester": "deeppavlov.models.api_requester.api_requester:ApiRequester", "api_router": "deeppavlov.models.api_requester.api_router:ApiRouter", "base64_decode_bytesIO": "deeppavlov.models.nemo.common:ascii_to_bytes_io", @@ -117,7 +116,6 @@ "query_generator_online": "deeppavlov.models.kbqa.query_generator_online:QueryGeneratorOnline", "question_sign_checker": "deeppavlov.models.kbqa.entity_detection_parser:QuestionSignChecker", "random_emb_mat": "deeppavlov.models.preprocessors.random_embeddings_matrix:RandomEmbeddingsMatrix", - "rasa_skill": "deeppavlov.skills.rasa_skill.rasa_skill:RASASkill", "rel_ranker": "deeppavlov.models.ranking.rel_ranker:RelRanker", "rel_ranking_bert_infer": "deeppavlov.models.kbqa.rel_ranking_bert_infer:RelRankerBertInfer", "rel_ranking_infer": "deeppavlov.models.kbqa.rel_ranking_infer:RelRankerInfer", diff --git a/deeppavlov/core/common/requirements_registry.json b/deeppavlov/core/common/requirements_registry.json index 9434087155..7d4f1bc84f 100644 --- a/deeppavlov/core/common/requirements_registry.json +++ b/deeppavlov/core/common/requirements_registry.json @@ -3,9 +3,6 @@ "{DEEPPAVLOV_PATH}/requirements/morpho_tagger.txt", "{DEEPPAVLOV_PATH}/requirements/tf.txt" ], - "aiml_skill": [ - "{DEEPPAVLOV_PATH}/requirements/aiml_skill.txt" - ], "bert_classifier": [ "{DEEPPAVLOV_PATH}/requirements/tf.txt", "{DEEPPAVLOV_PATH}/requirements/bert_dp.txt" @@ -137,10 +134,6 @@ "{DEEPPAVLOV_PATH}/requirements/morpho_tagger.txt", "{DEEPPAVLOV_PATH}/requirements/tf.txt" ], - "rasa_skill": [ - "{DEEPPAVLOV_PATH}/requirements/rasa_skill.txt", - "{DEEPPAVLOV_PATH}/requirements/tf.txt" - ], "rel_ranker": [ "{DEEPPAVLOV_PATH}/requirements/tf.txt" ], diff --git a/deeppavlov/requirements/aiml_skill.txt b/deeppavlov/requirements/aiml_skill.txt deleted file mode 100644 index 6a6602091e..0000000000 --- a/deeppavlov/requirements/aiml_skill.txt +++ /dev/null @@ -1 +0,0 @@ -python-aiml==0.9.3 \ No newline at end of file diff --git a/deeppavlov/requirements/rasa_skill.txt b/deeppavlov/requirements/rasa_skill.txt deleted file mode 100644 index bfb2598b2d..0000000000 --- a/deeppavlov/requirements/rasa_skill.txt +++ /dev/null @@ -1 +0,0 @@ -git+https://github.com/deepmipt/rasa.git@b0a80916e54ed9f4496c709a28f1093f7a5f2492#egg=rasa==1.2.7 diff --git a/deeppavlov/skills/__init__.py b/deeppavlov/skills/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/deeppavlov/skills/aiml_skill/README.md b/deeppavlov/skills/aiml_skill/README.md deleted file mode 100644 index cad5e100ed..0000000000 --- a/deeppavlov/skills/aiml_skill/README.md +++ /dev/null @@ -1,6 +0,0 @@ -This skill wraps python-aiml library and allows developer to integrate AIML scripts into DeepPavlov dialog system. - -If you'd like to find more free AIML scripts here is link: -https://github.com/pandorabots/Free-AIML - -You can set path to folder with your AIML scripts as config param (see attr `path_to_aiml_scripts`). \ No newline at end of file diff --git a/deeppavlov/skills/aiml_skill/__init__.py b/deeppavlov/skills/aiml_skill/__init__.py deleted file mode 100644 index e5b4b02f6b..0000000000 --- a/deeppavlov/skills/aiml_skill/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .aiml_skill import AIMLSkill diff --git a/deeppavlov/skills/aiml_skill/aiml_skill.py b/deeppavlov/skills/aiml_skill/aiml_skill.py deleted file mode 100644 index 51bf6f2360..0000000000 --- a/deeppavlov/skills/aiml_skill/aiml_skill.py +++ /dev/null @@ -1,158 +0,0 @@ -# Copyright 2017 Neural Networks and Deep Learning lab, MIPT -# -# 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. - -import uuid -from logging import getLogger -from pathlib import Path -from typing import Tuple, Optional, List - -import aiml - -from deeppavlov.core.common.registry import register -from deeppavlov.core.models.component import Component - -log = getLogger(__name__) - - -@register("aiml_skill") -class AIMLSkill(Component): - """Skill wraps python-aiml library into DeepPavlov interfrace. - AIML uses directory with AIML scripts which are loaded at initialization and used as patterns - for answering at each step. - """ - - def __init__(self, - path_to_aiml_scripts: str, - positive_confidence: float = 0.66, - null_response: str = "I don't know what to answer you", - null_confidence: float = 0.33, - **kwargs - ) -> None: - """ - Construct skill: - read AIML scripts, - load AIML kernel - - Args: - path_to_aiml_scripts: string path to folder with AIML scripts - null_response: Response string to answer if no AIML Patterns matched - positive_confidence: The confidence of response if response was found in AIML scripts - null_confidence: The confidence when AIML scripts has no rule for responding and system returns null_response - """ - # we need absolute path (expanded for user home and resolved if it relative path): - self.path_to_aiml_scripts = Path(path_to_aiml_scripts).expanduser().resolve() - log.info(f"path_to_aiml_scripts is: `{self.path_to_aiml_scripts}`") - - self.positive_confidence = positive_confidence - self.null_confidence = null_confidence - self.null_response = null_response - self.kernel = aiml.Kernel() - # to block AIML output: - self.kernel._verboseMode = False - self._load_scripts() - - def _load_scripts(self) -> None: - """ - Scripts are loaded recursively from files with extensions .xml and .aiml - Returns: None - - """ - # learn kernel to all aimls in directory tree: - all_files = sorted(self.path_to_aiml_scripts.rglob('*.*')) - learned_files = [] - for each_file_path in all_files: - if each_file_path.suffix in ['.aiml', '.xml']: - # learn the script file - self.kernel.learn(str(each_file_path)) - learned_files.append(each_file_path) - if not learned_files: - log.warning(f"No .aiml or .xml files found for AIML Kernel in directory {self.path_to_aiml_scripts}") - - def process_step(self, utterance_str: str, user_id: any) -> Tuple[str, float]: - response = self.kernel.respond(utterance_str, sessionID=user_id) - # here put your estimation of confidence: - if response: - # print(f"AIML responds: {response}") - confidence = self.positive_confidence - else: - # print("AIML responses silently...") - response = self.null_response - confidence = self.null_confidence - return response, confidence - - def _generate_user_id(self) -> str: - """Here you put user id generative logic if you want to implement it in the skill. - - Returns: - user_id: Random generated user ID. - - """ - return uuid.uuid1().hex - - def __call__(self, - utterances_batch: List[str], - states_batch: Optional[List] = None) -> Tuple[List[str], List[float], list]: - """Returns skill inference result. - - Returns batches of skill inference results, estimated confidence - levels and up to date states corresponding to incoming utterance - batch. - - Args: - utterances_batch: A batch of utterances of str type. - states_batch: A batch of arbitrary typed states for - each utterance. - - - Returns: - response: A batch of arbitrary typed skill inference results. - confidence: A batch of float typed confidence levels for each of - skill inference result. - output_states_batch: A batch of arbitrary typed states for - each utterance. - - """ - # grasp user_ids from states batch. - # We expect that skill receives None or dict of state for each utterance. - # if state has user_id then skill uses it, otherwise it generates user_id and calls the - # user with this name in further. - - # In this implementation we use current datetime for generating uniqe ids - output_states_batch = [] - user_ids = [] - if states_batch is None: - # generate states batch matching batch of utterances: - states_batch = [None] * len(utterances_batch) - - for state in states_batch: - if not state: - user_id = self._generate_user_id() - new_state = {'user_id': user_id} - - elif 'user_id' not in state: - new_state = state - user_id = self._generate_user_id() - new_state['user_id'] = self._generate_user_id() - - else: - new_state = state - user_id = new_state['user_id'] - - user_ids.append(user_id) - output_states_batch.append(new_state) - - confident_responses = map(self.process_step, utterances_batch, user_ids) - responses_batch, confidences_batch = zip(*confident_responses) - - return responses_batch, confidences_batch, output_states_batch diff --git a/deeppavlov/skills/dsl_skill/__init__.py b/deeppavlov/skills/dsl_skill/__init__.py deleted file mode 100644 index d2b332d4b6..0000000000 --- a/deeppavlov/skills/dsl_skill/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .context import UserContext -from .dsl_skill import DSLMeta -from .utils import SkillResponse, UserId diff --git a/deeppavlov/skills/dsl_skill/context.py b/deeppavlov/skills/dsl_skill/context.py deleted file mode 100644 index acbfc6c5b9..0000000000 --- a/deeppavlov/skills/dsl_skill/context.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2019 Neural Networks and Deep Learning lab, MIPT -# -# 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. - -import json -from typing import Optional, Union, Dict - -from deeppavlov.skills.dsl_skill.utils import UserId - - -class UserContext: - """ - UserContext object stores information that the current skill currently knows about the user. - - Args: - user_id: id of user - message: current message - current_state: current user state - payload: custom payload dictionary, or a JSON-serialized string of such dictionary - - Attributes: - handler_payload: stores information generated by the selected handler - - """ - - def __init__( - self, - user_id: Optional[UserId] = None, - message: Optional[str] = None, - current_state: Optional[str] = None, - payload: Optional[Union[Dict, str]] = None, - ): - self.user_id = user_id - self.message = message - self.current_state = current_state - self.handler_payload = {} - - # some custom data added by skill creator - self.payload = payload - if payload == '' or payload is None: - self.payload = {} - elif isinstance(payload, str): - self.payload = json.loads(payload) diff --git a/deeppavlov/skills/dsl_skill/dsl_skill.py b/deeppavlov/skills/dsl_skill/dsl_skill.py deleted file mode 100644 index 93e9f8544d..0000000000 --- a/deeppavlov/skills/dsl_skill/dsl_skill.py +++ /dev/null @@ -1,225 +0,0 @@ -# Copyright 2019 Neural Networks and Deep Learning lab, MIPT -# -# 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 abc import ABCMeta -from collections import defaultdict -from functools import partial -from itertools import zip_longest, starmap -from typing import List, Optional, Dict, Callable, Tuple - -from deeppavlov.core.common.registry import register -from deeppavlov.skills.dsl_skill.context import UserContext -from deeppavlov.skills.dsl_skill.handlers.handler import Handler -from deeppavlov.skills.dsl_skill.handlers.regex_handler import RegexHandler -from deeppavlov.skills.dsl_skill.utils import SkillResponse, UserId - - -class DSLMeta(ABCMeta): - """ - This metaclass is used for creating a skill. Skill is register by its class name in registry. - - Example: - - .. code:: python - - class ExampleSkill(metaclass=DSLMeta): - @DSLMeta.handler(commands=["hello", "hey"]) - def __greeting(context: UserContext): - response = "Hello, my friend!" - confidence = 1.0 - return response, confidence - - Attributes: - name: class name - state_to_handler: dict with states as keys and lists of Handler objects as values - user_to_context: dict with user ids as keys and UserContext objects as values - universal_handlers: list of handlers that can be activated from any state - - """ - skill_collection: Dict[str, 'DSLMeta'] = {} - - def __init__(cls, name: str, - bases, - namespace, - **kwargs): - super().__init__(name, bases, namespace, **kwargs) - cls.name = name - cls.state_to_handler = defaultdict(list) - cls.user_to_context = defaultdict(UserContext) - cls.universal_handlers = [] - - handlers = [attribute for attribute in namespace.values() if isinstance(attribute, Handler)] - - for handler in handlers: - if handler.state is None: - cls.universal_handlers.append(handler) - else: - cls.state_to_handler[handler.state].append(handler) - - cls.handle = partial(DSLMeta.__handle, cls) - cls.__call__ = partial(DSLMeta.__handle_batch, cls) - cls.__init__ = partial(DSLMeta.__init__class, cls) - register()(cls) - DSLMeta.__add_to_collection(cls) - - def __init__class(cls, - on_invalid_command: str = "Простите, я вас не понял", - null_confidence: float = 0, - *args, **kwargs) -> None: - """ - Initialize Skill class - - Args: - on_invalid_command: message to be sent on message with no associated handler - null_confidence: the confidence when DSL has no handler that fits request - """ - # message to be sent on message with no associated handler - cls.on_invalid_command = on_invalid_command - cls.null_confidence = null_confidence - - def __handle_batch(cls: 'DSLMeta', - utterances_batch: List[str], - user_ids_batch: List[UserId]) -> Tuple[List, ...]: - """Returns skill inference result. - Returns batches of skill inference results, estimated confidence - levels and up to date states corresponding to incoming utterance - batch. - - Args: - utterances_batch: A batch of utterances of str type. - user_ids_batch: A batch of user ids. - - Returns: - response_batch: A batch of arbitrary typed skill inference results. - confidence_batch: A batch of float typed confidence levels for each of - skill inference result. - - """ - return (*map(list, zip(*starmap(cls.handle, zip_longest(utterances_batch, user_ids_batch)))),) - - @staticmethod - def __add_to_collection(cls: 'DSLMeta') -> None: - """ - Adds Skill class to Skill classes collection - - Args: - cls: Skill class - - """ - DSLMeta.skill_collection[cls.name] = cls - - @staticmethod - def __handle(cls: 'DSLMeta', - utterance: str, - user_id: UserId) -> SkillResponse: - """ - Handles what is going to be after a message from user arrived. - Simple usage: - skill([], []) - - Args: - cls: instance of callee's class - utterance: a message to be handled - user_id: id of a user - - Returns: - result: handler function's result if succeeded - - """ - context = cls.user_to_context[user_id] - - context.user_id = user_id - context.message = utterance - - current_handler = cls.__select_handler(context) - return cls.__run_handler(current_handler, context) - - def __select_handler(cls, - context: UserContext) -> Optional[Callable]: - """ - Selects handler with the highest priority that could be triggered from the passed context. - - Returns: - handler function that is selected and None if no handler fits request - - """ - available_handlers = cls.state_to_handler[context.current_state] - available_handlers.extend(cls.universal_handlers) - available_handlers.sort(key=lambda h: h.priority, reverse=True) - for handler in available_handlers: - if handler.check(context): - handler.expand_context(context) - return handler.func - - def __run_handler(cls, handler: Optional[Callable], - context: UserContext) -> SkillResponse: - """ - Runs specified handler for current context - - Args: - handler: handler to be run. If None, on_invalid_command is returned - context: user context - - Returns: - SkillResponse - - """ - if handler is None: - return SkillResponse(cls.on_invalid_command, cls.null_confidence) - try: - return SkillResponse(*handler(context=context)) - except Exception as exc: - return SkillResponse(str(exc), 1.0) - - @staticmethod - def handler(commands: Optional[List[str]] = None, - state: Optional[str] = None, - context_condition: Optional[Callable] = None, - priority: int = 0) -> Callable: - """ - Decorator to be used in skills' classes. - Sample usage: - - .. code:: python - - class ExampleSkill(metaclass=DSLMeta): - @DSLMeta.handler(commands=["hello", "hi", "sup", "greetings"]) - def __greeting(context: UserContext): - response = "Hello, my friend!" - confidence = 1.0 - return response, confidence - - Args: - priority: integer value to indicate priority. If multiple handlers satisfy - all the requirements, the handler with the greatest priority value will be used - context_condition: function that takes context and - returns True if this handler should be enabled - and False otherwise. If None, no condition is checked - commands: phrases/regexs on what the function wrapped - by this decorator will trigger - state: state name - - Returns: - function decorated into Handler class - - """ - if commands is None: - commands = [".*"] - - def decorator(func: Callable) -> Handler: - return RegexHandler(func, commands, - context_condition=context_condition, - priority=priority, state=state) - - return decorator diff --git a/deeppavlov/skills/dsl_skill/handlers/__init__.py b/deeppavlov/skills/dsl_skill/handlers/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/deeppavlov/skills/dsl_skill/handlers/handler.py b/deeppavlov/skills/dsl_skill/handlers/handler.py deleted file mode 100644 index c041404e82..0000000000 --- a/deeppavlov/skills/dsl_skill/handlers/handler.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2019 Neural Networks and Deep Learning lab, MIPT -# -# 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 typing import Callable, Optional - -from deeppavlov.skills.dsl_skill.context import UserContext -from deeppavlov.skills.dsl_skill.utils import SkillResponse - - -class Handler: - """ - Handler instance helps DSLMeta class distinguish functions wrapped - by @DSLMeta.handler to add them to handlers storage. - It also checks if the handler function should be triggered based on the given context. - - Attributes: - func: handler function - state: state in which handler can be activated - priority: priority of the function. If 2 or more handlers can be activated, handler - with the highest priority is selected - context_condition: predicate that accepts user context and checks if the handler should be activated. Example: - `lambda context: context.user_id != 1` checks if user_id is not equal to 1. - That means a user with id 1 will be always ignored by the handler. - - """ - - def __init__(self, - func: Callable, - state: Optional[str] = None, - context_condition: Optional[Callable] = None, - priority: int = 0): - self.func = func - self.state = state - self.context_condition = context_condition - self.priority = priority - - def __call__(self, context: UserContext) -> SkillResponse: - return self.func(context) - - def check(self, context: UserContext) -> bool: - """ - Checks: - - if the handler function should be triggered based on the given context via context condition. - - Args: - context: user context - - Returns: - True, if handler should be activated, False otherwise - """ - if self.context_condition is not None: - return self.context_condition(context) - return True - - def expand_context(self, context: UserContext) -> UserContext: - context.handler_payload = {} - return context diff --git a/deeppavlov/skills/dsl_skill/handlers/regex_handler.py b/deeppavlov/skills/dsl_skill/handlers/regex_handler.py deleted file mode 100644 index 04cf171774..0000000000 --- a/deeppavlov/skills/dsl_skill/handlers/regex_handler.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2019 Neural Networks and Deep Learning lab, MIPT -# -# 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. - -import re -from typing import List, Callable, Optional - -from deeppavlov.skills.dsl_skill.context import UserContext -from deeppavlov.skills.dsl_skill.handlers.handler import Handler - - -class RegexHandler(Handler): - """ - This handler checks whether the message that is passed to it is matched by a regex. - - Adds the following key to ```context.handler_payload```: - - 'regex_groups' - groups parsed from regular expression in command, by name - - Attributes: - func: handler function - state: state in which handler can be activated - priority: priority of the function. If 2 or more handlers can be activated, function - with the highest priority is selected - context_condition: predicate that accepts user context and checks if the handler should be activated. - Example: `lambda context: context.user_id != 1` checks if user_id is not equal to 1. - That means a user with id 1 will be always ignored by the handler. - commands: handler is activated if regular expression from this list is matched with a user message - - """ - - def __init__(self, - func: Callable, - commands: Optional[List[str]] = None, - state: Optional[str] = None, - context_condition: Optional[Callable] = None, - priority: int = 0): - super().__init__(func, state, context_condition, priority) - self.commands = [re.compile(command) for command in commands] - - def check(self, context: UserContext) -> bool: - """ - Checks: - - if the handler function should be triggered based on the given context via context condition. - - if at least one of the commands is matched to the `context.message`. - - Args: - context: user context - - Returns: - True, if handler should be activated, False otherwise - """ - is_previous_matches = super().check(context) - if not is_previous_matches: - return False - - message = context.message - return any(re.search(regexp, ' '.join(message)) for regexp in self.commands) - - def expand_context(self, context: UserContext) -> UserContext: - context.handler_payload = {'regex_groups': {}} - message = context.message - for regexp in self.commands: - match = re.search(regexp, ' '.join(message)) - if match is not None: - for group_ind, span in enumerate(match.regs): - context.handler_payload['regex_groups'][group_ind] = message[span[0]: span[1]] - for group_name, group_ind in regexp.groupindex.items(): - context.handler_payload['regex_groups'][group_name] = \ - context.handler_payload['regex_groups'][group_ind] - return context diff --git a/deeppavlov/skills/dsl_skill/utils.py b/deeppavlov/skills/dsl_skill/utils.py deleted file mode 100644 index 717d52f637..0000000000 --- a/deeppavlov/skills/dsl_skill/utils.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2019 Neural Networks and Deep Learning lab, MIPT -# -# 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 typing import Union, NamedTuple - -UserId = Union[str, int] - - -class SkillResponse(NamedTuple): - response: str - confidence: float diff --git a/deeppavlov/skills/rasa_skill/__init__.py b/deeppavlov/skills/rasa_skill/__init__.py deleted file mode 100644 index d694bafa04..0000000000 --- a/deeppavlov/skills/rasa_skill/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .rasa_skill import RASASkill diff --git a/deeppavlov/skills/rasa_skill/rasa_skill.py b/deeppavlov/skills/rasa_skill/rasa_skill.py deleted file mode 100644 index e334f4b0ab..0000000000 --- a/deeppavlov/skills/rasa_skill/rasa_skill.py +++ /dev/null @@ -1,269 +0,0 @@ -# Copyright 2019 Neural Networks and Deep Learning lab, MIPT -# -# 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. - -import asyncio -import logging -import uuid -from functools import reduce -from pathlib import Path -from typing import Tuple, Optional, List - -from rasa.cli.utils import get_validated_path -from rasa.constants import DEFAULT_MODELS_PATH -from rasa.core.agent import Agent -from rasa.core.channels import CollectingOutputChannel -from rasa.core.channels import UserMessage -from rasa.model import get_model - -from deeppavlov.core.common.registry import register -from deeppavlov.core.models.component import Component - -logger = logging.getLogger(__name__) - - -@register("rasa_skill") -class RASASkill(Component): - """RASASkill lets you to wrap RASA Agent as a Skill within DeepPavlov environment. - - The component requires path to your RASA models (folder with timestamped tar.gz archieves) - as you use in command `rasa run -m models --enable-api --log-file out.log` - - """ - - def __init__(self, path_to_models: str, **kwargs) -> None: - """ - Constructs RASA Agent as a DeepPavlov skill: - read model folder, - initialize rasa.core.agent.Agent and wrap it's interfaces - - Args: - path_to_models: string path to folder with RASA models - - """ - # we need absolute path (expanded for user home and resolved if it relative path): - self.path_to_models = Path(path_to_models).expanduser().resolve() - - model = get_validated_path(self.path_to_models, "model", DEFAULT_MODELS_PATH) - - model_path = get_model(model) - if not model_path: - # can not laod model path - raise Exception("can not load model path: %s" % model) - - self._agent = Agent.load(model_path) - self.ioloop = asyncio.new_event_loop() - logger.info(f"path to RASA models is: `{self.path_to_models}`") - - def __call__(self, - utterances_batch: List[str], - states_batch: Optional[List] = None) -> Tuple[List[str], List[float], list]: - """Returns skill inference result. - - Returns batches of skill inference results, estimated confidence - levels and up to date states corresponding to incoming utterance - batch. - - Args: - utterances_batch: A batch of utterances of str type. - states_batch: A batch of arbitrary typed states for - each utterance. - - - Returns: - response: A batch of arbitrary typed skill inference results. - confidence: A batch of float typed confidence levels for each of - skill inference result. - output_states_batch: A batch of arbitrary typed states for - each utterance. - - """ - user_ids, output_states_batch = self._handle_user_identification(utterances_batch, states_batch) - ################################################################################# - # RASA use asyncio for handling messages and handle_text is async function, - # so we need to instantiate event loop - # futures = [rasa_confident_response_decorator(self._agent, utt, sender_id=uid) for utt, uid in - futures = [self.rasa_confident_response_decorator(self._agent, utt, sender_id=uid) for utt, uid in - zip(utterances_batch, user_ids)] - - asyncio.set_event_loop(self.ioloop) - results = self.ioloop.run_until_complete(asyncio.gather(*futures)) - - responses_batch, confidences_batch = zip(*results) - return responses_batch, confidences_batch, output_states_batch - - async def rasa_confident_response_decorator(self, rasa_agent, text_message, sender_id): - """ - Args: - rasa_agent: rasa.core.agent.Agent instance - text_message: str with utterance from user - sender_id: id of the user - - Returns: None or tuple with str and float, where first element is a message and second is - confidence - """ - - resp = await self.rasa_handle_text_verbosely(rasa_agent, text_message, sender_id) - if resp: - responses, confidences, actions = resp - else: - logger.warning("Null response from RASA Skill") - return None - - # for adaptation to deep pavlov arch we need to merge multi-messages into single string: - texts = [each_resp['text'] for each_resp in responses if 'text' in each_resp] - merged_message = "\n".join(texts) - - merged_confidence = reduce(lambda a, b: a * b, confidences) - # TODO possibly it better to choose another function for calculation of final confidence - # current realisation of confidence propagation may cause confidence decay for long actions - # chains. If long chains is your case, try max(confidence) or confidence[0] - return merged_message, merged_confidence - - async def rasa_handle_text_verbosely(self, rasa_agent, text_message, sender_id): - """ - This function reimplements RASA's rasa.core.agent.Agent.handle_text method to allow to retrieve - message responses with confidence estimation altogether. - - It reconstructs with merge RASA's methods: - https://github.com/RasaHQ/rasa_core/blob/master/rasa/core/agent.py#L401 - https://github.com/RasaHQ/rasa_core/blob/master/rasa/core/agent.py#L308 - https://github.com/RasaHQ/rasa/blob/master/rasa/core/processor.py#L327 - - This required to allow RASA to output confidences with actions altogether - (Out of the box RASA does not support such use case). - - Args: - rasa_agent: rasa.core.agent.Agent instance - text_message: str with utterance from user - sender_id: id of the user - - Returns: None or - tuple where first element is a list of messages dicts, the second element is a list - of confidence scores for all actions (it is longer than messages list, because some actions - does not produce messages) - - """ - message = UserMessage(text_message, - output_channel=None, - sender_id=sender_id) - - processor = rasa_agent.create_processor() - tracker = processor._get_tracker(message.sender_id) - - confidences = [] - actions = [] - await processor._handle_message_with_tracker(message, tracker) - # save tracker state to continue conversation from this state - processor._save_tracker(tracker) - - # here we restore some of logic in RASA management. - # ###### Loop of IntraStep decisions ########################################################## - # await processor._predict_and_execute_next_action(msg, tracker): - # https://github.com/RasaHQ/rasa/blob/master/rasa/core/processor.py#L327-L362 - # keep taking actions decided by the policy until it chooses to 'listen' - should_predict_another_action = True - num_predicted_actions = 0 - - def is_action_limit_reached(): - return (num_predicted_actions == processor.max_number_of_predictions and - should_predict_another_action) - - # action loop. predicts actions until we hit action listen - while (should_predict_another_action and - processor._should_handle_message(tracker) and - num_predicted_actions < processor.max_number_of_predictions): - # this actually just calls the policy's method by the same name - action, policy, confidence = processor.predict_next_action(tracker) - - confidences.append(confidence) - actions.append(action) - - should_predict_another_action = await processor._run_action( - action, - tracker, - message.output_channel, - processor.nlg, - policy, confidence - ) - num_predicted_actions += 1 - - if is_action_limit_reached(): - # circuit breaker was tripped - logger.warning( - "Circuit breaker tripped. Stopped predicting " - "more actions for sender '{}'".format(tracker.sender_id)) - if processor.on_circuit_break: - # call a registered callback - processor.on_circuit_break(tracker, message.output_channel, processor.nlg) - - if isinstance(message.output_channel, CollectingOutputChannel): - - return message.output_channel.messages, confidences, actions - else: - return None - - def _generate_user_id(self) -> str: - """ - Here you put user id generative logic if you want to implement it in the skill. - - Although it is better to delegate user_id generation to Agent Layer - Returns: str - - """ - return uuid.uuid1().hex - - def _handle_user_identification(self, utterances_batch, states_batch): - """Method preprocesses states batch to guarantee that all users are identified (or - identifiers are generated for all users). - - Args: - utterances_batch: batch of utterances - states_batch: batch of states - - Returns: - - """ - # grasp user_ids from states batch. - # We expect that skill receives None or dict of state for each utterance. - # if state has user_id then skill uses it, otherwise it generates user_id and calls the - # user with this name in further. - - # In this implementation we use current datetime for generating uniqe ids - output_states_batch = [] - user_ids = [] - if states_batch is None: - # generate states batch matching batch of utterances: - states_batch = [None] * len(utterances_batch) - - for state in states_batch: - if not state: - user_id = self._generate_user_id() - new_state = {'user_id': user_id} - - elif 'user_id' not in state: - new_state = state - user_id = self._generate_user_id() - new_state['user_id'] = self._generate_user_id() - - else: - new_state = state - user_id = new_state['user_id'] - - user_ids.append(user_id) - output_states_batch.append(new_state) - return user_ids, output_states_batch - - def destroy(self): - self.ioloop.close() - super().destroy() diff --git a/docs/apiref/skills.rst b/docs/apiref/skills.rst deleted file mode 100644 index bfb47a5e59..0000000000 --- a/docs/apiref/skills.rst +++ /dev/null @@ -1,12 +0,0 @@ -skills -====== -Skill classes. Skills are dialog models. - -.. automodule:: deeppavlov.skills - :members: - -.. toctree:: - :glob: - :caption: Skills - - skills/* \ No newline at end of file diff --git a/docs/apiref/skills/aiml_skill.rst b/docs/apiref/skills/aiml_skill.rst deleted file mode 100644 index 97e7e0ffce..0000000000 --- a/docs/apiref/skills/aiml_skill.rst +++ /dev/null @@ -1,5 +0,0 @@ -deeppavlov.skills.aiml_skill -============================ - -.. automodule:: deeppavlov.skills.aiml_skill.aiml_skill - :members: diff --git a/docs/apiref/skills/dsl_skill.rst b/docs/apiref/skills/dsl_skill.rst deleted file mode 100644 index 7bc6cf2fed..0000000000 --- a/docs/apiref/skills/dsl_skill.rst +++ /dev/null @@ -1,5 +0,0 @@ -deeppavlov.skills.dsl_skill -============================================ - -.. automodule:: deeppavlov.skills.dsl_skill.dsl_skill - :members: diff --git a/docs/apiref/skills/rasa_skill.rst b/docs/apiref/skills/rasa_skill.rst deleted file mode 100644 index 4dcd93f7ac..0000000000 --- a/docs/apiref/skills/rasa_skill.rst +++ /dev/null @@ -1,5 +0,0 @@ -deeppavlov.skills.rasa_skill -============================ - -.. automodule:: deeppavlov.skills.rasa_skill.rasa_skill - :members: diff --git a/docs/conf.py b/docs/conf.py index e9d5e42c9c..b3a4f11237 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -190,7 +190,7 @@ # -- Extension configuration ------------------------------------------------- -autodoc_mock_imports = ['aiml', 'bert_dp', 'bs4', 'faiss', 'fastText', 'fasttext', 'gensim', 'hdt', 'kenlm', 'librosa', +autodoc_mock_imports = ['bert_dp', 'bs4', 'faiss', 'fastText', 'fasttext', 'gensim', 'hdt', 'kenlm', 'librosa', 'lxml', 'nemo', 'nemo_asr', 'nemo_tts', 'nltk', 'opt_einsum', 'rapidfuzz', 'rasa', 'russian_tagsets', 'sacremoses', 'sortedcontainers', 'spacy', 'tensorflow', 'tensorflow_hub', 'torch', 'transformers', 'udapi', 'ufal_udpipe', 'whapi', 'xeger'] diff --git a/docs/features/skills/aiml_skill.rst b/docs/features/skills/aiml_skill.rst deleted file mode 100644 index ac385c7ea9..0000000000 --- a/docs/features/skills/aiml_skill.rst +++ /dev/null @@ -1,44 +0,0 @@ -AIML Skill -====================== - -An :doc:`AIML scripts wrapper implementation` that reads a folder with AIML scripts -(provided by `path_to_aiml_scripts` argument), loads it into AIML's Kernel and responds for incoming utterances -accroding to patterns learned by AIML Kernel. - -For the case when AIML kernel matched utterance and found response the AIML Wrapper outputs response with confidence -value (as specified by`positive_confidence` argument). - -For the case when no match occured the wrapper returns the argument `null_response` as utterance and sets confidence to -`null_confidence` attribute. - - -Quick Start ------------ -To setup AIML Skill you need load your AIML scripts to some folder and specify path to it with initilization -parameter `path_to_aiml_scripts`. - -You can download bunch of free and ready for use AIML scripts from pandorabots repo: -https://github.com/pandorabots/Free-AIML - -DeepPavlov library has default config for AIMLSkill here: :config:`configs/skills/aiml_skill.json ` - -Usage -^^^^^^^^ - -.. code:: python - - from deeppavlov.skills.aiml_skill import AIMLSkill - - aiml_skill_config = { - 'positive_confidence': 0.66, - 'path_to_aiml_scripts': , - 'null_response': "I don't know what to answer you", - 'null_confidence': 0.33 - } - - aiml_skill = AIMLSkill(**aiml_skill_config) - - states_batch = None - for utterance in ["Hello", "Hello to the same user_id"]: - responses_batch, confidences_batch, states_batch = aiml_skill([utterance], states_batch) - print(responses_batch[0]) diff --git a/docs/features/skills/dsl_skill.rst b/docs/features/skills/dsl_skill.rst deleted file mode 100644 index 919b1661a5..0000000000 --- a/docs/features/skills/dsl_skill.rst +++ /dev/null @@ -1,42 +0,0 @@ -DSL Skill -====================== - -A :doc:`DSL implementation`. DSL helps to easily create user-defined skills for dialog systems. - -For the case when DSL skill matched utterance and found response it outputs response with confidence value. - -For the case when no match occurred DSL skill returns the argument `on_invalid_command` ("Простите, я вас не понял" by delault) as utterance and sets confidence to `null_confidence` attribute (0 by default). - -`on_invalid_command` and `null_confidence` can be changed in model config - - -Quick Start ------------ - -DeepPavlov library has default config for DSLSkill here: :config:`configs/skills/dsl_skill.json ` - -Usage -^^^^^^^^ - -.. code:: python - - from deeppavlov import configs, build_model - from deeppavlov.core.common.file import read_json - from deeppavlov.skills.dsl_skill import DSLMeta - - - class DSLSkill(metaclass=DSLMeta): - @DSLMeta.handler(commands=["hello", "hi", "sup", "greetings"]) - def greeting(context): - response = "Hello, my friend!" - confidence = 1.0 - return response, confidence - - - skill_config = read_json(configs.skills.dsl_skill) - - skill = build_model(skill_config, download=True) - utterance = "Hello" - user_id = 1 - response = skill([utterance], [user_id]) - print(response) diff --git a/docs/features/skills/rasa_skill.rst b/docs/features/skills/rasa_skill.rst deleted file mode 100644 index 5f8ffdd3db..0000000000 --- a/docs/features/skills/rasa_skill.rst +++ /dev/null @@ -1,50 +0,0 @@ -Rasa Skill -====================== - -A :class:`Rasa wrapper implementation` that reads a folder with Rasa models -(provided by ``path_to_models`` argument), initializes Rasa Agent with this configuration and responds for incoming -utterances according to responses predicted by Rasa. Each response has confidence value estimated as product of -scores of executed actions by Rasa system in the current prediction step (each prediction step in Rasa usually consists of -multiple actions). If Rasa responds with multiple ``BotUttered`` actions, then such phrases are merged into one utterance -divided by ``'\n'``. - -Quick Start ------------ -To setup a Rasa Skill you need to have a working Rasa project at some path, then you can specify the path to Rasa's -models (usually it is a folder with name ``models`` inside the project path) at initialization of Rasa Skill class -by providing ``path_to_models`` attribute. - -Dummy Rasa project ------------------- -DeepPavlov library has :config:`a template config for RASASkill`. -This project is in essence a working Rasa project created with ``rasa init`` and ``rasa train`` commands -with minimal additions. The Rasa bot can greet, answer about what he can do and detect user's mood sentiment. - -The template DeepPavlov config specifies only one component (RASASkill) in :doc:`a pipeline`. -The ``metadata.download`` field in configuration allows to download and unpack the gzipped template project into -subdir ``{DOWNLOADS_PATH}``. - -If you create a configuration for a Rasa project hosted on your machine, you don't need to specify ``metadata.download`` -and just need to correctly set ``path_to_models`` of the ``rasa_skill`` component. -``path_to_models`` needs to be a path to your Rasa's ``models`` directory. - -See `Rasa's documentation `_ for explanation on how -to create project. - -Usage without DeepPavlov configuration files -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. code:: python - - from deeppavlov.skills.rasa_skill import RASASkill - - rasa_skill_config = { - 'path_to_models': , - } - - rasa_skill = RASASkill(**rasa_skill_config) - - states_batch = None - for utterance in ["Hello", "Hello to the same user_id"]: - responses_batch, confidences_batch, states_batch = rasa_skill([utterance], states_batch) - print(responses_batch[0]) diff --git a/docs/index.rst b/docs/index.rst index 1f5f795c33..723d7c8539 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -54,9 +54,6 @@ Welcome to DeepPavlov's documentation! Goal-Oriented Dialogue Bot Open-Domain Question Answering Frequently Asked Questions Answering - AIML - Rasa - DSL .. toctree:: diff --git a/examples/gobot_md_yaml_configs_tutorial.ipynb b/examples/gobot_md_yaml_configs_tutorial.ipynb index 69d9431d51..01426e40a2 100644 --- a/examples/gobot_md_yaml_configs_tutorial.ipynb +++ b/examples/gobot_md_yaml_configs_tutorial.ipynb @@ -54,7 +54,6 @@ "At DeepPavlov, we support a variety of industry-wide and popular standards to support developing Conversational AI solutions.\n", "DSLs, known as Domain-Specific Languages, provide a rich mechanism to define the behavior, or \"the what\", while\n", "the underlying system uses the parser to transform these definitions into commands that implement this behavior, or \"the how\" using the system's components.\n", - "Until very recently we supported two such DSLs, including industry-standard [AIML](http://docs.deeppavlov.ai/en/master/features/skills/aiml_skill.html), as well as [DSL](http://docs.deeppavlov.ai/en/master/features/skills/dsl_skill.html) designed by one of our partners, EORA.\n", "\n", "In this tutorial, you will learn how to use another industrial DSL, or, better said, set of DSLs, introduced by RASA.ai,\n", "to build simple goal-oriented chatbots using DeepPavlov's GO-bot.\n", diff --git a/tests/test_aiml_skill.py b/tests/test_aiml_skill.py deleted file mode 100644 index ffa08a3634..0000000000 --- a/tests/test_aiml_skill.py +++ /dev/null @@ -1,37 +0,0 @@ -from logging import getLogger - -from deeppavlov import configs, build_model -from deeppavlov.utils.pip_wrapper.pip_wrapper import install_from_config - -log = getLogger(__name__) - - -class TestAIMLSkill: - def setup(self): - config_ref = configs.skills.aiml_skill - install_from_config(config_ref) - self.aiml_skill = build_model(config_ref, download=True) - - def test_simple_reaction(self): - user_messages_sequence = [ - "Hello", - "What s up?", - "Tell me a joke", - "Learn my pants are Red", - "LET DISCUSS MOVIES", - "Comedy movies are nice to watch", - "I LIKE WATCHING COMEDY!", - "Ok, goodbye" - ] - - history_of_responses = [] - for each_utt in user_messages_sequence: - log.info(f"User says: {each_utt}") - responses_batch, _, _ = self.aiml_skill([each_utt], [None]) - log.info(f" Bot says: {responses_batch[0]}") - history_of_responses.append(responses_batch) - - # check the first greeting message in 0th batch - assert "Well, hello!" in history_of_responses[0][0] - # check fifth message in 0th batch - assert "Yes movies" in history_of_responses[4][0] diff --git a/tests/test_dsl_skill.py b/tests/test_dsl_skill.py deleted file mode 100644 index 6a332b44ce..0000000000 --- a/tests/test_dsl_skill.py +++ /dev/null @@ -1,109 +0,0 @@ -from logging import getLogger - -from deeppavlov import configs, build_model -from deeppavlov.core.common.file import read_json -from deeppavlov.skills.dsl_skill import DSLMeta -from deeppavlov.utils.pip_wrapper.pip_wrapper import install_from_config - -log = getLogger(__name__) - - -class DSLSkill(metaclass=DSLMeta): - @DSLMeta.handler(commands=["hello", "hi", "sup", "greetings"]) - def greeting(context): - response = "Hello, my friend!" - confidence = 1.0 - return response, confidence - - -class StateSkill(metaclass=DSLMeta): - @DSLMeta.handler(commands=["hello", "hi", "sup", "greetings"]) - def greeting(context): - response = "Hello, my friend!" - confidence = 1.0 - context.current_state = "state1" - return response, confidence - - @DSLMeta.handler(commands=["bye"], - state="state1") - def bye(context): - response = "bb!" - confidence = 1.0 - return response, confidence - - -class ContextConditionSkill(metaclass=DSLMeta): - @DSLMeta.handler(commands=["hello", "hi", "sup", "greetings"], - context_condition=lambda context: context.user_id != 1) - def greeting(context): - response = "Hello, my friend!" - confidence = 1.0 - return response, confidence - - -class TestDSLSkill: - def setup(self): - self.skill_config = read_json(configs.skills.dsl_skill) - install_from_config(self.skill_config) - - def test_simple_skill(self): - user_messages_sequence = [ - "Hello", - "Hi", - "Tell me a joke", - "Sup", - "Ok, goodbye" - ] - - skill = build_model(self.skill_config, download=True) - history_of_responses = [] - for user_id, each_utt in enumerate(user_messages_sequence): - log.info(f"User says: {each_utt}") - responses_batch = skill([each_utt], [user_id]) - log.info(f"Bot says: {responses_batch[0]}") - history_of_responses.append(responses_batch) - - # check the first greeting message in 0th batch - assert "Hello, my friend!" in history_of_responses[0][0] - # check the second greeting message in 0th batch - assert "Hello, my friend!" in history_of_responses[1][0] - # check `on_invalid_command` - assert "Sorry, I do not understand you" in history_of_responses[2][0] - - def test_switch_state(self): - user_messages_sequence = [ - "Hello", - "bye", - "bye" - ] - - self.skill_config["chainer"]["pipe"][1]["class_name"] = "StateSkill" - skill = build_model(self.skill_config, download=True) - - history_of_responses = [] - for user_id, each_utt in enumerate(user_messages_sequence): - log.info(f"User says: {each_utt}") - responses_batch = skill([each_utt], [user_id % 2]) - log.info(f"Bot says: {responses_batch[0]}") - history_of_responses.append(responses_batch) - assert "Hello, my friend!" in history_of_responses[0][0] - assert "Sorry, I do not understand you" in history_of_responses[1][0] - assert "bb!" in history_of_responses[2][0] - - def test_context_condition(self): - user_messages_sequence = [ - "Hello", - "Hi" - ] - - self.skill_config["chainer"]["pipe"][1]["class_name"] = "ContextConditionSkill" - skill = build_model(self.skill_config, download=True) - - history_of_responses = [] - for user_id, each_utt in enumerate(user_messages_sequence): - log.info(f"User says: {each_utt}") - responses_batch = skill([each_utt], [user_id]) - log.info(f"Bot says: {responses_batch[0]}") - history_of_responses.append(responses_batch) - assert "Hello, my friend!" in history_of_responses[0][0] - assert "Sorry, I do not understand you" in history_of_responses[1][0] diff --git a/tests/test_rasa_skill.py b/tests/test_rasa_skill.py deleted file mode 100644 index 7235ade7f3..0000000000 --- a/tests/test_rasa_skill.py +++ /dev/null @@ -1,39 +0,0 @@ -from logging import getLogger - -from deeppavlov import configs, build_model -from deeppavlov.utils.pip_wrapper.pip_wrapper import install_from_config - -log = getLogger(__name__) - - -class TestRASASkill: - def setup(self): - config_ref = configs.skills.rasa_skill - install_from_config(config_ref) - self.rasa_skill = build_model(config_ref, download=True) - - def test_simple_reaction(self): - user_messages_sequence = [ - "Hello", - "What can you do?", - "Tell me a joke", - "Learn my pants are Red", - "LET DISCUSS MOVIES", - "Comedy movies are nice to watch", - "I LIKE WATCHING COMEDY!", - "Ok, goodbye" - ] - - history_of_responses = [] - for each_utt in user_messages_sequence: - log.info(f"User says: {each_utt}") - responses_batch, _ = self.rasa_skill([each_utt]) - log.info(f" Bot says: {responses_batch[0]}") - history_of_responses.append(responses_batch) - - print("history_of_responses:") - print(history_of_responses) - # # check the first greeting message in 0th batch - # assert "Hey! How are you?" in history_of_responses[0][0] - # # check second response message in 0th batch - # assert "I can chat with you. You can greet me" in history_of_responses[1][0]