2021-07-27 23:10:01 +02:00
|
|
|
import glob
|
|
|
|
import os
|
2021-08-01 12:21:32 +02:00
|
|
|
import random
|
2021-08-01 19:00:51 +02:00
|
|
|
import threading
|
2021-07-28 19:31:47 +02:00
|
|
|
import types
|
2021-07-27 23:10:01 +02:00
|
|
|
|
2021-08-22 18:44:32 +02:00
|
|
|
from .. import get_path_file
|
|
|
|
from ..skills import intent_manager
|
2021-09-13 22:10:11 +02:00
|
|
|
from ..utils import languages_utils, client_utils, config_utils
|
2021-07-27 23:10:01 +02:00
|
|
|
|
|
|
|
|
|
|
|
class Skill:
|
2021-09-13 22:10:11 +02:00
|
|
|
def __init__(self, name, data, required_config: list = None):
|
|
|
|
if required_config is not None:
|
|
|
|
self.required_config = required_config
|
|
|
|
|
2021-07-27 23:10:01 +02:00
|
|
|
self.name = name
|
2021-07-28 20:35:20 +02:00
|
|
|
|
2021-08-01 11:48:57 +02:00
|
|
|
self.client_ip = data['client_ip']
|
|
|
|
self.client_port = data['client_port']
|
|
|
|
|
2021-07-28 20:35:20 +02:00
|
|
|
path = self.__module__.split(".")
|
|
|
|
self.category = path[2]
|
|
|
|
self.skill_folder = path[3]
|
2021-07-27 23:10:01 +02:00
|
|
|
|
2021-08-01 12:21:32 +02:00
|
|
|
self.path = os.path.dirname(get_path_file.__file__) + "/skills/" + self.category + "/" + self.skill_folder
|
|
|
|
|
2021-09-13 22:10:11 +02:00
|
|
|
if self.has_required_config():
|
|
|
|
self.on_load()
|
|
|
|
|
|
|
|
def on_load(self):
|
|
|
|
pass
|
|
|
|
|
2021-08-01 11:48:57 +02:00
|
|
|
def speak(self, sentence):
|
|
|
|
client_utils.speak(sentence, self.client_ip, self.client_port)
|
|
|
|
|
2021-08-01 17:02:21 +02:00
|
|
|
def speak_dialog(self, dialog, data=None):
|
|
|
|
if data is None:
|
|
|
|
data = {}
|
|
|
|
|
2021-08-01 12:21:32 +02:00
|
|
|
file = self.path + "/dialog/" + languages_utils.get_language() + "/" + dialog + ".dialog"
|
2021-08-02 20:04:28 +02:00
|
|
|
random_line = get_random_line_from_file(file)
|
2021-08-01 12:21:32 +02:00
|
|
|
|
2021-08-02 20:04:28 +02:00
|
|
|
for key, val in data.items():
|
2021-09-14 15:44:46 +02:00
|
|
|
if "{{" + key + "}}" in random_line or "{" + key + "}" in random_line:
|
2021-08-02 20:04:28 +02:00
|
|
|
# TODO: replace when found a better TTS engine for french
|
|
|
|
# as the french tts don't support float in sentence, convert it to an integer
|
|
|
|
if is_float(val):
|
|
|
|
# val = str(int(float(val))) # convert a float to integer
|
|
|
|
val = str(val).split(".")[0] + " virgule " + str(val).split(".")[1]
|
2021-08-01 19:00:51 +02:00
|
|
|
|
2021-09-14 15:44:46 +02:00
|
|
|
random_line = random_line.replace("{{" + key + "}}", val)
|
|
|
|
random_line = random_line.replace("{" + key + "}", val)
|
2021-08-01 12:21:32 +02:00
|
|
|
|
2021-09-14 15:44:46 +02:00
|
|
|
self.speak(random_line)
|
2021-08-01 12:21:32 +02:00
|
|
|
|
|
|
|
return "Error, dialog not found for : " + dialog
|
|
|
|
|
2021-08-01 19:00:51 +02:00
|
|
|
def speak_dialog_threaded(self, dialog, data=None):
|
|
|
|
thread = threading.Thread(target=self.speak_dialog, args=[dialog, data])
|
|
|
|
thread.start()
|
|
|
|
|
2021-07-27 23:10:01 +02:00
|
|
|
def register(self):
|
2021-09-13 22:10:11 +02:00
|
|
|
if self.has_required_config():
|
|
|
|
self.register_entities_adapt()
|
|
|
|
self.register_entities_padatious()
|
|
|
|
self.register_regex()
|
|
|
|
print("[" + self.name + "] Registered entity/entities and regex(s)")
|
|
|
|
else:
|
|
|
|
print("[WARN] Skipped skill " + self.name + " : please check your config.")
|
2021-07-27 23:10:01 +02:00
|
|
|
|
2021-08-02 11:57:16 +02:00
|
|
|
def register_entities_adapt(self):
|
2021-08-01 12:21:32 +02:00
|
|
|
path = self.path + "/vocab/" + languages_utils.get_language() + "/*.voc"
|
2021-07-27 23:10:01 +02:00
|
|
|
|
2021-08-02 20:04:28 +02:00
|
|
|
all_lines_by_file_dict = get_lines_of_all_files_in_path(path, return_as_dict_with_filename=True)
|
2021-07-27 23:10:01 +02:00
|
|
|
|
2021-08-02 20:04:28 +02:00
|
|
|
for filename in all_lines_by_file_dict:
|
|
|
|
for line in all_lines_by_file_dict.get(filename):
|
|
|
|
intent_manager.register_entity_adapt(line, filename, self.name)
|
2021-07-27 23:10:01 +02:00
|
|
|
|
2021-08-02 11:57:16 +02:00
|
|
|
def register_entities_padatious(self):
|
|
|
|
path = self.path + "/vocab/" + languages_utils.get_language() + "/*.entity"
|
|
|
|
|
2021-08-02 20:04:28 +02:00
|
|
|
all_lines_by_file_dict = get_lines_of_all_files_in_path(path, return_as_dict_with_filename=True)
|
2021-08-02 11:57:16 +02:00
|
|
|
|
2021-08-02 20:04:28 +02:00
|
|
|
for filename in all_lines_by_file_dict:
|
|
|
|
intent_manager.register_entity_padatious(filename, all_lines_by_file_dict.get(filename))
|
2021-08-02 11:57:16 +02:00
|
|
|
|
2021-07-27 23:10:01 +02:00
|
|
|
def register_regex(self):
|
2021-08-01 12:21:32 +02:00
|
|
|
path = self.path + "/regex/" + languages_utils.get_language() + "/*.rx"
|
2021-07-27 23:10:01 +02:00
|
|
|
|
2021-08-02 20:04:28 +02:00
|
|
|
result = get_lines_of_all_files_in_path(path)
|
|
|
|
for line in result:
|
|
|
|
intent_manager.register_regex_adapt(line, self.name)
|
|
|
|
|
2021-09-13 22:10:11 +02:00
|
|
|
def has_required_config(self):
|
|
|
|
if hasattr(self, "required_config") and self.required_config is not None:
|
|
|
|
for field in self.required_config:
|
|
|
|
if config_utils.get_in_config(field) is None:
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
2021-08-02 20:04:28 +02:00
|
|
|
|
|
|
|
def get_random_line_from_file(filepath):
|
|
|
|
if os.path.exists(filepath):
|
|
|
|
with open(filepath, "r") as infile:
|
|
|
|
random_line = random.choice(infile.readlines())
|
|
|
|
infile.close()
|
|
|
|
return random_line
|
|
|
|
else:
|
|
|
|
print("File " + filepath + " doesn't exist...")
|
|
|
|
|
|
|
|
|
|
|
|
def get_all_lines_from_file(filepath):
|
|
|
|
if os.path.exists(filepath):
|
|
|
|
with open(file=filepath, mode="r") as infile:
|
|
|
|
lines = []
|
|
|
|
|
|
|
|
for line in infile.readlines():
|
|
|
|
lines.append(line.removesuffix('\n'))
|
|
|
|
|
|
|
|
infile.close()
|
|
|
|
|
|
|
|
return lines
|
|
|
|
else:
|
|
|
|
print("File " + filepath + " doesn't exist...")
|
|
|
|
|
|
|
|
|
|
|
|
def get_lines_of_all_files_in_path(path, return_as_dict_with_filename=False):
|
|
|
|
files = glob.glob(path, recursive=True)
|
|
|
|
result = dict()
|
|
|
|
result_list = []
|
|
|
|
|
|
|
|
for file in files:
|
|
|
|
lines = get_all_lines_from_file(file)
|
|
|
|
|
|
|
|
if return_as_dict_with_filename:
|
|
|
|
filename = file.split("/")[-1].split('.')[0]
|
|
|
|
result[filename] = lines
|
|
|
|
else:
|
|
|
|
result_list.extend(lines)
|
|
|
|
|
|
|
|
if return_as_dict_with_filename:
|
|
|
|
return result
|
|
|
|
|
|
|
|
return result_list
|
2021-07-29 20:16:22 +02:00
|
|
|
|
|
|
|
|
|
|
|
def get_array_for_intent_file(filename, category, skill_folder):
|
|
|
|
path = os.path.dirname(get_path_file.__file__) + "/skills/" + category + "/" + skill_folder
|
|
|
|
path = path + "/vocab/" + languages_utils.get_language() + "/" + filename
|
|
|
|
|
2021-08-02 20:04:28 +02:00
|
|
|
return get_all_lines_from_file(path)
|
2021-07-28 18:05:34 +02:00
|
|
|
|
2021-07-28 19:31:47 +02:00
|
|
|
|
2021-08-01 19:00:51 +02:00
|
|
|
def is_float(value):
|
|
|
|
try:
|
|
|
|
float(value)
|
|
|
|
return True
|
|
|
|
except ValueError:
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
2021-07-28 19:31:47 +02:00
|
|
|
class SkillRegistering(type):
|
|
|
|
def __init__(cls, name, bases, attrs):
|
|
|
|
for key, val in attrs.items():
|
|
|
|
if type(val) is types.FunctionType and not str(val).__contains__("__"):
|
2021-07-29 20:16:22 +02:00
|
|
|
intent_type = getattr(val, "_type", None)
|
2021-07-29 14:57:55 +02:00
|
|
|
|
2021-07-29 20:16:22 +02:00
|
|
|
if intent_type is not None:
|
2021-07-29 14:57:55 +02:00
|
|
|
properties = getattr(val, "_data", None)
|
|
|
|
|
|
|
|
if properties is not None:
|
2021-07-29 20:16:22 +02:00
|
|
|
if intent_type == 'adapt':
|
2021-07-29 14:57:55 +02:00
|
|
|
intent = properties[0]
|
|
|
|
intent_name = intent.name
|
2021-07-30 12:31:59 +02:00
|
|
|
|
|
|
|
intent_manager.intents_handlers_adapt[f"{intent_name}"] = [getattr(cls, key), name, key,
|
|
|
|
attrs['__module__']]
|
2021-07-29 20:16:22 +02:00
|
|
|
elif intent_type == 'padatious':
|
2021-07-29 14:57:55 +02:00
|
|
|
intent_file = properties[0]
|
2021-07-29 20:16:22 +02:00
|
|
|
intent_name = properties[1]
|
|
|
|
|
|
|
|
intent_category = str(attrs['__module__']).split('.')[2]
|
|
|
|
skill_folder = str(attrs['__module__']).split('.')[3]
|
|
|
|
|
2021-07-30 12:31:59 +02:00
|
|
|
intent_manager.intents_handlers_padatious[f"{intent_name}"] = [key,
|
2021-07-29 20:16:22 +02:00
|
|
|
get_array_for_intent_file(
|
|
|
|
intent_file,
|
|
|
|
intent_category,
|
2021-07-30 12:31:59 +02:00
|
|
|
skill_folder),
|
|
|
|
attrs['__module__']]
|