Merge pull request #2009 from MycroftAI/bugfix/voc-match
Fix behavior of MycroftSkills.voc_match()pull/2017/head
commit
faf29d1fef
|
@ -26,6 +26,7 @@ from datetime import datetime, timedelta
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
import re
|
import re
|
||||||
|
from itertools import chain
|
||||||
from adapt.intent import Intent, IntentBuilder
|
from adapt.intent import Intent, IntentBuilder
|
||||||
from os.path import join, abspath, dirname, basename, exists
|
from os.path import join, abspath, dirname, basename, exists
|
||||||
from threading import Event, Timer
|
from threading import Event, Timer
|
||||||
|
@ -41,7 +42,8 @@ from mycroft.messagebus.message import Message
|
||||||
from mycroft.metrics import report_metric, report_timing, Stopwatch
|
from mycroft.metrics import report_metric, report_timing, Stopwatch
|
||||||
from mycroft.skills.settings import SkillSettings
|
from mycroft.skills.settings import SkillSettings
|
||||||
from mycroft.skills.skill_data import (load_vocabulary, load_regex, to_alnum,
|
from mycroft.skills.skill_data import (load_vocabulary, load_regex, to_alnum,
|
||||||
munge_regex, munge_intent_parser)
|
munge_regex, munge_intent_parser,
|
||||||
|
read_vocab_file)
|
||||||
from mycroft.util import camel_case_split, resolve_resource_file
|
from mycroft.util import camel_case_split, resolve_resource_file
|
||||||
from mycroft.util.log import LOG
|
from mycroft.util.log import LOG
|
||||||
|
|
||||||
|
@ -716,15 +718,15 @@ class MycroftSkill:
|
||||||
if not voc or not exists(voc):
|
if not voc or not exists(voc):
|
||||||
raise FileNotFoundError(
|
raise FileNotFoundError(
|
||||||
'Could not find {}.voc file'.format(voc_filename))
|
'Could not find {}.voc file'.format(voc_filename))
|
||||||
|
# load vocab and flatten into a simple list
|
||||||
with open(voc) as f:
|
vocab = list(chain(*read_vocab_file(voc)))
|
||||||
self.voc_match_cache[cache_key] = f.read().splitlines()
|
self.voc_match_cache[cache_key] = vocab
|
||||||
|
if utt:
|
||||||
# Check for match
|
# Check for matches against complete words
|
||||||
if utt and any(i.strip() in utt
|
return any([re.match(r'.*\b' + i + r'\b.*', utt)
|
||||||
for i in self.voc_match_cache[cache_key]):
|
for i in self.voc_match_cache[cache_key]])
|
||||||
return True
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def report_metric(self, name, data):
|
def report_metric(self, name, data):
|
||||||
""" Report a skill metric to the Mycroft servers
|
""" Report a skill metric to the Mycroft servers
|
||||||
|
|
|
@ -25,6 +25,28 @@ from mycroft.messagebus.message import Message
|
||||||
from mycroft.util.format import expand_options
|
from mycroft.util.format import expand_options
|
||||||
|
|
||||||
|
|
||||||
|
def read_vocab_file(path):
|
||||||
|
""" Read voc file.
|
||||||
|
|
||||||
|
This reads a .voc file, stripping out empty lines comments and expand
|
||||||
|
parentheses. It retruns each line as a list of all expanded
|
||||||
|
alternatives.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
path (str): path to vocab file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of Lists of strings.
|
||||||
|
"""
|
||||||
|
vocab = []
|
||||||
|
with open(path, 'r', encoding='utf8') as voc_file:
|
||||||
|
for line in voc_file.readlines():
|
||||||
|
if line.startswith('#') or line.strip() == '':
|
||||||
|
continue
|
||||||
|
vocab.append(expand_options(line))
|
||||||
|
return vocab
|
||||||
|
|
||||||
|
|
||||||
def load_vocab_from_file(path, vocab_type, bus):
|
def load_vocab_from_file(path, vocab_type, bus):
|
||||||
"""Load Mycroft vocabulary from file
|
"""Load Mycroft vocabulary from file
|
||||||
The vocab is sent to the intent handler using the message bus
|
The vocab is sent to the intent handler using the message bus
|
||||||
|
@ -36,19 +58,15 @@ def load_vocab_from_file(path, vocab_type, bus):
|
||||||
skill_id(str): skill id
|
skill_id(str): skill id
|
||||||
"""
|
"""
|
||||||
if path.endswith('.voc'):
|
if path.endswith('.voc'):
|
||||||
with open(path, 'r', encoding='utf8') as voc_file:
|
for parts in read_vocab_file(path):
|
||||||
for line in voc_file.readlines():
|
entity = parts[0]
|
||||||
if line.startswith("#"):
|
bus.emit(Message("register_vocab", {
|
||||||
continue
|
'start': entity, 'end': vocab_type
|
||||||
parts = expand_options(line)
|
}))
|
||||||
entity = parts[0]
|
for alias in parts[1:]:
|
||||||
bus.emit(Message("register_vocab", {
|
bus.emit(Message("register_vocab", {
|
||||||
'start': entity, 'end': vocab_type
|
'start': alias, 'end': vocab_type, 'alias_of': entity
|
||||||
}))
|
}))
|
||||||
for alias in parts[1:]:
|
|
||||||
bus.emit(Message("register_vocab", {
|
|
||||||
'start': alias, 'end': vocab_type, 'alias_of': entity
|
|
||||||
}))
|
|
||||||
|
|
||||||
|
|
||||||
def load_regex_from_file(path, bus, skill_id):
|
def load_regex_from_file(path, bus, skill_id):
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
(turn off|switch off)
|
|
@ -0,0 +1,3 @@
|
||||||
|
turn off
|
||||||
|
switch off
|
||||||
|
|
|
@ -484,6 +484,28 @@ class MycroftSkillTest(unittest.TestCase):
|
||||||
# handler
|
# handler
|
||||||
self.assertTrue('A:sched_handler1' not in [e[0] for e in s.events])
|
self.assertTrue('A:sched_handler1' not in [e[0] for e in s.events])
|
||||||
|
|
||||||
|
def test_voc_match(self):
|
||||||
|
s = SimpleSkill1()
|
||||||
|
s.root_dir = abspath(dirname(__file__))
|
||||||
|
|
||||||
|
self.assertTrue(s.voc_match("turn off the lights", "turn_off_test"))
|
||||||
|
self.assertTrue(s.voc_match("would you please turn off the lights",
|
||||||
|
"turn_off_test"))
|
||||||
|
self.assertFalse(s.voc_match("return office", "turn_off_test"))
|
||||||
|
self.assertTrue(s.voc_match("switch off the lights", "turn_off_test"))
|
||||||
|
self.assertFalse(s.voc_match("", "turn_off_test"))
|
||||||
|
self.assertFalse(s.voc_match("switch", "turn_off_test"))
|
||||||
|
self.assertFalse(s.voc_match("My hovercraft is full of eels",
|
||||||
|
"turn_off_test"))
|
||||||
|
|
||||||
|
self.assertTrue(s.voc_match("turn off the lights", "turn_off2_test"))
|
||||||
|
self.assertFalse(s.voc_match("return office", "turn_off2_test"))
|
||||||
|
self.assertTrue(s.voc_match("switch off the lights", "turn_off2_test"))
|
||||||
|
self.assertFalse(s.voc_match("", "turn_off_test"))
|
||||||
|
self.assertFalse(s.voc_match("switch", "turn_off_test"))
|
||||||
|
self.assertFalse(s.voc_match("My hovercraft is full of eels",
|
||||||
|
"turn_off_test"))
|
||||||
|
|
||||||
|
|
||||||
class _TestSkill(MycroftSkill):
|
class _TestSkill(MycroftSkill):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
Loading…
Reference in New Issue