neon-minerva 0.0.1a2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ # NEON AI (TM) SOFTWARE, Software Development Kit & Application Development System
2
+ # All trademark and other rights reserved by their respective owners
3
+ # Copyright 2008-2021 Neongecko.com Inc.
4
+ # BSD-3 License
5
+
6
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
7
+ following conditions are met:
8
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
9
+ disclaimer.
10
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
11
+ disclaimer in the documentation and/or other materials provided with the distribution.
12
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products
13
+ derived from this software without specific prior written permission.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
16
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
20
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
21
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,52 @@
1
+ Metadata-Version: 2.1
2
+ Name: neon-minerva
3
+ Version: 0.0.1a2
4
+ Summary: Modular INtelligent Evaluation for a Reliable Voice Assistant
5
+ Home-page: https://github.com/neongeckocom/neon-minerva
6
+ Author: Neongecko
7
+ Author-email: developers@neon.ai
8
+ License: BSD-3-Clause
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.6
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE.md
14
+
15
+ # Neon Minerva
16
+ Neon Minerva (Modular INtelligent Evaluation for a Reliable Voice Assistant)
17
+ provides tools for testing skills.
18
+
19
+ Install the Minerva Python package with: `pip install neon-minerva`
20
+ The `minerva` entrypoint is available to interact with a bus via CLI.
21
+ Help is available via `minerva --help`.
22
+
23
+ ## Installation
24
+ Since skill intents may use Padatious, the following system packages must be
25
+ installed before installing this package:
26
+ ```shell
27
+ sudo apt install swig libfann-dev
28
+ ```
29
+ To install this package from PyPI, simply run:
30
+ ```shell
31
+ pip install neon-minerva
32
+ ```
33
+
34
+ ## Usage
35
+ This package provides a CLI for local testing of skills. Skills installed with
36
+ `pip` can be specified by entrypoint, or skills cloned locally can be specified
37
+ by root directory.
38
+
39
+ ### Resource Tests
40
+ To test that skill resources are defined for all supported languages,
41
+ `minerva test-resources <skill-entrypoint> <test-file>`
42
+ > - <skill-entrypoint\> is the string entrypoint for the skill to test as specified in `setup.py` OR the path to
43
+ the skill's root directory
44
+ > - <test-file\> is a relative or absolute path to the resource test file, usually `test_resources.yaml`
45
+
46
+ ### Intent Tests
47
+ To test that skill intents match as expected for all supported languages,
48
+ `minerva test-intents <skill-entrypoint> <test-file>`
49
+ > - <skill-entrypoint\> is the string entrypoint for the skill to test as specified in `setup.py` OR the path to
50
+ the skill's root directory
51
+ > - <test-file\> is a relative or absolute path to the resource test file, usually `test_intents.yaml`
52
+ > - The `--padacioso` flag can be added to test with Padacioso instead of Padatious for relevant intents
@@ -0,0 +1,38 @@
1
+ # Neon Minerva
2
+ Neon Minerva (Modular INtelligent Evaluation for a Reliable Voice Assistant)
3
+ provides tools for testing skills.
4
+
5
+ Install the Minerva Python package with: `pip install neon-minerva`
6
+ The `minerva` entrypoint is available to interact with a bus via CLI.
7
+ Help is available via `minerva --help`.
8
+
9
+ ## Installation
10
+ Since skill intents may use Padatious, the following system packages must be
11
+ installed before installing this package:
12
+ ```shell
13
+ sudo apt install swig libfann-dev
14
+ ```
15
+ To install this package from PyPI, simply run:
16
+ ```shell
17
+ pip install neon-minerva
18
+ ```
19
+
20
+ ## Usage
21
+ This package provides a CLI for local testing of skills. Skills installed with
22
+ `pip` can be specified by entrypoint, or skills cloned locally can be specified
23
+ by root directory.
24
+
25
+ ### Resource Tests
26
+ To test that skill resources are defined for all supported languages,
27
+ `minerva test-resources <skill-entrypoint> <test-file>`
28
+ > - <skill-entrypoint\> is the string entrypoint for the skill to test as specified in `setup.py` OR the path to
29
+ the skill's root directory
30
+ > - <test-file\> is a relative or absolute path to the resource test file, usually `test_resources.yaml`
31
+
32
+ ### Intent Tests
33
+ To test that skill intents match as expected for all supported languages,
34
+ `minerva test-intents <skill-entrypoint> <test-file>`
35
+ > - <skill-entrypoint\> is the string entrypoint for the skill to test as specified in `setup.py` OR the path to
36
+ the skill's root directory
37
+ > - <test-file\> is a relative or absolute path to the resource test file, usually `test_intents.yaml`
38
+ > - The `--padacioso` flag can be added to test with Padacioso instead of Padatious for relevant intents
@@ -0,0 +1,25 @@
1
+ # NEON AI (TM) SOFTWARE, Software Development Kit & Application Development System
2
+ # All trademark and other rights reserved by their respective owners
3
+ # Copyright 2008-2021 Neongecko.com Inc.
4
+ # BSD-3
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ # 1. Redistributions of source code must retain the above copyright notice,
8
+ # this list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ # this list of conditions and the following disclaimer in the documentation
11
+ # and/or other materials provided with the distribution.
12
+ # 3. Neither the name of the copyright holder nor the names of its
13
+ # contributors may be used to endorse or promote products derived from this
14
+ # software without specific prior written permission.
15
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
22
+ # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,130 @@
1
+ # NEON AI (TM) SOFTWARE, Software Development Kit & Application Development System
2
+ # All trademark and other rights reserved by their respective owners
3
+ # Copyright 2008-2021 Neongecko.com Inc.
4
+ # BSD-3
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ # 1. Redistributions of source code must retain the above copyright notice,
8
+ # this list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ # this list of conditions and the following disclaimer in the documentation
11
+ # and/or other materials provided with the distribution.
12
+ # 3. Neither the name of the copyright holder nor the names of its
13
+ # contributors may be used to endorse or promote products derived from this
14
+ # software without specific prior written permission.
15
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
22
+ # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ import logging
27
+ import os
28
+ import click
29
+
30
+ from os.path import expanduser, relpath, isfile, isdir
31
+ from click_default_group import DefaultGroup
32
+ from unittest.runner import TextTestRunner
33
+ from unittest import makeSuite
34
+
35
+ from neon_minerva.version import __version__
36
+
37
+
38
+ def _init_tests(debug: bool = False):
39
+ from os.path import join
40
+ from os import makedirs
41
+ from tempfile import mkdtemp
42
+ base_dir = mkdtemp()
43
+ config = join(base_dir, "config")
44
+ data = join(base_dir, "data")
45
+ cache = join(base_dir, "cache")
46
+ makedirs(config, exist_ok=True)
47
+ makedirs(data, exist_ok=True)
48
+ makedirs(cache, exist_ok=True)
49
+ os.environ["XDG_CONFIG_HOME"] = config
50
+ os.environ["XDG_DATA_HOME"] = data
51
+ os.environ["XDG_CACHE_HOME"] = cache
52
+
53
+ if debug:
54
+ os.environ["OVOS_DEFAULT_LOG_LEVEL"] = "DEBUG"
55
+
56
+ def _get_test_file(test_file: str) -> str:
57
+ """
58
+ Parse an input path to locate a test file that may be relative to `~` or the
59
+ current working directory.
60
+ @param test_file: test file argument
61
+ @returns: best guess at the desired file path (may not exist)
62
+ """
63
+ test_file = expanduser(test_file)
64
+ if not isfile(test_file):
65
+ test_file = relpath(test_file)
66
+ return test_file
67
+
68
+
69
+ def _get_skill_entrypoint(skill_entrypoint: str) -> str:
70
+ """
71
+ Parse an input skill entrypoint and resolve either a locally installed skill
72
+ path, or an entrypoint for a plugin skill.
73
+ @param skill_entrypoint: Plugin entrypoint or path to skill
74
+ @returns: absolute file path if exists, else input entrypoint
75
+ """
76
+ skill_path = expanduser(skill_entrypoint)
77
+ if not isdir(skill_path):
78
+ skill_path = relpath(skill_path)
79
+ if isdir(skill_path):
80
+ return skill_path
81
+ return skill_entrypoint
82
+
83
+
84
+ @click.group("minerva", cls=DefaultGroup,
85
+ no_args_is_help=True, invoke_without_command=True,
86
+ help="Minerva: Modular INtelligent Evaluation for a Reliable "
87
+ "Voice Assistant.\n\n"
88
+ "See also: minerva COMMAND --help")
89
+ @click.option("--version", "-v", is_flag=True, required=False,
90
+ help="Print the current version")
91
+ def neon_minerva_cli(version: bool = False):
92
+ if version:
93
+ click.echo(f"Minerva version {__version__}")
94
+
95
+
96
+ @neon_minerva_cli.command
97
+ @click.option('--debug', is_flag=True, default=False,
98
+ help="Flag to enable debug logging")
99
+ @click.argument("skill_entrypoint")
100
+ @click.argument("test_file")
101
+ def test_resources(skill_entrypoint, test_file, debug):
102
+ _init_tests(debug)
103
+ os.environ["TEST_SKILL_ENTRYPOINT"] = _get_skill_entrypoint(skill_entrypoint)
104
+ test_file = _get_test_file(test_file)
105
+ if not isfile(test_file):
106
+ click.echo(f"Could not find test file: {test_file}")
107
+ exit(2)
108
+ os.environ["RESOURCE_TEST_FILE"] = test_file
109
+ from neon_minerva.tests.test_skill_resources import TestSkillResources
110
+ TextTestRunner().run(makeSuite(TestSkillResources))
111
+
112
+
113
+ @neon_minerva_cli.command
114
+ @click.option('--debug', is_flag=True, default=False,
115
+ help="Flag to enable debug logging")
116
+ @click.option('--padacioso', is_flag=True, default=False,
117
+ help="Flag to enable testing with Padacioso instead of Padatious")
118
+ @click.argument("skill_entrypoint")
119
+ @click.argument("test_file")
120
+ def test_intents(skill_entrypoint, test_file, debug, padacioso):
121
+ _init_tests(debug)
122
+ os.environ["TEST_PADACIOSO"] = "true" if padacioso else "false"
123
+ os.environ["TEST_SKILL_ENTRYPOINT"] = _get_skill_entrypoint(skill_entrypoint)
124
+ test_file = _get_test_file(test_file)
125
+ if not isfile(test_file):
126
+ click.echo(f"Could not find test file: {test_file}")
127
+ exit(2)
128
+ os.environ["INTENT_TEST_FILE"] = test_file
129
+ from neon_minerva.tests.test_skill_intents import TestSkillIntentMatching
130
+ TextTestRunner().run(makeSuite(TestSkillIntentMatching))
@@ -0,0 +1,43 @@
1
+ # NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework
2
+ # All trademark and other rights reserved by their respective owners
3
+ # Copyright 2008-2022 Neongecko.com Inc.
4
+ # Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds,
5
+ # Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo
6
+ # BSD-3 License
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are met:
9
+ # 1. Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ # 3. Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from this
16
+ # software without specific prior written permission.
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24
+ # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ class IntentException(Exception):
30
+ """
31
+ Base exception for an intent error
32
+ """
33
+
34
+ class IntentNotMatched(IntentException):
35
+ """
36
+ Exception indicating an intent match was expected but not found
37
+ """
38
+
39
+
40
+ class ConfidenceTooLow(IntentException):
41
+ """
42
+ Exception indicating an intent match confidence was below specified minimum.
43
+ """
@@ -0,0 +1,30 @@
1
+ # NEON AI (TM) SOFTWARE, Software Development Kit & Application Development System
2
+ # All trademark and other rights reserved by their respective owners
3
+ # Copyright 2008-2021 Neongecko.com Inc.
4
+ # BSD-3
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ # 1. Redistributions of source code must retain the above copyright notice,
8
+ # this list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ # this list of conditions and the following disclaimer in the documentation
11
+ # and/or other materials provided with the distribution.
12
+ # 3. Neither the name of the copyright holder nor the names of its
13
+ # contributors may be used to endorse or promote products derived from this
14
+ # software without specific prior written permission.
15
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
22
+ # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ from collections import namedtuple
27
+
28
+ IntentMatch = namedtuple('IntentMatch',
29
+ ['intent_service', 'intent_type',
30
+ 'intent_data', 'skill_id', 'utterance'])
@@ -0,0 +1,88 @@
1
+ # NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework
2
+ # All trademark and other rights reserved by their respective owners
3
+ # Copyright 2008-2022 Neongecko.com Inc.
4
+ # Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds,
5
+ # Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo
6
+ # BSD-3 License
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are met:
9
+ # 1. Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ # 3. Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from this
16
+ # software without specific prior written permission.
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24
+ # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ from typing import Optional
30
+ from adapt.engine import IntentDeterminationEngine
31
+ from ovos_utils.intents.intent_service_interface import open_intent_envelope
32
+ from ovos_utils.log import LOG
33
+ from ovos_utils.messagebus import FakeBus, get_message_lang
34
+
35
+ from neon_minerva.exceptions import IntentNotMatched, ConfidenceTooLow
36
+ from neon_minerva.intent_services import IntentMatch
37
+
38
+
39
+ class AdaptContainer:
40
+ def __init__(self, lang: str, bus: FakeBus):
41
+ self.lang = lang.lower()
42
+ self.bus = bus
43
+ self.adapt = IntentDeterminationEngine()
44
+ self.bus.on('register_vocab', self.handle_register_vocab)
45
+ self.bus.on('register_intent', self.handle_register_intent)
46
+
47
+ def handle_register_vocab(self, message):
48
+ entity_value = message.data.get('entity_value')
49
+ entity_type = message.data.get('entity_type')
50
+ regex_str = message.data.get('regex')
51
+ alias_of = message.data.get('alias_of')
52
+ lang = get_message_lang(message)
53
+ if lang != self.lang:
54
+ return
55
+ if regex_str:
56
+ self.adapt.register_regex_entity(regex_str)
57
+ else:
58
+ self.adapt.register_entity(entity_value, entity_type,
59
+ alias_of=alias_of)
60
+
61
+ def handle_register_intent(self, message):
62
+ intent = open_intent_envelope(message)
63
+ self.adapt.register_intent_parser(intent)
64
+
65
+ def test_intent(self, utterance: str) -> Optional[IntentMatch]:
66
+ best_intent = None
67
+ try:
68
+ intents = [i for i in self.adapt.determine_intent(
69
+ utterance, 100,
70
+ include_tags=True)]
71
+ if intents:
72
+ best_intent = max(intents,
73
+ key=lambda x: x.get('confidence', 0.0))
74
+ except Exception as err:
75
+ LOG.exception(err)
76
+
77
+ if not best_intent:
78
+ raise IntentNotMatched(utterance)
79
+ LOG.debug(best_intent)
80
+ skill_id = best_intent['intent_type'].split(":")[0]
81
+ _norm_id = skill_id.replace('.', '_')
82
+ intent_data = {k.replace(_norm_id, '', 1): v for k, v in
83
+ best_intent.items() if k.startswith(_norm_id) and
84
+ isinstance(v, str)}
85
+ LOG.debug(intent_data)
86
+ ret = IntentMatch('Adapt', best_intent['intent_type'], intent_data,
87
+ skill_id, utterance)
88
+ return ret
@@ -0,0 +1,73 @@
1
+ # NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework
2
+ # All trademark and other rights reserved by their respective owners
3
+ # Copyright 2008-2022 Neongecko.com Inc.
4
+ # Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds,
5
+ # Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo
6
+ # BSD-3 License
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are met:
9
+ # 1. Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ # 3. Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from this
16
+ # software without specific prior written permission.
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24
+ # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ from padacioso import IntentContainer
30
+ from ovos_utils.log import LOG
31
+ from ovos_utils.messagebus import FakeBus
32
+
33
+
34
+ class PadaciosoContainer:
35
+ def __init__(self, lang: str, cache_dir: str, bus: FakeBus):
36
+ self.cache_dir = cache_dir
37
+ self.lang = lang.lower()
38
+ self.bus = bus
39
+ self.padatious = IntentContainer(False)
40
+ self.bus.on('padatious:register_intent', self.register_intent)
41
+ self.bus.on('padatious:register_entity', self.register_entity)
42
+
43
+ def register_intent(self, message):
44
+ """Messagebus handler for registering intents.
45
+
46
+ Args:
47
+ message (Message): message triggering action
48
+ """
49
+ lang = message.data.get('lang', self.lang)
50
+ lang = lang.lower()
51
+ if lang == self.lang:
52
+ LOG.debug(f"Loading intent: {message.data['name']}")
53
+ self.padatious.add_intent(message.data['name'],
54
+ message.data["samples"])
55
+ else:
56
+ LOG.debug(f"Ignoring {message.data['name']}")
57
+
58
+ def register_entity(self, message):
59
+ """Messagebus handler for registering entities.
60
+
61
+ Args:
62
+ message (Message): message triggering action
63
+ """
64
+ lang = message.data.get('lang', self.lang)
65
+ lang = lang.lower()
66
+ if lang == self.lang:
67
+ self.padatious.add_entity(message.data['name'],
68
+ message.data['samples'])
69
+
70
+ def calc_intent(self, utt: str) -> dict:
71
+ intent = self.padatious.calc_intent(utt)
72
+ LOG.debug(intent)
73
+ return intent or dict()
@@ -0,0 +1,102 @@
1
+ # NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework
2
+ # All trademark and other rights reserved by their respective owners
3
+ # Copyright 2008-2022 Neongecko.com Inc.
4
+ # Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds,
5
+ # Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo
6
+ # BSD-3 License
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are met:
9
+ # 1. Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ # 3. Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from this
16
+ # software without specific prior written permission.
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24
+ # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ from padatious import IntentContainer
30
+ from ovos_utils.log import LOG
31
+ from ovos_utils.messagebus import FakeBus
32
+
33
+ from neon_minerva.exceptions import IntentNotMatched, ConfidenceTooLow
34
+ from neon_minerva.intent_services import IntentMatch
35
+
36
+
37
+ class PadatiousContainer:
38
+ def __init__(self, lang: str, cache_path: str, bus: FakeBus):
39
+ self.cache_dir = cache_path
40
+ self.lang = lang.lower()
41
+ self.bus = bus
42
+ self.padatious = IntentContainer(cache_path)
43
+ self.bus.on('padatious:register_intent', self.register_intent)
44
+ self.bus.on('padatious:register_entity', self.register_entity)
45
+
46
+ def register_intent(self, message):
47
+ """Messagebus handler for registering intents.
48
+
49
+ Args:
50
+ message (Message): message triggering action
51
+ """
52
+ lang = message.data.get('lang', self.lang)
53
+ lang = lang.lower()
54
+ if lang == self.lang:
55
+ LOG.debug(f"Loading intent: {message.data['name']}")
56
+ self.padatious.load_intent(message.data['name'],
57
+ message.data['file_name'])
58
+ else:
59
+ LOG.debug(f"Ignoring {message.data['name']}")
60
+
61
+ def register_entity(self, message):
62
+ """Messagebus handler for registering entities.
63
+
64
+ Args:
65
+ message (Message): message triggering action
66
+ """
67
+ lang = message.data.get('lang', self.lang)
68
+ lang = lang.lower()
69
+ if lang == self.lang:
70
+ self.padatious.load_entity(message.data['name'],
71
+ message.data['file_name'])
72
+
73
+ def calc_intent(self, utt: str) -> dict:
74
+ intent = self.padatious.calc_intent(utt)
75
+ LOG.debug(intent)
76
+ return intent.__dict__ if intent else dict()
77
+
78
+
79
+ class TestPadatiousMatcher:
80
+ def __init__(self, container: PadatiousContainer,
81
+ include_med: bool = True, include_low: bool = False):
82
+ LOG.debug("Creating test Padatious Matcher")
83
+ if include_low:
84
+ self.min_conf = 0.5
85
+ elif include_med:
86
+ self.min_conf = 0.8
87
+ else:
88
+ self.min_conf = 0.95
89
+ self.padatious = container
90
+
91
+ def test_intent(self, utterance: str) -> IntentMatch:
92
+ intent = self.padatious.calc_intent(utterance)
93
+ if not intent:
94
+ raise IntentNotMatched(utterance)
95
+ conf = intent.get("conf") or 0.0
96
+ if conf < self.min_conf:
97
+ raise ConfidenceTooLow(f"{conf} less than minimum {self.min_conf}")
98
+ skill_id = intent.get('name').split(':')[0]
99
+ sentence = ' '.join(intent.get('sent')) if intent.get('sent') else utterance
100
+ return IntentMatch('Padatious', intent.get('name'),
101
+ intent.get('matches') or intent.get('entities'),
102
+ skill_id, sentence)
@@ -0,0 +1,88 @@
1
+ # NEON AI (TM) SOFTWARE, Software Development Kit & Application Development System
2
+ # All trademark and other rights reserved by their respective owners
3
+ # Copyright 2008-2021 Neongecko.com Inc.
4
+ # BSD-3
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ # 1. Redistributions of source code must retain the above copyright notice,
8
+ # this list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ # this list of conditions and the following disclaimer in the documentation
11
+ # and/or other materials provided with the distribution.
12
+ # 3. Neither the name of the copyright holder nor the names of its
13
+ # contributors may be used to endorse or promote products derived from this
14
+ # software without specific prior written permission.
15
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
22
+ # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+
27
+ import yaml
28
+
29
+ from os.path import expanduser, isfile, isdir
30
+ from typing import Optional
31
+ from ovos_utils.messagebus import FakeBus
32
+ from ovos_workshop.skills.base import BaseSkill
33
+ from ovos_utils.log import LOG
34
+
35
+
36
+ def get_skill_object(skill_entrypoint: str, bus: FakeBus,
37
+ skill_id: str, config_patch: Optional[dict] = None) -> BaseSkill:
38
+ """
39
+ Get an initialized skill object by entrypoint with the requested skill_id.
40
+ @param skill_entrypoint: Skill plugin entrypoint or directory path
41
+ @param bus: FakeBus instance to bind to skill for testing
42
+ @param skill_id: skill_id to initialize skill with
43
+ @returns: Initialized skill object
44
+ """
45
+ if config_patch:
46
+ from ovos_config.config import update_mycroft_config
47
+ update_mycroft_config(config_patch)
48
+ if isdir(skill_entrypoint):
49
+ LOG.info(f"Loading local skill: {skill_entrypoint}")
50
+ from ovos_workshop.skill_launcher import SkillLoader
51
+ loader = SkillLoader(bus, skill_entrypoint, skill_id)
52
+ if loader.load():
53
+ return loader.instance
54
+ from ovos_plugin_manager.skills import find_skill_plugins
55
+ plugins = find_skill_plugins()
56
+ if skill_entrypoint not in plugins:
57
+ raise ValueError(f"Requested skill not found: {skill_entrypoint}")
58
+ plugin = plugins[skill_entrypoint]
59
+ skill = plugin(bus=bus, skill_id=skill_id)
60
+ return skill
61
+
62
+
63
+ def load_resource_tests(test_file: str) -> dict:
64
+ """
65
+ Load resource tests from a file
66
+ @param test_file: Test file to load
67
+ @returns: Loaded test spec
68
+ """
69
+ test_file = expanduser(test_file)
70
+ if not isfile(test_file):
71
+ raise FileNotFoundError(test_file)
72
+ with open(test_file) as f:
73
+ resources = yaml.safe_load(f)
74
+ return resources
75
+
76
+
77
+ def load_intent_tests(test_file: str) -> dict:
78
+ """
79
+ Load intent tests from a file
80
+ @param test_file: Test file to load
81
+ @returns: Loaded test spec
82
+ """
83
+ test_file = expanduser(test_file)
84
+ if not isfile(test_file):
85
+ raise FileNotFoundError(test_file)
86
+ with open(test_file) as f:
87
+ intents = yaml.safe_load(f)
88
+ return intents
@@ -0,0 +1,25 @@
1
+ # NEON AI (TM) SOFTWARE, Software Development Kit & Application Development System
2
+ # All trademark and other rights reserved by their respective owners
3
+ # Copyright 2008-2021 Neongecko.com Inc.
4
+ # BSD-3
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ # 1. Redistributions of source code must retain the above copyright notice,
8
+ # this list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ # this list of conditions and the following disclaimer in the documentation
11
+ # and/or other materials provided with the distribution.
12
+ # 3. Neither the name of the copyright holder nor the names of its
13
+ # contributors may be used to endorse or promote products derived from this
14
+ # software without specific prior written permission.
15
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
22
+ # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,145 @@
1
+ # NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework
2
+ # All trademark and other rights reserved by their respective owners
3
+ # Copyright 2008-2022 Neongecko.com Inc.
4
+ # Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds,
5
+ # Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo
6
+ # BSD-3 License
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are met:
9
+ # 1. Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ # 3. Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from this
16
+ # software without specific prior written permission.
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24
+ # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ import unittest
30
+
31
+ from os import getenv
32
+ from os.path import join, exists
33
+ from ovos_utils.messagebus import FakeBus
34
+ from ovos_utils.log import LOG
35
+
36
+ from neon_minerva.exceptions import IntentException
37
+ from neon_minerva.skill import get_skill_object, load_intent_tests
38
+ from neon_minerva.intent_services.padatious import PadatiousContainer, TestPadatiousMatcher
39
+ from neon_minerva.intent_services.adapt import AdaptContainer
40
+ from neon_minerva.intent_services.padacioso import PadaciosoContainer
41
+ from neon_minerva.intent_services import IntentMatch
42
+
43
+
44
+ class TestSkillIntentMatching(unittest.TestCase):
45
+ # Static parameters
46
+ bus = FakeBus()
47
+ bus.run_forever()
48
+ test_skill_id = 'test_skill.test'
49
+ padatious_cache = join(getenv("XDG_CACHE_HOME"), "padatious")
50
+
51
+ # Define skill and resource spec to use in tests
52
+ valid_intents = load_intent_tests(getenv("INTENT_TEST_FILE"))
53
+ skill_entrypoint = getenv("TEST_SKILL_ENTRYPOINT")
54
+
55
+ # Populate configuration
56
+ languages = list(valid_intents.keys())
57
+ core_config_patch = {"secondary_langs": languages}
58
+ negative_intents = valid_intents.pop('unmatched intents', dict())
59
+ common_query = valid_intents.pop("common query", dict())
60
+
61
+ # Define intent parsers for tests
62
+ if getenv("TEST_PADACIOSO") == "true":
63
+ container = PadaciosoContainer
64
+ else:
65
+ container = PadatiousContainer
66
+ padatious_services = dict()
67
+ adapt_services = dict()
68
+ for lang in languages:
69
+ padatious_services[lang] = container(lang, join(padatious_cache, lang),
70
+ bus)
71
+ adapt_services[lang] = AdaptContainer(lang, bus)
72
+
73
+ skill = get_skill_object(skill_entrypoint=skill_entrypoint,
74
+ skill_id=test_skill_id, bus=bus,
75
+ config_patch=core_config_patch)
76
+
77
+ @classmethod
78
+ def tearDownClass(cls) -> None:
79
+ import shutil
80
+ for service in cls.padatious_services.values():
81
+ try:
82
+ if exists(service.cache_dir):
83
+ shutil.rmtree(service.cache_dir)
84
+ except Exception as e:
85
+ LOG.exception(e)
86
+
87
+ def test_intents(self):
88
+ for lang in self.valid_intents.keys():
89
+ self.assertIsInstance(lang.split('-')[0], str)
90
+ self.assertIsInstance(lang.split('-')[1], str)
91
+ for intent, examples in self.valid_intents[lang].items():
92
+ # TODO: Better method to determine parser?
93
+ if intent.endswith('.intent'):
94
+ parser = TestPadatiousMatcher(self.padatious_services[lang])
95
+ else:
96
+ parser = self.adapt_services[lang]
97
+
98
+ for utt in examples:
99
+ if isinstance(utt, dict):
100
+ data = list(utt.values())[0]
101
+ utt = list(utt.keys())[0]
102
+ else:
103
+ data = list()
104
+
105
+ match = parser.test_intent(utt)
106
+ self.assertIsInstance(match, IntentMatch)
107
+ self.assertEqual(match.skill_id, self.test_skill_id)
108
+ self.assertEqual(match.intent_type,
109
+ f"{self.test_skill_id}:{intent}")
110
+ self.assertEqual(match.utterance, utt)
111
+
112
+ for datum in data:
113
+ if isinstance(datum, dict):
114
+ name = list(datum.keys())[0]
115
+ value = list(datum.values())[0]
116
+ else:
117
+ name = datum
118
+ value = None
119
+ self.assertIn(name, match.intent_data, utt)
120
+ if value:
121
+ self.assertEqual(match.intent_data[name], value)
122
+
123
+ def test_negative_intents(self):
124
+ config = self.negative_intents.pop('config', {})
125
+ include_med = config.get('include_med', True)
126
+ include_low = config.get('include_low', False)
127
+
128
+ for lang in self.negative_intents.keys():
129
+ adapt = self.adapt_services[lang]
130
+ padatious = TestPadatiousMatcher(self.padatious_services[lang],
131
+ include_med=include_med,
132
+ include_low=include_low)
133
+ for utt in self.negative_intents[lang]:
134
+ with self.assertRaises(IntentException, msg=utt):
135
+ adapt.test_intent(utt)
136
+ with self.assertRaises(IntentException, msg=utt):
137
+ padatious.test_intent(utt)
138
+
139
+ def test_common_query(self):
140
+ # TODO
141
+ pass
142
+
143
+ def test_common_play(self):
144
+ # TODO
145
+ pass
@@ -0,0 +1,144 @@
1
+ # NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework
2
+ # All trademark and other rights reserved by their respective owners
3
+ # Copyright 2008-2022 Neongecko.com Inc.
4
+ # Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds,
5
+ # Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo
6
+ # BSD-3 License
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are met:
9
+ # 1. Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ # 3. Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from this
16
+ # software without specific prior written permission.
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24
+ # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ import unittest
30
+ import os
31
+ import json
32
+
33
+ from os import getenv
34
+ from ovos_utils.messagebus import FakeBus
35
+
36
+ from neon_minerva.skill import get_skill_object, load_resource_tests
37
+
38
+
39
+ class TestSkillResources(unittest.TestCase):
40
+ # Static parameters
41
+ messages = list()
42
+ bus = FakeBus()
43
+ bus.run_forever()
44
+ test_skill_id = 'test_skill.test'
45
+
46
+ # Define skill and resource spec to use in tests
47
+ resources = load_resource_tests(getenv("RESOURCE_TEST_FILE"))
48
+ skill_entrypoint = getenv("TEST_SKILL_ENTRYPOINT")
49
+
50
+ # Specify valid languages to test
51
+ supported_languages = resources['languages']
52
+
53
+ # Specify skill intents as sets
54
+ adapt_intents = set(resources['intents']['adapt'])
55
+ padatious_intents = set(resources['intents']['padatious'])
56
+
57
+ # regex entities, not necessarily filenames
58
+ regex = set(resources['regex'])
59
+ # vocab is lowercase .voc file basenames
60
+ vocab = set(resources['vocab'])
61
+ # dialog is .dialog file basenames (case-sensitive)
62
+ dialog = set(resources['dialog'])
63
+
64
+ core_config_patch = {"secondary_langs": supported_languages}
65
+
66
+ @classmethod
67
+ def setUpClass(cls) -> None:
68
+ cls.bus.on("message", cls._on_message)
69
+
70
+ cls.skill = get_skill_object(skill_entrypoint=cls.skill_entrypoint,
71
+ bus=cls.bus, skill_id=cls.test_skill_id,
72
+ config_patch=cls.core_config_patch)
73
+
74
+ cls.adapt_intents = {f'{cls.test_skill_id}:{intent}'
75
+ for intent in cls.adapt_intents}
76
+ cls.padatious_intents = {f'{cls.test_skill_id}:{intent}'
77
+ for intent in cls.padatious_intents}
78
+
79
+ @classmethod
80
+ def _on_message(cls, message):
81
+ cls.messages.append(json.loads(message))
82
+
83
+ def test_skill_setup(self):
84
+ self.assertEqual(self.skill.skill_id, self.test_skill_id)
85
+ self.assertEqual(set([self.skill._core_lang] +
86
+ self.skill._secondary_langs),
87
+ set(self.supported_languages))
88
+
89
+ def test_intent_registration(self):
90
+ registered_adapt = list()
91
+ registered_padatious = dict()
92
+ registered_vocab = dict()
93
+ registered_regex = dict()
94
+ for msg in self.messages:
95
+ if msg["type"] == "register_intent":
96
+ registered_adapt.append(msg["data"]["name"])
97
+ elif msg["type"] == "padatious:register_intent":
98
+ lang = msg["data"]["lang"]
99
+ registered_padatious.setdefault(lang, list())
100
+ registered_padatious[lang].append(msg["data"]["name"])
101
+ elif msg["type"] == "register_vocab":
102
+ lang = msg["data"]["lang"]
103
+ if msg['data'].get('regex'):
104
+ registered_regex.setdefault(lang, dict())
105
+ regex = msg["data"]["regex"].split(
106
+ '<', 1)[1].split('>', 1)[0].replace(
107
+ self.test_skill_id.replace('.', '_'), '')
108
+ registered_regex[lang].setdefault(regex, list())
109
+ registered_regex[lang][regex].append(msg["data"]["regex"])
110
+ else:
111
+ registered_vocab.setdefault(lang, dict())
112
+ voc_filename = msg["data"]["entity_type"].replace(
113
+ self.test_skill_id.replace('.', '_'), '').lower()
114
+ registered_vocab[lang].setdefault(voc_filename, list())
115
+ registered_vocab[lang][voc_filename].append(
116
+ msg["data"]["entity_value"])
117
+ self.assertEqual(set(registered_adapt), self.adapt_intents,
118
+ registered_adapt)
119
+ for lang in self.supported_languages:
120
+ if self.padatious_intents:
121
+ self.assertEqual(set(registered_padatious[lang]),
122
+ self.padatious_intents,
123
+ registered_padatious[lang])
124
+ if self.vocab:
125
+ self.assertEqual(set(registered_vocab[lang].keys()),
126
+ self.vocab, registered_vocab)
127
+ if self.regex:
128
+ self.assertEqual(set(registered_regex[lang].keys()),
129
+ self.regex, registered_regex)
130
+ for voc in self.vocab:
131
+ # Ensure every vocab file has at least one entry
132
+ self.assertGreater(len(registered_vocab[lang][voc]), 0)
133
+ for rx in self.regex:
134
+ # Ensure every rx file has exactly one entry
135
+ self.assertTrue(all((rx in line for line in
136
+ registered_regex[lang][rx])), self.regex)
137
+
138
+ def test_dialog_files(self):
139
+ for lang in self.supported_languages:
140
+ for dialog in self.dialog:
141
+ file = self.skill.find_resource(f"{dialog}.dialog", "dialog",
142
+ lang)
143
+ self.assertIsInstance(file, str, f"{dialog} in {self.dialog}")
144
+ self.assertTrue(os.path.isfile(file), dialog)
@@ -0,0 +1,29 @@
1
+ # NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework
2
+ # All trademark and other rights reserved by their respective owners
3
+ # Copyright 2008-2022 Neongecko.com Inc.
4
+ # Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds,
5
+ # Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo
6
+ # BSD-3 License
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are met:
9
+ # 1. Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ # 3. Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from this
16
+ # software without specific prior written permission.
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24
+ # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ __version__ = "0.0.1a2"
@@ -0,0 +1,52 @@
1
+ Metadata-Version: 2.1
2
+ Name: neon-minerva
3
+ Version: 0.0.1a2
4
+ Summary: Modular INtelligent Evaluation for a Reliable Voice Assistant
5
+ Home-page: https://github.com/neongeckocom/neon-minerva
6
+ Author: Neongecko
7
+ Author-email: developers@neon.ai
8
+ License: BSD-3-Clause
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.6
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE.md
14
+
15
+ # Neon Minerva
16
+ Neon Minerva (Modular INtelligent Evaluation for a Reliable Voice Assistant)
17
+ provides tools for testing skills.
18
+
19
+ Install the Minerva Python package with: `pip install neon-minerva`
20
+ The `minerva` entrypoint is available to interact with a bus via CLI.
21
+ Help is available via `minerva --help`.
22
+
23
+ ## Installation
24
+ Since skill intents may use Padatious, the following system packages must be
25
+ installed before installing this package:
26
+ ```shell
27
+ sudo apt install swig libfann-dev
28
+ ```
29
+ To install this package from PyPI, simply run:
30
+ ```shell
31
+ pip install neon-minerva
32
+ ```
33
+
34
+ ## Usage
35
+ This package provides a CLI for local testing of skills. Skills installed with
36
+ `pip` can be specified by entrypoint, or skills cloned locally can be specified
37
+ by root directory.
38
+
39
+ ### Resource Tests
40
+ To test that skill resources are defined for all supported languages,
41
+ `minerva test-resources <skill-entrypoint> <test-file>`
42
+ > - <skill-entrypoint\> is the string entrypoint for the skill to test as specified in `setup.py` OR the path to
43
+ the skill's root directory
44
+ > - <test-file\> is a relative or absolute path to the resource test file, usually `test_resources.yaml`
45
+
46
+ ### Intent Tests
47
+ To test that skill intents match as expected for all supported languages,
48
+ `minerva test-intents <skill-entrypoint> <test-file>`
49
+ > - <skill-entrypoint\> is the string entrypoint for the skill to test as specified in `setup.py` OR the path to
50
+ the skill's root directory
51
+ > - <test-file\> is a relative or absolute path to the resource test file, usually `test_intents.yaml`
52
+ > - The `--padacioso` flag can be added to test with Padacioso instead of Padatious for relevant intents
@@ -0,0 +1,21 @@
1
+ LICENSE.md
2
+ README.md
3
+ setup.py
4
+ neon_minerva/__init__.py
5
+ neon_minerva/cli.py
6
+ neon_minerva/exceptions.py
7
+ neon_minerva/skill.py
8
+ neon_minerva/version.py
9
+ neon_minerva.egg-info/PKG-INFO
10
+ neon_minerva.egg-info/SOURCES.txt
11
+ neon_minerva.egg-info/dependency_links.txt
12
+ neon_minerva.egg-info/entry_points.txt
13
+ neon_minerva.egg-info/requires.txt
14
+ neon_minerva.egg-info/top_level.txt
15
+ neon_minerva/intent_services/__init__.py
16
+ neon_minerva/intent_services/adapt.py
17
+ neon_minerva/intent_services/padacioso.py
18
+ neon_minerva/intent_services/padatious.py
19
+ neon_minerva/tests/__init__.py
20
+ neon_minerva/tests/test_skill_intents.py
21
+ neon_minerva/tests/test_skill_resources.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ minerva = neon_minerva.cli:neon_minerva_cli
@@ -0,0 +1,7 @@
1
+ click~=8.0
2
+ click-default-group~=1.2
3
+ ovos-utils~=0.0.35
4
+ ovos-workshop~=0.0.12
5
+ fann2==1.0.7
6
+ padatious~=0.4.8
7
+ padacioso~=0.2
@@ -0,0 +1 @@
1
+ neon_minerva
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,80 @@
1
+ # NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework
2
+ # All trademark and other rights reserved by their respective owners
3
+ # Copyright 2008-2022 Neongecko.com Inc.
4
+ # Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds,
5
+ # Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo
6
+ # BSD-3 License
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are met:
9
+ # 1. Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ # 3. Neither the name of the copyright holder nor the names of its
15
+ # contributors may be used to endorse or promote products derived from this
16
+ # software without specific prior written permission.
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24
+ # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ import setuptools
30
+
31
+ from os import path
32
+
33
+
34
+ BASE_PATH = path.abspath(path.dirname(__file__))
35
+
36
+
37
+ def get_requirements(requirements_filename: str):
38
+ requirements_file = path.join(BASE_PATH, "requirements",
39
+ requirements_filename)
40
+ with open(requirements_file, 'r', encoding='utf-8') as r:
41
+ requirements = r.readlines()
42
+ requirements = [r.strip() for r in requirements if r.strip() and
43
+ not r.strip().startswith("#")]
44
+ return requirements
45
+
46
+
47
+ with open(path.join(BASE_PATH, "README.md"), "r") as f:
48
+ long_description = f.read()
49
+
50
+ with open(path.join(BASE_PATH, "neon_minerva", "version.py"),
51
+ "r", encoding="utf-8") as v:
52
+ for line in v.readlines():
53
+ if line.startswith("__version__"):
54
+ if '"' in line:
55
+ version = line.split('"')[1]
56
+ else:
57
+ version = line.split("'")[1]
58
+
59
+ setuptools.setup(
60
+ name="neon-minerva",
61
+ version=version,
62
+ author='Neongecko',
63
+ author_email='developers@neon.ai',
64
+ license='BSD-3-Clause',
65
+ description="Modular INtelligent Evaluation for a Reliable Voice Assistant",
66
+ long_description=long_description,
67
+ long_description_content_type="text/markdown",
68
+ url="https://github.com/neongeckocom/neon-minerva",
69
+ packages=setuptools.find_packages(),
70
+ include_package_data=True,
71
+ classifiers=[
72
+ "Programming Language :: Python :: 3",
73
+ "Operating System :: OS Independent"
74
+ ],
75
+ python_requires='>=3.6',
76
+ install_requires=get_requirements("requirements.txt"),
77
+ entry_points={
78
+ 'console_scripts': ['minerva=neon_minerva.cli:neon_minerva_cli']
79
+ }
80
+ )