2021-12-14 12:51:47 +03:00
|
|
|
import os
|
|
|
|
|
import traceback
|
2022-05-12 00:51:12 +03:00
|
|
|
import hashlib
|
2021-12-14 12:51:47 +03:00
|
|
|
|
2022-05-12 18:45:20 +03:00
|
|
|
from termcolor import colored, cprint
|
2021-12-14 12:51:47 +03:00
|
|
|
import time
|
2022-03-18 12:04:28 +03:00
|
|
|
from threading import Timer
|
2021-12-14 12:51:47 +03:00
|
|
|
|
2023-01-24 18:00:12 +03:00
|
|
|
from typing import Dict
|
|
|
|
|
|
2021-12-14 12:51:47 +03:00
|
|
|
from jaa import JaaCore
|
|
|
|
|
|
2023-01-24 18:00:12 +03:00
|
|
|
from collections.abc import Callable
|
|
|
|
|
|
2023-03-16 10:11:40 +03:00
|
|
|
version = "7.7"
|
2022-03-18 12:04:28 +03:00
|
|
|
|
|
|
|
|
# main VACore class
|
2021-12-14 12:51:47 +03:00
|
|
|
|
2021-12-15 12:53:52 +03:00
|
|
|
class VACore(JaaCore):
|
2021-12-14 12:51:47 +03:00
|
|
|
def __init__(self):
|
|
|
|
|
JaaCore.__init__(self)
|
|
|
|
|
|
|
|
|
|
self.timers = [-1,-1,-1,-1,-1,-1,-1,-1]
|
|
|
|
|
self.timersFuncUpd = [None,None,None,None,None,None,None,None]
|
|
|
|
|
self.timersFuncEnd = [None,None,None,None,None,None,None,None]
|
|
|
|
|
self.timersDuration = [0,0,0,0,0,0,0,0]
|
|
|
|
|
|
|
|
|
|
self.commands = {
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-11 22:28:55 +03:00
|
|
|
self.plugin_commands = {
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-14 12:51:47 +03:00
|
|
|
self.ttss = {
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-18 11:30:37 +03:00
|
|
|
self.playwavs = {
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-24 18:00:12 +03:00
|
|
|
self.fuzzy_processors: Dict[str, tuple[Callable,Callable]] = {
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-14 12:51:47 +03:00
|
|
|
# more options
|
|
|
|
|
self.mpcHcPath = ""
|
|
|
|
|
self.mpcIsUse = False
|
|
|
|
|
self.mpcIsUseHttpRemote = False
|
|
|
|
|
|
|
|
|
|
self.isOnline = False
|
|
|
|
|
self.version = version
|
|
|
|
|
|
|
|
|
|
self.voiceAssNames = []
|
|
|
|
|
|
2022-05-12 00:51:12 +03:00
|
|
|
self.useTTSCache = False
|
|
|
|
|
self.tts_cache_dir = "tts_cache"
|
2021-12-14 12:51:47 +03:00
|
|
|
self.ttsEngineId = ""
|
2022-04-17 11:11:22 +03:00
|
|
|
self.ttsEngineId2 = ""
|
2022-04-18 11:30:37 +03:00
|
|
|
self.playWavEngineId = ""
|
2021-12-14 12:51:47 +03:00
|
|
|
|
|
|
|
|
self.logPolicy = ""
|
2022-02-07 22:20:48 +03:00
|
|
|
self.tmpdir = "temp"
|
|
|
|
|
self.tmpcnt = 0
|
2021-12-14 12:51:47 +03:00
|
|
|
|
2022-02-08 00:35:31 +03:00
|
|
|
self.lastSay = ""
|
|
|
|
|
self.remoteTTS = "none"
|
|
|
|
|
self.remoteTTSResult = None
|
|
|
|
|
|
2022-03-18 12:04:28 +03:00
|
|
|
self.context = None
|
|
|
|
|
self.contextTimer = None
|
|
|
|
|
self.contextTimerLastDuration = 0
|
|
|
|
|
|
2022-05-12 19:53:31 +03:00
|
|
|
self.contextDefaultDuration = 10
|
|
|
|
|
self.contextRemoteWaitForCall = False
|
|
|
|
|
|
2021-12-14 12:51:47 +03:00
|
|
|
import mpcapi.core
|
|
|
|
|
self.mpchc = mpcapi.core.MpcAPI()
|
|
|
|
|
|
2023-01-25 11:03:09 +03:00
|
|
|
self.cur_callname:str = ""
|
|
|
|
|
|
2022-02-07 22:20:48 +03:00
|
|
|
|
|
|
|
|
|
2021-12-14 12:51:47 +03:00
|
|
|
def init_with_plugins(self):
|
|
|
|
|
self.init_plugins(["core"])
|
2022-05-11 22:28:55 +03:00
|
|
|
self.display_init_info()
|
2021-12-14 12:51:47 +03:00
|
|
|
|
|
|
|
|
self.setup_assistant_voice()
|
|
|
|
|
|
|
|
|
|
# ----------- process plugins functions ------
|
|
|
|
|
def process_plugin_manifest(self,modname,manifest):
|
|
|
|
|
# is req online?
|
|
|
|
|
plugin_req_online = True
|
|
|
|
|
if "require_online" in manifest:
|
|
|
|
|
plugin_req_online = manifest["require_online"]
|
|
|
|
|
|
|
|
|
|
# adding commands from plugin manifest
|
|
|
|
|
if "commands" in manifest: # process commands
|
|
|
|
|
for cmd in manifest["commands"].keys():
|
|
|
|
|
if not self.isOnline and plugin_req_online:
|
|
|
|
|
# special processing
|
|
|
|
|
self.commands[cmd] = self.stub_online_required
|
|
|
|
|
else:
|
|
|
|
|
# normal add command
|
|
|
|
|
self.commands[cmd] = manifest["commands"][cmd]
|
|
|
|
|
|
2022-05-11 22:28:55 +03:00
|
|
|
if modname in self.plugin_commands:
|
|
|
|
|
self.plugin_commands[modname].append(cmd)
|
|
|
|
|
else:
|
|
|
|
|
self.plugin_commands[modname] = [cmd]
|
|
|
|
|
|
2021-12-14 12:51:47 +03:00
|
|
|
# adding tts engines from plugin manifest
|
|
|
|
|
if "tts" in manifest: # process commands
|
|
|
|
|
for cmd in manifest["tts"].keys():
|
|
|
|
|
self.ttss[cmd] = manifest["tts"][cmd]
|
|
|
|
|
|
2022-04-18 11:30:37 +03:00
|
|
|
# adding playwav engines from plugin manifest
|
|
|
|
|
if "playwav" in manifest: # process commands
|
|
|
|
|
for cmd in manifest["playwav"].keys():
|
|
|
|
|
self.playwavs[cmd] = manifest["playwav"][cmd]
|
|
|
|
|
|
2023-01-24 18:00:12 +03:00
|
|
|
# adding fuzzy processors engines from plugin manifest
|
|
|
|
|
if "fuzzy_processor" in manifest: # process commands
|
|
|
|
|
for cmd in manifest["fuzzy_processor"].keys():
|
|
|
|
|
self.fuzzy_processors[cmd] = manifest["fuzzy_processor"][cmd]
|
|
|
|
|
|
2021-12-14 12:51:47 +03:00
|
|
|
def stub_online_required(self,core,phrase):
|
2022-02-05 15:18:44 +03:00
|
|
|
self.play_voice_assistant_speech(self.plugin_options("core")["replyOnlineRequired"])
|
2021-12-14 12:51:47 +03:00
|
|
|
|
2022-06-16 23:44:58 +03:00
|
|
|
def print_error(self,err_txt,e:Exception = None):
|
|
|
|
|
cprint(err_txt,"red")
|
|
|
|
|
# if e != None:
|
|
|
|
|
# cprint(e,"red")
|
|
|
|
|
import traceback
|
|
|
|
|
traceback.print_exc()
|
|
|
|
|
|
|
|
|
|
def print_red(self,txt):
|
|
|
|
|
cprint(txt,"red")
|
|
|
|
|
|
2021-12-14 12:51:47 +03:00
|
|
|
# ----------- text-to-speech functions ------
|
|
|
|
|
|
|
|
|
|
def setup_assistant_voice(self):
|
2022-04-18 11:30:37 +03:00
|
|
|
# init playwav engine
|
2022-06-16 23:44:58 +03:00
|
|
|
try:
|
|
|
|
|
self.playwavs[self.playWavEngineId][0](self)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
self.print_error("Ошибка инициализации плагина проигрывания WAV (playWavEngineId)", e)
|
|
|
|
|
self.print_red('Попробуйте установить в options/core.json: "playWavEngineId": "sounddevice"')
|
2022-06-16 23:51:45 +03:00
|
|
|
self.print_red('...временно переключаюсь на консольный вывод ответа...')
|
|
|
|
|
self.ttsEngineId = "console"
|
2022-04-18 11:30:37 +03:00
|
|
|
|
|
|
|
|
# init tts engine
|
2022-06-16 23:44:58 +03:00
|
|
|
try:
|
|
|
|
|
self.ttss[self.ttsEngineId][0](self)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
self.print_error("Ошибка инициализации плагина TTS (ttsEngineId)", e)
|
|
|
|
|
cprint('Попробуйте установить в options/core.json: "ttsEngineId": "console" для тестирования вывода через консоль', "red")
|
|
|
|
|
cprint('Позднее, если все заработает, вы сможете настроить свой TTS-движок', "red")
|
|
|
|
|
|
|
|
|
|
from sys import platform
|
|
|
|
|
if platform == "linux" or platform == "linux2":
|
|
|
|
|
cprint("Подробнее об установке на Linux: https://github.com/janvarev/Irene-Voice-Assistant/blob/master/docs/INSTALL_LINUX.md", "red")
|
|
|
|
|
elif platform == "darwin":
|
|
|
|
|
cprint("Подробнее об установке на Mac: https://github.com/janvarev/Irene-Voice-Assistant/blob/master/docs/INSTALL_MAC.md", "red")
|
|
|
|
|
elif platform == "win32":
|
2022-06-16 23:55:33 +03:00
|
|
|
#cprint("Подробнее об установке на Linux: https://github.com/janvarev/Irene-Voice-Assistant/blob/master/docs/INSTALL_LINUX.md", "red")
|
2022-06-16 23:44:58 +03:00
|
|
|
pass
|
2022-04-18 11:30:37 +03:00
|
|
|
|
2022-06-16 23:51:45 +03:00
|
|
|
self.print_red('...временно переключаюсь на консольный вывод ответа...')
|
|
|
|
|
self.ttsEngineId = "console"
|
|
|
|
|
|
2022-04-18 11:30:37 +03:00
|
|
|
# init tts2 engine
|
2022-04-17 11:11:22 +03:00
|
|
|
if self.ttsEngineId2 == "":
|
|
|
|
|
self.ttsEngineId2 = self.ttsEngineId
|
|
|
|
|
if self.ttsEngineId2 != self.ttsEngineId:
|
2022-06-16 23:44:58 +03:00
|
|
|
try:
|
|
|
|
|
self.ttss[self.ttsEngineId2][0](self)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
self.print_error("Ошибка инициализации плагина TTS2 (ttsEngineId2)", e)
|
2021-12-14 12:51:47 +03:00
|
|
|
|
2023-01-24 18:00:12 +03:00
|
|
|
# init all fuzzy_processors
|
|
|
|
|
for k in self.fuzzy_processors.keys():
|
|
|
|
|
try:
|
|
|
|
|
self.fuzzy_processors[k][0](self)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
self.print_error("Ошибка инициализации fuzzy_processor {0}".format(k), e)
|
|
|
|
|
|
2021-12-14 12:51:47 +03:00
|
|
|
def play_voice_assistant_speech(self,text_to_speech:str):
|
2022-02-08 00:35:31 +03:00
|
|
|
self.lastSay = text_to_speech
|
2022-03-19 11:58:45 +03:00
|
|
|
remoteTTSList = self.remoteTTS.split(",")
|
|
|
|
|
|
|
|
|
|
self.remoteTTSResult = {}
|
2023-03-02 11:33:58 +03:00
|
|
|
is_processed = False
|
2022-03-19 11:58:45 +03:00
|
|
|
if "none" in remoteTTSList: # no remote tts, do locally anything
|
|
|
|
|
#self.remoteTTSResult = "" # anywhere, set it ""
|
2022-02-08 00:35:31 +03:00
|
|
|
|
|
|
|
|
if self.ttss[self.ttsEngineId][1] != None:
|
|
|
|
|
self.ttss[self.ttsEngineId][1](self,text_to_speech)
|
|
|
|
|
else:
|
2022-05-12 00:51:12 +03:00
|
|
|
if self.useTTSCache:
|
|
|
|
|
tts_file = self.get_tts_cache_file(text_to_speech)
|
|
|
|
|
else:
|
|
|
|
|
tts_file = self.get_tempfilename()+".wav"
|
|
|
|
|
|
|
|
|
|
#print('Temp TTS filename: ', tts_file)
|
|
|
|
|
if not self.useTTSCache or self.useTTSCache and not os.path.exists(tts_file):
|
|
|
|
|
self.tts_to_filewav(text_to_speech, tts_file)
|
|
|
|
|
|
|
|
|
|
self.play_wav(tts_file)
|
|
|
|
|
if not self.useTTSCache and os.path.exists(tts_file):
|
|
|
|
|
os.unlink(tts_file)
|
2022-02-08 00:35:31 +03:00
|
|
|
|
2023-03-02 11:33:58 +03:00
|
|
|
is_processed = True
|
|
|
|
|
|
2022-03-19 11:58:45 +03:00
|
|
|
if "saytxt" in remoteTTSList: # return only last say txt
|
|
|
|
|
self.remoteTTSResult["restxt"] = text_to_speech
|
2022-02-08 00:35:31 +03:00
|
|
|
|
2023-03-02 11:33:58 +03:00
|
|
|
is_processed = True
|
|
|
|
|
|
2022-03-19 11:58:45 +03:00
|
|
|
if "saywav" in remoteTTSList:
|
2022-05-12 00:51:12 +03:00
|
|
|
if self.useTTSCache:
|
|
|
|
|
tts_file = self.get_tts_cache_file(text_to_speech)
|
|
|
|
|
else:
|
|
|
|
|
tts_file = self.get_tempfilename()+".wav"
|
2022-02-08 00:35:31 +03:00
|
|
|
|
2022-05-12 00:51:12 +03:00
|
|
|
if not self.useTTSCache or self.useTTSCache and not os.path.exists(tts_file):
|
|
|
|
|
self.tts_to_filewav(text_to_speech, tts_file)
|
|
|
|
|
#self.play_wav(tts_file)
|
2022-02-08 00:35:31 +03:00
|
|
|
import base64
|
|
|
|
|
|
2022-05-12 00:51:12 +03:00
|
|
|
with open(tts_file, "rb") as wav_file:
|
2022-02-08 00:35:31 +03:00
|
|
|
encoded_string = base64.b64encode(wav_file.read())
|
|
|
|
|
|
2022-05-12 00:51:12 +03:00
|
|
|
if not self.useTTSCache and os.path.exists(tts_file):
|
|
|
|
|
os.unlink(tts_file)
|
2021-12-14 12:51:47 +03:00
|
|
|
|
2022-05-25 15:23:15 +03:00
|
|
|
self.remoteTTSResult["wav_base64"] = encoded_string
|
2022-02-08 00:35:31 +03:00
|
|
|
|
2023-03-02 11:33:58 +03:00
|
|
|
is_processed = True
|
|
|
|
|
|
|
|
|
|
if not is_processed:
|
|
|
|
|
print("Ошибка при выводе TTS - remoteTTS не был обработан.")
|
|
|
|
|
print("Текущий remoteTTS: {}".format(self.remoteTTS))
|
|
|
|
|
print("Текущий remoteTTSList: {}".format(remoteTTSList))
|
|
|
|
|
print("Ожидаемый remoteTTS (например): 'none'")
|
|
|
|
|
|
|
|
|
|
|
2022-02-08 00:35:31 +03:00
|
|
|
|
2021-12-14 12:51:47 +03:00
|
|
|
def say(self,text_to_speech:str): # alias for play_voice_assistant_speech
|
|
|
|
|
self.play_voice_assistant_speech(text_to_speech)
|
|
|
|
|
|
2022-04-17 11:11:22 +03:00
|
|
|
def say2(self,text_to_speech:str): # озвучивает через второй движок
|
|
|
|
|
if self.ttss[self.ttsEngineId2][1] != None:
|
|
|
|
|
self.ttss[self.ttsEngineId2][1](self,text_to_speech)
|
|
|
|
|
else:
|
|
|
|
|
tempfilename = self.get_tempfilename()+".wav"
|
|
|
|
|
#print('Temp TTS filename: ', tempfilename)
|
|
|
|
|
self.tts_to_filewav2(text_to_speech,tempfilename)
|
|
|
|
|
self.play_wav(tempfilename)
|
|
|
|
|
if os.path.exists(tempfilename):
|
|
|
|
|
os.unlink(tempfilename)
|
|
|
|
|
|
|
|
|
|
|
2022-02-07 22:20:48 +03:00
|
|
|
def tts_to_filewav(self,text_to_speech:str,filename:str):
|
|
|
|
|
if len(self.ttss[self.ttsEngineId]) > 2:
|
|
|
|
|
self.ttss[self.ttsEngineId][2](self,text_to_speech,filename)
|
|
|
|
|
else:
|
|
|
|
|
print("File save not supported by this TTS")
|
2022-04-17 11:11:22 +03:00
|
|
|
|
|
|
|
|
def tts_to_filewav2(self,text_to_speech:str,filename:str): # через второй движок
|
|
|
|
|
if len(self.ttss[self.ttsEngineId2]) > 2:
|
|
|
|
|
self.ttss[self.ttsEngineId2][2](self,text_to_speech,filename)
|
|
|
|
|
else:
|
|
|
|
|
print("File save not supported by this TTS")
|
2022-02-07 22:20:48 +03:00
|
|
|
|
|
|
|
|
def get_tempfilename(self):
|
|
|
|
|
self.tmpcnt += 1
|
|
|
|
|
return self.tmpdir+"/vacore_"+str(self.tmpcnt)
|
2021-12-14 12:51:47 +03:00
|
|
|
|
2022-05-12 00:51:12 +03:00
|
|
|
def get_tts_cache_file(self, text_to_speech:str):
|
|
|
|
|
hash = hashlib.md5(text_to_speech.encode('utf-8')).hexdigest()
|
2022-05-12 15:23:09 +03:00
|
|
|
text_slice = text_to_speech[:40]
|
2022-05-12 15:34:16 +03:00
|
|
|
filename = ".".join([text_slice, hash, "wav"])
|
|
|
|
|
return self.tts_cache_dir+"/"+self.ttsEngineId+"/"+filename
|
2022-05-12 00:51:12 +03:00
|
|
|
|
2022-04-18 12:55:33 +03:00
|
|
|
def all_num_to_text(self,text:str):
|
|
|
|
|
from utils.all_num_to_text import all_num_to_text
|
|
|
|
|
return all_num_to_text(text)
|
|
|
|
|
|
2022-02-05 15:18:44 +03:00
|
|
|
# -------- main function ----------
|
2021-12-14 12:51:47 +03:00
|
|
|
|
|
|
|
|
def execute_next(self,command,context):
|
|
|
|
|
if context == None:
|
|
|
|
|
context = self.commands
|
|
|
|
|
|
|
|
|
|
if isinstance(context,dict):
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
# it is function to call!
|
|
|
|
|
#context(self,command)
|
2022-03-18 12:04:28 +03:00
|
|
|
self.context_clear()
|
2021-12-14 12:51:47 +03:00
|
|
|
self.call_ext_func_phrase(command,context)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
try:
|
2022-03-18 12:04:28 +03:00
|
|
|
# первый проход - ищем полное совпадение
|
|
|
|
|
for keyall in context.keys():
|
|
|
|
|
keys = keyall.split("|")
|
|
|
|
|
for key in keys:
|
|
|
|
|
if command == key:
|
|
|
|
|
rest_phrase = ""
|
|
|
|
|
next_context = context[keyall]
|
|
|
|
|
self.execute_next(rest_phrase,next_context)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# второй проход - ищем частичное совпадение
|
2021-12-14 12:51:47 +03:00
|
|
|
for keyall in context.keys():
|
|
|
|
|
keys = keyall.split("|")
|
|
|
|
|
for key in keys:
|
|
|
|
|
if command.startswith(key):
|
|
|
|
|
rest_phrase = command[(len(key)+1):]
|
|
|
|
|
next_context = context[keyall]
|
|
|
|
|
self.execute_next(rest_phrase,next_context)
|
|
|
|
|
return
|
2022-03-18 12:04:28 +03:00
|
|
|
|
2023-01-24 18:00:12 +03:00
|
|
|
# третий проход - ищем с помощью fuzzy_processors
|
|
|
|
|
# TODO: по хорошему надо пробежаться по всем процессорам, и выдать лучший результат,
|
|
|
|
|
# но пока берется просто первый прошедший пороговое значение
|
|
|
|
|
for fuzzy_processor_k in self.fuzzy_processors.keys():
|
|
|
|
|
res = self.fuzzy_processors[fuzzy_processor_k][1](self,command,context)
|
|
|
|
|
|
|
|
|
|
# fuzzy processor должен вернуть либо None либо
|
|
|
|
|
# (context_key:str,уверенность:float[0:1],rest_phrase:str) для лучшей фразы
|
|
|
|
|
print("Fuzzy processor {0}, result for '{1}': {2}".format(fuzzy_processor_k, command, res))
|
|
|
|
|
|
|
|
|
|
if res is not None:
|
|
|
|
|
keyall, probability, rest_phrase = res
|
|
|
|
|
if self.plugin_options("core")["fuzzyThreshold"] < probability:
|
|
|
|
|
next_context = context[keyall]
|
|
|
|
|
self.execute_next(rest_phrase, next_context)
|
2023-01-24 18:28:15 +03:00
|
|
|
return
|
2021-12-14 12:51:47 +03:00
|
|
|
|
|
|
|
|
# if not founded
|
2022-03-18 12:04:28 +03:00
|
|
|
if self.context == None:
|
|
|
|
|
# no context
|
|
|
|
|
self.say(self.plugin_options("core")["replyNoCommandFound"])
|
|
|
|
|
else:
|
|
|
|
|
# in context
|
|
|
|
|
self.say(self.plugin_options("core")["replyNoCommandFoundInContext"])
|
|
|
|
|
# restart timer for context
|
|
|
|
|
if self.contextTimer != None:
|
|
|
|
|
self.context_set(self.context,self.contextTimerLastDuration)
|
2021-12-14 12:51:47 +03:00
|
|
|
except Exception as err:
|
|
|
|
|
print(traceback.format_exc())
|
|
|
|
|
|
2023-01-27 16:19:27 +03:00
|
|
|
# fuzzy util
|
|
|
|
|
def fuzzy_get_command_key_from_context(self, predicted_command:str, context:dict):
|
|
|
|
|
# возвращает ключ в context по одной из распознанных команд внутри
|
|
|
|
|
# нужно для fuzzy, так как одним из возвратов должен быть КЛЮЧ в контексте, а не команда
|
|
|
|
|
for keyall in context.keys():
|
|
|
|
|
for key in keyall.split("|"):
|
|
|
|
|
if key == predicted_command:
|
|
|
|
|
return keyall
|
|
|
|
|
return None
|
|
|
|
|
|
2022-02-05 15:18:44 +03:00
|
|
|
# ----------- timers -----------
|
2021-12-14 12:51:47 +03:00
|
|
|
def set_timer(self, duration, timerFuncEnd, timerFuncUpd = None):
|
|
|
|
|
# print "Start set_timer!"
|
|
|
|
|
curtime = time.time()
|
|
|
|
|
for i in range(len(self.timers)):
|
|
|
|
|
if self.timers[i] <= 0:
|
|
|
|
|
# print "Found timer!"
|
|
|
|
|
self.timers[i] = curtime+duration #duration
|
|
|
|
|
self.timersFuncEnd[i] = timerFuncEnd
|
|
|
|
|
print("New Timer ID =", str(i), ' curtime=', curtime, 'duration=', duration, 'endtime=', self.timers[i])
|
|
|
|
|
return i
|
|
|
|
|
return -1 # no more timer valid
|
|
|
|
|
|
|
|
|
|
def clear_timer(self, index, runEndFunc=False):
|
|
|
|
|
if runEndFunc and self.timersFuncEnd[index] != None:
|
|
|
|
|
self.call_ext_func(self.timersFuncEnd[index])
|
|
|
|
|
self.timers[index] = -1
|
|
|
|
|
self.timersDuration[index] = 0
|
|
|
|
|
self.timersFuncEnd[index] = None
|
|
|
|
|
|
|
|
|
|
def clear_timers(self): # not calling end function
|
|
|
|
|
for i in range(len(self.timers)):
|
|
|
|
|
if self.timers[i] >= 0:
|
|
|
|
|
self.timers[i] = -1
|
|
|
|
|
self.timersFuncEnd[i] = None
|
|
|
|
|
|
|
|
|
|
def _update_timers(self):
|
|
|
|
|
curtime = time.time()
|
|
|
|
|
for i in range(len(self.timers)):
|
|
|
|
|
if(self.timers[i] > 0):
|
|
|
|
|
if curtime >= self.timers[i]:
|
|
|
|
|
print("End Timer ID =", str(i), ' curtime=', curtime, 'endtime=', self.timers[i])
|
|
|
|
|
self.clear_timer(i,True)
|
|
|
|
|
|
|
|
|
|
# --------- calling functions -----------
|
|
|
|
|
|
|
|
|
|
def call_ext_func(self,funcparam):
|
|
|
|
|
if isinstance(funcparam,tuple): # funcparam =(func, param)
|
|
|
|
|
funcparam[0](self,funcparam[1])
|
|
|
|
|
else: # funcparam = func
|
|
|
|
|
funcparam(self)
|
|
|
|
|
|
|
|
|
|
def call_ext_func_phrase(self,phrase,funcparam):
|
|
|
|
|
if isinstance(funcparam,tuple): # funcparam =(func, param)
|
|
|
|
|
funcparam[0](self,phrase,funcparam[1])
|
|
|
|
|
else: # funcparam = func
|
|
|
|
|
funcparam(self,phrase)
|
|
|
|
|
|
|
|
|
|
# ------- play wav from subfolder ----------
|
|
|
|
|
def play_wav(self,wavfile):
|
2022-04-18 11:30:37 +03:00
|
|
|
self.playwavs[self.playWavEngineId][1](self,wavfile)
|
|
|
|
|
|
2021-12-14 12:51:47 +03:00
|
|
|
|
2022-03-18 12:04:28 +03:00
|
|
|
# -------- raw txt running -----------------
|
|
|
|
|
def run_input_str(self,voice_input_str,func_before_run_cmd = None): # voice_input_str - строка распознавания голоса, разделенная пробелами
|
|
|
|
|
# пример: "ирина таймер пять"
|
2022-03-18 23:13:02 +03:00
|
|
|
haveRun = False
|
|
|
|
|
if voice_input_str == None:
|
|
|
|
|
return False
|
|
|
|
|
|
2022-03-18 12:04:28 +03:00
|
|
|
if self.logPolicy == "all":
|
|
|
|
|
if self.context == None:
|
|
|
|
|
print("Input: ",voice_input_str)
|
|
|
|
|
else:
|
|
|
|
|
print("Input (in context): ",voice_input_str)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
voice_input = voice_input_str.split(" ")
|
|
|
|
|
#callname = voice_input[0]
|
|
|
|
|
haveRun = False
|
|
|
|
|
if self.context == None:
|
|
|
|
|
for ind in range(len(voice_input)):
|
|
|
|
|
callname = voice_input[ind]
|
|
|
|
|
|
|
|
|
|
if callname in self.voiceAssNames: # найдено имя ассистента
|
2023-01-25 11:03:09 +03:00
|
|
|
self.cur_callname = callname
|
2022-03-18 12:04:28 +03:00
|
|
|
if self.logPolicy == "cmd":
|
|
|
|
|
print("Input (cmd): ",voice_input_str)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
command_options = " ".join([str(input_part) for input_part in voice_input[(ind+1):len(voice_input)]])
|
|
|
|
|
|
|
|
|
|
# running some cmd before run cmd
|
|
|
|
|
if func_before_run_cmd != None:
|
|
|
|
|
func_before_run_cmd()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#context = self.context
|
|
|
|
|
#self.context_clear()
|
|
|
|
|
self.execute_next(command_options, None)
|
|
|
|
|
haveRun = True
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
if self.logPolicy == "cmd":
|
|
|
|
|
print("Input (cmd in context): ",voice_input_str)
|
|
|
|
|
|
|
|
|
|
# running some cmd before run cmd
|
|
|
|
|
if func_before_run_cmd != None:
|
|
|
|
|
func_before_run_cmd()
|
|
|
|
|
|
|
|
|
|
self.execute_next(voice_input_str, self.context)
|
|
|
|
|
haveRun = True
|
|
|
|
|
|
|
|
|
|
except Exception as err:
|
|
|
|
|
print(traceback.format_exc())
|
|
|
|
|
|
|
|
|
|
return haveRun
|
|
|
|
|
|
|
|
|
|
# ------------ context handling functions ----------------
|
|
|
|
|
|
|
|
|
|
def context_set(self,context,duration = None):
|
|
|
|
|
if duration == None:
|
2022-05-12 19:53:31 +03:00
|
|
|
duration = self.contextDefaultDuration
|
2022-03-18 12:04:28 +03:00
|
|
|
|
|
|
|
|
self.context_clear()
|
|
|
|
|
|
|
|
|
|
self.context = context
|
|
|
|
|
self.contextTimerLastDuration = duration
|
|
|
|
|
self.contextTimer = Timer(duration,self._context_clear_timer)
|
2022-05-12 19:53:31 +03:00
|
|
|
|
|
|
|
|
remoteTTSList = self.remoteTTS.split(",")
|
|
|
|
|
if self.contextRemoteWaitForCall and ("saytxt" in remoteTTSList or "saywav" in remoteTTSList):
|
|
|
|
|
pass # wait for run context timer
|
|
|
|
|
else:
|
|
|
|
|
self.contextTimer.start()
|
|
|
|
|
|
|
|
|
|
|
2022-03-18 12:04:28 +03:00
|
|
|
|
|
|
|
|
#def _timer_context
|
|
|
|
|
def _context_clear_timer(self):
|
|
|
|
|
print("Context cleared after timeout")
|
|
|
|
|
self.contextTimer = None
|
|
|
|
|
self.context_clear()
|
|
|
|
|
|
|
|
|
|
def context_clear(self):
|
|
|
|
|
self.context = None
|
|
|
|
|
if self.contextTimer != None:
|
|
|
|
|
self.contextTimer.cancel()
|
|
|
|
|
self.contextTimer = None
|
|
|
|
|
|
2022-05-11 22:28:55 +03:00
|
|
|
# ----------- display info functions ------
|
|
|
|
|
|
|
|
|
|
def display_init_info(self):
|
2022-05-12 19:00:42 +03:00
|
|
|
cprint("VoiceAssistantCore v{0}:".format(version), "blue", end=' ')
|
|
|
|
|
print("run ONLINE" if self.isOnline else "run OFFLINE")
|
2022-05-11 22:28:55 +03:00
|
|
|
|
|
|
|
|
self.format_print_key_list("TTS engines", self.ttss.keys())
|
2023-01-03 16:01:31 +03:00
|
|
|
self.format_print_key_list("PlayWavs engines", self.playwavs.keys())
|
2023-01-24 18:00:12 +03:00
|
|
|
self.format_print_key_list("FuzzyProcessor engines", self.fuzzy_processors.keys())
|
2022-05-11 22:28:55 +03:00
|
|
|
self.format_print_key_list("Assistant names", self.voiceAssNames)
|
|
|
|
|
|
2023-01-24 16:55:01 +03:00
|
|
|
|
|
|
|
|
|
2022-05-12 18:45:20 +03:00
|
|
|
cprint("Commands list: "+"#"*65, "blue")
|
2022-05-11 22:28:55 +03:00
|
|
|
for plugin in self.plugin_commands:
|
|
|
|
|
self.format_print_key_list(plugin, self.plugin_commands[plugin])
|
2022-05-12 18:45:20 +03:00
|
|
|
cprint("#"*80, "blue")
|
2022-03-18 12:04:28 +03:00
|
|
|
|
2023-01-24 16:55:01 +03:00
|
|
|
# dump assistant names, cmds, numbers to file
|
|
|
|
|
|
|
|
|
|
# with open("options/commandslist.txt", 'w', encoding="utf-8") as f:
|
|
|
|
|
# for k1 in self.voiceAssNames:
|
|
|
|
|
# f.write(k1 + "\n")
|
|
|
|
|
# for plugin in self.plugin_commands:
|
|
|
|
|
# for k in self.plugin_commands[plugin]:
|
|
|
|
|
# ar_k = str(k).split("|")
|
|
|
|
|
# for k1 in ar_k:
|
|
|
|
|
# f.write(k1 + "\n")
|
|
|
|
|
# import utils.num_to_text_ru
|
|
|
|
|
# for i in range(101):
|
|
|
|
|
# f.write(utils.num_to_text_ru.num2text(i)+"\n")
|
|
|
|
|
|
2022-05-11 22:28:55 +03:00
|
|
|
def format_print_key_list(self, key:str, value:list):
|
2022-05-12 18:45:20 +03:00
|
|
|
print(colored(key+": ", "blue")+", ".join(value))
|